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