2 * QEMU Ultrasparc APB PCI host
4 * Copyright (c) 2006 Fabrice Bellard
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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
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. */
37 #define APB_DPRINTF(fmt, ...) \
38 do { printf("APB: " fmt , ## __VA_ARGS__); } while (0)
40 #define APB_DPRINTF(fmt, ...)
45 * PBM: "UltraSPARC IIi User's Manual",
46 * http://www.sun.com/processors/manuals/805-0087.pdf
48 * APB: "Advanced PCI Bridge (APB) User's Manual",
49 * http://www.sun.com/processors/manuals/805-1251.pdf
52 typedef struct APBState
{
54 PCIHostState host_state
;
57 static void apb_config_writel (void *opaque
, target_phys_addr_t addr
,
62 switch (addr
& 0x3f) {
63 case 0x00: // Control/Status
66 case 0x20: // Diagnostic
67 case 0x28: // Target address space
74 static uint32_t apb_config_readl (void *opaque
,
75 target_phys_addr_t addr
)
80 switch (addr
& 0x3f) {
81 case 0x00: // Control/Status
84 case 0x20: // Diagnostic
85 case 0x28: // Target address space
94 static CPUWriteMemoryFunc
* const apb_config_write
[] = {
100 static CPUReadMemoryFunc
* const apb_config_read
[] = {
106 static void pci_apb_iowriteb (void *opaque
, target_phys_addr_t addr
,
109 cpu_outb(addr
& IOPORTS_MASK
, val
);
112 static void pci_apb_iowritew (void *opaque
, target_phys_addr_t addr
,
115 cpu_outw(addr
& IOPORTS_MASK
, val
);
118 static void pci_apb_iowritel (void *opaque
, target_phys_addr_t addr
,
121 cpu_outl(addr
& IOPORTS_MASK
, val
);
124 static uint32_t pci_apb_ioreadb (void *opaque
, target_phys_addr_t addr
)
128 val
= cpu_inb(addr
& IOPORTS_MASK
);
132 static uint32_t pci_apb_ioreadw (void *opaque
, target_phys_addr_t addr
)
136 val
= cpu_inw(addr
& IOPORTS_MASK
);
140 static uint32_t pci_apb_ioreadl (void *opaque
, target_phys_addr_t addr
)
144 val
= cpu_inl(addr
& IOPORTS_MASK
);
148 static CPUWriteMemoryFunc
* const pci_apb_iowrite
[] = {
154 static CPUReadMemoryFunc
* const pci_apb_ioread
[] = {
160 /* The APB host has an IRQ line for each IRQ line of each slot. */
161 static int pci_apb_map_irq(PCIDevice
*pci_dev
, int irq_num
)
163 return ((pci_dev
->devfn
& 0x18) >> 1) + irq_num
;
166 static int pci_pbm_map_irq(PCIDevice
*pci_dev
, int irq_num
)
169 if (pci_dev
->devfn
& 1)
173 return bus_offset
+ irq_num
;
176 static void pci_apb_set_irq(void *opaque
, int irq_num
, int level
)
178 qemu_irq
*pic
= opaque
;
180 /* PCI IRQ map onto the first 32 INO. */
181 qemu_set_irq(pic
[irq_num
], level
);
184 PCIBus
*pci_apb_init(target_phys_addr_t special_base
,
185 target_phys_addr_t mem_base
,
186 qemu_irq
*pic
, PCIBus
**bus2
, PCIBus
**bus3
)
192 /* Ultrasparc PBM main bus */
193 dev
= qdev_create(NULL
, "pbm");
194 qdev_init_nofail(dev
);
195 s
= sysbus_from_qdev(dev
);
197 sysbus_mmio_map(s
, 0, special_base
+ 0x2000ULL
);
199 sysbus_mmio_map(s
, 1, special_base
+ 0x2000000ULL
);
200 /* mem_config: XXX size should be 4G-prom */
201 sysbus_mmio_map(s
, 2, special_base
+ 0x1000000ULL
);
203 sysbus_mmio_map(s
, 3, mem_base
);
204 d
= FROM_SYSBUS(APBState
, s
);
205 d
->host_state
.bus
= pci_register_bus(&d
->busdev
.qdev
, "pci",
206 pci_apb_set_irq
, pci_pbm_map_irq
, pic
,
208 pci_create_simple(d
->host_state
.bus
, 0, "pbm");
209 /* APB secondary busses */
210 *bus2
= pci_bridge_init(d
->host_state
.bus
, PCI_DEVFN(1, 0),
211 PCI_VENDOR_ID_SUN
, PCI_DEVICE_ID_SUN_SIMBA
,
213 "Advanced PCI Bus secondary bridge 1");
214 *bus3
= pci_bridge_init(d
->host_state
.bus
, PCI_DEVFN(1, 1),
215 PCI_VENDOR_ID_SUN
, PCI_DEVICE_ID_SUN_SIMBA
,
217 "Advanced PCI Bus secondary bridge 2");
219 return d
->host_state
.bus
;
222 static int pci_pbm_init_device(SysBusDevice
*dev
)
226 int pci_mem_config
, pci_mem_data
, apb_config
, pci_ioport
;
228 s
= FROM_SYSBUS(APBState
, dev
);
230 apb_config
= cpu_register_io_memory(apb_config_read
,
231 apb_config_write
, s
);
232 sysbus_init_mmio(dev
, 0x40ULL
, apb_config
);
234 pci_ioport
= cpu_register_io_memory(pci_apb_ioread
,
236 sysbus_init_mmio(dev
, 0x10000ULL
, pci_ioport
);
238 pci_mem_config
= pci_host_config_register_io_memory(&s
->host_state
);
239 sysbus_init_mmio(dev
, 0x10ULL
, pci_mem_config
);
241 pci_mem_data
= pci_host_data_register_io_memory(&s
->host_state
);
242 sysbus_init_mmio(dev
, 0x10000000ULL
, pci_mem_data
);
246 static int pbm_pci_host_init(PCIDevice
*d
)
248 pci_config_set_vendor_id(d
->config
, PCI_VENDOR_ID_SUN
);
249 pci_config_set_device_id(d
->config
, PCI_DEVICE_ID_SUN_SABRE
);
250 d
->config
[0x04] = 0x06; // command = bus master, pci mem
251 d
->config
[0x05] = 0x00;
252 d
->config
[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
253 d
->config
[0x07] = 0x03; // status = medium devsel
254 d
->config
[0x08] = 0x00; // revision
255 d
->config
[0x09] = 0x00; // programming i/f
256 pci_config_set_class(d
->config
, PCI_CLASS_BRIDGE_HOST
);
257 d
->config
[0x0D] = 0x10; // latency_timer
258 d
->config
[PCI_HEADER_TYPE
] = PCI_HEADER_TYPE_NORMAL
; // header_type
262 static PCIDeviceInfo pbm_pci_host_info
= {
264 .qdev
.size
= sizeof(PCIDevice
),
265 .init
= pbm_pci_host_init
,
268 static void pbm_register_devices(void)
270 sysbus_register_dev("pbm", sizeof(APBState
), pci_pbm_init_device
);
271 pci_qdev_register(&pbm_pci_host_info
);
274 device_init(pbm_register_devices
)