11e5459a3Sbalrog /* 21e5459a3Sbalrog * SuperH on-chip PCIC emulation. 31e5459a3Sbalrog * 41e5459a3Sbalrog * Copyright (c) 2008 Takashi YOSHII 51e5459a3Sbalrog * 61e5459a3Sbalrog * Permission is hereby granted, free of charge, to any person obtaining a copy 71e5459a3Sbalrog * of this software and associated documentation files (the "Software"), to deal 81e5459a3Sbalrog * in the Software without restriction, including without limitation the rights 91e5459a3Sbalrog * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 101e5459a3Sbalrog * copies of the Software, and to permit persons to whom the Software is 111e5459a3Sbalrog * furnished to do so, subject to the following conditions: 121e5459a3Sbalrog * 131e5459a3Sbalrog * The above copyright notice and this permission notice shall be included in 141e5459a3Sbalrog * all copies or substantial portions of the Software. 151e5459a3Sbalrog * 161e5459a3Sbalrog * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 171e5459a3Sbalrog * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 181e5459a3Sbalrog * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 191e5459a3Sbalrog * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 201e5459a3Sbalrog * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 211e5459a3Sbalrog * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 221e5459a3Sbalrog * THE SOFTWARE. 231e5459a3Sbalrog */ 240b8fa32fSMarkus Armbruster 259d4c9946SPeter Maydell #include "qemu/osdep.h" 2683c9f4caSPaolo Bonzini #include "hw/sysbus.h" 270d09e41aSPaolo Bonzini #include "hw/sh4/sh.h" 2864552b6bSMarkus Armbruster #include "hw/irq.h" 2983c9f4caSPaolo Bonzini #include "hw/pci/pci.h" 3083c9f4caSPaolo Bonzini #include "hw/pci/pci_host.h" 311de7afc9SPaolo Bonzini #include "qemu/bswap.h" 320b8fa32fSMarkus Armbruster #include "qemu/module.h" 33db1015e9SEduardo Habkost #include "qom/object.h" 341e5459a3Sbalrog 35b23ea25fSPaolo Bonzini #define TYPE_SH_PCI_HOST_BRIDGE "sh_pci" 36b23ea25fSPaolo Bonzini 378063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(SHPCIState, SH_PCI_HOST_BRIDGE) 38b23ea25fSPaolo Bonzini 39db1015e9SEduardo Habkost struct SHPCIState { 40b23ea25fSPaolo Bonzini PCIHostState parent_obj; 41b23ea25fSPaolo Bonzini 421e5459a3Sbalrog PCIDevice *dev; 43cf154394SAurelien Jarno qemu_irq irq[4]; 44fb57117aSAvi Kivity MemoryRegion memconfig_p4; 45fb57117aSAvi Kivity MemoryRegion memconfig_a7; 46fb57117aSAvi Kivity MemoryRegion isa; 471e5459a3Sbalrog uint32_t par; 481e5459a3Sbalrog uint32_t mbr; 491e5459a3Sbalrog uint32_t iobr; 50db1015e9SEduardo Habkost }; 511e5459a3Sbalrog 52*f94bff13SBALATON Zoltan static void sh_pci_reg_write(void *p, hwaddr addr, uint64_t val, unsigned size) 531e5459a3Sbalrog { 54cf154394SAurelien Jarno SHPCIState *pcic = p; 55b23ea25fSPaolo Bonzini PCIHostState *phb = PCI_HOST_BRIDGE(pcic); 56b23ea25fSPaolo Bonzini 571e5459a3Sbalrog switch (addr) { 581e5459a3Sbalrog case 0 ... 0xfc: 59b7a51124SPeter Maydell stl_le_p(pcic->dev->config + addr, val); 601e5459a3Sbalrog break; 611e5459a3Sbalrog case 0x1c0: 621e5459a3Sbalrog pcic->par = val; 631e5459a3Sbalrog break; 641e5459a3Sbalrog case 0x1c4: 655ba9e952SAurelien Jarno pcic->mbr = val & 0xff000001; 661e5459a3Sbalrog break; 671e5459a3Sbalrog case 0x1c8: 685ba9e952SAurelien Jarno pcic->iobr = val & 0xfffc0001; 6947d2d36cSGuenter Roeck memory_region_set_alias_offset(&pcic->isa, val & 0xfffc0000); 701e5459a3Sbalrog break; 711e5459a3Sbalrog case 0x220: 72b23ea25fSPaolo Bonzini pci_data_write(phb->bus, pcic->par, val, 4); 731e5459a3Sbalrog break; 741e5459a3Sbalrog } 751e5459a3Sbalrog } 761e5459a3Sbalrog 77*f94bff13SBALATON Zoltan static uint64_t sh_pci_reg_read(void *p, hwaddr addr, unsigned size) 781e5459a3Sbalrog { 79cf154394SAurelien Jarno SHPCIState *pcic = p; 80b23ea25fSPaolo Bonzini PCIHostState *phb = PCI_HOST_BRIDGE(pcic); 81b23ea25fSPaolo Bonzini 821e5459a3Sbalrog switch (addr) { 831e5459a3Sbalrog case 0 ... 0xfc: 84b7a51124SPeter Maydell return ldl_le_p(pcic->dev->config + addr); 851e5459a3Sbalrog case 0x1c0: 861e5459a3Sbalrog return pcic->par; 875ba9e952SAurelien Jarno case 0x1c4: 885ba9e952SAurelien Jarno return pcic->mbr; 895ba9e952SAurelien Jarno case 0x1c8: 905ba9e952SAurelien Jarno return pcic->iobr; 911e5459a3Sbalrog case 0x220: 92b23ea25fSPaolo Bonzini return pci_data_read(phb->bus, pcic->par, 4); 931e5459a3Sbalrog } 941e5459a3Sbalrog return 0; 951e5459a3Sbalrog } 961e5459a3Sbalrog 97fb57117aSAvi Kivity static const MemoryRegionOps sh_pci_reg_ops = { 98fb57117aSAvi Kivity .read = sh_pci_reg_read, 99fb57117aSAvi Kivity .write = sh_pci_reg_write, 100fb57117aSAvi Kivity .endianness = DEVICE_NATIVE_ENDIAN, 101fb57117aSAvi Kivity .valid = { 102fb57117aSAvi Kivity .min_access_size = 4, 103fb57117aSAvi Kivity .max_access_size = 4, 104fb57117aSAvi Kivity }, 1051e5459a3Sbalrog }; 1061e5459a3Sbalrog 107cf154394SAurelien Jarno static int sh_pci_map_irq(PCIDevice *d, int irq_num) 1081e5459a3Sbalrog { 1098d40def6SPhilippe Mathieu-Daudé return PCI_SLOT(d->devfn); 1101e5459a3Sbalrog } 111cf154394SAurelien Jarno 112cf154394SAurelien Jarno static void sh_pci_set_irq(void *opaque, int irq_num, int level) 113cf154394SAurelien Jarno { 114cf154394SAurelien Jarno qemu_irq *pic = opaque; 115cf154394SAurelien Jarno 116cf154394SAurelien Jarno qemu_set_irq(pic[irq_num], level); 117cf154394SAurelien Jarno } 118cf154394SAurelien Jarno 1190e372e58SPhilippe Mathieu-Daudé static void sh_pci_device_realize(DeviceState *dev, Error **errp) 120cf154394SAurelien Jarno { 1210e372e58SPhilippe Mathieu-Daudé SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 1220e372e58SPhilippe Mathieu-Daudé SHPCIState *s = SH_PCI_HOST_BRIDGE(dev); 1230e372e58SPhilippe Mathieu-Daudé PCIHostState *phb = PCI_HOST_BRIDGE(s); 124cf154394SAurelien Jarno int i; 125cf154394SAurelien Jarno 126cf154394SAurelien Jarno for (i = 0; i < 4; i++) { 1270e372e58SPhilippe Mathieu-Daudé sysbus_init_irq(sbd, &s->irq[i]); 128cf154394SAurelien Jarno } 1298e5c952bSPhilippe Mathieu-Daudé phb->bus = pci_register_root_bus(dev, "pci", 130cf154394SAurelien Jarno sh_pci_set_irq, sh_pci_map_irq, 131aee97b84SAvi Kivity s->irq, 132aee97b84SAvi Kivity get_system_memory(), 133aee97b84SAvi Kivity get_system_io(), 13460a0e443SAlex Williamson PCI_DEVFN(0, 0), 4, TYPE_PCI_BUS); 13529776739SPaolo Bonzini memory_region_init_io(&s->memconfig_p4, OBJECT(s), &sh_pci_reg_ops, s, 136fb57117aSAvi Kivity "sh_pci", 0x224); 13729776739SPaolo Bonzini memory_region_init_alias(&s->memconfig_a7, OBJECT(s), "sh_pci.2", 13829776739SPaolo Bonzini &s->memconfig_p4, 0, 0x224); 1394759ab6bSPaolo Bonzini memory_region_init_alias(&s->isa, OBJECT(s), "sh_pci.isa", 1404759ab6bSPaolo Bonzini get_system_io(), 0, 0x40000); 1410e372e58SPhilippe Mathieu-Daudé sysbus_init_mmio(sbd, &s->memconfig_p4); 1420e372e58SPhilippe Mathieu-Daudé sysbus_init_mmio(sbd, &s->memconfig_a7); 14347d2d36cSGuenter Roeck memory_region_add_subregion(get_system_memory(), 0xfe240000, &s->isa); 1448c106233SBenoît Canet 145b23ea25fSPaolo Bonzini s->dev = pci_create_simple(phb->bus, PCI_DEVFN(0, 0), "sh_pci_host"); 146cf154394SAurelien Jarno } 147cf154394SAurelien Jarno 1489f23b27dSCao jin static void sh_pci_host_realize(PCIDevice *d, Error **errp) 149cf154394SAurelien Jarno { 150cf154394SAurelien Jarno pci_set_word(d->config + PCI_COMMAND, PCI_COMMAND_WAIT); 151cf154394SAurelien Jarno pci_set_word(d->config + PCI_STATUS, PCI_STATUS_CAP_LIST | 152cf154394SAurelien Jarno PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM); 153cf154394SAurelien Jarno } 154cf154394SAurelien Jarno 15540021f08SAnthony Liguori static void sh_pci_host_class_init(ObjectClass *klass, void *data) 15640021f08SAnthony Liguori { 15740021f08SAnthony Liguori PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); 15808c58f92SMarkus Armbruster DeviceClass *dc = DEVICE_CLASS(klass); 15940021f08SAnthony Liguori 1609f23b27dSCao jin k->realize = sh_pci_host_realize; 16140021f08SAnthony Liguori k->vendor_id = PCI_VENDOR_ID_HITACHI; 16240021f08SAnthony Liguori k->device_id = PCI_DEVICE_ID_HITACHI_SH7751R; 16308c58f92SMarkus Armbruster /* 16408c58f92SMarkus Armbruster * PCI-facing part of the host bridge, not usable without the 16508c58f92SMarkus Armbruster * host-facing part, which can't be device_add'ed, yet. 16608c58f92SMarkus Armbruster */ 167e90f2a8cSEduardo Habkost dc->user_creatable = false; 16840021f08SAnthony Liguori } 16940021f08SAnthony Liguori 1708c43a6f0SAndreas Färber static const TypeInfo sh_pci_host_info = { 17140021f08SAnthony Liguori .name = "sh_pci_host", 17239bffca2SAnthony Liguori .parent = TYPE_PCI_DEVICE, 17339bffca2SAnthony Liguori .instance_size = sizeof(PCIDevice), 17440021f08SAnthony Liguori .class_init = sh_pci_host_class_init, 175fd3b02c8SEduardo Habkost .interfaces = (InterfaceInfo[]) { 176fd3b02c8SEduardo Habkost { INTERFACE_CONVENTIONAL_PCI_DEVICE }, 177fd3b02c8SEduardo Habkost { }, 178fd3b02c8SEduardo Habkost }, 179cf154394SAurelien Jarno }; 180cf154394SAurelien Jarno 181999e12bbSAnthony Liguori static void sh_pci_device_class_init(ObjectClass *klass, void *data) 182999e12bbSAnthony Liguori { 1830e372e58SPhilippe Mathieu-Daudé DeviceClass *dc = DEVICE_CLASS(klass); 184999e12bbSAnthony Liguori 1850e372e58SPhilippe Mathieu-Daudé dc->realize = sh_pci_device_realize; 186999e12bbSAnthony Liguori } 187999e12bbSAnthony Liguori 1888c43a6f0SAndreas Färber static const TypeInfo sh_pci_device_info = { 189b23ea25fSPaolo Bonzini .name = TYPE_SH_PCI_HOST_BRIDGE, 190b23ea25fSPaolo Bonzini .parent = TYPE_PCI_HOST_BRIDGE, 19139bffca2SAnthony Liguori .instance_size = sizeof(SHPCIState), 192999e12bbSAnthony Liguori .class_init = sh_pci_device_class_init, 193999e12bbSAnthony Liguori }; 194999e12bbSAnthony Liguori 19583f7d43aSAndreas Färber static void sh_pci_register_types(void) 196cf154394SAurelien Jarno { 19739bffca2SAnthony Liguori type_register_static(&sh_pci_device_info); 19839bffca2SAnthony Liguori type_register_static(&sh_pci_host_info); 199cf154394SAurelien Jarno } 200cf154394SAurelien Jarno 20183f7d43aSAndreas Färber type_init(sh_pci_register_types) 202