xref: /qemu/hw/pci-host/grackle.c (revision b950914d)
1c0907c9eSPaolo Bonzini /*
2c0907c9eSPaolo Bonzini  * QEMU Grackle PCI host (heathrow OldWorld PowerMac)
3c0907c9eSPaolo Bonzini  *
4c0907c9eSPaolo Bonzini  * Copyright (c) 2006-2007 Fabrice Bellard
5c0907c9eSPaolo Bonzini  * Copyright (c) 2007 Jocelyn Mayer
6c0907c9eSPaolo Bonzini  *
7c0907c9eSPaolo Bonzini  * Permission is hereby granted, free of charge, to any person obtaining a copy
8c0907c9eSPaolo Bonzini  * of this software and associated documentation files (the "Software"), to deal
9c0907c9eSPaolo Bonzini  * in the Software without restriction, including without limitation the rights
10c0907c9eSPaolo Bonzini  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11c0907c9eSPaolo Bonzini  * copies of the Software, and to permit persons to whom the Software is
12c0907c9eSPaolo Bonzini  * furnished to do so, subject to the following conditions:
13c0907c9eSPaolo Bonzini  *
14c0907c9eSPaolo Bonzini  * The above copyright notice and this permission notice shall be included in
15c0907c9eSPaolo Bonzini  * all copies or substantial portions of the Software.
16c0907c9eSPaolo Bonzini  *
17c0907c9eSPaolo Bonzini  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18c0907c9eSPaolo Bonzini  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19c0907c9eSPaolo Bonzini  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20c0907c9eSPaolo Bonzini  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21c0907c9eSPaolo Bonzini  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22c0907c9eSPaolo Bonzini  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23c0907c9eSPaolo Bonzini  * THE SOFTWARE.
24c0907c9eSPaolo Bonzini  */
25c0907c9eSPaolo Bonzini 
260d75590dSPeter Maydell #include "qemu/osdep.h"
27c0907c9eSPaolo Bonzini #include "hw/pci/pci_host.h"
28c0907c9eSPaolo Bonzini #include "hw/ppc/mac.h"
29a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
30c0907c9eSPaolo Bonzini #include "hw/pci/pci.h"
3164552b6bSMarkus Armbruster #include "hw/irq.h"
32b0318ec1SMark Cave-Ayland #include "qapi/error.h"
330b8fa32fSMarkus Armbruster #include "qemu/module.h"
34b728fbbcSMark Cave-Ayland #include "trace.h"
35db1015e9SEduardo Habkost #include "qom/object.h"
36c0907c9eSPaolo Bonzini 
378063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(GrackleState, GRACKLE_PCI_HOST_BRIDGE)
38c0907c9eSPaolo Bonzini 
39db1015e9SEduardo Habkost struct GrackleState {
40c0907c9eSPaolo Bonzini     PCIHostState parent_obj;
41c0907c9eSPaolo Bonzini 
42ac43eb2eSMark Cave-Ayland     uint32_t ofw_addr;
43b0318ec1SMark Cave-Ayland     qemu_irq irqs[4];
44c0907c9eSPaolo Bonzini     MemoryRegion pci_mmio;
45c0907c9eSPaolo Bonzini     MemoryRegion pci_hole;
46a94e5f99SMark Cave-Ayland     MemoryRegion pci_io;
47db1015e9SEduardo Habkost };
48c0907c9eSPaolo Bonzini 
49c0907c9eSPaolo Bonzini /* Don't know if this matches real hardware, but it agrees with OHW.  */
50c0907c9eSPaolo Bonzini static int pci_grackle_map_irq(PCIDevice *pci_dev, int irq_num)
51c0907c9eSPaolo Bonzini {
52c0907c9eSPaolo Bonzini     return (irq_num + (pci_dev->devfn >> 3)) & 3;
53c0907c9eSPaolo Bonzini }
54c0907c9eSPaolo Bonzini 
55c0907c9eSPaolo Bonzini static void pci_grackle_set_irq(void *opaque, int irq_num, int level)
56c0907c9eSPaolo Bonzini {
57b0318ec1SMark Cave-Ayland     GrackleState *s = opaque;
58c0907c9eSPaolo Bonzini 
59b728fbbcSMark Cave-Ayland     trace_grackle_set_irq(irq_num, level);
60b0318ec1SMark Cave-Ayland     qemu_set_irq(s->irqs[irq_num], level);
61c0907c9eSPaolo Bonzini }
62c0907c9eSPaolo Bonzini 
63b0318ec1SMark Cave-Ayland static void grackle_realize(DeviceState *dev, Error **errp)
64c0907c9eSPaolo Bonzini {
65b0318ec1SMark Cave-Ayland     GrackleState *s = GRACKLE_PCI_HOST_BRIDGE(dev);
66b0318ec1SMark Cave-Ayland     PCIHostState *phb = PCI_HOST_BRIDGE(dev);
67c0907c9eSPaolo Bonzini 
68b0318ec1SMark Cave-Ayland     phb->bus = pci_register_root_bus(dev, NULL,
69b0318ec1SMark Cave-Ayland                                      pci_grackle_set_irq,
70b0318ec1SMark Cave-Ayland                                      pci_grackle_map_irq,
71b0318ec1SMark Cave-Ayland                                      s,
72b0318ec1SMark Cave-Ayland                                      &s->pci_mmio,
73a94e5f99SMark Cave-Ayland                                      &s->pci_io,
74b0318ec1SMark Cave-Ayland                                      0, 4, TYPE_PCI_BUS);
75c0907c9eSPaolo Bonzini 
76b0318ec1SMark Cave-Ayland     pci_create_simple(phb->bus, 0, "grackle");
77c0907c9eSPaolo Bonzini }
78c0907c9eSPaolo Bonzini 
79b0318ec1SMark Cave-Ayland static void grackle_init(Object *obj)
80b0318ec1SMark Cave-Ayland {
81b0318ec1SMark Cave-Ayland     GrackleState *s = GRACKLE_PCI_HOST_BRIDGE(obj);
82b0318ec1SMark Cave-Ayland     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
83b0318ec1SMark Cave-Ayland     PCIHostState *phb = PCI_HOST_BRIDGE(obj);
84b0318ec1SMark Cave-Ayland 
85b0318ec1SMark Cave-Ayland     memory_region_init(&s->pci_mmio, OBJECT(s), "pci-mmio", 0x100000000ULL);
86a94e5f99SMark Cave-Ayland     memory_region_init_io(&s->pci_io, OBJECT(s), &unassigned_io_ops, obj,
87a94e5f99SMark Cave-Ayland                           "pci-isa-mmio", 0x00200000);
88a94e5f99SMark Cave-Ayland 
89b0318ec1SMark Cave-Ayland     memory_region_init_alias(&s->pci_hole, OBJECT(s), "pci-hole", &s->pci_mmio,
90b0318ec1SMark Cave-Ayland                              0x80000000ULL, 0x7e000000ULL);
91b0318ec1SMark Cave-Ayland 
92b0318ec1SMark Cave-Ayland     memory_region_init_io(&phb->conf_mem, obj, &pci_host_conf_le_ops,
93b0318ec1SMark Cave-Ayland                           DEVICE(obj), "pci-conf-idx", 0x1000);
94b0318ec1SMark Cave-Ayland     memory_region_init_io(&phb->data_mem, obj, &pci_host_data_le_ops,
95b0318ec1SMark Cave-Ayland                           DEVICE(obj), "pci-data-idx", 0x1000);
96b0318ec1SMark Cave-Ayland 
97b0318ec1SMark Cave-Ayland     sysbus_init_mmio(sbd, &phb->conf_mem);
98b0318ec1SMark Cave-Ayland     sysbus_init_mmio(sbd, &phb->data_mem);
99a773e64aSMark Cave-Ayland     sysbus_init_mmio(sbd, &s->pci_hole);
100a94e5f99SMark Cave-Ayland     sysbus_init_mmio(sbd, &s->pci_io);
101*b950914dSMark Cave-Ayland 
102*b950914dSMark Cave-Ayland     qdev_init_gpio_out(DEVICE(obj), s->irqs, ARRAY_SIZE(s->irqs));
103b0318ec1SMark Cave-Ayland }
104b0318ec1SMark Cave-Ayland 
105b0318ec1SMark Cave-Ayland static void grackle_pci_realize(PCIDevice *d, Error **errp)
106c0907c9eSPaolo Bonzini {
107c0907c9eSPaolo Bonzini     d->config[0x09] = 0x01;
108c0907c9eSPaolo Bonzini }
109c0907c9eSPaolo Bonzini 
110c0907c9eSPaolo Bonzini static void grackle_pci_class_init(ObjectClass *klass, void *data)
111c0907c9eSPaolo Bonzini {
112c0907c9eSPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
113b0318ec1SMark Cave-Ayland     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
114c0907c9eSPaolo Bonzini 
115b0318ec1SMark Cave-Ayland     k->realize   = grackle_pci_realize;
116c0907c9eSPaolo Bonzini     k->vendor_id = PCI_VENDOR_ID_MOTOROLA;
117c0907c9eSPaolo Bonzini     k->device_id = PCI_DEVICE_ID_MOTOROLA_MPC106;
118c0907c9eSPaolo Bonzini     k->revision  = 0x00;
119c0907c9eSPaolo Bonzini     k->class_id  = PCI_CLASS_BRIDGE_HOST;
12008c58f92SMarkus Armbruster     /*
12108c58f92SMarkus Armbruster      * PCI-facing part of the host bridge, not usable without the
12208c58f92SMarkus Armbruster      * host-facing part, which can't be device_add'ed, yet.
12308c58f92SMarkus Armbruster      */
124e90f2a8cSEduardo Habkost     dc->user_creatable = false;
125c0907c9eSPaolo Bonzini }
126c0907c9eSPaolo Bonzini 
127c0907c9eSPaolo Bonzini static const TypeInfo grackle_pci_info = {
128c0907c9eSPaolo Bonzini     .name          = "grackle",
129c0907c9eSPaolo Bonzini     .parent        = TYPE_PCI_DEVICE,
130c0907c9eSPaolo Bonzini     .instance_size = sizeof(PCIDevice),
131c0907c9eSPaolo Bonzini     .class_init = grackle_pci_class_init,
132fd3b02c8SEduardo Habkost     .interfaces = (InterfaceInfo[]) {
133fd3b02c8SEduardo Habkost         { INTERFACE_CONVENTIONAL_PCI_DEVICE },
134fd3b02c8SEduardo Habkost         { },
135fd3b02c8SEduardo Habkost     },
136c0907c9eSPaolo Bonzini };
137c0907c9eSPaolo Bonzini 
138ac43eb2eSMark Cave-Ayland static char *grackle_ofw_unit_address(const SysBusDevice *dev)
139ac43eb2eSMark Cave-Ayland {
140ac43eb2eSMark Cave-Ayland     GrackleState *s = GRACKLE_PCI_HOST_BRIDGE(dev);
141ac43eb2eSMark Cave-Ayland 
142ac43eb2eSMark Cave-Ayland     return g_strdup_printf("%x", s->ofw_addr);
143ac43eb2eSMark Cave-Ayland }
144ac43eb2eSMark Cave-Ayland 
145ac43eb2eSMark Cave-Ayland static Property grackle_properties[] = {
146ac43eb2eSMark Cave-Ayland     DEFINE_PROP_UINT32("ofw-addr", GrackleState, ofw_addr, -1),
147ac43eb2eSMark Cave-Ayland     DEFINE_PROP_END_OF_LIST()
148ac43eb2eSMark Cave-Ayland };
149ac43eb2eSMark Cave-Ayland 
150b0318ec1SMark Cave-Ayland static void grackle_class_init(ObjectClass *klass, void *data)
151c0907c9eSPaolo Bonzini {
152e1624435SLaurent Vivier     DeviceClass *dc = DEVICE_CLASS(klass);
153ac43eb2eSMark Cave-Ayland     SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
154c0907c9eSPaolo Bonzini 
155b0318ec1SMark Cave-Ayland     dc->realize = grackle_realize;
1564f67d30bSMarc-André Lureau     device_class_set_props(dc, grackle_properties);
157e1624435SLaurent Vivier     set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
158ac43eb2eSMark Cave-Ayland     dc->fw_name = "pci";
159ac43eb2eSMark Cave-Ayland     sbc->explicit_ofw_unit_address = grackle_ofw_unit_address;
160c0907c9eSPaolo Bonzini }
161c0907c9eSPaolo Bonzini 
162b0318ec1SMark Cave-Ayland static const TypeInfo grackle_host_info = {
163c0907c9eSPaolo Bonzini     .name          = TYPE_GRACKLE_PCI_HOST_BRIDGE,
164c0907c9eSPaolo Bonzini     .parent        = TYPE_PCI_HOST_BRIDGE,
165c0907c9eSPaolo Bonzini     .instance_size = sizeof(GrackleState),
166b0318ec1SMark Cave-Ayland     .instance_init = grackle_init,
167b0318ec1SMark Cave-Ayland     .class_init    = grackle_class_init,
168c0907c9eSPaolo Bonzini };
169c0907c9eSPaolo Bonzini 
170c0907c9eSPaolo Bonzini static void grackle_register_types(void)
171c0907c9eSPaolo Bonzini {
172c0907c9eSPaolo Bonzini     type_register_static(&grackle_pci_info);
173b0318ec1SMark Cave-Ayland     type_register_static(&grackle_host_info);
174c0907c9eSPaolo Bonzini }
175c0907c9eSPaolo Bonzini 
176c0907c9eSPaolo Bonzini type_init(grackle_register_types)
177