All of lore.kernel.org
 help / color / mirror / Atom feed
From: Daniel Henrique Barboza <danielhb413@gmail.com>
To: qemu-devel@nongnu.org
Cc: qemu-ppc@nongnu.org, danielhb413@gmail.com,
	peter.maydell@linaro.org, BALATON Zoltan <balaton@eik.bme.hu>,
	Rene Engel <ReneEngel80@emailn.de>
Subject: [PULL 1/9] hw/pci-host: Add emulation of Mai Logic Articia S
Date: Tue,  7 Nov 2023 17:47:58 -0300	[thread overview]
Message-ID: <20231107204806.8507-2-danielhb413@gmail.com> (raw)
In-Reply-To: <20231107204806.8507-1-danielhb413@gmail.com>

From: BALATON Zoltan <balaton@eik.bme.hu>

The Articia S is a generic chipset supporting several different CPUs
that were among others used on some PPC boards. This is a minimal
emulation of the parts needed for emulating the AmigaOne board.

Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
Tested-by: Rene Engel <ReneEngel80@emailn.de>
Acked-by: Daniel Henrique Barboza <danielhb413@gmail.com>
Message-ID: <83822787431701cf4d460298d3e3845f362e5da1.1698406922.git.balaton@eik.bme.hu>
Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
 hw/pci-host/Kconfig           |   5 +
 hw/pci-host/articia.c         | 293 ++++++++++++++++++++++++++++++++++
 hw/pci-host/meson.build       |   2 +
 include/hw/pci-host/articia.h |  17 ++
 4 files changed, 317 insertions(+)
 create mode 100644 hw/pci-host/articia.c
 create mode 100644 include/hw/pci-host/articia.h

diff --git a/hw/pci-host/Kconfig b/hw/pci-host/Kconfig
index 54a609d2ca..f046d76a68 100644
--- a/hw/pci-host/Kconfig
+++ b/hw/pci-host/Kconfig
@@ -73,6 +73,11 @@ config SH_PCI
     bool
     select PCI
 
+config ARTICIA
+    bool
+    select PCI
+    select I8259
+
 config MV64361
     bool
     select PCI
