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, ®);
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