]> Git Repo - qemu.git/blob - hw/apb_pci.c
pci: use PCI_SLOT() and PCI_FUNC().
[qemu.git] / hw / apb_pci.c
1 /*
2  * QEMU Ultrasparc APB PCI host
3  *
4  * Copyright (c) 2006 Fabrice Bellard
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24
25 /* XXX This file and most of its contents are somewhat misnamed.  The
26    Ultrasparc PCI host is called the PCI Bus Module (PBM).  The APB is
27    the secondary PCI bridge.  */
28
29 #include "sysbus.h"
30 #include "pci.h"
31
32 /* debug APB */
33 //#define DEBUG_APB
34
35 #ifdef DEBUG_APB
36 #define APB_DPRINTF(fmt, ...) \
37 do { printf("APB: " fmt , ## __VA_ARGS__); } while (0)
38 #else
39 #define APB_DPRINTF(fmt, ...)
40 #endif
41
42 /*
43  * Chipset docs:
44  * PBM: "UltraSPARC IIi User's Manual",
45  * http://www.sun.com/processors/manuals/805-0087.pdf
46  *
47  * APB: "Advanced PCI Bridge (APB) User's Manual",
48  * http://www.sun.com/processors/manuals/805-1251.pdf
49  */
50
51 typedef target_phys_addr_t pci_addr_t;
52 #include "pci_host.h"
53
54 typedef struct APBState {
55     SysBusDevice busdev;
56     PCIHostState host_state;
57 } APBState;
58
59 static void pci_apb_config_writel (void *opaque, target_phys_addr_t addr,
60                                          uint32_t val)
61 {
62     APBState *s = opaque;
63
64 #ifdef TARGET_WORDS_BIGENDIAN
65     val = bswap32(val);
66 #endif
67     APB_DPRINTF("config_writel addr " TARGET_FMT_plx " val %x\n", addr,
68                 val);
69     s->host_state.config_reg = val;
70 }
71
72 static uint32_t pci_apb_config_readl (void *opaque,
73                                             target_phys_addr_t addr)
74 {
75     APBState *s = opaque;
76     uint32_t val;
77
78     val = s->host_state.config_reg;
79 #ifdef TARGET_WORDS_BIGENDIAN
80     val = bswap32(val);
81 #endif
82     APB_DPRINTF("config_readl addr " TARGET_FMT_plx " val %x\n", addr,
83                 val);
84     return val;
85 }
86
87 static CPUWriteMemoryFunc * const pci_apb_config_write[] = {
88     &pci_apb_config_writel,
89     &pci_apb_config_writel,
90     &pci_apb_config_writel,
91 };
92
93 static CPUReadMemoryFunc * const pci_apb_config_read[] = {
94     &pci_apb_config_readl,
95     &pci_apb_config_readl,
96     &pci_apb_config_readl,
97 };
98
99 static void apb_config_writel (void *opaque, target_phys_addr_t addr,
100                                uint32_t val)
101 {
102     //PCIBus *s = opaque;
103
104     switch (addr & 0x3f) {
105     case 0x00: // Control/Status
106     case 0x10: // AFSR
107     case 0x18: // AFAR
108     case 0x20: // Diagnostic
109     case 0x28: // Target address space
110         // XXX
111     default:
112         break;
113     }
114 }
115
116 static uint32_t apb_config_readl (void *opaque,
117                                   target_phys_addr_t addr)
118 {
119     //PCIBus *s = opaque;
120     uint32_t val;
121
122     switch (addr & 0x3f) {
123     case 0x00: // Control/Status
124     case 0x10: // AFSR
125     case 0x18: // AFAR
126     case 0x20: // Diagnostic
127     case 0x28: // Target address space
128         // XXX
129     default:
130         val = 0;
131         break;
132     }
133     return val;
134 }
135
136 static CPUWriteMemoryFunc * const apb_config_write[] = {
137     &apb_config_writel,
138     &apb_config_writel,
139     &apb_config_writel,
140 };
141
142 static CPUReadMemoryFunc * const apb_config_read[] = {
143     &apb_config_readl,
144     &apb_config_readl,
145     &apb_config_readl,
146 };
147
148 static CPUWriteMemoryFunc * const pci_apb_write[] = {
149     &pci_host_data_writeb,
150     &pci_host_data_writew,
151     &pci_host_data_writel,
152 };
153
154 static CPUReadMemoryFunc * const pci_apb_read[] = {
155     &pci_host_data_readb,
156     &pci_host_data_readw,
157     &pci_host_data_readl,
158 };
159
160 static void pci_apb_iowriteb (void *opaque, target_phys_addr_t addr,
161                                   uint32_t val)
162 {
163     cpu_outb(addr & IOPORTS_MASK, val);
164 }
165
166 static void pci_apb_iowritew (void *opaque, target_phys_addr_t addr,
167                                   uint32_t val)
168 {
169     cpu_outw(addr & IOPORTS_MASK, val);
170 }
171
172 static void pci_apb_iowritel (void *opaque, target_phys_addr_t addr,
173                                 uint32_t val)
174 {
175     cpu_outl(addr & IOPORTS_MASK, val);
176 }
177
178 static uint32_t pci_apb_ioreadb (void *opaque, target_phys_addr_t addr)
179 {
180     uint32_t val;
181
182     val = cpu_inb(addr & IOPORTS_MASK);
183     return val;
184 }
185
186 static uint32_t pci_apb_ioreadw (void *opaque, target_phys_addr_t addr)
187 {
188     uint32_t val;
189
190     val = cpu_inw(addr & IOPORTS_MASK);
191     return val;
192 }
193
194 static uint32_t pci_apb_ioreadl (void *opaque, target_phys_addr_t addr)
195 {
196     uint32_t val;
197
198     val = cpu_inl(addr & IOPORTS_MASK);
199     return val;
200 }
201
202 static CPUWriteMemoryFunc * const pci_apb_iowrite[] = {
203     &pci_apb_iowriteb,
204     &pci_apb_iowritew,
205     &pci_apb_iowritel,
206 };
207
208 static CPUReadMemoryFunc * const pci_apb_ioread[] = {
209     &pci_apb_ioreadb,
210     &pci_apb_ioreadw,
211     &pci_apb_ioreadl,
212 };
213
214 /* The APB host has an IRQ line for each IRQ line of each slot.  */
215 static int pci_apb_map_irq(PCIDevice *pci_dev, int irq_num)
216 {
217     return ((pci_dev->devfn & 0x18) >> 1) + irq_num;
218 }
219
220 static int pci_pbm_map_irq(PCIDevice *pci_dev, int irq_num)
221 {
222     int bus_offset;
223     if (pci_dev->devfn & 1)
224         bus_offset = 16;
225     else
226         bus_offset = 0;
227     return bus_offset + irq_num;
228 }
229
230 static void pci_apb_set_irq(void *opaque, int irq_num, int level)
231 {
232     qemu_irq *pic = opaque;
233
234     /* PCI IRQ map onto the first 32 INO.  */
235     qemu_set_irq(pic[irq_num], level);
236 }
237
238 PCIBus *pci_apb_init(target_phys_addr_t special_base,
239                      target_phys_addr_t mem_base,
240                      qemu_irq *pic, PCIBus **bus2, PCIBus **bus3)
241 {
242     DeviceState *dev;
243     SysBusDevice *s;
244     APBState *d;
245
246     /* Ultrasparc PBM main bus */
247     dev = qdev_create(NULL, "pbm");
248     qdev_init_nofail(dev);
249     s = sysbus_from_qdev(dev);
250     /* apb_config */
251     sysbus_mmio_map(s, 0, special_base + 0x2000ULL);
252     /* pci_ioport */
253     sysbus_mmio_map(s, 1, special_base + 0x2000000ULL);
254     /* mem_config: XXX size should be 4G-prom */
255     sysbus_mmio_map(s, 2, special_base + 0x1000000ULL);
256     /* mem_data */
257     sysbus_mmio_map(s, 3, mem_base);
258     d = FROM_SYSBUS(APBState, s);
259     d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
260                                          pci_apb_set_irq, pci_pbm_map_irq, pic,
261                                          0, 32);
262     pci_create_simple(d->host_state.bus, 0, "pbm");
263     /* APB secondary busses */
264     *bus2 = pci_bridge_init(d->host_state.bus, PCI_DEVFN(1, 0),
265                             PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_SIMBA,
266                             pci_apb_map_irq,
267                             "Advanced PCI Bus secondary bridge 1");
268     *bus3 = pci_bridge_init(d->host_state.bus, PCI_DEVFN(1, 1),
269                             PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_SIMBA,
270                             pci_apb_map_irq,
271                             "Advanced PCI Bus secondary bridge 2");
272
273     return d->host_state.bus;
274 }
275
276 static int pci_pbm_init_device(SysBusDevice *dev)
277 {
278
279     APBState *s;
280     int pci_mem_config, pci_mem_data, apb_config, pci_ioport;
281
282     s = FROM_SYSBUS(APBState, dev);
283     /* apb_config */
284     apb_config = cpu_register_io_memory(apb_config_read,
285                                         apb_config_write, s);
286     sysbus_init_mmio(dev, 0x40ULL, apb_config);
287     /* pci_ioport */
288     pci_ioport = cpu_register_io_memory(pci_apb_ioread,
289                                           pci_apb_iowrite, s);
290     sysbus_init_mmio(dev, 0x10000ULL, pci_ioport);
291     /* mem_config  */
292     pci_mem_config = cpu_register_io_memory(pci_apb_config_read,
293                                             pci_apb_config_write, s);
294     sysbus_init_mmio(dev, 0x10ULL, pci_mem_config);
295     /* mem_data */
296     pci_mem_data = cpu_register_io_memory(pci_apb_read,
297                                           pci_apb_write, &s->host_state);
298     sysbus_init_mmio(dev, 0x10000000ULL, pci_mem_data);
299     return 0;
300 }
301
302 static int pbm_pci_host_init(PCIDevice *d)
303 {
304     pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_SUN);
305     pci_config_set_device_id(d->config, PCI_DEVICE_ID_SUN_SABRE);
306     d->config[0x04] = 0x06; // command = bus master, pci mem
307     d->config[0x05] = 0x00;
308     d->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
309     d->config[0x07] = 0x03; // status = medium devsel
310     d->config[0x08] = 0x00; // revision
311     d->config[0x09] = 0x00; // programming i/f
312     pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
313     d->config[0x0D] = 0x10; // latency_timer
314     d->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
315     return 0;
316 }
317
318 static PCIDeviceInfo pbm_pci_host_info = {
319     .qdev.name = "pbm",
320     .qdev.size = sizeof(PCIDevice),
321     .init      = pbm_pci_host_init,
322 };
323
324 static void pbm_register_devices(void)
325 {
326     sysbus_register_dev("pbm", sizeof(APBState), pci_pbm_init_device);
327     pci_qdev_register(&pbm_pci_host_info);
328 }
329
330 device_init(pbm_register_devices)
This page took 0.041791 seconds and 4 git commands to generate.