blob: 1747628f3d66a9bfcdd83e4da797584ea915db68 [file] [log] [blame]
balrog1e5459a2008-12-07 19:08:45 +00001/*
2 * SuperH on-chip PCIC emulation.
3 *
4 * Copyright (c) 2008 Takashi YOSHII
5 *
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 */
Peter Maydell9d4c9942016-01-26 18:17:20 +000024#include "qemu/osdep.h"
Paolo Bonzini83c9f4c2013-02-04 15:40:22 +010025#include "hw/sysbus.h"
Paolo Bonzini0d09e412013-02-05 17:06:20 +010026#include "hw/sh4/sh.h"
Paolo Bonzini83c9f4c2013-02-04 15:40:22 +010027#include "hw/pci/pci.h"
28#include "hw/pci/pci_host.h"
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010029#include "qemu/bswap.h"
Paolo Bonzini022c62c2012-12-17 18:19:49 +010030#include "exec/address-spaces.h"
balrog1e5459a2008-12-07 19:08:45 +000031
Paolo Bonzinib23ea252013-07-22 15:54:29 +020032#define TYPE_SH_PCI_HOST_BRIDGE "sh_pci"
33
34#define SH_PCI_HOST_BRIDGE(obj) \
35 OBJECT_CHECK(SHPCIState, (obj), TYPE_SH_PCI_HOST_BRIDGE)
36
Aurelien Jarnocf154392011-01-19 18:23:59 +010037typedef struct SHPCIState {
Paolo Bonzinib23ea252013-07-22 15:54:29 +020038 PCIHostState parent_obj;
39
balrog1e5459a2008-12-07 19:08:45 +000040 PCIDevice *dev;
Aurelien Jarnocf154392011-01-19 18:23:59 +010041 qemu_irq irq[4];
Avi Kivityfb571172011-08-15 17:17:30 +030042 MemoryRegion memconfig_p4;
43 MemoryRegion memconfig_a7;
44 MemoryRegion isa;
balrog1e5459a2008-12-07 19:08:45 +000045 uint32_t par;
46 uint32_t mbr;
47 uint32_t iobr;
Aurelien Jarnocf154392011-01-19 18:23:59 +010048} SHPCIState;
balrog1e5459a2008-12-07 19:08:45 +000049
Avi Kivitya8170e52012-10-23 12:30:10 +020050static void sh_pci_reg_write (void *p, hwaddr addr, uint64_t val,
Avi Kivityfb571172011-08-15 17:17:30 +030051 unsigned size)
balrog1e5459a2008-12-07 19:08:45 +000052{
Aurelien Jarnocf154392011-01-19 18:23:59 +010053 SHPCIState *pcic = p;
Paolo Bonzinib23ea252013-07-22 15:54:29 +020054 PCIHostState *phb = PCI_HOST_BRIDGE(pcic);
55
balrog1e5459a2008-12-07 19:08:45 +000056 switch(addr) {
57 case 0 ... 0xfc:
Peter Maydellb7a511242016-06-10 17:10:21 +010058 stl_le_p(pcic->dev->config + addr, val);
balrog1e5459a2008-12-07 19:08:45 +000059 break;
60 case 0x1c0:
61 pcic->par = val;
62 break;
63 case 0x1c4:
Aurelien Jarno5ba9e952010-04-11 23:59:39 +020064 pcic->mbr = val & 0xff000001;
balrog1e5459a2008-12-07 19:08:45 +000065 break;
66 case 0x1c8:
Aurelien Jarno5ba9e952010-04-11 23:59:39 +020067 if ((val & 0xfffc0000) != (pcic->iobr & 0xfffc0000)) {
Avi Kivityfb571172011-08-15 17:17:30 +030068 memory_region_del_subregion(get_system_memory(), &pcic->isa);
Aurelien Jarno5ba9e952010-04-11 23:59:39 +020069 pcic->iobr = val & 0xfffc0001;
Avi Kivityfb571172011-08-15 17:17:30 +030070 memory_region_add_subregion(get_system_memory(),
71 pcic->iobr & 0xfffc0000, &pcic->isa);
Aurelien Jarno5ba9e952010-04-11 23:59:39 +020072 }
balrog1e5459a2008-12-07 19:08:45 +000073 break;
74 case 0x220:
Paolo Bonzinib23ea252013-07-22 15:54:29 +020075 pci_data_write(phb->bus, pcic->par, val, 4);
balrog1e5459a2008-12-07 19:08:45 +000076 break;
77 }
78}
79
Avi Kivitya8170e52012-10-23 12:30:10 +020080static uint64_t sh_pci_reg_read (void *p, hwaddr addr,
Avi Kivityfb571172011-08-15 17:17:30 +030081 unsigned size)
balrog1e5459a2008-12-07 19:08:45 +000082{
Aurelien Jarnocf154392011-01-19 18:23:59 +010083 SHPCIState *pcic = p;
Paolo Bonzinib23ea252013-07-22 15:54:29 +020084 PCIHostState *phb = PCI_HOST_BRIDGE(pcic);
85
balrog1e5459a2008-12-07 19:08:45 +000086 switch(addr) {
87 case 0 ... 0xfc:
Peter Maydellb7a511242016-06-10 17:10:21 +010088 return ldl_le_p(pcic->dev->config + addr);
balrog1e5459a2008-12-07 19:08:45 +000089 case 0x1c0:
90 return pcic->par;
Aurelien Jarno5ba9e952010-04-11 23:59:39 +020091 case 0x1c4:
92 return pcic->mbr;
93 case 0x1c8:
94 return pcic->iobr;
balrog1e5459a2008-12-07 19:08:45 +000095 case 0x220:
Paolo Bonzinib23ea252013-07-22 15:54:29 +020096 return pci_data_read(phb->bus, pcic->par, 4);
balrog1e5459a2008-12-07 19:08:45 +000097 }
98 return 0;
99}
100
Avi Kivityfb571172011-08-15 17:17:30 +0300101static const MemoryRegionOps sh_pci_reg_ops = {
102 .read = sh_pci_reg_read,
103 .write = sh_pci_reg_write,
104 .endianness = DEVICE_NATIVE_ENDIAN,
105 .valid = {
106 .min_access_size = 4,
107 .max_access_size = 4,
108 },
balrog1e5459a2008-12-07 19:08:45 +0000109};
110
Aurelien Jarnocf154392011-01-19 18:23:59 +0100111static int sh_pci_map_irq(PCIDevice *d, int irq_num)
balrog1e5459a2008-12-07 19:08:45 +0000112{
Aurelien Jarnocf154392011-01-19 18:23:59 +0100113 return (d->devfn >> 3);
balrog1e5459a2008-12-07 19:08:45 +0000114}
Aurelien Jarnocf154392011-01-19 18:23:59 +0100115
116static void sh_pci_set_irq(void *opaque, int irq_num, int level)
117{
118 qemu_irq *pic = opaque;
119
120 qemu_set_irq(pic[irq_num], level);
121}
122
Anthony Liguori999e12b2012-01-24 13:12:29 -0600123static int sh_pci_device_init(SysBusDevice *dev)
Aurelien Jarnocf154392011-01-19 18:23:59 +0100124{
Paolo Bonzinib23ea252013-07-22 15:54:29 +0200125 PCIHostState *phb;
Aurelien Jarnocf154392011-01-19 18:23:59 +0100126 SHPCIState *s;
127 int i;
128
Paolo Bonzinib23ea252013-07-22 15:54:29 +0200129 s = SH_PCI_HOST_BRIDGE(dev);
130 phb = PCI_HOST_BRIDGE(s);
Aurelien Jarnocf154392011-01-19 18:23:59 +0100131 for (i = 0; i < 4; i++) {
132 sysbus_init_irq(dev, &s->irq[i]);
133 }
Paolo Bonzinib23ea252013-07-22 15:54:29 +0200134 phb->bus = pci_register_bus(DEVICE(dev), "pci",
135 sh_pci_set_irq, sh_pci_map_irq,
136 s->irq,
137 get_system_memory(),
138 get_system_io(),
139 PCI_DEVFN(0, 0), 4, TYPE_PCI_BUS);
Paolo Bonzini29776732013-06-06 21:25:08 -0400140 memory_region_init_io(&s->memconfig_p4, OBJECT(s), &sh_pci_reg_ops, s,
Avi Kivityfb571172011-08-15 17:17:30 +0300141 "sh_pci", 0x224);
Paolo Bonzini29776732013-06-06 21:25:08 -0400142 memory_region_init_alias(&s->memconfig_a7, OBJECT(s), "sh_pci.2",
143 &s->memconfig_p4, 0, 0x224);
Paolo Bonzini4759ab62013-07-22 15:54:11 +0200144 memory_region_init_alias(&s->isa, OBJECT(s), "sh_pci.isa",
145 get_system_io(), 0, 0x40000);
Benoît Canet8c106232011-12-16 23:37:46 +0100146 sysbus_init_mmio(dev, &s->memconfig_p4);
Avi Kivity750ecd42011-11-27 11:38:10 +0200147 sysbus_init_mmio(dev, &s->memconfig_a7);
Benoît Canet8c106232011-12-16 23:37:46 +0100148 s->iobr = 0xfe240000;
149 memory_region_add_subregion(get_system_memory(), s->iobr, &s->isa);
150
Paolo Bonzinib23ea252013-07-22 15:54:29 +0200151 s->dev = pci_create_simple(phb->bus, PCI_DEVFN(0, 0), "sh_pci_host");
Aurelien Jarnocf154392011-01-19 18:23:59 +0100152 return 0;
153}
154
Cao jin9f23b272015-12-18 19:03:48 +0800155static void sh_pci_host_realize(PCIDevice *d, Error **errp)
Aurelien Jarnocf154392011-01-19 18:23:59 +0100156{
Aurelien Jarnocf154392011-01-19 18:23:59 +0100157 pci_set_word(d->config + PCI_COMMAND, PCI_COMMAND_WAIT);
158 pci_set_word(d->config + PCI_STATUS, PCI_STATUS_CAP_LIST |
159 PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM);
Aurelien Jarnocf154392011-01-19 18:23:59 +0100160}
161
Anthony Liguori40021f02011-12-04 12:22:06 -0600162static void sh_pci_host_class_init(ObjectClass *klass, void *data)
163{
164 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
Markus Armbruster08c58f92013-11-28 17:26:58 +0100165 DeviceClass *dc = DEVICE_CLASS(klass);
Anthony Liguori40021f02011-12-04 12:22:06 -0600166
Cao jin9f23b272015-12-18 19:03:48 +0800167 k->realize = sh_pci_host_realize;
Anthony Liguori40021f02011-12-04 12:22:06 -0600168 k->vendor_id = PCI_VENDOR_ID_HITACHI;
169 k->device_id = PCI_DEVICE_ID_HITACHI_SH7751R;
Markus Armbruster08c58f92013-11-28 17:26:58 +0100170 /*
171 * PCI-facing part of the host bridge, not usable without the
172 * host-facing part, which can't be device_add'ed, yet.
173 */
174 dc->cannot_instantiate_with_device_add_yet = true;
Anthony Liguori40021f02011-12-04 12:22:06 -0600175}
176
Andreas Färber8c43a6f2013-01-10 16:19:07 +0100177static const TypeInfo sh_pci_host_info = {
Anthony Liguori39bffca2011-12-07 21:34:16 -0600178 .name = "sh_pci_host",
179 .parent = TYPE_PCI_DEVICE,
180 .instance_size = sizeof(PCIDevice),
181 .class_init = sh_pci_host_class_init,
Aurelien Jarnocf154392011-01-19 18:23:59 +0100182};
183
Anthony Liguori999e12b2012-01-24 13:12:29 -0600184static void sh_pci_device_class_init(ObjectClass *klass, void *data)
185{
186 SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
187
188 sdc->init = sh_pci_device_init;
189}
190
Andreas Färber8c43a6f2013-01-10 16:19:07 +0100191static const TypeInfo sh_pci_device_info = {
Paolo Bonzinib23ea252013-07-22 15:54:29 +0200192 .name = TYPE_SH_PCI_HOST_BRIDGE,
193 .parent = TYPE_PCI_HOST_BRIDGE,
Anthony Liguori39bffca2011-12-07 21:34:16 -0600194 .instance_size = sizeof(SHPCIState),
195 .class_init = sh_pci_device_class_init,
Anthony Liguori999e12b2012-01-24 13:12:29 -0600196};
197
Andreas Färber83f7d432012-02-09 15:20:55 +0100198static void sh_pci_register_types(void)
Aurelien Jarnocf154392011-01-19 18:23:59 +0100199{
Anthony Liguori39bffca2011-12-07 21:34:16 -0600200 type_register_static(&sh_pci_device_info);
201 type_register_static(&sh_pci_host_info);
Aurelien Jarnocf154392011-01-19 18:23:59 +0100202}
203
Andreas Färber83f7d432012-02-09 15:20:55 +0100204type_init(sh_pci_register_types)