2 * QEMU Ultrasparc APB PCI host
4 * Copyright (c) 2006 Fabrice Bellard
5 * Copyright (c) 2012,2013 Artyom Tarasenko
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 /* XXX This file and most of its contents are somewhat misnamed. The
27 Ultrasparc PCI host is called the PCI Bus Module (PBM). The APB is
28 the secondary PCI bridge. */
30 #include "hw/sysbus.h"
31 #include "hw/pci/pci.h"
32 #include "hw/pci/pci_host.h"
33 #include "hw/pci/pci_bridge.h"
34 #include "hw/pci/pci_bus.h"
35 #include "hw/pci-host/apb.h"
36 #include "sysemu/sysemu.h"
37 #include "exec/address-spaces.h"
43 #define APB_DPRINTF(fmt, ...) \
44 do { printf("APB: " fmt , ## __VA_ARGS__); } while (0)
46 #define APB_DPRINTF(fmt, ...)
51 * PBM: "UltraSPARC IIi User's Manual",
52 * http://www.sun.com/processors/manuals/805-0087.pdf
54 * APB: "Advanced PCI Bridge (APB) User's Manual",
55 * http://www.sun.com/processors/manuals/805-1251.pdf
58 #define PBM_PCI_IMR_MASK 0x7fffffff
59 #define PBM_PCI_IMR_ENABLED 0x80000000
62 #define SOFT_POR (1 << 30)
63 #define SOFT_XIR (1 << 29)
64 #define BTN_POR (1 << 28)
65 #define BTN_XIR (1 << 27)
66 #define RESET_MASK 0xf8000000
67 #define RESET_WCMASK 0x98000000
68 #define RESET_WMASK 0x60000000
71 #define NO_IRQ_REQUEST (MAX_IVEC + 1)
73 typedef struct APBState
{
76 MemoryRegion apb_config
;
77 MemoryRegion pci_config
;
78 MemoryRegion pci_mmio
;
79 MemoryRegion pci_ioport
;
82 uint32_t pci_control
[16];
83 uint32_t pci_irq_map
[8];
84 uint32_t obio_irq_map
[32];
87 unsigned int irq_request
;
88 uint32_t reset_control
;
89 unsigned int nr_resets
;
92 static inline void pbm_set_request(APBState
*s
, unsigned int irq_num
)
94 APB_DPRINTF("%s: request irq %d\n", __func__
, irq_num
);
96 s
->irq_request
= irq_num
;
97 qemu_set_irq(s
->ivec_irqs
[irq_num
], 1);
100 static inline void pbm_check_irqs(APBState
*s
)
105 /* Previous request is not acknowledged, resubmit */
106 if (s
->irq_request
!= NO_IRQ_REQUEST
) {
107 pbm_set_request(s
, s
->irq_request
);
110 /* no request pending */
111 if (s
->pci_irq_in
== 0ULL) {
114 for (i
= 0; i
< 32; i
++) {
115 if (s
->pci_irq_in
& (1ULL << i
)) {
116 if (s
->pci_irq_map
[i
>> 2] & PBM_PCI_IMR_ENABLED
) {
117 pbm_set_request(s
, i
);
122 for (i
= 32; i
< 64; i
++) {
123 if (s
->pci_irq_in
& (1ULL << i
)) {
124 if (s
->obio_irq_map
[i
- 32] & PBM_PCI_IMR_ENABLED
) {
125 pbm_set_request(s
, i
);
132 static inline void pbm_clear_request(APBState
*s
, unsigned int irq_num
)
134 APB_DPRINTF("%s: clear request irq %d\n", __func__
, irq_num
);
135 qemu_set_irq(s
->ivec_irqs
[irq_num
], 0);
136 s
->irq_request
= NO_IRQ_REQUEST
;
139 static void apb_config_writel (void *opaque
, hwaddr addr
,
140 uint64_t val
, unsigned size
)
142 APBState
*s
= opaque
;
144 APB_DPRINTF("%s: addr " TARGET_FMT_plx
" val %" PRIx64
"\n", __func__
, addr
, val
);
146 switch (addr
& 0xffff) {
147 case 0x30 ... 0x4f: /* DMA error registers */
148 /* XXX: not implemented yet */
150 case 0x200 ... 0x20b: /* IOMMU */
151 s
->iommu
[(addr
& 0xf) >> 2] = val
;
153 case 0x20c ... 0x3ff: /* IOMMU flush */
155 case 0xc00 ... 0xc3f: /* PCI interrupt control */
157 unsigned int ino
= (addr
& 0x3f) >> 3;
158 s
->pci_irq_map
[ino
] &= PBM_PCI_IMR_MASK
;
159 s
->pci_irq_map
[ino
] |= val
& ~PBM_PCI_IMR_MASK
;
160 if ((s
->irq_request
== ino
) && !(val
& ~PBM_PCI_IMR_MASK
)) {
161 pbm_clear_request(s
, ino
);
166 case 0x1000 ... 0x1080: /* OBIO interrupt control */
168 unsigned int ino
= ((addr
& 0xff) >> 3);
169 s
->obio_irq_map
[ino
] &= PBM_PCI_IMR_MASK
;
170 s
->obio_irq_map
[ino
] |= val
& ~PBM_PCI_IMR_MASK
;
171 if ((s
->irq_request
== (ino
| 0x20))
172 && !(val
& ~PBM_PCI_IMR_MASK
)) {
173 pbm_clear_request(s
, ino
| 0x20);
178 case 0x1400 ... 0x14ff: /* PCI interrupt clear */
180 unsigned int ino
= (addr
& 0xff) >> 5;
181 if ((s
->irq_request
/ 4) == ino
) {
182 pbm_clear_request(s
, s
->irq_request
);
187 case 0x1800 ... 0x1860: /* OBIO interrupt clear */
189 unsigned int ino
= ((addr
& 0xff) >> 3) | 0x20;
190 if (s
->irq_request
== ino
) {
191 pbm_clear_request(s
, ino
);
196 case 0x2000 ... 0x202f: /* PCI control */
197 s
->pci_control
[(addr
& 0x3f) >> 2] = val
;
199 case 0xf020 ... 0xf027: /* Reset control */
202 s
->reset_control
&= ~(val
& RESET_WCMASK
);
203 s
->reset_control
|= val
& RESET_WMASK
;
204 if (val
& SOFT_POR
) {
206 qemu_system_reset_request();
207 } else if (val
& SOFT_XIR
) {
208 qemu_system_reset_request();
212 case 0x5000 ... 0x51cf: /* PIO/DMA diagnostics */
213 case 0xa400 ... 0xa67f: /* IOMMU diagnostics */
214 case 0xa800 ... 0xa80f: /* Interrupt diagnostics */
215 case 0xf000 ... 0xf01f: /* FFB config, memory control */
222 static uint64_t apb_config_readl (void *opaque
,
223 hwaddr addr
, unsigned size
)
225 APBState
*s
= opaque
;
228 switch (addr
& 0xffff) {
229 case 0x30 ... 0x4f: /* DMA error registers */
231 /* XXX: not implemented yet */
233 case 0x200 ... 0x20b: /* IOMMU */
234 val
= s
->iommu
[(addr
& 0xf) >> 2];
236 case 0x20c ... 0x3ff: /* IOMMU flush */
239 case 0xc00 ... 0xc3f: /* PCI interrupt control */
241 val
= s
->pci_irq_map
[(addr
& 0x3f) >> 3];
246 case 0x1000 ... 0x1080: /* OBIO interrupt control */
248 val
= s
->obio_irq_map
[(addr
& 0xff) >> 3];
253 case 0x2000 ... 0x202f: /* PCI control */
254 val
= s
->pci_control
[(addr
& 0x3f) >> 2];
256 case 0xf020 ... 0xf027: /* Reset control */
258 val
= s
->reset_control
;
263 case 0x5000 ... 0x51cf: /* PIO/DMA diagnostics */
264 case 0xa400 ... 0xa67f: /* IOMMU diagnostics */
265 case 0xa800 ... 0xa80f: /* Interrupt diagnostics */
266 case 0xf000 ... 0xf01f: /* FFB config, memory control */
272 APB_DPRINTF("%s: addr " TARGET_FMT_plx
" -> %x\n", __func__
, addr
, val
);
277 static const MemoryRegionOps apb_config_ops
= {
278 .read
= apb_config_readl
,
279 .write
= apb_config_writel
,
280 .endianness
= DEVICE_NATIVE_ENDIAN
,
283 static void apb_pci_config_write(void *opaque
, hwaddr addr
,
284 uint64_t val
, unsigned size
)
286 APBState
*s
= opaque
;
288 val
= qemu_bswap_len(val
, size
);
289 APB_DPRINTF("%s: addr " TARGET_FMT_plx
" val %" PRIx64
"\n", __func__
, addr
, val
);
290 pci_data_write(s
->bus
, addr
, val
, size
);
293 static uint64_t apb_pci_config_read(void *opaque
, hwaddr addr
,
297 APBState
*s
= opaque
;
299 ret
= pci_data_read(s
->bus
, addr
, size
);
300 ret
= qemu_bswap_len(ret
, size
);
301 APB_DPRINTF("%s: addr " TARGET_FMT_plx
" -> %x\n", __func__
, addr
, ret
);
305 static void pci_apb_iowriteb (void *opaque
, hwaddr addr
,
308 cpu_outb(addr
& IOPORTS_MASK
, val
);
311 static void pci_apb_iowritew (void *opaque
, hwaddr addr
,
314 cpu_outw(addr
& IOPORTS_MASK
, bswap16(val
));
317 static void pci_apb_iowritel (void *opaque
, hwaddr addr
,
320 cpu_outl(addr
& IOPORTS_MASK
, bswap32(val
));
323 static uint32_t pci_apb_ioreadb (void *opaque
, hwaddr addr
)
327 val
= cpu_inb(addr
& IOPORTS_MASK
);
331 static uint32_t pci_apb_ioreadw (void *opaque
, hwaddr addr
)
335 val
= bswap16(cpu_inw(addr
& IOPORTS_MASK
));
339 static uint32_t pci_apb_ioreadl (void *opaque
, hwaddr addr
)
343 val
= bswap32(cpu_inl(addr
& IOPORTS_MASK
));
347 static const MemoryRegionOps pci_ioport_ops
= {
349 .read
= { pci_apb_ioreadb
, pci_apb_ioreadw
, pci_apb_ioreadl
},
350 .write
= { pci_apb_iowriteb
, pci_apb_iowritew
, pci_apb_iowritel
, },
352 .endianness
= DEVICE_NATIVE_ENDIAN
,
355 /* The APB host has an IRQ line for each IRQ line of each slot. */
356 static int pci_apb_map_irq(PCIDevice
*pci_dev
, int irq_num
)
358 return ((pci_dev
->devfn
& 0x18) >> 1) + irq_num
;
361 static int pci_pbm_map_irq(PCIDevice
*pci_dev
, int irq_num
)
364 if (pci_dev
->devfn
& 1)
368 return (bus_offset
+ (PCI_SLOT(pci_dev
->devfn
) << 2) + irq_num
) & 0x1f;
371 static void pci_apb_set_irq(void *opaque
, int irq_num
, int level
)
373 APBState
*s
= opaque
;
375 APB_DPRINTF("%s: set irq_in %d level %d\n", __func__
, irq_num
, level
);
376 /* PCI IRQ map onto the first 32 INO. */
379 s
->pci_irq_in
|= 1ULL << irq_num
;
380 if (s
->pci_irq_map
[irq_num
>> 2] & PBM_PCI_IMR_ENABLED
) {
381 pbm_set_request(s
, irq_num
);
384 s
->pci_irq_in
&= ~(1ULL << irq_num
);
387 /* OBIO IRQ map onto the next 32 INO. */
389 APB_DPRINTF("%s: set irq %d level %d\n", __func__
, irq_num
, level
);
390 s
->pci_irq_in
|= 1ULL << irq_num
;
391 if ((s
->irq_request
== NO_IRQ_REQUEST
)
392 && (s
->obio_irq_map
[irq_num
- 32] & PBM_PCI_IMR_ENABLED
)) {
393 pbm_set_request(s
, irq_num
);
396 s
->pci_irq_in
&= ~(1ULL << irq_num
);
401 static int apb_pci_bridge_initfn(PCIDevice
*dev
)
405 rc
= pci_bridge_initfn(dev
, TYPE_PCI_BUS
);
412 * According to PCI bridge spec, after reset
413 * bus master bit is off
414 * memory space enable bit is off
415 * According to manual (805-1251.pdf).
416 * the reset value should be zero unless the boot pin is tied high
417 * (which is true) and thus it should be PCI_COMMAND_MEMORY.
419 pci_set_word(dev
->config
+ PCI_COMMAND
,
421 pci_set_word(dev
->config
+ PCI_STATUS
,
422 PCI_STATUS_FAST_BACK
| PCI_STATUS_66MHZ
|
423 PCI_STATUS_DEVSEL_MEDIUM
);
427 PCIBus
*pci_apb_init(hwaddr special_base
,
429 qemu_irq
*ivec_irqs
, PCIBus
**bus2
, PCIBus
**bus3
,
438 /* Ultrasparc PBM main bus */
439 dev
= qdev_create(NULL
, "pbm");
440 qdev_init_nofail(dev
);
441 s
= SYS_BUS_DEVICE(dev
);
443 sysbus_mmio_map(s
, 0, special_base
);
444 /* PCI configuration space */
445 sysbus_mmio_map(s
, 1, special_base
+ 0x1000000ULL
);
447 sysbus_mmio_map(s
, 2, special_base
+ 0x2000000ULL
);
448 d
= FROM_SYSBUS(APBState
, s
);
450 memory_region_init(&d
->pci_mmio
, "pci-mmio", 0x100000000ULL
);
451 memory_region_add_subregion(get_system_memory(), mem_base
, &d
->pci_mmio
);
453 d
->bus
= pci_register_bus(&d
->busdev
.qdev
, "pci",
454 pci_apb_set_irq
, pci_pbm_map_irq
, d
,
457 0, 32, TYPE_PCI_BUS
);
459 *pbm_irqs
= d
->pbm_irqs
;
460 d
->ivec_irqs
= ivec_irqs
;
462 pci_create_simple(d
->bus
, 0, "pbm-pci");
464 /* APB secondary busses */
465 pci_dev
= pci_create_multifunction(d
->bus
, PCI_DEVFN(1, 0), true,
467 br
= DO_UPCAST(PCIBridge
, dev
, pci_dev
);
468 pci_bridge_map_irq(br
, "Advanced PCI Bus secondary bridge 1",
470 qdev_init_nofail(&pci_dev
->qdev
);
471 *bus2
= pci_bridge_get_sec_bus(br
);
473 pci_dev
= pci_create_multifunction(d
->bus
, PCI_DEVFN(1, 1), true,
475 br
= DO_UPCAST(PCIBridge
, dev
, pci_dev
);
476 pci_bridge_map_irq(br
, "Advanced PCI Bus secondary bridge 2",
478 qdev_init_nofail(&pci_dev
->qdev
);
479 *bus3
= pci_bridge_get_sec_bus(br
);
484 static void pci_pbm_reset(DeviceState
*d
)
487 APBState
*s
= container_of(d
, APBState
, busdev
.qdev
);
489 for (i
= 0; i
< 8; i
++) {
490 s
->pci_irq_map
[i
] &= PBM_PCI_IMR_MASK
;
492 for (i
= 0; i
< 32; i
++) {
493 s
->obio_irq_map
[i
] &= PBM_PCI_IMR_MASK
;
496 s
->irq_request
= NO_IRQ_REQUEST
;
497 s
->pci_irq_in
= 0ULL;
499 if (s
->nr_resets
++ == 0) {
501 s
->reset_control
= POR
;
505 static const MemoryRegionOps pci_config_ops
= {
506 .read
= apb_pci_config_read
,
507 .write
= apb_pci_config_write
,
508 .endianness
= DEVICE_NATIVE_ENDIAN
,
511 static int pci_pbm_init_device(SysBusDevice
*dev
)
516 s
= FROM_SYSBUS(APBState
, dev
);
517 for (i
= 0; i
< 8; i
++) {
518 s
->pci_irq_map
[i
] = (0x1f << 6) | (i
<< 2);
520 for (i
= 0; i
< 32; i
++) {
521 s
->obio_irq_map
[i
] = ((0x1f << 6) | 0x20) + i
;
523 s
->pbm_irqs
= qemu_allocate_irqs(pci_apb_set_irq
, s
, MAX_IVEC
);
524 s
->irq_request
= NO_IRQ_REQUEST
;
525 s
->pci_irq_in
= 0ULL;
528 memory_region_init_io(&s
->apb_config
, &apb_config_ops
, s
, "apb-config",
531 sysbus_init_mmio(dev
, &s
->apb_config
);
533 memory_region_init_io(&s
->pci_config
, &pci_config_ops
, s
, "apb-pci-config",
536 sysbus_init_mmio(dev
, &s
->pci_config
);
539 memory_region_init_io(&s
->pci_ioport
, &pci_ioport_ops
, s
,
540 "apb-pci-ioport", 0x10000);
542 sysbus_init_mmio(dev
, &s
->pci_ioport
);
547 static int pbm_pci_host_init(PCIDevice
*d
)
549 pci_set_word(d
->config
+ PCI_COMMAND
,
550 PCI_COMMAND_MEMORY
| PCI_COMMAND_MASTER
);
551 pci_set_word(d
->config
+ PCI_STATUS
,
552 PCI_STATUS_FAST_BACK
| PCI_STATUS_66MHZ
|
553 PCI_STATUS_DEVSEL_MEDIUM
);
557 static void pbm_pci_host_class_init(ObjectClass
*klass
, void *data
)
559 PCIDeviceClass
*k
= PCI_DEVICE_CLASS(klass
);
561 k
->init
= pbm_pci_host_init
;
562 k
->vendor_id
= PCI_VENDOR_ID_SUN
;
563 k
->device_id
= PCI_DEVICE_ID_SUN_SABRE
;
564 k
->class_id
= PCI_CLASS_BRIDGE_HOST
;
567 static const TypeInfo pbm_pci_host_info
= {
569 .parent
= TYPE_PCI_DEVICE
,
570 .instance_size
= sizeof(PCIDevice
),
571 .class_init
= pbm_pci_host_class_init
,
574 static void pbm_host_class_init(ObjectClass
*klass
, void *data
)
576 DeviceClass
*dc
= DEVICE_CLASS(klass
);
577 SysBusDeviceClass
*k
= SYS_BUS_DEVICE_CLASS(klass
);
579 k
->init
= pci_pbm_init_device
;
580 dc
->reset
= pci_pbm_reset
;
583 static const TypeInfo pbm_host_info
= {
585 .parent
= TYPE_SYS_BUS_DEVICE
,
586 .instance_size
= sizeof(APBState
),
587 .class_init
= pbm_host_class_init
,
590 static void pbm_pci_bridge_class_init(ObjectClass
*klass
, void *data
)
592 DeviceClass
*dc
= DEVICE_CLASS(klass
);
593 PCIDeviceClass
*k
= PCI_DEVICE_CLASS(klass
);
595 k
->init
= apb_pci_bridge_initfn
;
596 k
->exit
= pci_bridge_exitfn
;
597 k
->vendor_id
= PCI_VENDOR_ID_SUN
;
598 k
->device_id
= PCI_DEVICE_ID_SUN_SIMBA
;
600 k
->config_write
= pci_bridge_write_config
;
602 dc
->reset
= pci_bridge_reset
;
603 dc
->vmsd
= &vmstate_pci_device
;
606 static const TypeInfo pbm_pci_bridge_info
= {
607 .name
= "pbm-bridge",
608 .parent
= TYPE_PCI_DEVICE
,
609 .instance_size
= sizeof(PCIBridge
),
610 .class_init
= pbm_pci_bridge_class_init
,
613 static void pbm_register_types(void)
615 type_register_static(&pbm_host_info
);
616 type_register_static(&pbm_pci_host_info
);
617 type_register_static(&pbm_pci_bridge_info
);
620 type_init(pbm_register_types
)