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