blob: 84e9af76a219632c5e2f26221d32f142c3a430a0 [file] [log] [blame]
pbrook502a5392006-05-13 16:11:23 +00001/*
2 * QEMU Ultrasparc APB PCI host
3 *
4 * Copyright (c) 2006 Fabrice Bellard
ths5fafdf22007-09-16 21:08:06 +00005 *
pbrook502a5392006-05-13 16:11:23 +00006 * 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 */
pbrook80b3ada2006-09-24 17:01:44 +000024
blueswir1a94fd952009-01-09 20:53:30 +000025/* XXX This file and most of its contents are somewhat misnamed. The
pbrook80b3ada2006-09-24 17:01:44 +000026 Ultrasparc PCI host is called the PCI Bus Module (PBM). The APB is
27 the secondary PCI bridge. */
28
Blue Swirl72f44c82009-07-21 08:36:37 +000029#include "sysbus.h"
pbrook87ecb682007-11-17 17:14:51 +000030#include "pci.h"
Isaku Yamahata4f5e19e2009-10-30 21:21:06 +090031#include "pci_host.h"
Isaku Yamahata783753f2010-07-13 13:01:39 +090032#include "pci_bridge.h"
Isaku Yamahata68f79992010-07-13 13:01:42 +090033#include "pci_internals.h"
Michael S. Tsirkin63e6f312010-02-22 12:38:25 +020034#include "rwhandler.h"
Michael S. Tsirkin18e08a52009-11-11 14:59:56 +020035#include "apb_pci.h"
Markus Armbruster666daa62010-06-02 18:48:27 +020036#include "sysemu.h"
blueswir1a94fd952009-01-09 20:53:30 +000037
38/* debug APB */
39//#define DEBUG_APB
40
41#ifdef DEBUG_APB
Blue Swirl001faf32009-05-13 17:53:17 +000042#define APB_DPRINTF(fmt, ...) \
43do { printf("APB: " fmt , ## __VA_ARGS__); } while (0)
blueswir1a94fd952009-01-09 20:53:30 +000044#else
Blue Swirl001faf32009-05-13 17:53:17 +000045#define APB_DPRINTF(fmt, ...)
blueswir1a94fd952009-01-09 20:53:30 +000046#endif
47
Blue Swirl930f3fe2009-10-13 18:56:27 +000048/*
49 * Chipset docs:
50 * PBM: "UltraSPARC IIi User's Manual",
51 * http://www.sun.com/processors/manuals/805-0087.pdf
52 *
53 * APB: "Advanced PCI Bridge (APB) User's Manual",
54 * http://www.sun.com/processors/manuals/805-1251.pdf
55 */
56
Blue Swirl95819af2010-01-30 19:48:12 +000057#define PBM_PCI_IMR_MASK 0x7fffffff
58#define PBM_PCI_IMR_ENABLED 0x80000000
59
60#define POR (1 << 31)
61#define SOFT_POR (1 << 30)
62#define SOFT_XIR (1 << 29)
63#define BTN_POR (1 << 28)
64#define BTN_XIR (1 << 27)
65#define RESET_MASK 0xf8000000
66#define RESET_WCMASK 0x98000000
67#define RESET_WMASK 0x60000000
68
Blue Swirl72f44c82009-07-21 08:36:37 +000069typedef struct APBState {
70 SysBusDevice busdev;
Igor V. Kovalenkod63baf92010-05-25 16:09:03 +040071 PCIBus *bus;
Michael S. Tsirkin63e6f312010-02-22 12:38:25 +020072 ReadWriteHandler pci_config_handler;
Blue Swirl95819af2010-01-30 19:48:12 +000073 uint32_t iommu[4];
74 uint32_t pci_control[16];
75 uint32_t pci_irq_map[8];
76 uint32_t obio_irq_map[32];
77 qemu_irq pci_irqs[32];
78 uint32_t reset_control;
Blue Swirl9c0afd02010-05-12 19:27:23 +000079 unsigned int nr_resets;
Blue Swirl72f44c82009-07-21 08:36:37 +000080} APBState;
pbrook502a5392006-05-13 16:11:23 +000081
Anthony Liguoric227f092009-10-01 16:12:16 -050082static void apb_config_writel (void *opaque, target_phys_addr_t addr,
blueswir1f930d072007-10-06 11:28:21 +000083 uint32_t val)
pbrook502a5392006-05-13 16:11:23 +000084{
Blue Swirl95819af2010-01-30 19:48:12 +000085 APBState *s = opaque;
pbrook502a5392006-05-13 16:11:23 +000086
Blue Swirl95819af2010-01-30 19:48:12 +000087 APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %x\n", __func__, addr, val);
88
89 switch (addr & 0xffff) {
90 case 0x30 ... 0x4f: /* DMA error registers */
91 /* XXX: not implemented yet */
92 break;
93 case 0x200 ... 0x20b: /* IOMMU */
94 s->iommu[(addr & 0xf) >> 2] = val;
95 break;
96 case 0x20c ... 0x3ff: /* IOMMU flush */
97 break;
98 case 0xc00 ... 0xc3f: /* PCI interrupt control */
99 if (addr & 4) {
100 s->pci_irq_map[(addr & 0x3f) >> 3] &= PBM_PCI_IMR_MASK;
101 s->pci_irq_map[(addr & 0x3f) >> 3] |= val & ~PBM_PCI_IMR_MASK;
102 }
103 break;
104 case 0x2000 ... 0x202f: /* PCI control */
105 s->pci_control[(addr & 0x3f) >> 2] = val;
106 break;
107 case 0xf020 ... 0xf027: /* Reset control */
108 if (addr & 4) {
109 val &= RESET_MASK;
110 s->reset_control &= ~(val & RESET_WCMASK);
111 s->reset_control |= val & RESET_WMASK;
112 if (val & SOFT_POR) {
Blue Swirl9c0afd02010-05-12 19:27:23 +0000113 s->nr_resets = 0;
Blue Swirl95819af2010-01-30 19:48:12 +0000114 qemu_system_reset_request();
115 } else if (val & SOFT_XIR) {
116 qemu_system_reset_request();
117 }
118 }
119 break;
120 case 0x5000 ... 0x51cf: /* PIO/DMA diagnostics */
121 case 0xa400 ... 0xa67f: /* IOMMU diagnostics */
122 case 0xa800 ... 0xa80f: /* Interrupt diagnostics */
123 case 0xf000 ... 0xf01f: /* FFB config, memory control */
124 /* we don't care */
pbrook502a5392006-05-13 16:11:23 +0000125 default:
blueswir1f930d072007-10-06 11:28:21 +0000126 break;
pbrook502a5392006-05-13 16:11:23 +0000127 }
128}
129
130static uint32_t apb_config_readl (void *opaque,
Anthony Liguoric227f092009-10-01 16:12:16 -0500131 target_phys_addr_t addr)
pbrook502a5392006-05-13 16:11:23 +0000132{
Blue Swirl95819af2010-01-30 19:48:12 +0000133 APBState *s = opaque;
pbrook502a5392006-05-13 16:11:23 +0000134 uint32_t val;
135
Blue Swirl95819af2010-01-30 19:48:12 +0000136 switch (addr & 0xffff) {
137 case 0x30 ... 0x4f: /* DMA error registers */
138 val = 0;
139 /* XXX: not implemented yet */
140 break;
141 case 0x200 ... 0x20b: /* IOMMU */
142 val = s->iommu[(addr & 0xf) >> 2];
143 break;
144 case 0x20c ... 0x3ff: /* IOMMU flush */
145 val = 0;
146 break;
147 case 0xc00 ... 0xc3f: /* PCI interrupt control */
148 if (addr & 4) {
149 val = s->pci_irq_map[(addr & 0x3f) >> 3];
150 } else {
151 val = 0;
152 }
153 break;
154 case 0x2000 ... 0x202f: /* PCI control */
155 val = s->pci_control[(addr & 0x3f) >> 2];
156 break;
157 case 0xf020 ... 0xf027: /* Reset control */
158 if (addr & 4) {
159 val = s->reset_control;
160 } else {
161 val = 0;
162 }
163 break;
164 case 0x5000 ... 0x51cf: /* PIO/DMA diagnostics */
165 case 0xa400 ... 0xa67f: /* IOMMU diagnostics */
166 case 0xa800 ... 0xa80f: /* Interrupt diagnostics */
167 case 0xf000 ... 0xf01f: /* FFB config, memory control */
168 /* we don't care */
pbrook502a5392006-05-13 16:11:23 +0000169 default:
blueswir1f930d072007-10-06 11:28:21 +0000170 val = 0;
171 break;
pbrook502a5392006-05-13 16:11:23 +0000172 }
Blue Swirl95819af2010-01-30 19:48:12 +0000173 APB_DPRINTF("%s: addr " TARGET_FMT_lx " -> %x\n", __func__, addr, val);
174
pbrook502a5392006-05-13 16:11:23 +0000175 return val;
176}
177
Blue Swirld60efc62009-08-25 18:29:31 +0000178static CPUWriteMemoryFunc * const apb_config_write[] = {
pbrook502a5392006-05-13 16:11:23 +0000179 &apb_config_writel,
180 &apb_config_writel,
181 &apb_config_writel,
182};
183
Blue Swirld60efc62009-08-25 18:29:31 +0000184static CPUReadMemoryFunc * const apb_config_read[] = {
pbrook502a5392006-05-13 16:11:23 +0000185 &apb_config_readl,
186 &apb_config_readl,
187 &apb_config_readl,
188};
189
Michael S. Tsirkin63e6f312010-02-22 12:38:25 +0200190static void apb_pci_config_write(ReadWriteHandler *h, pcibus_t addr,
Blue Swirl5a5d4a72010-01-11 21:20:53 +0000191 uint32_t val, int size)
192{
Michael S. Tsirkin63e6f312010-02-22 12:38:25 +0200193 APBState *s = container_of(h, APBState, pci_config_handler);
194
195 val = qemu_bswap_len(val, size);
Blue Swirl5a5d4a72010-01-11 21:20:53 +0000196 APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %x\n", __func__, addr, val);
Igor V. Kovalenkod63baf92010-05-25 16:09:03 +0400197 pci_data_write(s->bus, addr, val, size);
Blue Swirl5a5d4a72010-01-11 21:20:53 +0000198}
199
Michael S. Tsirkin63e6f312010-02-22 12:38:25 +0200200static uint32_t apb_pci_config_read(ReadWriteHandler *h, pcibus_t addr,
Blue Swirl5a5d4a72010-01-11 21:20:53 +0000201 int size)
202{
203 uint32_t ret;
Michael S. Tsirkin63e6f312010-02-22 12:38:25 +0200204 APBState *s = container_of(h, APBState, pci_config_handler);
Blue Swirl5a5d4a72010-01-11 21:20:53 +0000205
Igor V. Kovalenkod63baf92010-05-25 16:09:03 +0400206 ret = pci_data_read(s->bus, addr, size);
Michael S. Tsirkin63e6f312010-02-22 12:38:25 +0200207 ret = qemu_bswap_len(ret, size);
Blue Swirl5a5d4a72010-01-11 21:20:53 +0000208 APB_DPRINTF("%s: addr " TARGET_FMT_lx " -> %x\n", __func__, addr, ret);
209 return ret;
210}
211
Anthony Liguoric227f092009-10-01 16:12:16 -0500212static void pci_apb_iowriteb (void *opaque, target_phys_addr_t addr,
pbrook502a5392006-05-13 16:11:23 +0000213 uint32_t val)
214{
Blue Swirlafcea8c2009-09-20 16:05:47 +0000215 cpu_outb(addr & IOPORTS_MASK, val);
pbrook502a5392006-05-13 16:11:23 +0000216}
217
Anthony Liguoric227f092009-10-01 16:12:16 -0500218static void pci_apb_iowritew (void *opaque, target_phys_addr_t addr,
pbrook502a5392006-05-13 16:11:23 +0000219 uint32_t val)
220{
Blue Swirla4d5f622010-01-29 18:15:21 +0000221 cpu_outw(addr & IOPORTS_MASK, bswap16(val));
pbrook502a5392006-05-13 16:11:23 +0000222}
223
Anthony Liguoric227f092009-10-01 16:12:16 -0500224static void pci_apb_iowritel (void *opaque, target_phys_addr_t addr,
pbrook502a5392006-05-13 16:11:23 +0000225 uint32_t val)
226{
Blue Swirla4d5f622010-01-29 18:15:21 +0000227 cpu_outl(addr & IOPORTS_MASK, bswap32(val));
pbrook502a5392006-05-13 16:11:23 +0000228}
229
Anthony Liguoric227f092009-10-01 16:12:16 -0500230static uint32_t pci_apb_ioreadb (void *opaque, target_phys_addr_t addr)
pbrook502a5392006-05-13 16:11:23 +0000231{
232 uint32_t val;
233
Blue Swirlafcea8c2009-09-20 16:05:47 +0000234 val = cpu_inb(addr & IOPORTS_MASK);
pbrook502a5392006-05-13 16:11:23 +0000235 return val;
236}
237
Anthony Liguoric227f092009-10-01 16:12:16 -0500238static uint32_t pci_apb_ioreadw (void *opaque, target_phys_addr_t addr)
pbrook502a5392006-05-13 16:11:23 +0000239{
240 uint32_t val;
241
Blue Swirla4d5f622010-01-29 18:15:21 +0000242 val = bswap16(cpu_inw(addr & IOPORTS_MASK));
pbrook502a5392006-05-13 16:11:23 +0000243 return val;
244}
245
Anthony Liguoric227f092009-10-01 16:12:16 -0500246static uint32_t pci_apb_ioreadl (void *opaque, target_phys_addr_t addr)
pbrook502a5392006-05-13 16:11:23 +0000247{
248 uint32_t val;
249
Blue Swirla4d5f622010-01-29 18:15:21 +0000250 val = bswap32(cpu_inl(addr & IOPORTS_MASK));
pbrook502a5392006-05-13 16:11:23 +0000251 return val;
252}
253
Blue Swirld60efc62009-08-25 18:29:31 +0000254static CPUWriteMemoryFunc * const pci_apb_iowrite[] = {
pbrook502a5392006-05-13 16:11:23 +0000255 &pci_apb_iowriteb,
256 &pci_apb_iowritew,
257 &pci_apb_iowritel,
258};
259
Blue Swirld60efc62009-08-25 18:29:31 +0000260static CPUReadMemoryFunc * const pci_apb_ioread[] = {
pbrook502a5392006-05-13 16:11:23 +0000261 &pci_apb_ioreadb,
262 &pci_apb_ioreadw,
263 &pci_apb_ioreadl,
264};
265
pbrook80b3ada2006-09-24 17:01:44 +0000266/* The APB host has an IRQ line for each IRQ line of each slot. */
pbrookd2b59312006-09-24 00:16:34 +0000267static int pci_apb_map_irq(PCIDevice *pci_dev, int irq_num)
pbrook502a5392006-05-13 16:11:23 +0000268{
pbrook80b3ada2006-09-24 17:01:44 +0000269 return ((pci_dev->devfn & 0x18) >> 1) + irq_num;
270}
271
272static int pci_pbm_map_irq(PCIDevice *pci_dev, int irq_num)
273{
274 int bus_offset;
275 if (pci_dev->devfn & 1)
276 bus_offset = 16;
277 else
278 bus_offset = 0;
279 return bus_offset + irq_num;
pbrookd2b59312006-09-24 00:16:34 +0000280}
281
Juan Quintela5d4e84c2009-08-28 15:28:17 +0200282static void pci_apb_set_irq(void *opaque, int irq_num, int level)
pbrookd2b59312006-09-24 00:16:34 +0000283{
Blue Swirl95819af2010-01-30 19:48:12 +0000284 APBState *s = opaque;
Juan Quintela5d4e84c2009-08-28 15:28:17 +0200285
pbrook80b3ada2006-09-24 17:01:44 +0000286 /* PCI IRQ map onto the first 32 INO. */
Blue Swirl95819af2010-01-30 19:48:12 +0000287 if (irq_num < 32) {
288 if (s->pci_irq_map[irq_num >> 2] & PBM_PCI_IMR_ENABLED) {
289 APB_DPRINTF("%s: set irq %d level %d\n", __func__, irq_num, level);
290 qemu_set_irq(s->pci_irqs[irq_num], level);
291 } else {
292 APB_DPRINTF("%s: not enabled: lower irq %d\n", __func__, irq_num);
293 qemu_irq_lower(s->pci_irqs[irq_num]);
294 }
295 }
pbrook502a5392006-05-13 16:11:23 +0000296}
297
Isaku Yamahata68f79992010-07-13 13:01:42 +0900298static int apb_pci_bridge_initfn(PCIDevice *dev)
Michael S. Tsirkind6318732009-11-11 14:33:54 +0200299{
Isaku Yamahata68f79992010-07-13 13:01:42 +0900300 int rc;
301
302 rc = pci_bridge_initfn(dev);
303 if (rc < 0) {
304 return rc;
305 }
306
307 pci_config_set_vendor_id(dev->config, PCI_VENDOR_ID_SUN);
308 pci_config_set_device_id(dev->config, PCI_DEVICE_ID_SUN_SIMBA);
Michael S. Tsirkind6318732009-11-11 14:33:54 +0200309
310 /*
311 * command register:
312 * According to PCI bridge spec, after reset
313 * bus master bit is off
314 * memory space enable bit is off
315 * According to manual (805-1251.pdf).
316 * the reset value should be zero unless the boot pin is tied high
317 * (which is true) and thus it should be PCI_COMMAND_MEMORY.
318 */
319 pci_set_word(dev->config + PCI_COMMAND,
Blue Swirl9fe52c72010-02-14 08:27:19 +0000320 PCI_COMMAND_MEMORY);
321 pci_set_word(dev->config + PCI_STATUS,
322 PCI_STATUS_FAST_BACK | PCI_STATUS_66MHZ |
323 PCI_STATUS_DEVSEL_MEDIUM);
324 pci_set_byte(dev->config + PCI_REVISION_ID, 0x11);
Isaku Yamahata68f79992010-07-13 13:01:42 +0900325 return 0;
Michael S. Tsirkind6318732009-11-11 14:33:54 +0200326}
327
Anthony Liguoric227f092009-10-01 16:12:16 -0500328PCIBus *pci_apb_init(target_phys_addr_t special_base,
329 target_phys_addr_t mem_base,
blueswir1c190ea02009-01-10 11:33:32 +0000330 qemu_irq *pic, PCIBus **bus2, PCIBus **bus3)
pbrook502a5392006-05-13 16:11:23 +0000331{
Blue Swirl72f44c82009-07-21 08:36:37 +0000332 DeviceState *dev;
333 SysBusDevice *s;
334 APBState *d;
Blue Swirl95819af2010-01-30 19:48:12 +0000335 unsigned int i;
Isaku Yamahata68f79992010-07-13 13:01:42 +0900336 PCIDevice *pci_dev;
337 PCIBridge *br;
Blue Swirl72f44c82009-07-21 08:36:37 +0000338
339 /* Ultrasparc PBM main bus */
340 dev = qdev_create(NULL, "pbm");
Markus Armbrustere23a1b32009-10-07 01:15:58 +0200341 qdev_init_nofail(dev);
Blue Swirl72f44c82009-07-21 08:36:37 +0000342 s = sysbus_from_qdev(dev);
343 /* apb_config */
Blue Swirlbae7b512010-01-10 18:25:48 +0000344 sysbus_mmio_map(s, 0, special_base);
Igor V. Kovalenkod63baf92010-05-25 16:09:03 +0400345 /* PCI configuration space */
346 sysbus_mmio_map(s, 1, special_base + 0x1000000ULL);
Blue Swirl72f44c82009-07-21 08:36:37 +0000347 /* pci_ioport */
Igor V. Kovalenkod63baf92010-05-25 16:09:03 +0400348 sysbus_mmio_map(s, 2, special_base + 0x2000000ULL);
Blue Swirl72f44c82009-07-21 08:36:37 +0000349 d = FROM_SYSBUS(APBState, s);
Igor V. Kovalenkod63baf92010-05-25 16:09:03 +0400350
351 d->bus = pci_register_bus(&d->busdev.qdev, "pci",
Blue Swirl95819af2010-01-30 19:48:12 +0000352 pci_apb_set_irq, pci_pbm_map_irq, d,
Blue Swirl72f44c82009-07-21 08:36:37 +0000353 0, 32);
Igor V. Kovalenkod63baf92010-05-25 16:09:03 +0400354 pci_bus_set_mem_base(d->bus, mem_base);
Blue Swirlf6b6f1b2009-12-27 20:52:39 +0000355
Blue Swirl95819af2010-01-30 19:48:12 +0000356 for (i = 0; i < 32; i++) {
357 sysbus_connect_irq(s, i, pic[i]);
358 }
359
Igor V. Kovalenkod63baf92010-05-25 16:09:03 +0400360 pci_create_simple(d->bus, 0, "pbm");
361
Blue Swirl72f44c82009-07-21 08:36:37 +0000362 /* APB secondary busses */
Isaku Yamahata68f79992010-07-13 13:01:42 +0900363 pci_dev = pci_create_multifunction(d->bus, PCI_DEVFN(1, 0), true,
364 "pbm-bridge");
365 br = DO_UPCAST(PCIBridge, dev, pci_dev);
366 pci_bridge_map_irq(br, "Advanced PCI Bus secondary bridge 1",
367 pci_apb_map_irq);
368 qdev_init_nofail(&pci_dev->qdev);
369 *bus2 = pci_bridge_get_sec_bus(br);
Michael S. Tsirkind6318732009-11-11 14:33:54 +0200370
Isaku Yamahata68f79992010-07-13 13:01:42 +0900371 pci_dev = pci_create_multifunction(d->bus, PCI_DEVFN(1, 1), true,
372 "pbm-bridge");
373 br = DO_UPCAST(PCIBridge, dev, pci_dev);
374 pci_bridge_map_irq(br, "Advanced PCI Bus secondary bridge 2",
375 pci_apb_map_irq);
376 qdev_init_nofail(&pci_dev->qdev);
377 *bus3 = pci_bridge_get_sec_bus(br);
Blue Swirl72f44c82009-07-21 08:36:37 +0000378
Igor V. Kovalenkod63baf92010-05-25 16:09:03 +0400379 return d->bus;
Blue Swirl72f44c82009-07-21 08:36:37 +0000380}
381
Blue Swirl95819af2010-01-30 19:48:12 +0000382static void pci_pbm_reset(DeviceState *d)
383{
384 unsigned int i;
385 APBState *s = container_of(d, APBState, busdev.qdev);
386
387 for (i = 0; i < 8; i++) {
388 s->pci_irq_map[i] &= PBM_PCI_IMR_MASK;
389 }
390
Blue Swirl9c0afd02010-05-12 19:27:23 +0000391 if (s->nr_resets++ == 0) {
Blue Swirl95819af2010-01-30 19:48:12 +0000392 /* Power on reset */
393 s->reset_control = POR;
394 }
395}
396
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200397static int pci_pbm_init_device(SysBusDevice *dev)
Blue Swirl72f44c82009-07-21 08:36:37 +0000398{
pbrook502a5392006-05-13 16:11:23 +0000399 APBState *s;
Igor V. Kovalenkod63baf92010-05-25 16:09:03 +0400400 int pci_config, apb_config, pci_ioport;
Blue Swirl95819af2010-01-30 19:48:12 +0000401 unsigned int i;
pbrook502a5392006-05-13 16:11:23 +0000402
Blue Swirl72f44c82009-07-21 08:36:37 +0000403 s = FROM_SYSBUS(APBState, dev);
Blue Swirl95819af2010-01-30 19:48:12 +0000404 for (i = 0; i < 8; i++) {
405 s->pci_irq_map[i] = (0x1f << 6) | (i << 2);
406 }
407 for (i = 0; i < 32; i++) {
408 sysbus_init_irq(dev, &s->pci_irqs[i]);
409 }
410
Blue Swirl72f44c82009-07-21 08:36:37 +0000411 /* apb_config */
Avi Kivity1eed09c2009-06-14 11:38:51 +0300412 apb_config = cpu_register_io_memory(apb_config_read,
Alexander Graf2507c122010-12-08 12:05:37 +0100413 apb_config_write, s,
414 DEVICE_NATIVE_ENDIAN);
Igor V. Kovalenkod63baf92010-05-25 16:09:03 +0400415 /* at region 0 */
Blue Swirlbae7b512010-01-10 18:25:48 +0000416 sysbus_init_mmio(dev, 0x10000ULL, apb_config);
Igor V. Kovalenkod63baf92010-05-25 16:09:03 +0400417
418 /* PCI configuration space */
Michael S. Tsirkin63e6f312010-02-22 12:38:25 +0200419 s->pci_config_handler.read = apb_pci_config_read;
420 s->pci_config_handler.write = apb_pci_config_write;
Alexander Graf6bef0432010-12-08 12:05:38 +0100421 pci_config = cpu_register_io_memory_simple(&s->pci_config_handler,
422 DEVICE_NATIVE_ENDIAN);
Michael S. Tsirkin63e6f312010-02-22 12:38:25 +0200423 assert(pci_config >= 0);
Igor V. Kovalenkod63baf92010-05-25 16:09:03 +0400424 /* at region 1 */
Blue Swirl5a5d4a72010-01-11 21:20:53 +0000425 sysbus_init_mmio(dev, 0x1000000ULL, pci_config);
Igor V. Kovalenkod63baf92010-05-25 16:09:03 +0400426
427 /* pci_ioport */
428 pci_ioport = cpu_register_io_memory(pci_apb_ioread,
Alexander Graf2507c122010-12-08 12:05:37 +0100429 pci_apb_iowrite, s,
430 DEVICE_NATIVE_ENDIAN);
Igor V. Kovalenkod63baf92010-05-25 16:09:03 +0400431 /* at region 2 */
432 sysbus_init_mmio(dev, 0x10000ULL, pci_ioport);
433
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200434 return 0;
Blue Swirl72f44c82009-07-21 08:36:37 +0000435}
pbrook502a5392006-05-13 16:11:23 +0000436
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200437static int pbm_pci_host_init(PCIDevice *d)
Blue Swirl72f44c82009-07-21 08:36:37 +0000438{
aliguorideb54392009-01-26 15:37:35 +0000439 pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_SUN);
440 pci_config_set_device_id(d->config, PCI_DEVICE_ID_SUN_SABRE);
Blue Swirl9fe52c72010-02-14 08:27:19 +0000441 pci_set_word(d->config + PCI_COMMAND,
442 PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
443 pci_set_word(d->config + PCI_STATUS,
444 PCI_STATUS_FAST_BACK | PCI_STATUS_66MHZ |
445 PCI_STATUS_DEVSEL_MEDIUM);
blueswir1173a5432009-02-01 19:26:20 +0000446 pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200447 return 0;
pbrook502a5392006-05-13 16:11:23 +0000448}
Blue Swirl72f44c82009-07-21 08:36:37 +0000449
450static PCIDeviceInfo pbm_pci_host_info = {
451 .qdev.name = "pbm",
452 .qdev.size = sizeof(PCIDevice),
453 .init = pbm_pci_host_init,
Isaku Yamahatae327e322010-06-23 16:15:28 +0900454 .is_bridge = 1,
Blue Swirl72f44c82009-07-21 08:36:37 +0000455};
456
Blue Swirl95819af2010-01-30 19:48:12 +0000457static SysBusDeviceInfo pbm_host_info = {
458 .qdev.name = "pbm",
459 .qdev.size = sizeof(APBState),
460 .qdev.reset = pci_pbm_reset,
461 .init = pci_pbm_init_device,
462};
Isaku Yamahata68f79992010-07-13 13:01:42 +0900463
464static PCIDeviceInfo pbm_pci_bridge_info = {
465 .qdev.name = "pbm-bridge",
466 .qdev.size = sizeof(PCIBridge),
467 .qdev.vmsd = &vmstate_pci_device,
468 .qdev.reset = pci_bridge_reset,
469 .init = apb_pci_bridge_initfn,
470 .exit = pci_bridge_exitfn,
471 .config_write = pci_bridge_write_config,
472 .is_bridge = 1,
473};
474
Blue Swirl72f44c82009-07-21 08:36:37 +0000475static void pbm_register_devices(void)
476{
Blue Swirl95819af2010-01-30 19:48:12 +0000477 sysbus_register_withprop(&pbm_host_info);
Blue Swirl72f44c82009-07-21 08:36:37 +0000478 pci_qdev_register(&pbm_pci_host_info);
Isaku Yamahata68f79992010-07-13 13:01:42 +0900479 pci_qdev_register(&pbm_pci_bridge_info);
Blue Swirl72f44c82009-07-21 08:36:37 +0000480}
481
482device_init(pbm_register_devices)