blob: 48929d17af27fb917528d8cb0fd1c8458ed6b359 [file] [log] [blame]
ths5fafdf22007-09-16 21:08:06 +00001/*
pbrook502a5392006-05-13 16:11:23 +00002 * ARM Versatile/PB PCI host controller
3 *
Paul Brook0027b062009-05-14 22:35:08 +01004 * Copyright (c) 2006-2009 CodeSourcery.
pbrook502a5392006-05-13 16:11:23 +00005 * Written by Paul Brook
6 *
Matthew Fernandez8e31bf32011-06-26 12:21:35 +10007 * This code is licensed under the LGPL.
pbrook502a5392006-05-13 16:11:23 +00008 */
9
Paul Brook0027b062009-05-14 22:35:08 +010010#include "sysbus.h"
Michael S. Tsirkina2cb15b2012-12-12 14:24:50 +020011#include "pci/pci.h"
Peter Maydell833a26d2013-03-01 15:52:59 +000012#include "pci/pci_bus.h"
Michael S. Tsirkina2cb15b2012-12-12 14:24:50 +020013#include "pci/pci_host.h"
Paolo Bonzini022c62c2012-12-17 18:19:49 +010014#include "exec/address-spaces.h"
Paul Brook0027b062009-05-14 22:35:08 +010015
16typedef struct {
Peter Maydell833a26d2013-03-01 15:52:59 +000017 PCIHostState parent_obj;
18
Paul Brook0027b062009-05-14 22:35:08 +010019 qemu_irq irq[4];
Avi Kivity45de0942011-08-15 17:17:32 +030020 MemoryRegion mem_config;
21 MemoryRegion mem_config2;
Peter Maydell042f0882013-03-01 17:35:36 +000022 MemoryRegion pci_io_space;
Peter Maydell833a26d2013-03-01 15:52:59 +000023 PCIBus pci_bus;
24 PCIDevice pci_dev;
Paul Brook0027b062009-05-14 22:35:08 +010025} PCIVPBState;
pbrook502a5392006-05-13 16:11:23 +000026
Peter Maydell8bea7cb2013-03-01 14:42:54 +000027#define TYPE_VERSATILE_PCI "versatile_pci"
28#define PCI_VPB(obj) \
29 OBJECT_CHECK(PCIVPBState, (obj), TYPE_VERSATILE_PCI)
30
31#define TYPE_VERSATILE_PCI_HOST "versatile_pci_host"
32#define PCI_VPB_HOST(obj) \
33 OBJECT_CHECK(PCIDevice), (obj), TYPE_VERSATILE_PCIHOST)
34
Avi Kivitya8170e52012-10-23 12:30:10 +020035static inline uint32_t vpb_pci_config_addr(hwaddr addr)
pbrook502a5392006-05-13 16:11:23 +000036{
pbrook80b3ada2006-09-24 17:01:44 +000037 return addr & 0xffffff;
pbrook502a5392006-05-13 16:11:23 +000038}
39
Avi Kivitya8170e52012-10-23 12:30:10 +020040static void pci_vpb_config_write(void *opaque, hwaddr addr,
Avi Kivity45de0942011-08-15 17:17:32 +030041 uint64_t val, unsigned size)
pbrook502a5392006-05-13 16:11:23 +000042{
Avi Kivity45de0942011-08-15 17:17:32 +030043 pci_data_write(opaque, vpb_pci_config_addr(addr), val, size);
pbrook502a5392006-05-13 16:11:23 +000044}
45
Avi Kivitya8170e52012-10-23 12:30:10 +020046static uint64_t pci_vpb_config_read(void *opaque, hwaddr addr,
Avi Kivity45de0942011-08-15 17:17:32 +030047 unsigned size)
pbrook502a5392006-05-13 16:11:23 +000048{
49 uint32_t val;
Avi Kivity45de0942011-08-15 17:17:32 +030050 val = pci_data_read(opaque, vpb_pci_config_addr(addr), size);
pbrook502a5392006-05-13 16:11:23 +000051 return val;
52}
53
Avi Kivity45de0942011-08-15 17:17:32 +030054static const MemoryRegionOps pci_vpb_config_ops = {
55 .read = pci_vpb_config_read,
56 .write = pci_vpb_config_write,
57 .endianness = DEVICE_NATIVE_ENDIAN,
pbrook502a5392006-05-13 16:11:23 +000058};
59
pbrookd2b59312006-09-24 00:16:34 +000060static int pci_vpb_map_irq(PCIDevice *d, int irq_num)
61{
Peter Maydell7e8ce1b2013-03-01 18:03:12 +000062 /* Slot to IRQ mapping for RealView Platform Baseboard 926 backplane
63 * name slot IntA IntB IntC IntD
64 * A 31 IRQ28 IRQ29 IRQ30 IRQ27
65 * B 30 IRQ27 IRQ28 IRQ29 IRQ30
66 * C 29 IRQ30 IRQ27 IRQ28 IRQ29
67 * Slot C is for the host bridge; A and B the peripherals.
68 * Our output irqs 0..3 correspond to the baseboard's 27..30.
69 */
70 return (PCI_SLOT(d->devfn) + irq_num - 2) % PCI_NUM_PINS;
pbrookd2b59312006-09-24 00:16:34 +000071}
72
Juan Quintela5d4e84c2009-08-28 15:28:17 +020073static void pci_vpb_set_irq(void *opaque, int irq_num, int level)
pbrook502a5392006-05-13 16:11:23 +000074{
Juan Quintela5d4e84c2009-08-28 15:28:17 +020075 qemu_irq *pic = opaque;
76
Paul Brook97aff482009-05-14 22:35:07 +010077 qemu_set_irq(pic[irq_num], level);
pbrook502a5392006-05-13 16:11:23 +000078}
79
Peter Maydell833a26d2013-03-01 15:52:59 +000080static void pci_vpb_init(Object *obj)
81{
82 PCIHostState *h = PCI_HOST_BRIDGE(obj);
83 PCIVPBState *s = PCI_VPB(obj);
84
Peter Maydell042f0882013-03-01 17:35:36 +000085 // XXX size of region?
86 memory_region_init(&s->pci_io_space, "pci_io", 0x100000);
87
Peter Maydell833a26d2013-03-01 15:52:59 +000088 pci_bus_new_inplace(&s->pci_bus, DEVICE(obj), "pci",
Peter Maydell042f0882013-03-01 17:35:36 +000089 get_system_memory(), &s->pci_io_space,
Peter Maydell7e8ce1b2013-03-01 18:03:12 +000090 PCI_DEVFN(29, 0));
Peter Maydell833a26d2013-03-01 15:52:59 +000091 h->bus = &s->pci_bus;
92
93 object_initialize(&s->pci_dev, TYPE_VERSATILE_PCI_HOST);
94 qdev_set_parent_bus(DEVICE(&s->pci_dev), BUS(&s->pci_bus));
Peter Maydell7e8ce1b2013-03-01 18:03:12 +000095 object_property_set_int(OBJECT(&s->pci_dev), PCI_DEVFN(29, 0), "addr",
96 NULL);
Peter Maydell833a26d2013-03-01 15:52:59 +000097}
98
Peter Maydell8bea7cb2013-03-01 14:42:54 +000099static void pci_vpb_realize(DeviceState *dev, Error **errp)
Paul Brook0027b062009-05-14 22:35:08 +0100100{
Peter Maydell8bea7cb2013-03-01 14:42:54 +0000101 PCIVPBState *s = PCI_VPB(dev);
102 SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
Paul Brook0027b062009-05-14 22:35:08 +0100103 int i;
104
105 for (i = 0; i < 4; i++) {
Peter Maydell8bea7cb2013-03-01 14:42:54 +0000106 sysbus_init_irq(sbd, &s->irq[i]);
Paul Brook0027b062009-05-14 22:35:08 +0100107 }
Peter Maydell833a26d2013-03-01 15:52:59 +0000108
109 pci_bus_irqs(&s->pci_bus, pci_vpb_set_irq, pci_vpb_map_irq, s->irq, 4);
Paul Brook0027b062009-05-14 22:35:08 +0100110
111 /* ??? Register memory space. */
112
Peter Maydell7d6e7712011-09-01 18:36:53 +0100113 /* Our memory regions are:
114 * 0 : PCI self config window
115 * 1 : PCI config window
Peter Maydell720667a2013-03-01 13:57:45 +0000116 * 2 : PCI IO window
Peter Maydell7d6e7712011-09-01 18:36:53 +0100117 */
Peter Maydell833a26d2013-03-01 15:52:59 +0000118 memory_region_init_io(&s->mem_config, &pci_vpb_config_ops, &s->pci_bus,
Avi Kivity45de0942011-08-15 17:17:32 +0300119 "pci-vpb-selfconfig", 0x1000000);
Peter Maydell8bea7cb2013-03-01 14:42:54 +0000120 sysbus_init_mmio(sbd, &s->mem_config);
Peter Maydell833a26d2013-03-01 15:52:59 +0000121 memory_region_init_io(&s->mem_config2, &pci_vpb_config_ops, &s->pci_bus,
Avi Kivity45de0942011-08-15 17:17:32 +0300122 "pci-vpb-config", 0x1000000);
Peter Maydell8bea7cb2013-03-01 14:42:54 +0000123 sysbus_init_mmio(sbd, &s->mem_config2);
Peter Maydell042f0882013-03-01 17:35:36 +0000124
125 sysbus_init_mmio(sbd, &s->pci_io_space);
Avi Kivity45de0942011-08-15 17:17:32 +0300126
Peter Maydell833a26d2013-03-01 15:52:59 +0000127 /* TODO Remove once realize propagates to child devices. */
128 object_property_set_bool(OBJECT(&s->pci_dev), true, "realized", errp);
Paul Brook0027b062009-05-14 22:35:08 +0100129}
130
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200131static int versatile_pci_host_init(PCIDevice *d)
Paul Brook0027b062009-05-14 22:35:08 +0100132{
Michael S. Tsirkina408b1d2010-02-08 23:36:02 +0200133 pci_set_word(d->config + PCI_STATUS,
134 PCI_STATUS_66MHZ | PCI_STATUS_DEVSEL_MEDIUM);
Michael S. Tsirkin01764fe2010-02-08 23:33:33 +0200135 pci_set_byte(d->config + PCI_LATENCY_TIMER, 0x10);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200136 return 0;
pbrook502a5392006-05-13 16:11:23 +0000137}
Paul Brook0027b062009-05-14 22:35:08 +0100138
Anthony Liguori40021f02011-12-04 12:22:06 -0600139static void versatile_pci_host_class_init(ObjectClass *klass, void *data)
140{
141 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
142
143 k->init = versatile_pci_host_init;
144 k->vendor_id = PCI_VENDOR_ID_XILINX;
145 k->device_id = PCI_DEVICE_ID_XILINX_XC2VP30;
146 k->class_id = PCI_CLASS_PROCESSOR_CO;
147}
148
Andreas Färber8c43a6f2013-01-10 16:19:07 +0100149static const TypeInfo versatile_pci_host_info = {
Peter Maydell8bea7cb2013-03-01 14:42:54 +0000150 .name = TYPE_VERSATILE_PCI_HOST,
Anthony Liguori39bffca2011-12-07 21:34:16 -0600151 .parent = TYPE_PCI_DEVICE,
152 .instance_size = sizeof(PCIDevice),
153 .class_init = versatile_pci_host_class_init,
Gerd Hoffmann0aab0d32009-06-30 14:12:07 +0200154};
155
Anthony Liguori999e12b2012-01-24 13:12:29 -0600156static void pci_vpb_class_init(ObjectClass *klass, void *data)
157{
Peter Maydell8bea7cb2013-03-01 14:42:54 +0000158 DeviceClass *dc = DEVICE_CLASS(klass);
Anthony Liguori999e12b2012-01-24 13:12:29 -0600159
Peter Maydell8bea7cb2013-03-01 14:42:54 +0000160 dc->realize = pci_vpb_realize;
Anthony Liguori999e12b2012-01-24 13:12:29 -0600161}
162
Andreas Färber8c43a6f2013-01-10 16:19:07 +0100163static const TypeInfo pci_vpb_info = {
Peter Maydell8bea7cb2013-03-01 14:42:54 +0000164 .name = TYPE_VERSATILE_PCI,
Peter Maydell833a26d2013-03-01 15:52:59 +0000165 .parent = TYPE_PCI_HOST_BRIDGE,
Anthony Liguori39bffca2011-12-07 21:34:16 -0600166 .instance_size = sizeof(PCIVPBState),
Peter Maydell833a26d2013-03-01 15:52:59 +0000167 .instance_init = pci_vpb_init,
Anthony Liguori39bffca2011-12-07 21:34:16 -0600168 .class_init = pci_vpb_class_init,
Anthony Liguori999e12b2012-01-24 13:12:29 -0600169};
170
Andreas Färber83f7d432012-02-09 15:20:55 +0100171static void versatile_pci_register_types(void)
Paul Brook0027b062009-05-14 22:35:08 +0100172{
Anthony Liguori39bffca2011-12-07 21:34:16 -0600173 type_register_static(&pci_vpb_info);
Anthony Liguori39bffca2011-12-07 21:34:16 -0600174 type_register_static(&versatile_pci_host_info);
Paul Brook0027b062009-05-14 22:35:08 +0100175}
176
Andreas Färber83f7d432012-02-09 15:20:55 +0100177type_init(versatile_pci_register_types)