Merge branch 'upstream-merge'
[qemu-kvm/markmc.git] / hw / apb_pci.c
blob43be7ceeb515d016a0d3625c51641cdf1bf96b7b
1 /*
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
22 * THE SOFTWARE.
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. */
29 #include "sysbus.h"
30 #include "pci.h"
32 /* debug APB */
33 //#define DEBUG_APB
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
43 * Chipset docs:
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;
52 #include "pci_host.h"
54 typedef struct APBState {
55 SysBusDevice busdev;
56 PCIHostState host_state;
57 } APBState;
59 static void pci_apb_config_writel (void *opaque, target_phys_addr_t addr,
60 uint32_t val)
62 APBState *s = opaque;
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;
72 static uint32_t pci_apb_config_readl (void *opaque,
73 target_phys_addr_t addr)
75 APBState *s = opaque;
76 uint32_t val;
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;
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,
100 uint32_t val)
102 //PCIBus *s = opaque;
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;
116 static uint32_t apb_config_readl (void *opaque,
117 target_phys_addr_t addr)
119 //PCIBus *s = opaque;
120 uint32_t val;
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;
133 return val;
136 static CPUWriteMemoryFunc * const apb_config_write[] = {
137 &apb_config_writel,
138 &apb_config_writel,
139 &apb_config_writel,
142 static CPUReadMemoryFunc * const apb_config_read[] = {
143 &apb_config_readl,
144 &apb_config_readl,
145 &apb_config_readl,
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,
161 uint32_t val)
163 cpu_outb(addr & IOPORTS_MASK, val);
166 static void pci_apb_iowritew (void *opaque, target_phys_addr_t addr,
167 uint32_t val)
169 cpu_outw(addr & IOPORTS_MASK, val);
172 static void pci_apb_iowritel (void *opaque, target_phys_addr_t addr,
173 uint32_t val)
175 cpu_outl(addr & IOPORTS_MASK, val);
178 static uint32_t pci_apb_ioreadb (void *opaque, target_phys_addr_t addr)
180 uint32_t val;
182 val = cpu_inb(addr & IOPORTS_MASK);
183 return val;
186 static uint32_t pci_apb_ioreadw (void *opaque, target_phys_addr_t addr)
188 uint32_t val;
190 val = cpu_inw(addr & IOPORTS_MASK);
191 return val;
194 static uint32_t pci_apb_ioreadl (void *opaque, target_phys_addr_t addr)
196 uint32_t val;
198 val = cpu_inl(addr & IOPORTS_MASK);
199 return val;
202 static CPUWriteMemoryFunc * const pci_apb_iowrite[] = {
203 &pci_apb_iowriteb,
204 &pci_apb_iowritew,
205 &pci_apb_iowritel,
208 static CPUReadMemoryFunc * const pci_apb_ioread[] = {
209 &pci_apb_ioreadb,
210 &pci_apb_ioreadw,
211 &pci_apb_ioreadl,
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)
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;
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)
242 DeviceState *dev;
243 SysBusDevice *s;
244 APBState *d;
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, 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)
277 APBState *s;
278 int pci_mem_config, pci_mem_data, apb_config, pci_ioport;
280 s = FROM_SYSBUS(APBState, dev);
281 /* apb_config */
282 apb_config = cpu_register_io_memory(apb_config_read,
283 apb_config_write, s);
284 sysbus_init_mmio(dev, 0x40ULL, apb_config);
285 /* pci_ioport */
286 pci_ioport = cpu_register_io_memory(pci_apb_ioread,
287 pci_apb_iowrite, s);
288 sysbus_init_mmio(dev, 0x10000ULL, pci_ioport);
289 /* mem_config */
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);
293 /* mem_data */
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);
297 return 0;
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
313 return 0;
316 static PCIDeviceInfo pbm_pci_host_info = {
317 .qdev.name = "pbm",
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)