197d3b2cdSBALATON Zoltan /* 297d3b2cdSBALATON Zoltan * Mai Logic Articia S emulation 397d3b2cdSBALATON Zoltan * 497d3b2cdSBALATON Zoltan * Copyright (c) 2023 BALATON Zoltan 597d3b2cdSBALATON Zoltan * 697d3b2cdSBALATON Zoltan * This work is licensed under the GNU GPL license version 2 or later. 797d3b2cdSBALATON Zoltan * 897d3b2cdSBALATON Zoltan */ 997d3b2cdSBALATON Zoltan 1097d3b2cdSBALATON Zoltan #include "qemu/osdep.h" 1197d3b2cdSBALATON Zoltan #include "qemu/log.h" 1297d3b2cdSBALATON Zoltan #include "qapi/error.h" 1397d3b2cdSBALATON Zoltan #include "hw/pci/pci_device.h" 1497d3b2cdSBALATON Zoltan #include "hw/pci/pci_host.h" 1597d3b2cdSBALATON Zoltan #include "hw/irq.h" 1697d3b2cdSBALATON Zoltan #include "hw/i2c/bitbang_i2c.h" 1797d3b2cdSBALATON Zoltan #include "hw/intc/i8259.h" 1897d3b2cdSBALATON Zoltan #include "hw/pci-host/articia.h" 1997d3b2cdSBALATON Zoltan 2097d3b2cdSBALATON Zoltan /* 2197d3b2cdSBALATON Zoltan * This is a minimal emulation of this chip as used in AmigaOne board. 2297d3b2cdSBALATON Zoltan * Most features are missing but those are not needed by firmware and guests. 2397d3b2cdSBALATON Zoltan */ 2497d3b2cdSBALATON Zoltan 2597d3b2cdSBALATON Zoltan OBJECT_DECLARE_SIMPLE_TYPE(ArticiaState, ARTICIA) 2697d3b2cdSBALATON Zoltan 2797d3b2cdSBALATON Zoltan OBJECT_DECLARE_SIMPLE_TYPE(ArticiaHostState, ARTICIA_PCI_HOST) 2897d3b2cdSBALATON Zoltan struct ArticiaHostState { 2997d3b2cdSBALATON Zoltan PCIDevice parent_obj; 3097d3b2cdSBALATON Zoltan 3197d3b2cdSBALATON Zoltan ArticiaState *as; 3297d3b2cdSBALATON Zoltan }; 3397d3b2cdSBALATON Zoltan 3497d3b2cdSBALATON Zoltan /* TYPE_ARTICIA */ 3597d3b2cdSBALATON Zoltan 3697d3b2cdSBALATON Zoltan struct ArticiaState { 3797d3b2cdSBALATON Zoltan PCIHostState parent_obj; 3897d3b2cdSBALATON Zoltan 3997d3b2cdSBALATON Zoltan qemu_irq irq[PCI_NUM_PINS]; 4097d3b2cdSBALATON Zoltan MemoryRegion io; 4197d3b2cdSBALATON Zoltan MemoryRegion mem; 4297d3b2cdSBALATON Zoltan MemoryRegion reg; 4397d3b2cdSBALATON Zoltan 4497d3b2cdSBALATON Zoltan bitbang_i2c_interface smbus; 4597d3b2cdSBALATON Zoltan uint32_t gpio; /* bits 0-7 in, 8-15 out, 16-23 direction (0 in, 1 out) */ 4697d3b2cdSBALATON Zoltan hwaddr gpio_base; 4797d3b2cdSBALATON Zoltan MemoryRegion gpio_reg; 4897d3b2cdSBALATON Zoltan }; 4997d3b2cdSBALATON Zoltan 5097d3b2cdSBALATON Zoltan static uint64_t articia_gpio_read(void *opaque, hwaddr addr, unsigned int size) 5197d3b2cdSBALATON Zoltan { 5297d3b2cdSBALATON Zoltan ArticiaState *s = opaque; 5397d3b2cdSBALATON Zoltan 5497d3b2cdSBALATON Zoltan return (s->gpio >> (addr * 8)) & 0xff; 5597d3b2cdSBALATON Zoltan } 5697d3b2cdSBALATON Zoltan 5797d3b2cdSBALATON Zoltan static void articia_gpio_write(void *opaque, hwaddr addr, uint64_t val, 5897d3b2cdSBALATON Zoltan unsigned int size) 5997d3b2cdSBALATON Zoltan { 6097d3b2cdSBALATON Zoltan ArticiaState *s = opaque; 6197d3b2cdSBALATON Zoltan uint32_t sh = addr * 8; 6297d3b2cdSBALATON Zoltan 6397d3b2cdSBALATON Zoltan if (addr == 0) { 6497d3b2cdSBALATON Zoltan /* in bits read only? */ 6597d3b2cdSBALATON Zoltan return; 6697d3b2cdSBALATON Zoltan } 6797d3b2cdSBALATON Zoltan 6897d3b2cdSBALATON Zoltan if ((s->gpio & (0xff << sh)) != (val & 0xff) << sh) { 6997d3b2cdSBALATON Zoltan s->gpio &= ~(0xff << sh | 0xff); 7097d3b2cdSBALATON Zoltan s->gpio |= (val & 0xff) << sh; 7197d3b2cdSBALATON Zoltan s->gpio |= bitbang_i2c_set(&s->smbus, BITBANG_I2C_SDA, 7297d3b2cdSBALATON Zoltan s->gpio & BIT(16) ? 7397d3b2cdSBALATON Zoltan !!(s->gpio & BIT(8)) : 1); 7497d3b2cdSBALATON Zoltan if ((s->gpio & BIT(17))) { 7597d3b2cdSBALATON Zoltan s->gpio &= ~BIT(0); 7697d3b2cdSBALATON Zoltan s->gpio |= bitbang_i2c_set(&s->smbus, BITBANG_I2C_SCL, 7797d3b2cdSBALATON Zoltan !!(s->gpio & BIT(9))); 7897d3b2cdSBALATON Zoltan } 7997d3b2cdSBALATON Zoltan } 8097d3b2cdSBALATON Zoltan } 8197d3b2cdSBALATON Zoltan 8297d3b2cdSBALATON Zoltan static const MemoryRegionOps articia_gpio_ops = { 8397d3b2cdSBALATON Zoltan .read = articia_gpio_read, 8497d3b2cdSBALATON Zoltan .write = articia_gpio_write, 8597d3b2cdSBALATON Zoltan .valid.min_access_size = 1, 8697d3b2cdSBALATON Zoltan .valid.max_access_size = 1, 8797d3b2cdSBALATON Zoltan .endianness = DEVICE_LITTLE_ENDIAN, 8897d3b2cdSBALATON Zoltan }; 8997d3b2cdSBALATON Zoltan 9097d3b2cdSBALATON Zoltan static uint64_t articia_reg_read(void *opaque, hwaddr addr, unsigned int size) 9197d3b2cdSBALATON Zoltan { 9297d3b2cdSBALATON Zoltan ArticiaState *s = opaque; 9397d3b2cdSBALATON Zoltan uint64_t ret = UINT_MAX; 9497d3b2cdSBALATON Zoltan 9597d3b2cdSBALATON Zoltan switch (addr) { 9697d3b2cdSBALATON Zoltan case 0xc00cf8: 9797d3b2cdSBALATON Zoltan ret = pci_host_conf_le_ops.read(PCI_HOST_BRIDGE(s), 0, size); 9897d3b2cdSBALATON Zoltan break; 9997d3b2cdSBALATON Zoltan case 0xe00cfc ... 0xe00cff: 10097d3b2cdSBALATON Zoltan ret = pci_host_data_le_ops.read(PCI_HOST_BRIDGE(s), addr - 0xe00cfc, size); 10197d3b2cdSBALATON Zoltan break; 10297d3b2cdSBALATON Zoltan case 0xf00000: 10397d3b2cdSBALATON Zoltan ret = pic_read_irq(isa_pic); 10497d3b2cdSBALATON Zoltan break; 10597d3b2cdSBALATON Zoltan default: 10697d3b2cdSBALATON Zoltan qemu_log_mask(LOG_UNIMP, "%s: Unimplemented register read 0x%" 10797d3b2cdSBALATON Zoltan HWADDR_PRIx " %d\n", __func__, addr, size); 10897d3b2cdSBALATON Zoltan break; 10997d3b2cdSBALATON Zoltan } 11097d3b2cdSBALATON Zoltan return ret; 11197d3b2cdSBALATON Zoltan } 11297d3b2cdSBALATON Zoltan 11397d3b2cdSBALATON Zoltan static void articia_reg_write(void *opaque, hwaddr addr, uint64_t val, 11497d3b2cdSBALATON Zoltan unsigned int size) 11597d3b2cdSBALATON Zoltan { 11697d3b2cdSBALATON Zoltan ArticiaState *s = opaque; 11797d3b2cdSBALATON Zoltan 11897d3b2cdSBALATON Zoltan switch (addr) { 11997d3b2cdSBALATON Zoltan case 0xc00cf8: 12097d3b2cdSBALATON Zoltan pci_host_conf_le_ops.write(PCI_HOST_BRIDGE(s), 0, val, size); 12197d3b2cdSBALATON Zoltan break; 12297d3b2cdSBALATON Zoltan case 0xe00cfc ... 0xe00cff: 12397d3b2cdSBALATON Zoltan pci_host_data_le_ops.write(PCI_HOST_BRIDGE(s), addr, val, size); 12497d3b2cdSBALATON Zoltan break; 12597d3b2cdSBALATON Zoltan default: 12697d3b2cdSBALATON Zoltan qemu_log_mask(LOG_UNIMP, "%s: Unimplemented register write 0x%" 12797d3b2cdSBALATON Zoltan HWADDR_PRIx " %d <- %"PRIx64"\n", __func__, addr, size, val); 12897d3b2cdSBALATON Zoltan break; 12997d3b2cdSBALATON Zoltan } 13097d3b2cdSBALATON Zoltan } 13197d3b2cdSBALATON Zoltan 13297d3b2cdSBALATON Zoltan static const MemoryRegionOps articia_reg_ops = { 13397d3b2cdSBALATON Zoltan .read = articia_reg_read, 13497d3b2cdSBALATON Zoltan .write = articia_reg_write, 13597d3b2cdSBALATON Zoltan .valid.min_access_size = 1, 13697d3b2cdSBALATON Zoltan .valid.max_access_size = 4, 13797d3b2cdSBALATON Zoltan .endianness = DEVICE_LITTLE_ENDIAN, 13897d3b2cdSBALATON Zoltan }; 13997d3b2cdSBALATON Zoltan 14097d3b2cdSBALATON Zoltan static void articia_pcihost_set_irq(void *opaque, int n, int level) 14197d3b2cdSBALATON Zoltan { 14297d3b2cdSBALATON Zoltan ArticiaState *s = opaque; 14397d3b2cdSBALATON Zoltan qemu_set_irq(s->irq[n], level); 14497d3b2cdSBALATON Zoltan } 14597d3b2cdSBALATON Zoltan 14697d3b2cdSBALATON Zoltan /* 14797d3b2cdSBALATON Zoltan * AmigaOne SE PCI slot to IRQ routing 14897d3b2cdSBALATON Zoltan * 14997d3b2cdSBALATON Zoltan * repository: https://source.denx.de/u-boot/custodians/u-boot-avr32.git 15097d3b2cdSBALATON Zoltan * refspec: v2010.06 15197d3b2cdSBALATON Zoltan * file: board/MAI/AmigaOneG3SE/articiaS_pci.c 15297d3b2cdSBALATON Zoltan */ 15397d3b2cdSBALATON Zoltan static int amigaone_pcihost_bus0_map_irq(PCIDevice *pdev, int pin) 15497d3b2cdSBALATON Zoltan { 15597d3b2cdSBALATON Zoltan int devfn_slot = PCI_SLOT(pdev->devfn); 15697d3b2cdSBALATON Zoltan 15797d3b2cdSBALATON Zoltan switch (devfn_slot) { 15897d3b2cdSBALATON Zoltan case 6: /* On board ethernet */ 15997d3b2cdSBALATON Zoltan return 3; 16097d3b2cdSBALATON Zoltan case 7: /* South bridge */ 16197d3b2cdSBALATON Zoltan return pin; 16297d3b2cdSBALATON Zoltan default: /* PCI Slot 1 Devfn slot 8, Slot 2 Devfn 9, Slot 3 Devfn 10 */ 16397d3b2cdSBALATON Zoltan return pci_swizzle(devfn_slot, pin); 16497d3b2cdSBALATON Zoltan } 16597d3b2cdSBALATON Zoltan 16697d3b2cdSBALATON Zoltan } 16797d3b2cdSBALATON Zoltan 16897d3b2cdSBALATON Zoltan static void articia_realize(DeviceState *dev, Error **errp) 16997d3b2cdSBALATON Zoltan { 17097d3b2cdSBALATON Zoltan ArticiaState *s = ARTICIA(dev); 17197d3b2cdSBALATON Zoltan PCIHostState *h = PCI_HOST_BRIDGE(dev); 17297d3b2cdSBALATON Zoltan PCIDevice *pdev; 17397d3b2cdSBALATON Zoltan 17497d3b2cdSBALATON Zoltan bitbang_i2c_init(&s->smbus, i2c_init_bus(dev, "smbus")); 17597d3b2cdSBALATON Zoltan memory_region_init_io(&s->gpio_reg, OBJECT(s), &articia_gpio_ops, s, 17697d3b2cdSBALATON Zoltan TYPE_ARTICIA, 4); 17797d3b2cdSBALATON Zoltan 17897d3b2cdSBALATON Zoltan memory_region_init(&s->mem, OBJECT(dev), "pci-mem", UINT64_MAX); 17997d3b2cdSBALATON Zoltan memory_region_init(&s->io, OBJECT(dev), "pci-io", 0xc00000); 18097d3b2cdSBALATON Zoltan memory_region_init_io(&s->reg, OBJECT(s), &articia_reg_ops, s, 18197d3b2cdSBALATON Zoltan TYPE_ARTICIA, 0x1000000); 18297d3b2cdSBALATON Zoltan memory_region_add_subregion_overlap(&s->reg, 0, &s->io, 1); 18397d3b2cdSBALATON Zoltan 18497d3b2cdSBALATON Zoltan /* devfn_min is 8 that matches first PCI slot in AmigaOne */ 18597d3b2cdSBALATON Zoltan h->bus = pci_register_root_bus(dev, NULL, articia_pcihost_set_irq, 18697d3b2cdSBALATON Zoltan amigaone_pcihost_bus0_map_irq, dev, &s->mem, 18797d3b2cdSBALATON Zoltan &s->io, PCI_DEVFN(8, 0), 4, TYPE_PCI_BUS); 18897d3b2cdSBALATON Zoltan pdev = pci_create_simple_multifunction(h->bus, PCI_DEVFN(0, 0), 18997d3b2cdSBALATON Zoltan TYPE_ARTICIA_PCI_HOST); 19097d3b2cdSBALATON Zoltan ARTICIA_PCI_HOST(pdev)->as = s; 19197d3b2cdSBALATON Zoltan pci_create_simple(h->bus, PCI_DEVFN(0, 1), TYPE_ARTICIA_PCI_BRIDGE); 19297d3b2cdSBALATON Zoltan 19397d3b2cdSBALATON Zoltan sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->reg); 19497d3b2cdSBALATON Zoltan sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mem); 19597d3b2cdSBALATON Zoltan qdev_init_gpio_out(dev, s->irq, ARRAY_SIZE(s->irq)); 19697d3b2cdSBALATON Zoltan } 19797d3b2cdSBALATON Zoltan 19812d1a768SPhilippe Mathieu-Daudé static void articia_class_init(ObjectClass *klass, const void *data) 19997d3b2cdSBALATON Zoltan { 20097d3b2cdSBALATON Zoltan DeviceClass *dc = DEVICE_CLASS(klass); 20197d3b2cdSBALATON Zoltan 20297d3b2cdSBALATON Zoltan dc->realize = articia_realize; 20397d3b2cdSBALATON Zoltan set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); 20497d3b2cdSBALATON Zoltan } 20597d3b2cdSBALATON Zoltan 20697d3b2cdSBALATON Zoltan /* TYPE_ARTICIA_PCI_HOST */ 20797d3b2cdSBALATON Zoltan 20897d3b2cdSBALATON Zoltan static void articia_pci_host_cfg_write(PCIDevice *d, uint32_t addr, 20997d3b2cdSBALATON Zoltan uint32_t val, int len) 21097d3b2cdSBALATON Zoltan { 21197d3b2cdSBALATON Zoltan ArticiaState *s = ARTICIA_PCI_HOST(d)->as; 21297d3b2cdSBALATON Zoltan 21397d3b2cdSBALATON Zoltan pci_default_write_config(d, addr, val, len); 21497d3b2cdSBALATON Zoltan switch (addr) { 21597d3b2cdSBALATON Zoltan case 0x40: 21697d3b2cdSBALATON Zoltan s->gpio_base = val; 21797d3b2cdSBALATON Zoltan break; 21897d3b2cdSBALATON Zoltan case 0x44: 21997d3b2cdSBALATON Zoltan if (val != 0x11) { 22097d3b2cdSBALATON Zoltan /* FIXME what do the bits actually mean? */ 22197d3b2cdSBALATON Zoltan break; 22297d3b2cdSBALATON Zoltan } 22397d3b2cdSBALATON Zoltan if (memory_region_is_mapped(&s->gpio_reg)) { 22497d3b2cdSBALATON Zoltan memory_region_del_subregion(&s->io, &s->gpio_reg); 22597d3b2cdSBALATON Zoltan } 22697d3b2cdSBALATON Zoltan memory_region_add_subregion(&s->io, s->gpio_base + 0x38, &s->gpio_reg); 22797d3b2cdSBALATON Zoltan break; 22897d3b2cdSBALATON Zoltan } 22997d3b2cdSBALATON Zoltan } 23097d3b2cdSBALATON Zoltan 23112d1a768SPhilippe Mathieu-Daudé static void articia_pci_host_class_init(ObjectClass *klass, const void *data) 23297d3b2cdSBALATON Zoltan { 23397d3b2cdSBALATON Zoltan DeviceClass *dc = DEVICE_CLASS(klass); 23497d3b2cdSBALATON Zoltan PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); 23597d3b2cdSBALATON Zoltan 23697d3b2cdSBALATON Zoltan k->config_write = articia_pci_host_cfg_write; 23797d3b2cdSBALATON Zoltan k->vendor_id = 0x10cc; 23897d3b2cdSBALATON Zoltan k->device_id = 0x0660; 23997d3b2cdSBALATON Zoltan k->class_id = PCI_CLASS_BRIDGE_HOST; 24097d3b2cdSBALATON Zoltan /* 24197d3b2cdSBALATON Zoltan * PCI-facing part of the host bridge, 24297d3b2cdSBALATON Zoltan * not usable without the host-facing part 24397d3b2cdSBALATON Zoltan */ 24497d3b2cdSBALATON Zoltan dc->user_creatable = false; 24597d3b2cdSBALATON Zoltan } 24697d3b2cdSBALATON Zoltan 24797d3b2cdSBALATON Zoltan /* TYPE_ARTICIA_PCI_BRIDGE */ 24897d3b2cdSBALATON Zoltan 24912d1a768SPhilippe Mathieu-Daudé static void articia_pci_bridge_class_init(ObjectClass *klass, const void *data) 25097d3b2cdSBALATON Zoltan { 25197d3b2cdSBALATON Zoltan DeviceClass *dc = DEVICE_CLASS(klass); 25297d3b2cdSBALATON Zoltan PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); 25397d3b2cdSBALATON Zoltan 25497d3b2cdSBALATON Zoltan k->vendor_id = 0x10cc; 25597d3b2cdSBALATON Zoltan k->device_id = 0x0661; 25697d3b2cdSBALATON Zoltan k->class_id = PCI_CLASS_BRIDGE_HOST; 25797d3b2cdSBALATON Zoltan /* 25897d3b2cdSBALATON Zoltan * PCI-facing part of the host bridge, 25997d3b2cdSBALATON Zoltan * not usable without the host-facing part 26097d3b2cdSBALATON Zoltan */ 26197d3b2cdSBALATON Zoltan dc->user_creatable = false; 26297d3b2cdSBALATON Zoltan } 26397d3b2cdSBALATON Zoltan 26497d3b2cdSBALATON Zoltan static const TypeInfo articia_types[] = { 26597d3b2cdSBALATON Zoltan { 26697d3b2cdSBALATON Zoltan .name = TYPE_ARTICIA, 26797d3b2cdSBALATON Zoltan .parent = TYPE_PCI_HOST_BRIDGE, 26897d3b2cdSBALATON Zoltan .instance_size = sizeof(ArticiaState), 26997d3b2cdSBALATON Zoltan .class_init = articia_class_init, 27097d3b2cdSBALATON Zoltan }, 27197d3b2cdSBALATON Zoltan { 27297d3b2cdSBALATON Zoltan .name = TYPE_ARTICIA_PCI_HOST, 27397d3b2cdSBALATON Zoltan .parent = TYPE_PCI_DEVICE, 27497d3b2cdSBALATON Zoltan .instance_size = sizeof(ArticiaHostState), 27597d3b2cdSBALATON Zoltan .class_init = articia_pci_host_class_init, 276*2cd09e47SPhilippe Mathieu-Daudé .interfaces = (const InterfaceInfo[]) { 27797d3b2cdSBALATON Zoltan { INTERFACE_CONVENTIONAL_PCI_DEVICE }, 27897d3b2cdSBALATON Zoltan { }, 27997d3b2cdSBALATON Zoltan }, 28097d3b2cdSBALATON Zoltan }, 28197d3b2cdSBALATON Zoltan { 28297d3b2cdSBALATON Zoltan .name = TYPE_ARTICIA_PCI_BRIDGE, 28397d3b2cdSBALATON Zoltan .parent = TYPE_PCI_DEVICE, 28497d3b2cdSBALATON Zoltan .instance_size = sizeof(PCIDevice), 28597d3b2cdSBALATON Zoltan .class_init = articia_pci_bridge_class_init, 286*2cd09e47SPhilippe Mathieu-Daudé .interfaces = (const InterfaceInfo[]) { 28797d3b2cdSBALATON Zoltan { INTERFACE_CONVENTIONAL_PCI_DEVICE }, 28897d3b2cdSBALATON Zoltan { }, 28997d3b2cdSBALATON Zoltan }, 29097d3b2cdSBALATON Zoltan }, 29197d3b2cdSBALATON Zoltan }; 29297d3b2cdSBALATON Zoltan 29397d3b2cdSBALATON Zoltan DEFINE_TYPES(articia_types) 294