diff --git a/hw/pci-host/articia.c b/hw/pci-host/articia.c
new file mode 100644
index 0000000000..f3fcc49f81
--- /dev/null
+++ b/hw/pci-host/articia.c
@@ -0,0 +1,293 @@
+/*
+ * Mai Logic Articia S emulation
+ *
+ * Copyright (c) 2023 BALATON Zoltan
+ *
+ * This work is licensed under the GNU GPL license version 2 or later.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qapi/error.h"
+#include "hw/pci/pci_device.h"
+#include "hw/pci/pci_host.h"
+#include "hw/irq.h"
+#include "hw/i2c/bitbang_i2c.h"
+#include "hw/intc/i8259.h"
+#include "hw/pci-host/articia.h"
+
+/*
+ * This is a minimal emulation of this chip as used in AmigaOne board.
+ * Most features are missing but those are not needed by firmware and guests.
+ */
+
+OBJECT_DECLARE_SIMPLE_TYPE(ArticiaState, ARTICIA)
+
+OBJECT_DECLARE_SIMPLE_TYPE(ArticiaHostState, ARTICIA_PCI_HOST)
+struct ArticiaHostState {
+    PCIDevice parent_obj;
+
+    ArticiaState *as;
+};
+
+/* TYPE_ARTICIA */
+
+struct ArticiaState {
+    PCIHostState parent_obj;
+
+    qemu_irq irq[PCI_NUM_PINS];
+    MemoryRegion io;
+    MemoryRegion mem;
+    MemoryRegion reg;
+
+    bitbang_i2c_interface smbus;
+    uint32_t gpio; /* bits 0-7 in, 8-15 out, 16-23 direction (0 in, 1 out) */
+    hwaddr gpio_base;
+    MemoryRegion gpio_reg;
+};
+
+static uint64_t articia_gpio_read(void *opaque, hwaddr addr, unsigned int size)
+{
+    ArticiaState *s = opaque;
+
+    return (s->gpio >> (addr * 8)) & 0xff;
+}
+
+static void articia_gpio_write(void *opaque, hwaddr addr, uint64_t val,
+                               unsigned int size)
+{
+    ArticiaState *s = opaque;
+    uint32_t sh = addr * 8;
+
+    if (addr == 0) {
+        /* in bits read only? */
+        return;
+    }
+
+    if ((s->gpio & (0xff << sh)) != (val & 0xff) << sh) {
+        s->gpio &= ~(0xff << sh | 0xff);
+        s->gpio |= (val & 0xff) << sh;
+        s->gpio |= bitbang_i2c_set(&s->smbus, BITBANG_I2C_SDA,
+                                   s->gpio & BIT(16) ?
+                                   !!(s->gpio & BIT(8)) : 1);
+        if ((s->gpio & BIT(17))) {
+            s->gpio &= ~BIT(0);
+            s->gpio |= bitbang_i2c_set(&s->smbus, BITBANG_I2C_SCL,
+                                       !!(s->gpio & BIT(9)));
+        }
+    }
+}
+
+static const MemoryRegionOps articia_gpio_ops = {
+    .read = articia_gpio_read,
+    .write = articia_gpio_write,
+    .valid.min_access_size = 1,
+    .valid.max_access_size = 1,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static uint64_t articia_reg_read(void *opaque, hwaddr addr, unsigned int size)
+{
+    ArticiaState *s = opaque;
+    uint64_t ret = UINT_MAX;
+
+    switch (addr) {
+    case 0xc00cf8:
+        ret = pci_host_conf_le_ops.read(PCI_HOST_BRIDGE(s), 0, size);
+        break;
+    case 0xe00cfc ... 0xe00cff:
+        ret = pci_host_data_le_ops.read(PCI_HOST_BRIDGE(s), addr - 0xe00cfc, size);
+        break;
+    case 0xf00000:
+        ret = pic_read_irq(isa_pic);
+        break;
+    default:
+        qemu_log_mask(LOG_UNIMP, "%s: Unimplemented register read 0x%"
+                      HWADDR_PRIx " %d\n", __func__, addr, size);
+        break;
+    }
+    return ret;
+}
+
+static void articia_reg_write(void *opaque, hwaddr addr, uint64_t val,
+                              unsigned int size)
+{
+    ArticiaState *s = opaque;
+
+    switch (addr) {
+    case 0xc00cf8:
+        pci_host_conf_le_ops.write(PCI_HOST_BRIDGE(s), 0, val, size);
+        break;
+    case 0xe00cfc ... 0xe00cff:
+        pci_host_data_le_ops.write(PCI_HOST_BRIDGE(s), addr, val, size);
+        break;
+    default:
+        qemu_log_mask(LOG_UNIMP, "%s: Unimplemented register write 0x%"
+                      HWADDR_PRIx " %d <- %"PRIx64"\n", __func__, addr, size, val);
+        break;
+    }
+}
+
+static const MemoryRegionOps articia_reg_ops = {
+    .read = articia_reg_read,
+    .write = articia_reg_write,
+    .valid.min_access_size = 1,
+    .valid.max_access_size = 4,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void articia_pcihost_set_irq(void *opaque, int n, int level)
+{
+    ArticiaState *s = opaque;
+    qemu_set_irq(s->irq[n], level);
+}
+
+/*
+ * AmigaOne SE PCI slot to IRQ routing
+ *
+ * repository: https://source.denx.de/u-boot/custodians/u-boot-avr32.git
+ * refspec: v2010.06
+ * file: board/MAI/AmigaOneG3SE/articiaS_pci.c
+ */
+static int amigaone_pcihost_bus0_map_irq(PCIDevice *pdev, int pin)
+{
+    int devfn_slot = PCI_SLOT(pdev->devfn);
+
+    switch (devfn_slot) {
+    case 6:  /* On board ethernet */
+        return 3;
+    case 7:  /* South bridge */
+        return pin;
+    default: /* PCI Slot 1 Devfn slot 8, Slot 2 Devfn 9, Slot 3 Devfn 10 */
+        return pci_swizzle(devfn_slot, pin);
+    }
+
+}
+
+static void articia_realize(DeviceState *dev, Error **errp)
+{
+    ArticiaState *s = ARTICIA(dev);
+    PCIHostState *h = PCI_HOST_BRIDGE(dev);
+    PCIDevice *pdev;
+
+    bitbang_i2c_init(&s->smbus, i2c_init_bus(dev, "smbus"));
+    memory_region_init_io(&s->gpio_reg, OBJECT(s), &articia_gpio_ops, s,
+                          TYPE_ARTICIA, 4);
+
+    memory_region_init(&s->mem, OBJECT(dev), "pci-mem", UINT64_MAX);
+    memory_region_init(&s->io, OBJECT(dev), "pci-io", 0xc00000);
+    memory_region_init_io(&s->reg, OBJECT(s), &articia_reg_ops, s,
+                          TYPE_ARTICIA, 0x1000000);
+    memory_region_add_subregion_overlap(&s->reg, 0, &s->io, 1);
+
+    /* devfn_min is 8 that matches first PCI slot in AmigaOne */
+    h->bus = pci_register_root_bus(dev, NULL, articia_pcihost_set_irq,
+                                   amigaone_pcihost_bus0_map_irq, dev, &s->mem,
+                                   &s->io, PCI_DEVFN(8, 0), 4, TYPE_PCI_BUS);
+    pdev = pci_create_simple_multifunction(h->bus, PCI_DEVFN(0, 0),
+                                           TYPE_ARTICIA_PCI_HOST);
+    ARTICIA_PCI_HOST(pdev)->as = s;
+    pci_create_simple(h->bus, PCI_DEVFN(0, 1), TYPE_ARTICIA_PCI_BRIDGE);
+
+    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->reg);
+    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mem);
+    qdev_init_gpio_out(dev, s->irq, ARRAY_SIZE(s->irq));
+}
+
+static void articia_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->realize = articia_realize;
+    set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
+}
+
+/* TYPE_ARTICIA_PCI_HOST */
+
+static void articia_pci_host_cfg_write(PCIDevice *d, uint32_t addr,
+                                       uint32_t val, int len)
+{
+    ArticiaState *s = ARTICIA_PCI_HOST(d)->as;
+
+    pci_default_write_config(d, addr, val, len);
+    switch (addr) {
+    case 0x40:
+        s->gpio_base = val;
+        break;
+    case 0x44:
+        if (val != 0x11) {
+            /* FIXME what do the bits actually mean? */
+            break;
+        }
+        if (memory_region_is_mapped(&s->gpio_reg)) {
+            memory_region_del_subregion(&s->io, &s->gpio_reg);
+        }
+        memory_region_add_subregion(&s->io, s->gpio_base + 0x38, &s->gpio_reg);
+        break;
+    }
+}
+
+static void articia_pci_host_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->config_write = articia_pci_host_cfg_write;
+    k->vendor_id = 0x10cc;
+    k->device_id = 0x0660;
+    k->class_id = PCI_CLASS_BRIDGE_HOST;
+    /*
+     * PCI-facing part of the host bridge,
+     * not usable without the host-facing part
+     */
+    dc->user_creatable = false;
+}
+
+/* TYPE_ARTICIA_PCI_BRIDGE */
+
+static void articia_pci_bridge_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->vendor_id = 0x10cc;
+    k->device_id = 0x0661;
+    k->class_id = PCI_CLASS_BRIDGE_HOST;
+    /*
+     * PCI-facing part of the host bridge,
+     * not usable without the host-facing part
+     */
+    dc->user_creatable = false;
+}
+
+static const TypeInfo articia_types[] = {
+    {
+        .name          = TYPE_ARTICIA,
+        .parent        = TYPE_PCI_HOST_BRIDGE,
+        .instance_size = sizeof(ArticiaState),
+        .class_init    = articia_class_init,
+    },
+    {
+        .name          = TYPE_ARTICIA_PCI_HOST,
+        .parent        = TYPE_PCI_DEVICE,
+        .instance_size = sizeof(ArticiaHostState),
+        .class_init    = articia_pci_host_class_init,
+        .interfaces = (InterfaceInfo[]) {
+              { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+              { },
+        },
+    },
+    {
+        .name          = TYPE_ARTICIA_PCI_BRIDGE,
+        .parent        = TYPE_PCI_DEVICE,
+        .instance_size = sizeof(PCIDevice),
+        .class_init    = articia_pci_bridge_class_init,
+        .interfaces = (InterfaceInfo[]) {
+              { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+              { },
+        },
+    },
+};
+
+DEFINE_TYPES(articia_types)
diff --git a/hw/pci-host/meson.build b/hw/pci-host/meson.build
index f891f026cb..de7bfb5a62 100644
--- a/hw/pci-host/meson.build
+++ b/hw/pci-host/meson.build
@@ -20,6 +20,8 @@ pci_ss.add(when: 'CONFIG_GRACKLE_PCI', if_true: files('grackle.c'))
 pci_ss.add(when: 'CONFIG_UNIN_PCI', if_true: files('uninorth.c'))
 # PowerPC E500 boards
 pci_ss.add(when: 'CONFIG_PPCE500_PCI', if_true: files('ppce500.c'))
+# AmigaOne
+pci_ss.add(when: 'CONFIG_ARTICIA', if_true: files('articia.c'))
 # Pegasos2
 pci_ss.add(when: 'CONFIG_MV64361', if_true: files('mv64361.c'))
 
diff --git a/include/hw/pci-host/articia.h b/include/hw/pci-host/articia.h
new file mode 100644
index 0000000000..529c240274
--- /dev/null
+++ b/include/hw/pci-host/articia.h
@@ -0,0 +1,17 @@
+/*
+ * Mai Logic Articia S emulation
+ *
+ * Copyright (c) 2023 BALATON Zoltan
+ *
+ * This work is licensed under the GNU GPL license version 2 or later.
+ *
+ */
+
+#ifndef ARTICIA_H
+#define ARTICIA_H
+
+#define TYPE_ARTICIA "articia"
+#define TYPE_ARTICIA_PCI_HOST "articia-pci-host"
+#define TYPE_ARTICIA_PCI_BRIDGE "articia-pci-bridge"
+
+#endif
-- 
2.41.0



  reply	other threads:[~2023-11-07 20:49 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-11-07 20:47 [PULL 0/9] ppc queue Daniel Henrique Barboza
2023-11-07 20:47 ` Daniel Henrique Barboza [this message]
2023-11-07 20:47 ` [PULL 2/9] hw/ppc: Add emulation of AmigaOne XE board Daniel Henrique Barboza
2023-11-07 20:48 ` [PULL 3/9] tests/avocado: Add test for amigaone board Daniel Henrique Barboza
2023-11-07 20:48 ` [PULL 4/9] ppc/pnv: Add an I2C controller model Daniel Henrique Barboza
2023-11-07 20:48 ` [PULL 5/9] ppc/pnv: Connect I2C controller model to powernv9 chip Daniel Henrique Barboza
2023-11-07 20:48 ` [PULL 6/9] ppc/pnv: Connect PNV I2C controller to powernv10 Daniel Henrique Barboza
2023-11-07 20:48 ` [PULL 7/9] ppc/pnv: Fix number of I2C engines and ports for power9/10 Daniel Henrique Barboza
2023-11-07 20:48 ` [PULL 8/9] hw/pci-host: Update PHB5 XSCOM registers Daniel Henrique Barboza
2023-11-07 20:48 ` [PULL 9/9] ppc: qtest already exports qtest_rtas_call() Daniel Henrique Barboza
2023-11-08 14:20 ` [PULL 0/9] ppc queue Stefan Hajnoczi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20231107204806.8507-2-danielhb413@gmail.com \
    --to=danielhb413@gmail.com \
    --cc=ReneEngel80@emailn.de \
    --cc=balaton@eik.bme.hu \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-devel@nongnu.org \
    --cc=qemu-ppc@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.