1 /*
2  *  Copyright (C) 2005-2009  Anders Gavare.  All rights reserved.
3  *
4  *  Redistribution and use in source and binary forms, with or without
5  *  modification, are permitted provided that the following conditions are met:
6  *
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. The name of the author may not be used to endorse or promote products
13  *     derived from this software without specific prior written permission.
14  *
15  *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  *  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  *  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  *  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  *  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  *  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  *  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  *  SUCH DAMAGE.
26  *
27  *
28  *  COMMENT: Uni-North PCI controller (used by MacPPC machines)
29  */
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 
35 #include "bus_pci.h"
36 #include "cpu.h"
37 #include "devices.h"
38 #include "machine.h"
39 #include "memory.h"
40 #include "misc.h"
41 
42 
43 struct uninorth_data {
44 	int		pciirq;
45 
46 	struct pci_data	*pci_data;
47 	uint64_t	cur_addr;
48 };
49 
50 
DEVICE_ACCESS(uninorth_addr)51 DEVICE_ACCESS(uninorth_addr)
52 {
53 	struct uninorth_data *d = (struct uninorth_data *) extra;
54 
55 	if (writeflag == MEM_WRITE) {
56 		uint64_t idata = memory_readmax64(cpu, data, len
57 		    | MEM_PCI_LITTLE_ENDIAN);
58 		int bus, dev, func, reg;
59 
60 		d->cur_addr = idata;
61 		if (idata == 0)
62 			return 0;
63 
64 		/*  Decompose the Uni-North tag:  */
65 		if (idata & 1) {
66 			idata &= ~1;
67 			bus_pci_decompose_1(idata, &bus, &dev, &func, &reg);
68 		} else {
69 			bus = 0;
70 			for (dev=11; dev<32; dev++)
71 				if (idata & (1 << dev))
72 					break;
73 			if (dev == 32)
74 				fatal("[ dev_uninorth_addr_access: no dev? "
75 				    "idata=0x%08x ]\n", (int)idata);
76 
77 			func = (idata >> 8) & 7;
78 			reg = idata & 0xff;
79 		}
80 
81 		bus_pci_setaddr(cpu, d->pci_data, bus, dev, func, reg);
82 	} else {
83 		/*  TODO: is returning the current address like this
84 		    the correct behaviour?  */
85 		memory_writemax64(cpu, data, len | MEM_PCI_LITTLE_ENDIAN,
86 		    d->cur_addr);
87 	}
88 
89 	return 1;
90 }
91 
92 
DEVICE_ACCESS(uninorth_data)93 DEVICE_ACCESS(uninorth_data)
94 {
95 	struct uninorth_data *d = (struct uninorth_data *) extra;
96 	uint64_t idata = 0, odata = 0;
97 
98 	if (writeflag == MEM_WRITE)
99 		idata = memory_readmax64(cpu, data, len|MEM_PCI_LITTLE_ENDIAN);
100 
101 	bus_pci_data_access(cpu, d->pci_data, writeflag == MEM_READ? &odata :
102 	    &idata, len, writeflag);
103 
104 	if (writeflag == MEM_READ)
105 		memory_writemax64(cpu, data, len|MEM_PCI_LITTLE_ENDIAN, odata);
106 
107 	return 1;
108 }
109 
110 
dev_uninorth_init(struct machine * machine,struct memory * mem,uint64_t addr,int isa_irqbase,int pciirq)111 struct pci_data *dev_uninorth_init(struct machine *machine, struct memory *mem,
112 	uint64_t addr, int isa_irqbase, int pciirq)
113 {
114 	struct uninorth_data *d;
115 	uint64_t pci_io_offset, pci_mem_offset;
116 	uint64_t isa_portbase = 0, isa_membase = 0;
117 	uint64_t pci_portbase = 0, pci_membase = 0;
118 
119 	CHECK_ALLOCATION(d = (struct uninorth_data *) malloc(sizeof(struct uninorth_data)));
120 	memset(d, 0, sizeof(struct uninorth_data));
121 
122 	d->pciirq = pciirq;
123 
124 	pci_io_offset  = 0x00000000ULL;
125 	pci_mem_offset = 0x00000000ULL;
126 	pci_portbase   = 0xd0000000ULL;
127 	pci_membase    = 0xd1000000ULL;
128 	isa_portbase   = 0xd2000000ULL;
129 	isa_membase    = 0xd3000000ULL;
130 
131 	/*  Create a PCI bus:  */
132 	d->pci_data = bus_pci_init(machine, "ZZZ_irq_stuff",
133 	    pci_io_offset, pci_mem_offset,
134 	    pci_portbase, pci_membase, "XXX_pci_irqbase",
135 	    isa_portbase, isa_membase, "YYY_isa_irqbase");
136 
137 	/*  Add the PCI glue for the controller itself:  */
138 	bus_pci_add(machine, d->pci_data, mem, 0, 11, 0, "uninorth");
139 
140 	/*  ADDR and DATA configuration ports:  */
141 	memory_device_register(mem, "uninorth_pci_addr", addr + 0x800000,
142 	    4, dev_uninorth_addr_access, d, DM_DEFAULT, NULL);
143 	memory_device_register(mem, "uninorth_pci_data", addr + 0xc00000,
144 	    8, dev_uninorth_data_access, d, DM_DEFAULT, NULL);
145 
146 	return d->pci_data;
147 }
148 
149