xref: /illumos-kvm-cmd/hw/apb_pci.c (revision 68396ea9)
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 #include "pci_host.h"
32 #include "pci_bridge.h"
33 #include "pci_internals.h"
34 #include "rwhandler.h"
35 #include "apb_pci.h"
36 #include "sysemu.h"
37 
38 /* debug APB */
39 //#define DEBUG_APB
40 
41 #ifdef DEBUG_APB
42 #define APB_DPRINTF(fmt, ...) \
43 do { printf("APB: " fmt , ## __VA_ARGS__); } while (0)
44 #else
45 #define APB_DPRINTF(fmt, ...)
46 #endif
47 
48 /*
49  * Chipset docs:
50  * PBM: "UltraSPARC IIi User's Manual",
51  * http://www.sun.com/processors/manuals/805-0087.pdf
52  *
53  * APB: "Advanced PCI Bridge (APB) User's Manual",
54  * http://www.sun.com/processors/manuals/805-1251.pdf
55  */
56 
57 #define PBM_PCI_IMR_MASK    0x7fffffff
58 #define PBM_PCI_IMR_ENABLED 0x80000000
59 
60 #define POR          (1 << 31)
61 #define SOFT_POR     (1 << 30)
62 #define SOFT_XIR     (1 << 29)
63 #define BTN_POR      (1 << 28)
64 #define BTN_XIR      (1 << 27)
65 #define RESET_MASK   0xf8000000
66 #define RESET_WCMASK 0x98000000
67 #define RESET_WMASK  0x60000000
68 
69 typedef struct APBState {
70     SysBusDevice busdev;
71     PCIBus      *bus;
72     ReadWriteHandler pci_config_handler;
73     uint32_t iommu[4];
74     uint32_t pci_control[16];
75     uint32_t pci_irq_map[8];
76     uint32_t obio_irq_map[32];
77     qemu_irq pci_irqs[32];
78     uint32_t reset_control;
79     unsigned int nr_resets;
80 } APBState;
81 
apb_config_writel(void * opaque,target_phys_addr_t addr,uint32_t val)82 static void apb_config_writel (void *opaque, target_phys_addr_t addr,
83                                uint32_t val)
84 {
85     APBState *s = opaque;
86 
87     APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %x\n", __func__, addr, val);
88 
89     switch (addr & 0xffff) {
90     case 0x30 ... 0x4f: /* DMA error registers */
91         /* XXX: not implemented yet */
92         break;
93     case 0x200 ... 0x20b: /* IOMMU */
94         s->iommu[(addr & 0xf) >> 2] = val;
95         break;
96     case 0x20c ... 0x3ff: /* IOMMU flush */
97         break;
98     case 0xc00 ... 0xc3f: /* PCI interrupt control */
99         if (addr & 4) {
100             s->pci_irq_map[(addr & 0x3f) >> 3] &= PBM_PCI_IMR_MASK;
101             s->pci_irq_map[(addr & 0x3f) >> 3] |= val & ~PBM_PCI_IMR_MASK;
102         }
103         break;
104     case 0x2000 ... 0x202f: /* PCI control */
105         s->pci_control[(addr & 0x3f) >> 2] = val;
106         break;
107     case 0xf020 ... 0xf027: /* Reset control */
108         if (addr & 4) {
109             val &= RESET_MASK;
110             s->reset_control &= ~(val & RESET_WCMASK);
111             s->reset_control |= val & RESET_WMASK;
112             if (val & SOFT_POR) {
113                 s->nr_resets = 0;
114                 qemu_system_reset_request();
115             } else if (val & SOFT_XIR) {
116                 qemu_system_reset_request();
117             }
118         }
119         break;
120     case 0x5000 ... 0x51cf: /* PIO/DMA diagnostics */
121     case 0xa400 ... 0xa67f: /* IOMMU diagnostics */
122     case 0xa800 ... 0xa80f: /* Interrupt diagnostics */
123     case 0xf000 ... 0xf01f: /* FFB config, memory control */
124         /* we don't care */
125     default:
126         break;
127     }
128 }
129 
apb_config_readl(void * opaque,target_phys_addr_t addr)130 static uint32_t apb_config_readl (void *opaque,
131                                   target_phys_addr_t addr)
132 {
133     APBState *s = opaque;
134     uint32_t val;
135 
136     switch (addr & 0xffff) {
137     case 0x30 ... 0x4f: /* DMA error registers */
138         val = 0;
139         /* XXX: not implemented yet */
140         break;
141     case 0x200 ... 0x20b: /* IOMMU */
142         val = s->iommu[(addr & 0xf) >> 2];
143         break;
144     case 0x20c ... 0x3ff: /* IOMMU flush */
145         val = 0;
146         break;
147     case 0xc00 ... 0xc3f: /* PCI interrupt control */
148         if (addr & 4) {
149             val = s->pci_irq_map[(addr & 0x3f) >> 3];
150         } else {
151             val = 0;
152         }
153         break;
154     case 0x2000 ... 0x202f: /* PCI control */
155         val = s->pci_control[(addr & 0x3f) >> 2];
156         break;
157     case 0xf020 ... 0xf027: /* Reset control */
158         if (addr & 4) {
159             val = s->reset_control;
160         } else {
161             val = 0;
162         }
163         break;
164     case 0x5000 ... 0x51cf: /* PIO/DMA diagnostics */
165     case 0xa400 ... 0xa67f: /* IOMMU diagnostics */
166     case 0xa800 ... 0xa80f: /* Interrupt diagnostics */
167     case 0xf000 ... 0xf01f: /* FFB config, memory control */
168         /* we don't care */
169     default:
170         val = 0;
171         break;
172     }
173     APB_DPRINTF("%s: addr " TARGET_FMT_lx " -> %x\n", __func__, addr, val);
174 
175     return val;
176 }
177 
178 static CPUWriteMemoryFunc * const apb_config_write[] = {
179     &apb_config_writel,
180     &apb_config_writel,
181     &apb_config_writel,
182 };
183 
184 static CPUReadMemoryFunc * const apb_config_read[] = {
185     &apb_config_readl,
186     &apb_config_readl,
187     &apb_config_readl,
188 };
189 
apb_pci_config_write(ReadWriteHandler * h,pcibus_t addr,uint32_t val,int size)190 static void apb_pci_config_write(ReadWriteHandler *h, pcibus_t addr,
191                                  uint32_t val, int size)
192 {
193     APBState *s = container_of(h, APBState, pci_config_handler);
194 
195     val = qemu_bswap_len(val, size);
196     APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %x\n", __func__, addr, val);
197     pci_data_write(s->bus, addr, val, size);
198 }
199 
apb_pci_config_read(ReadWriteHandler * h,pcibus_t addr,int size)200 static uint32_t apb_pci_config_read(ReadWriteHandler *h, pcibus_t addr,
201                                     int size)
202 {
203     uint32_t ret;
204     APBState *s = container_of(h, APBState, pci_config_handler);
205 
206     ret = pci_data_read(s->bus, addr, size);
207     ret = qemu_bswap_len(ret, size);
208     APB_DPRINTF("%s: addr " TARGET_FMT_lx " -> %x\n", __func__, addr, ret);
209     return ret;
210 }
211 
pci_apb_iowriteb(void * opaque,target_phys_addr_t addr,uint32_t val)212 static void pci_apb_iowriteb (void *opaque, target_phys_addr_t addr,
213                                   uint32_t val)
214 {
215     cpu_outb(addr & IOPORTS_MASK, val);
216 }
217 
pci_apb_iowritew(void * opaque,target_phys_addr_t addr,uint32_t val)218 static void pci_apb_iowritew (void *opaque, target_phys_addr_t addr,
219                                   uint32_t val)
220 {
221     cpu_outw(addr & IOPORTS_MASK, bswap16(val));
222 }
223 
pci_apb_iowritel(void * opaque,target_phys_addr_t addr,uint32_t val)224 static void pci_apb_iowritel (void *opaque, target_phys_addr_t addr,
225                                 uint32_t val)
226 {
227     cpu_outl(addr & IOPORTS_MASK, bswap32(val));
228 }
229 
pci_apb_ioreadb(void * opaque,target_phys_addr_t addr)230 static uint32_t pci_apb_ioreadb (void *opaque, target_phys_addr_t addr)
231 {
232     uint32_t val;
233 
234     val = cpu_inb(addr & IOPORTS_MASK);
235     return val;
236 }
237 
pci_apb_ioreadw(void * opaque,target_phys_addr_t addr)238 static uint32_t pci_apb_ioreadw (void *opaque, target_phys_addr_t addr)
239 {
240     uint32_t val;
241 
242     val = bswap16(cpu_inw(addr & IOPORTS_MASK));
243     return val;
244 }
245 
pci_apb_ioreadl(void * opaque,target_phys_addr_t addr)246 static uint32_t pci_apb_ioreadl (void *opaque, target_phys_addr_t addr)
247 {
248     uint32_t val;
249 
250     val = bswap32(cpu_inl(addr & IOPORTS_MASK));
251     return val;
252 }
253 
254 static CPUWriteMemoryFunc * const pci_apb_iowrite[] = {
255     &pci_apb_iowriteb,
256     &pci_apb_iowritew,
257     &pci_apb_iowritel,
258 };
259 
260 static CPUReadMemoryFunc * const pci_apb_ioread[] = {
261     &pci_apb_ioreadb,
262     &pci_apb_ioreadw,
263     &pci_apb_ioreadl,
264 };
265 
266 /* The APB host has an IRQ line for each IRQ line of each slot.  */
pci_apb_map_irq(PCIDevice * pci_dev,int irq_num)267 static int pci_apb_map_irq(PCIDevice *pci_dev, int irq_num)
268 {
269     return ((pci_dev->devfn & 0x18) >> 1) + irq_num;
270 }
271 
pci_pbm_map_irq(PCIDevice * pci_dev,int irq_num)272 static int pci_pbm_map_irq(PCIDevice *pci_dev, int irq_num)
273 {
274     int bus_offset;
275     if (pci_dev->devfn & 1)
276         bus_offset = 16;
277     else
278         bus_offset = 0;
279     return bus_offset + irq_num;
280 }
281 
pci_apb_set_irq(void * opaque,int irq_num,int level)282 static void pci_apb_set_irq(void *opaque, int irq_num, int level)
283 {
284     APBState *s = opaque;
285 
286     /* PCI IRQ map onto the first 32 INO.  */
287     if (irq_num < 32) {
288         if (s->pci_irq_map[irq_num >> 2] & PBM_PCI_IMR_ENABLED) {
289             APB_DPRINTF("%s: set irq %d level %d\n", __func__, irq_num, level);
290             qemu_set_irq(s->pci_irqs[irq_num], level);
291         } else {
292             APB_DPRINTF("%s: not enabled: lower irq %d\n", __func__, irq_num);
293             qemu_irq_lower(s->pci_irqs[irq_num]);
294         }
295     }
296 }
297 
apb_pci_bridge_initfn(PCIDevice * dev)298 static int apb_pci_bridge_initfn(PCIDevice *dev)
299 {
300     int rc;
301 
302     rc = pci_bridge_initfn(dev);
303     if (rc < 0) {
304         return rc;
305     }
306 
307     pci_config_set_vendor_id(dev->config, PCI_VENDOR_ID_SUN);
308     pci_config_set_device_id(dev->config, PCI_DEVICE_ID_SUN_SIMBA);
309 
310     /*
311      * command register:
312      * According to PCI bridge spec, after reset
313      *   bus master bit is off
314      *   memory space enable bit is off
315      * According to manual (805-1251.pdf).
316      *   the reset value should be zero unless the boot pin is tied high
317      *   (which is true) and thus it should be PCI_COMMAND_MEMORY.
318      */
319     pci_set_word(dev->config + PCI_COMMAND,
320                  PCI_COMMAND_MEMORY);
321     pci_set_word(dev->config + PCI_STATUS,
322                  PCI_STATUS_FAST_BACK | PCI_STATUS_66MHZ |
323                  PCI_STATUS_DEVSEL_MEDIUM);
324     pci_set_byte(dev->config + PCI_REVISION_ID, 0x11);
325     return 0;
326 }
327 
pci_apb_init(target_phys_addr_t special_base,target_phys_addr_t mem_base,qemu_irq * pic,PCIBus ** bus2,PCIBus ** bus3)328 PCIBus *pci_apb_init(target_phys_addr_t special_base,
329                      target_phys_addr_t mem_base,
330                      qemu_irq *pic, PCIBus **bus2, PCIBus **bus3)
331 {
332     DeviceState *dev;
333     SysBusDevice *s;
334     APBState *d;
335     unsigned int i;
336     PCIDevice *pci_dev;
337     PCIBridge *br;
338 
339     /* Ultrasparc PBM main bus */
340     dev = qdev_create(NULL, "pbm");
341     qdev_init_nofail(dev);
342     s = sysbus_from_qdev(dev);
343     /* apb_config */
344     sysbus_mmio_map(s, 0, special_base);
345     /* PCI configuration space */
346     sysbus_mmio_map(s, 1, special_base + 0x1000000ULL);
347     /* pci_ioport */
348     sysbus_mmio_map(s, 2, special_base + 0x2000000ULL);
349     d = FROM_SYSBUS(APBState, s);
350 
351     d->bus = pci_register_bus(&d->busdev.qdev, "pci",
352                                          pci_apb_set_irq, pci_pbm_map_irq, d,
353                                          0, 32);
354     pci_bus_set_mem_base(d->bus, mem_base);
355 
356     for (i = 0; i < 32; i++) {
357         sysbus_connect_irq(s, i, pic[i]);
358     }
359 
360     pci_create_simple(d->bus, 0, "pbm");
361 
362     /* APB secondary busses */
363     pci_dev = pci_create_multifunction(d->bus, PCI_DEVFN(1, 0), true,
364                                    "pbm-bridge");
365     br = DO_UPCAST(PCIBridge, dev, pci_dev);
366     pci_bridge_map_irq(br, "Advanced PCI Bus secondary bridge 1",
367                        pci_apb_map_irq);
368     qdev_init_nofail(&pci_dev->qdev);
369     *bus2 = pci_bridge_get_sec_bus(br);
370 
371     pci_dev = pci_create_multifunction(d->bus, PCI_DEVFN(1, 1), true,
372                                    "pbm-bridge");
373     br = DO_UPCAST(PCIBridge, dev, pci_dev);
374     pci_bridge_map_irq(br, "Advanced PCI Bus secondary bridge 2",
375                        pci_apb_map_irq);
376     qdev_init_nofail(&pci_dev->qdev);
377     *bus3 = pci_bridge_get_sec_bus(br);
378 
379     return d->bus;
380 }
381 
pci_pbm_reset(DeviceState * d)382 static void pci_pbm_reset(DeviceState *d)
383 {
384     unsigned int i;
385     APBState *s = container_of(d, APBState, busdev.qdev);
386 
387     for (i = 0; i < 8; i++) {
388         s->pci_irq_map[i] &= PBM_PCI_IMR_MASK;
389     }
390 
391     if (s->nr_resets++ == 0) {
392         /* Power on reset */
393         s->reset_control = POR;
394     }
395 }
396 
pci_pbm_init_device(SysBusDevice * dev)397 static int pci_pbm_init_device(SysBusDevice *dev)
398 {
399     APBState *s;
400     int pci_config, apb_config, pci_ioport;
401     unsigned int i;
402 
403     s = FROM_SYSBUS(APBState, dev);
404     for (i = 0; i < 8; i++) {
405         s->pci_irq_map[i] = (0x1f << 6) | (i << 2);
406     }
407     for (i = 0; i < 32; i++) {
408         sysbus_init_irq(dev, &s->pci_irqs[i]);
409     }
410 
411     /* apb_config */
412     apb_config = cpu_register_io_memory(apb_config_read,
413                                         apb_config_write, s,
414                                         DEVICE_NATIVE_ENDIAN);
415     /* at region 0 */
416     sysbus_init_mmio(dev, 0x10000ULL, apb_config);
417 
418     /* PCI configuration space */
419     s->pci_config_handler.read = apb_pci_config_read;
420     s->pci_config_handler.write = apb_pci_config_write;
421     pci_config = cpu_register_io_memory_simple(&s->pci_config_handler,
422                                                DEVICE_NATIVE_ENDIAN);
423     assert(pci_config >= 0);
424     /* at region 1 */
425     sysbus_init_mmio(dev, 0x1000000ULL, pci_config);
426 
427     /* pci_ioport */
428     pci_ioport = cpu_register_io_memory(pci_apb_ioread,
429                                         pci_apb_iowrite, s,
430                                         DEVICE_NATIVE_ENDIAN);
431     /* at region 2 */
432     sysbus_init_mmio(dev, 0x10000ULL, pci_ioport);
433 
434     return 0;
435 }
436 
pbm_pci_host_init(PCIDevice * d)437 static int pbm_pci_host_init(PCIDevice *d)
438 {
439     pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_SUN);
440     pci_config_set_device_id(d->config, PCI_DEVICE_ID_SUN_SABRE);
441     pci_set_word(d->config + PCI_COMMAND,
442                  PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
443     pci_set_word(d->config + PCI_STATUS,
444                  PCI_STATUS_FAST_BACK | PCI_STATUS_66MHZ |
445                  PCI_STATUS_DEVSEL_MEDIUM);
446     pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
447     return 0;
448 }
449 
450 static PCIDeviceInfo pbm_pci_host_info = {
451     .qdev.name = "pbm",
452     .qdev.size = sizeof(PCIDevice),
453     .init      = pbm_pci_host_init,
454     .is_bridge = 1,
455 };
456 
457 static SysBusDeviceInfo pbm_host_info = {
458     .qdev.name = "pbm",
459     .qdev.size = sizeof(APBState),
460     .qdev.reset = pci_pbm_reset,
461     .init = pci_pbm_init_device,
462 };
463 
464 static PCIDeviceInfo pbm_pci_bridge_info = {
465     .qdev.name = "pbm-bridge",
466     .qdev.size = sizeof(PCIBridge),
467     .qdev.vmsd = &vmstate_pci_device,
468     .qdev.reset = pci_bridge_reset,
469     .init = apb_pci_bridge_initfn,
470     .exit = pci_bridge_exitfn,
471     .config_write = pci_bridge_write_config,
472     .is_bridge = 1,
473 };
474 
pbm_register_devices(void)475 static void pbm_register_devices(void)
476 {
477     sysbus_register_withprop(&pbm_host_info);
478     pci_qdev_register(&pbm_pci_host_info);
479     pci_qdev_register(&pbm_pci_bridge_info);
480 }
481 
482 device_init(pbm_register_devices)
483