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. */
36 #define APB_DPRINTF(fmt, ...) \
37 do { printf("APB: " fmt , ## __VA_ARGS__); } while (0)
39 #define APB_DPRINTF(fmt, ...)
44 * PBM: "UltraSPARC IIi User's Manual",
45 * http://www.sun.com/processors/manuals/805-0087.pdf
47 * APB: "Advanced PCI Bridge (APB) User's Manual",
48 * http://www.sun.com/processors/manuals/805-1251.pdf
51 typedef target_phys_addr_t pci_addr_t
;
54 typedef struct APBState
{
56 PCIHostState host_state
;
59 static void pci_apb_config_writel (void *opaque
, target_phys_addr_t addr
,
64 #ifdef TARGET_WORDS_BIGENDIAN
67 APB_DPRINTF("config_writel addr " TARGET_FMT_plx
" val %x\n", addr
,
69 s
->host_state
.config_reg
= val
;
72 static uint32_t pci_apb_config_readl (void *opaque
,
73 target_phys_addr_t addr
)
78 val
= s
->host_state
.config_reg
;
79 #ifdef TARGET_WORDS_BIGENDIAN
82 APB_DPRINTF("config_readl addr " TARGET_FMT_plx
" val %x\n", addr
,
87 static CPUWriteMemoryFunc
* const pci_apb_config_write
[] = {
88 &pci_apb_config_writel
,
89 &pci_apb_config_writel
,
90 &pci_apb_config_writel
,
93 static CPUReadMemoryFunc
* const pci_apb_config_read
[] = {
94 &pci_apb_config_readl
,
95 &pci_apb_config_readl
,
96 &pci_apb_config_readl
,
99 static void apb_config_writel (void *opaque
, target_phys_addr_t addr
,
102 //PCIBus *s = opaque;
104 switch (addr
& 0x3f) {
105 case 0x00: // Control/Status
108 case 0x20: // Diagnostic
109 case 0x28: // Target address space
116 static uint32_t apb_config_readl (void *opaque
,
117 target_phys_addr_t addr
)
119 //PCIBus *s = opaque;
122 switch (addr
& 0x3f) {
123 case 0x00: // Control/Status
126 case 0x20: // Diagnostic
127 case 0x28: // Target address space
136 static CPUWriteMemoryFunc
* const apb_config_write
[] = {
142 static CPUReadMemoryFunc
* const apb_config_read
[] = {
148 static CPUWriteMemoryFunc
* const pci_apb_write
[] = {
149 &pci_host_data_writeb
,
150 &pci_host_data_writew
,
151 &pci_host_data_writel
,
154 static CPUReadMemoryFunc
* const pci_apb_read
[] = {
155 &pci_host_data_readb
,
156 &pci_host_data_readw
,
157 &pci_host_data_readl
,
160 static void pci_apb_iowriteb (void *opaque
, target_phys_addr_t addr
,
163 cpu_outb(addr
& IOPORTS_MASK
, val
);
166 static void pci_apb_iowritew (void *opaque
, target_phys_addr_t addr
,
169 cpu_outw(addr
& IOPORTS_MASK
, val
);
172 static void pci_apb_iowritel (void *opaque
, target_phys_addr_t addr
,
175 cpu_outl(addr
& IOPORTS_MASK
, val
);
178 static uint32_t pci_apb_ioreadb (void *opaque
, target_phys_addr_t addr
)
182 val
= cpu_inb(addr
& IOPORTS_MASK
);
186 static uint32_t pci_apb_ioreadw (void *opaque
, target_phys_addr_t addr
)
190 val
= cpu_inw(addr
& IOPORTS_MASK
);
194 static uint32_t pci_apb_ioreadl (void *opaque
, target_phys_addr_t addr
)
198 val
= cpu_inl(addr
& IOPORTS_MASK
);
202 static CPUWriteMemoryFunc
* const pci_apb_iowrite
[] = {
208 static CPUReadMemoryFunc
* const pci_apb_ioread
[] = {
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
)
217 return ((pci_dev
->devfn
& 0x18) >> 1) + irq_num
;
220 static int pci_pbm_map_irq(PCIDevice
*pci_dev
, int irq_num
)
223 if (pci_dev
->devfn
& 1)
227 return bus_offset
+ irq_num
;
230 static void pci_apb_set_irq(void *opaque
, int irq_num
, int level
)
232 qemu_irq
*pic
= opaque
;
234 /* PCI IRQ map onto the first 32 INO. */
235 qemu_set_irq(pic
[irq_num
], level
);
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
)
246 /* Ultrasparc PBM main bus */
247 dev
= qdev_create(NULL
, "pbm");
248 qdev_init_nofail(dev
);
249 s
= sysbus_from_qdev(dev
);
251 sysbus_mmio_map(s
, 0, special_base
+ 0x2000ULL
);
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
);
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
,
262 pci_create_simple(d
->host_state
.bus
, 0, "pbm");
263 /* APB secondary busses */
264 *bus2
= pci_bridge_init(d
->host_state
.bus
, 8, PCI_VENDOR_ID_SUN
,
265 PCI_DEVICE_ID_SUN_SIMBA
, pci_apb_map_irq
,
266 "Advanced PCI Bus secondary bridge 1");
267 *bus3
= pci_bridge_init(d
->host_state
.bus
, 9, PCI_VENDOR_ID_SUN
,
268 PCI_DEVICE_ID_SUN_SIMBA
, pci_apb_map_irq
,
269 "Advanced PCI Bus secondary bridge 2");
271 return d
->host_state
.bus
;
274 static int pci_pbm_init_device(SysBusDevice
*dev
)
278 int pci_mem_config
, pci_mem_data
, apb_config
, pci_ioport
;
280 s
= FROM_SYSBUS(APBState
, dev
);
282 apb_config
= cpu_register_io_memory(apb_config_read
,
283 apb_config_write
, s
);
284 sysbus_init_mmio(dev
, 0x40ULL
, apb_config
);
286 pci_ioport
= cpu_register_io_memory(pci_apb_ioread
,
288 sysbus_init_mmio(dev
, 0x10000ULL
, pci_ioport
);
290 pci_mem_config
= cpu_register_io_memory(pci_apb_config_read
,
291 pci_apb_config_write
, s
);
292 sysbus_init_mmio(dev
, 0x10ULL
, pci_mem_config
);
294 pci_mem_data
= cpu_register_io_memory(pci_apb_read
,
295 pci_apb_write
, &s
->host_state
);
296 sysbus_init_mmio(dev
, 0x10000000ULL
, pci_mem_data
);
300 static int pbm_pci_host_init(PCIDevice
*d
)
302 pci_config_set_vendor_id(d
->config
, PCI_VENDOR_ID_SUN
);
303 pci_config_set_device_id(d
->config
, PCI_DEVICE_ID_SUN_SABRE
);
304 d
->config
[0x04] = 0x06; // command = bus master, pci mem
305 d
->config
[0x05] = 0x00;
306 d
->config
[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
307 d
->config
[0x07] = 0x03; // status = medium devsel
308 d
->config
[0x08] = 0x00; // revision
309 d
->config
[0x09] = 0x00; // programming i/f
310 pci_config_set_class(d
->config
, PCI_CLASS_BRIDGE_HOST
);
311 d
->config
[0x0D] = 0x10; // latency_timer
312 d
->config
[PCI_HEADER_TYPE
] = PCI_HEADER_TYPE_NORMAL
; // header_type
316 static PCIDeviceInfo pbm_pci_host_info
= {
318 .qdev
.size
= sizeof(PCIDevice
),
319 .init
= pbm_pci_host_init
,
322 static void pbm_register_devices(void)
324 sysbus_register_dev("pbm", sizeof(APBState
), pci_pbm_init_device
);
325 pci_qdev_register(&pbm_pci_host_info
);
328 device_init(pbm_register_devices
)