qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PULL 0/9] ppc queue
@ 2023-11-07 20:47 Daniel Henrique Barboza
  2023-11-07 20:47 ` [PULL 1/9] hw/pci-host: Add emulation of Mai Logic Articia S Daniel Henrique Barboza
                   ` (9 more replies)
  0 siblings, 10 replies; 11+ messages in thread
From: Daniel Henrique Barboza @ 2023-11-07 20:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-ppc, danielhb413, peter.maydell

The following changes since commit 462ad017ed76889d46696a3581e1b52343f9b683:

  Merge tag 'pixman-pull-request' of https://gitlab.com/marcandre.lureau/qemu into staging (2023-11-07 19:00:03 +0800)

are available in the Git repository at:

  https://gitlab.com/danielhb/qemu.git tags/pull-ppc-20231107

for you to fetch changes up to 5bf4ceec109289356f50f69bf277c99b045182e7:

  ppc: qtest already exports qtest_rtas_call() (2023-11-07 15:49:41 -0300)

----------------------------------------------------------------
ppc patch queue for 2023-11-07:

This queue, the last one before the 8.2 feature freeze, has miscellanous
changes that includes new PowerNV features and the new AmigaONE XE
board.

----------------------------------------------------------------
BALATON Zoltan (3):
      hw/pci-host: Add emulation of Mai Logic Articia S
      hw/ppc: Add emulation of AmigaOne XE board
      tests/avocado: Add test for amigaone board

Cédric Le Goater (2):
      ppc/pnv: Add an I2C controller model
      ppc/pnv: Connect I2C controller model to powernv9 chip

Glenn Miles (2):
      ppc/pnv: Connect PNV I2C controller to powernv10
      ppc/pnv: Fix number of I2C engines and ports for power9/10

Juan Quintela (1):
      ppc: qtest already exports qtest_rtas_call()

Saif Abrar (1):
      hw/pci-host: Update PHB5 XSCOM registers

 MAINTAINERS                             |   8 +
 configs/devices/ppc-softmmu/default.mak |   1 +
 hw/pci-host/Kconfig                     |   5 +
 hw/pci-host/articia.c                   | 293 ++++++++++++++
 hw/pci-host/meson.build                 |   2 +
 hw/pci-host/pnv_phb4.c                  |  46 ++-
 hw/pci-host/pnv_phb4_pec.c              |  33 +-
 hw/ppc/Kconfig                          |   7 +
 hw/ppc/amigaone.c                       | 166 ++++++++
 hw/ppc/meson.build                      |   3 +
 hw/ppc/pnv.c                            |  61 +++
 hw/ppc/pnv_i2c.c                        | 697 ++++++++++++++++++++++++++++++++
 hw/ppc/spapr_rtas.c                     |   5 +-
 include/hw/pci-host/articia.h           |  17 +
 include/hw/pci-host/pnv_phb4.h          |   2 +-
 include/hw/pci-host/pnv_phb4_regs.h     |   4 +-
 include/hw/ppc/pnv_chip.h               |  10 +
 include/hw/ppc/pnv_i2c.h                |  38 ++
 include/hw/ppc/pnv_xscom.h              |   6 +
 include/hw/ppc/spapr_rtas.h             |  10 -
 tests/avocado/ppc_amiga.py              |  38 ++
 21 files changed, 1414 insertions(+), 38 deletions(-)
 create mode 100644 hw/pci-host/articia.c
 create mode 100644 hw/ppc/amigaone.c
 create mode 100644 hw/ppc/pnv_i2c.c
 create mode 100644 include/hw/pci-host/articia.h
 create mode 100644 include/hw/ppc/pnv_i2c.h
 delete mode 100644 include/hw/ppc/spapr_rtas.h
 create mode 100644 tests/avocado/ppc_amiga.py


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PULL 1/9] hw/pci-host: Add emulation of Mai Logic Articia S
  2023-11-07 20:47 [PULL 0/9] ppc queue Daniel Henrique Barboza
@ 2023-11-07 20:47 ` Daniel Henrique Barboza
  2023-11-07 20:47 ` [PULL 2/9] hw/ppc: Add emulation of AmigaOne XE board Daniel Henrique Barboza
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Daniel Henrique Barboza @ 2023-11-07 20:47 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-ppc, danielhb413, peter.maydell, BALATON Zoltan, Rene Engel

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



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PULL 2/9] hw/ppc: Add emulation of AmigaOne XE board
  2023-11-07 20:47 [PULL 0/9] ppc queue Daniel Henrique Barboza
  2023-11-07 20:47 ` [PULL 1/9] hw/pci-host: Add emulation of Mai Logic Articia S Daniel Henrique Barboza
@ 2023-11-07 20:47 ` Daniel Henrique Barboza
  2023-11-07 20:48 ` [PULL 3/9] tests/avocado: Add test for amigaone board Daniel Henrique Barboza
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Daniel Henrique Barboza @ 2023-11-07 20:47 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-ppc, danielhb413, peter.maydell, BALATON Zoltan, Rene Engel

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

The AmigaOne is a rebranded MAI Teron board that uses U-Boot firmware
with patches to support AmigaOS and is very similar to pegasos2 so can
be easily emulated sharing most code with pegasos2. The reason to
emulate it is that AmigaOS comes in different versions for AmigaOne
and PegasosII which only have drivers for one machine and firmware so
these only run on the specific machine. Adding this board allows
another AmigaOS version to be used reusing already existing peagasos2
emulation. (The AmigaOne was the first of these boards so likely most
widespread which then inspired Pegasos that was later replaced with
PegasosII due to problems with Articia S, so these have a lot of
similarity. Pegasos mainly ran MorphOS while the PegasosII version of
AmigaOS was added later and therefore less common than the AmigaOne
version.)

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: <804935e7a5921548d630576159ae2c758fe6e275.1699382232.git.balaton@eik.bme.hu>
Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
 MAINTAINERS                             |   8 ++
 configs/devices/ppc-softmmu/default.mak |   1 +
 hw/ppc/Kconfig                          |   7 +
 hw/ppc/amigaone.c                       | 166 ++++++++++++++++++++++++
 hw/ppc/meson.build                      |   2 +
 5 files changed, 184 insertions(+)
 create mode 100644 hw/ppc/amigaone.c

diff --git a/MAINTAINERS b/MAINTAINERS
index b86ea7f75a..3d0aec7ffa 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1536,6 +1536,14 @@ F: hw/pci-host/mv64361.c
 F: hw/pci-host/mv643xx.h
 F: include/hw/pci-host/mv64361.h
 
+amigaone
+M: BALATON Zoltan <balaton@eik.bme.hu>
+L: qemu-ppc@nongnu.org
+S: Maintained
+F: hw/ppc/amigaone.c
+F: hw/pci-host/articia.c
+F: include/hw/pci-host/articia.h
+
 Virtual Open Firmware (VOF)
 M: Alexey Kardashevskiy <aik@ozlabs.ru>
 R: David Gibson <david@gibson.dropbear.id.au>
diff --git a/configs/devices/ppc-softmmu/default.mak b/configs/devices/ppc-softmmu/default.mak
index a887f5438b..b85fd2bcd7 100644
--- a/configs/devices/ppc-softmmu/default.mak
+++ b/configs/devices/ppc-softmmu/default.mak
@@ -14,6 +14,7 @@ CONFIG_SAM460EX=y
 CONFIG_MAC_OLDWORLD=y
 CONFIG_MAC_NEWWORLD=y
 
+CONFIG_AMIGAONE=y
 CONFIG_PEGASOS2=y
 
 # For PReP
diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig
index 5dfbf47ef5..56f0475a8e 100644
--- a/hw/ppc/Kconfig
+++ b/hw/ppc/Kconfig
@@ -69,6 +69,13 @@ config SAM460EX
     select USB_OHCI
     select FDT_PPC
 
+config AMIGAONE
+    bool
+    imply ATI_VGA
+    select ARTICIA
+    select VT82C686
+    select SMBUS_EEPROM
+
 config PEGASOS2
     bool
     imply ATI_VGA
diff --git a/hw/ppc/amigaone.c b/hw/ppc/amigaone.c
new file mode 100644
index 0000000000..992a55e632
--- /dev/null
+++ b/hw/ppc/amigaone.c
@@ -0,0 +1,166 @@
+/*
+ * QEMU Eyetech AmigaOne/Mai Logic Teron 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/units.h"
+#include "qemu/datadir.h"
+#include "qemu/log.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+#include "hw/ppc/ppc.h"
+#include "hw/boards.h"
+#include "hw/loader.h"
+#include "hw/pci-host/articia.h"
+#include "hw/isa/vt82c686.h"
+#include "hw/ide/pci.h"
+#include "hw/i2c/smbus_eeprom.h"
+#include "hw/ppc/ppc.h"
+#include "sysemu/qtest.h"
+#include "sysemu/reset.h"
+#include "kvm_ppc.h"
+
+#define BUS_FREQ_HZ 100000000
+
+/*
+ * Firmware binary available at
+ * https://www.hyperion-entertainment.com/index.php/downloads?view=files&parent=28
+ * then "tail -c 524288 updater.image >u-boot-amigaone.bin"
+ *
+ * BIOS emulator in firmware cannot run QEMU vgabios and hangs on it, use
+ * -device VGA,romfile=VGABIOS-lgpl-latest.bin
+ * from http://www.nongnu.org/vgabios/ instead.
+ */
+#define PROM_FILENAME "u-boot-amigaone.bin"
+#define PROM_ADDR 0xfff00000
+#define PROM_SIZE (512 * KiB)
+
+static void amigaone_cpu_reset(void *opaque)
+{
+    PowerPCCPU *cpu = opaque;
+
+    cpu_reset(CPU(cpu));
+    cpu_ppc_tb_reset(&cpu->env);
+}
+
+static void fix_spd_data(uint8_t *spd)
+{
+    uint32_t bank_size = 4 * MiB * spd[31];
+    uint32_t rows = bank_size / spd[13] / spd[17];
+    spd[3] = ctz32(rows) - spd[4];
+}
+
+static void amigaone_init(MachineState *machine)
+{
+    PowerPCCPU *cpu;
+    CPUPPCState *env;
+    MemoryRegion *rom, *pci_mem, *mr;
+    const char *fwname = machine->firmware ?: PROM_FILENAME;
+    char *filename;
+    ssize_t sz;
+    PCIBus *pci_bus;
+    Object *via;
+    DeviceState *dev;
+    I2CBus *i2c_bus;
+    uint8_t *spd_data;
+    int i;
+
+    /* init CPU */
+    cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
+    env = &cpu->env;
+    if (PPC_INPUT(env) != PPC_FLAGS_INPUT_6xx) {
+        error_report("Incompatible CPU, only 6xx bus supported");
+        exit(1);
+    }
+    cpu_ppc_tb_init(env, BUS_FREQ_HZ / 4);
+    qemu_register_reset(amigaone_cpu_reset, cpu);
+
+    /* RAM */
+    if (machine->ram_size > 2 * GiB) {
+        error_report("RAM size more than 2 GiB is not supported");
+        exit(1);
+    }
+    memory_region_add_subregion(get_system_memory(), 0, machine->ram);
+    if (machine->ram_size < 1 * GiB + 32 * KiB) {
+        /* Firmware uses this area for startup */
+        mr = g_new(MemoryRegion, 1);
+        memory_region_init_ram(mr, NULL, "init-cache", 32 * KiB, &error_fatal);
+        memory_region_add_subregion(get_system_memory(), 0x40000000, mr);
+    }
+
+    /* allocate and load firmware */
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, fwname);
+    if (filename) {
+        rom = g_new(MemoryRegion, 1);
+        memory_region_init_rom(rom, NULL, "rom", PROM_SIZE, &error_fatal);
+        memory_region_add_subregion(get_system_memory(), PROM_ADDR, rom);
+        sz = load_image_targphys(filename, PROM_ADDR, PROM_SIZE);
+        if (sz <= 0 || sz > PROM_SIZE) {
+            error_report("Could not load firmware '%s'", filename);
+            exit(1);
+        }
+        g_free(filename);
+    } else if (!qtest_enabled()) {
+        error_report("Could not find firmware '%s'", fwname);
+        exit(1);
+    }
+
+    /* Articia S */
+    dev = sysbus_create_simple(TYPE_ARTICIA, 0xfe000000, NULL);
+
+    i2c_bus = I2C_BUS(qdev_get_child_bus(dev, "smbus"));
+    if (machine->ram_size > 512 * MiB) {
+        spd_data = spd_data_generate(SDR, machine->ram_size / 2);
+    } else {
+        spd_data = spd_data_generate(SDR, machine->ram_size);
+    }
+    fix_spd_data(spd_data);
+    smbus_eeprom_init_one(i2c_bus, 0x51, spd_data);
+    if (machine->ram_size > 512 * MiB) {
+        smbus_eeprom_init_one(i2c_bus, 0x52, spd_data);
+    }
+
+    pci_mem = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
+    mr = g_new(MemoryRegion, 1);
+    memory_region_init_alias(mr, OBJECT(dev), "pci-mem-low", pci_mem,
+                             0, 0x1000000);
+    memory_region_add_subregion(get_system_memory(), 0xfd000000, mr);
+    mr = g_new(MemoryRegion, 1);
+    memory_region_init_alias(mr, OBJECT(dev), "pci-mem-high", pci_mem,
+                             0x80000000, 0x7d000000);
+    memory_region_add_subregion(get_system_memory(), 0x80000000, mr);
+    pci_bus = PCI_BUS(qdev_get_child_bus(dev, "pci.0"));
+
+    /* VIA VT82c686B South Bridge (multifunction PCI device) */
+    via = OBJECT(pci_create_simple_multifunction(pci_bus, PCI_DEVFN(7, 0),
+                                                 TYPE_VT82C686B_ISA));
+    object_property_add_alias(OBJECT(machine), "rtc-time",
+                              object_resolve_path_component(via, "rtc"),
+                              "date");
+    qdev_connect_gpio_out(DEVICE(via), 0,
+                          qdev_get_gpio_in(DEVICE(cpu), PPC6xx_INPUT_INT));
+    for (i = 0; i < PCI_NUM_PINS; i++) {
+        qdev_connect_gpio_out(dev, i, qdev_get_gpio_in_named(DEVICE(via),
+                                                             "pirq", i));
+    }
+    pci_ide_create_devs(PCI_DEVICE(object_resolve_path_component(via, "ide")));
+    pci_vga_init(pci_bus);
+}
+
+static void amigaone_machine_init(MachineClass *mc)
+{
+    mc->desc = "Eyetech AmigaOne/Mai Logic Teron";
+    mc->init = amigaone_init;
+    mc->block_default_type = IF_IDE;
+    mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("7457_v1.2");
+    mc->default_display = "std";
+    mc->default_ram_id = "ram";
+    mc->default_ram_size = 512 * MiB;
+}
+
+DEFINE_MACHINE("amigaone", amigaone_machine_init)
diff --git a/hw/ppc/meson.build b/hw/ppc/meson.build
index 7c2c52434a..7338f9432a 100644
--- a/hw/ppc/meson.build
+++ b/hw/ppc/meson.build
@@ -81,6 +81,8 @@ ppc_ss.add(when: 'CONFIG_E500', if_true: files(
 ))
 # PowerPC 440 Xilinx ML507 reference board.
 ppc_ss.add(when: 'CONFIG_VIRTEX', if_true: files('virtex_ml507.c'))
+# AmigaOne
+ppc_ss.add(when: 'CONFIG_AMIGAONE', if_true: files('amigaone.c'))
 # Pegasos2
 ppc_ss.add(when: 'CONFIG_PEGASOS2', if_true: files('pegasos2.c'))
 
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PULL 3/9] tests/avocado: Add test for amigaone board
  2023-11-07 20:47 [PULL 0/9] ppc queue Daniel Henrique Barboza
  2023-11-07 20:47 ` [PULL 1/9] hw/pci-host: Add emulation of Mai Logic Articia S Daniel Henrique Barboza
  2023-11-07 20:47 ` [PULL 2/9] hw/ppc: Add emulation of AmigaOne XE board Daniel Henrique Barboza
@ 2023-11-07 20:48 ` Daniel Henrique Barboza
  2023-11-07 20:48 ` [PULL 4/9] ppc/pnv: Add an I2C controller model Daniel Henrique Barboza
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Daniel Henrique Barboza @ 2023-11-07 20:48 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-ppc, danielhb413, peter.maydell, BALATON Zoltan

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

Add an avocado test for the amigaone board that tests it with the
firmware.

Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
Reviewed-by: Daniel Henrique Barboza <danielhb413@gmail.com>
Message-ID: <b1a0246840fcff1fe6bbd8685e2474a9231b34c5.1698406922.git.balaton@eik.bme.hu>
Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
 tests/avocado/ppc_amiga.py | 38 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)
 create mode 100644 tests/avocado/ppc_amiga.py

diff --git a/tests/avocado/ppc_amiga.py b/tests/avocado/ppc_amiga.py
new file mode 100644
index 0000000000..b6f866f91d
--- /dev/null
+++ b/tests/avocado/ppc_amiga.py
@@ -0,0 +1,38 @@
+# Test AmigaNG boards
+#
+# Copyright (c) 2023 BALATON Zoltan
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later.  See the COPYING file in the top-level directory.
+
+from avocado.utils import archive
+from avocado.utils import process
+from avocado_qemu import QemuSystemTest
+from avocado_qemu import wait_for_console_pattern
+
+class AmigaOneMachine(QemuSystemTest):
+
+    timeout = 90
+
+    def test_ppc_amigaone(self):
+        """
+        :avocado: tags=arch:ppc
+        :avocado: tags=machine:amigaone
+        :avocado: tags=device:articia
+        :avocado: tags=accel:tcg
+        """
+        self.require_accelerator("tcg")
+        tar_name = 'A1Firmware_Floppy_05-Mar-2005.zip'
+        tar_url = ('https://www.hyperion-entertainment.com/index.php/'
+                   'downloads?view=download&format=raw&file=25')
+        tar_hash = 'c52e59bc73e31d8bcc3cc2106778f7ac84f6c755'
+        zip_file = self.fetch_asset(tar_name, locations=tar_url,
+                                    asset_hash=tar_hash)
+        archive.extract(zip_file, self.workdir)
+        cmd = f"tail -c 524288 {self.workdir}/floppy_edition/updater.image >{self.workdir}/u-boot-amigaone.bin"
+        process.run(cmd, shell=True)
+
+        self.vm.set_console()
+        self.vm.add_args('-bios', self.workdir + '/u-boot-amigaone.bin')
+        self.vm.launch()
+        wait_for_console_pattern(self, 'FLASH:')
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PULL 4/9] ppc/pnv: Add an I2C controller model
  2023-11-07 20:47 [PULL 0/9] ppc queue Daniel Henrique Barboza
                   ` (2 preceding siblings ...)
  2023-11-07 20:48 ` [PULL 3/9] tests/avocado: Add test for amigaone board Daniel Henrique Barboza
@ 2023-11-07 20:48 ` Daniel Henrique Barboza
  2023-11-07 20:48 ` [PULL 5/9] ppc/pnv: Connect I2C controller model to powernv9 chip Daniel Henrique Barboza
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Daniel Henrique Barboza @ 2023-11-07 20:48 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-ppc, danielhb413, peter.maydell, Cédric Le Goater,
	Glenn Miles

From: Cédric Le Goater <clg@kaod.org>

The more recent IBM power processors have an embedded I2C
controller that is accessible by software via the XSCOM
address space.

Each instance of the I2C controller is capable of controlling
multiple I2C buses (one at a time).  Prior to beginning a
transaction on an I2C bus, the bus must be selected by writing
the port number associated with the bus into the PORT_NUM
field of the MODE register.  Once an I2C bus is selected,
the status of the bus can be determined by reading the
Status and Extended Status registers.

I2C bus transactions can be started by writing a command to
the Command register and reading/writing data from/to the
FIFO register.

Not supported :

 . 10 bit I2C addresses
 . Multimaster
 . Slave

Signed-off-by: Cédric Le Goater <clg@kaod.org>
[milesg: Split wiring to powernv9 into its own commit]
[milesg: Added more detail to commit message]
[milesg: Added SPDX Licensed Identifier to new files]
[milesg: updated copyright dates]
[milesg: Added use of g_autofree]
[milesg: Added NULL check after pnv_i2c_get_bus]
Signed-off-by: Glenn Miles <milesg@linux.vnet.ibm.com>
Acked-by: Daniel Henrique Barboza <danielhb413@gmail.com>
Message-ID: <20231016222013.3739530-2-milesg@linux.vnet.ibm.com>
Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
 hw/ppc/meson.build         |   1 +
 hw/ppc/pnv_i2c.c           | 697 +++++++++++++++++++++++++++++++++++++
 include/hw/ppc/pnv_i2c.h   |  38 ++
 include/hw/ppc/pnv_xscom.h |   3 +
 4 files changed, 739 insertions(+)
 create mode 100644 hw/ppc/pnv_i2c.c
 create mode 100644 include/hw/ppc/pnv_i2c.h

diff --git a/hw/ppc/meson.build b/hw/ppc/meson.build
index 7338f9432a..ea44856d43 100644
--- a/hw/ppc/meson.build
+++ b/hw/ppc/meson.build
@@ -43,6 +43,7 @@ ppc_ss.add(when: 'CONFIG_POWERNV', if_true: files(
   'pnv.c',
   'pnv_xscom.c',
   'pnv_core.c',
+  'pnv_i2c.c',
   'pnv_lpc.c',
   'pnv_psi.c',
   'pnv_occ.c',
diff --git a/hw/ppc/pnv_i2c.c b/hw/ppc/pnv_i2c.c
new file mode 100644
index 0000000000..f75e59e709
--- /dev/null
+++ b/hw/ppc/pnv_i2c.c
@@ -0,0 +1,697 @@
+/*
+ * QEMU PowerPC PowerNV Processor I2C model
+ *
+ * Copyright (c) 2019-2023, IBM Corporation.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/module.h"
+#include "qemu/log.h"
+#include "sysemu/reset.h"
+
+#include "hw/irq.h"
+#include "hw/qdev-properties.h"
+
+#include "hw/ppc/pnv.h"
+#include "hw/ppc/pnv_chip.h"
+#include "hw/ppc/pnv_i2c.h"
+#include "hw/ppc/pnv_xscom.h"
+#include "hw/ppc/fdt.h"
+
+#include <libfdt.h>
+
+/* I2C FIFO register */
+#define I2C_FIFO_REG                    0x4
+#define I2C_FIFO                        PPC_BITMASK(0, 7)
+
+/* I2C command register */
+#define I2C_CMD_REG                     0x5
+#define I2C_CMD_WITH_START              PPC_BIT(0)
+#define I2C_CMD_WITH_ADDR               PPC_BIT(1)
+#define I2C_CMD_READ_CONT               PPC_BIT(2)
+#define I2C_CMD_WITH_STOP               PPC_BIT(3)
+#define I2C_CMD_INTR_STEERING           PPC_BITMASK(6, 7) /* P9 */
+#define   I2C_CMD_INTR_STEER_HOST       1
+#define   I2C_CMD_INTR_STEER_OCC        2
+#define I2C_CMD_DEV_ADDR                PPC_BITMASK(8, 14)
+#define I2C_CMD_READ_NOT_WRITE          PPC_BIT(15)
+#define I2C_CMD_LEN_BYTES               PPC_BITMASK(16, 31)
+#define I2C_MAX_TFR_LEN                 0xfff0ull
+
+/* I2C mode register */
+#define I2C_MODE_REG                    0x6
+#define I2C_MODE_BIT_RATE_DIV           PPC_BITMASK(0, 15)
+#define I2C_MODE_PORT_NUM               PPC_BITMASK(16, 21)
+#define I2C_MODE_ENHANCED               PPC_BIT(28)
+#define I2C_MODE_DIAGNOSTIC             PPC_BIT(29)
+#define I2C_MODE_PACING_ALLOW           PPC_BIT(30)
+#define I2C_MODE_WRAP                   PPC_BIT(31)
+
+/* I2C watermark register */
+#define I2C_WATERMARK_REG               0x7
+#define I2C_WATERMARK_HIGH              PPC_BITMASK(16, 19)
+#define I2C_WATERMARK_LOW               PPC_BITMASK(24, 27)
+
+/*
+ * I2C interrupt mask and condition registers
+ *
+ * NB: The function of 0x9 and 0xa changes depending on whether you're reading
+ *     or writing to them. When read they return the interrupt condition bits
+ *     and on writes they update the interrupt mask register.
+ *
+ *  The bit definitions are the same for all the interrupt registers.
+ */
+#define I2C_INTR_MASK_REG               0x8
+
+#define I2C_INTR_RAW_COND_REG           0x9 /* read */
+#define I2C_INTR_MASK_OR_REG            0x9 /* write*/
+
+#define I2C_INTR_COND_REG               0xa /* read */
+#define I2C_INTR_MASK_AND_REG           0xa /* write */
+
+#define I2C_INTR_ALL                    PPC_BITMASK(16, 31)
+#define I2C_INTR_INVALID_CMD            PPC_BIT(16)
+#define I2C_INTR_LBUS_PARITY_ERR        PPC_BIT(17)
+#define I2C_INTR_BKEND_OVERRUN_ERR      PPC_BIT(18)
+#define I2C_INTR_BKEND_ACCESS_ERR       PPC_BIT(19)
+#define I2C_INTR_ARBT_LOST_ERR          PPC_BIT(20)
+#define I2C_INTR_NACK_RCVD_ERR          PPC_BIT(21)
+#define I2C_INTR_DATA_REQ               PPC_BIT(22)
+#define I2C_INTR_CMD_COMP               PPC_BIT(23)
+#define I2C_INTR_STOP_ERR               PPC_BIT(24)
+#define I2C_INTR_I2C_BUSY               PPC_BIT(25)
+#define I2C_INTR_NOT_I2C_BUSY           PPC_BIT(26)
+#define I2C_INTR_SCL_EQ_1               PPC_BIT(28)
+#define I2C_INTR_SCL_EQ_0               PPC_BIT(29)
+#define I2C_INTR_SDA_EQ_1               PPC_BIT(30)
+#define I2C_INTR_SDA_EQ_0               PPC_BIT(31)
+
+/* I2C status register */
+#define I2C_RESET_I2C_REG               0xb /* write */
+#define I2C_RESET_ERRORS                0xc
+#define I2C_STAT_REG                    0xb /* read */
+#define I2C_STAT_INVALID_CMD            PPC_BIT(0)
+#define I2C_STAT_LBUS_PARITY_ERR        PPC_BIT(1)
+#define I2C_STAT_BKEND_OVERRUN_ERR      PPC_BIT(2)
+#define I2C_STAT_BKEND_ACCESS_ERR       PPC_BIT(3)
+#define I2C_STAT_ARBT_LOST_ERR          PPC_BIT(4)
+#define I2C_STAT_NACK_RCVD_ERR          PPC_BIT(5)
+#define I2C_STAT_DATA_REQ               PPC_BIT(6)
+#define I2C_STAT_CMD_COMP               PPC_BIT(7)
+#define I2C_STAT_STOP_ERR               PPC_BIT(8)
+#define I2C_STAT_UPPER_THRS             PPC_BITMASK(9, 15)
+#define I2C_STAT_ANY_I2C_INTR           PPC_BIT(16)
+#define I2C_STAT_PORT_HISTORY_BUSY      PPC_BIT(19)
+#define I2C_STAT_SCL_INPUT_LEVEL        PPC_BIT(20)
+#define I2C_STAT_SDA_INPUT_LEVEL        PPC_BIT(21)
+#define I2C_STAT_PORT_BUSY              PPC_BIT(22)
+#define I2C_STAT_INTERFACE_BUSY         PPC_BIT(23)
+#define I2C_STAT_FIFO_ENTRY_COUNT       PPC_BITMASK(24, 31)
+
+#define I2C_STAT_ANY_ERR (I2C_STAT_INVALID_CMD | I2C_STAT_LBUS_PARITY_ERR | \
+                          I2C_STAT_BKEND_OVERRUN_ERR | \
+                          I2C_STAT_BKEND_ACCESS_ERR | I2C_STAT_ARBT_LOST_ERR | \
+                          I2C_STAT_NACK_RCVD_ERR | I2C_STAT_STOP_ERR)
+
+
+#define I2C_INTR_ACTIVE \
+        ((I2C_STAT_ANY_ERR >> 16) | I2C_INTR_CMD_COMP | I2C_INTR_DATA_REQ)
+
+/* Pseudo-status used for timeouts */
+#define I2C_STAT_PSEUDO_TIMEOUT         PPC_BIT(63)
+
+/* I2C extended status register */
+#define I2C_EXTD_STAT_REG               0xc
+#define I2C_EXTD_STAT_FIFO_SIZE         PPC_BITMASK(0, 7)
+#define I2C_EXTD_STAT_MSM_CURSTATE      PPC_BITMASK(11, 15)
+#define I2C_EXTD_STAT_SCL_IN_SYNC       PPC_BIT(16)
+#define I2C_EXTD_STAT_SDA_IN_SYNC       PPC_BIT(17)
+#define I2C_EXTD_STAT_S_SCL             PPC_BIT(18)
+#define I2C_EXTD_STAT_S_SDA             PPC_BIT(19)
+#define I2C_EXTD_STAT_M_SCL             PPC_BIT(20)
+#define I2C_EXTD_STAT_M_SDA             PPC_BIT(21)
+#define I2C_EXTD_STAT_HIGH_WATER        PPC_BIT(22)
+#define I2C_EXTD_STAT_LOW_WATER         PPC_BIT(23)
+#define I2C_EXTD_STAT_I2C_BUSY          PPC_BIT(24)
+#define I2C_EXTD_STAT_SELF_BUSY         PPC_BIT(25)
+#define I2C_EXTD_STAT_I2C_VERSION       PPC_BITMASK(27, 31)
+
+/* I2C residual front end/back end length */
+#define I2C_RESIDUAL_LEN_REG            0xd
+#define I2C_RESIDUAL_FRONT_END          PPC_BITMASK(0, 15)
+#define I2C_RESIDUAL_BACK_END           PPC_BITMASK(16, 31)
+
+/* Port busy register */
+#define I2C_PORT_BUSY_REG               0xe
+#define I2C_SET_S_SCL_REG               0xd
+#define I2C_RESET_S_SCL_REG             0xf
+#define I2C_SET_S_SDA_REG               0x10
+#define I2C_RESET_S_SDA_REG             0x11
+
+#define PNV_I2C_FIFO_SIZE 8
+
+static I2CBus *pnv_i2c_get_bus(PnvI2C *i2c)
+{
+    uint8_t port = GETFIELD(I2C_MODE_PORT_NUM, i2c->regs[I2C_MODE_REG]);
+
+    if (port >= i2c->num_busses) {
+        qemu_log_mask(LOG_GUEST_ERROR, "I2C: invalid bus number %d/%d\n", port,
+                      i2c->num_busses);
+        return NULL;
+    }
+    return i2c->busses[port];
+}
+
+static void pnv_i2c_update_irq(PnvI2C *i2c)
+{
+    I2CBus *bus = pnv_i2c_get_bus(i2c);
+    bool recv = !!(i2c->regs[I2C_CMD_REG] & I2C_CMD_READ_NOT_WRITE);
+    uint16_t front_end = GETFIELD(I2C_RESIDUAL_FRONT_END,
+                                  i2c->regs[I2C_RESIDUAL_LEN_REG]);
+    uint16_t back_end = GETFIELD(I2C_RESIDUAL_BACK_END,
+                                 i2c->regs[I2C_RESIDUAL_LEN_REG]);
+    uint8_t fifo_count = GETFIELD(I2C_STAT_FIFO_ENTRY_COUNT,
+                                   i2c->regs[I2C_STAT_REG]);
+    uint8_t fifo_free = PNV_I2C_FIFO_SIZE - fifo_count;
+
+    if (!bus) {
+        qemu_log_mask(LOG_GUEST_ERROR, "I2C: invalid port\n");
+        return;
+    }
+
+    if (i2c_bus_busy(bus)) {
+        i2c->regs[I2C_STAT_REG] &= ~I2C_STAT_DATA_REQ;
+
+        if (recv) {
+            if (fifo_count >=
+                GETFIELD(I2C_WATERMARK_HIGH, i2c->regs[I2C_WATERMARK_REG])) {
+                i2c->regs[I2C_EXTD_STAT_REG] |= I2C_EXTD_STAT_HIGH_WATER;
+            } else {
+                i2c->regs[I2C_EXTD_STAT_REG] &= ~I2C_EXTD_STAT_HIGH_WATER;
+            }
+
+            if (((i2c->regs[I2C_EXTD_STAT_REG] & I2C_EXTD_STAT_HIGH_WATER) &&
+                 fifo_count != 0) || front_end == 0) {
+                i2c->regs[I2C_STAT_REG] |= I2C_STAT_DATA_REQ;
+            }
+        } else {
+            if (fifo_count <=
+                GETFIELD(I2C_WATERMARK_LOW, i2c->regs[I2C_WATERMARK_REG])) {
+                i2c->regs[I2C_EXTD_STAT_REG] |= I2C_EXTD_STAT_LOW_WATER;
+            } else {
+                i2c->regs[I2C_EXTD_STAT_REG] &= ~I2C_EXTD_STAT_LOW_WATER;
+            }
+
+            if (back_end > 0 &&
+                (fifo_free >= back_end ||
+                 (i2c->regs[I2C_EXTD_STAT_REG] & I2C_EXTD_STAT_LOW_WATER))) {
+                i2c->regs[I2C_STAT_REG] |= I2C_STAT_DATA_REQ;
+            }
+        }
+
+        if (back_end == 0 && front_end == 0) {
+            i2c->regs[I2C_STAT_REG] &= ~I2C_STAT_DATA_REQ;
+            i2c->regs[I2C_STAT_REG] |= I2C_STAT_CMD_COMP;
+
+            if (i2c->regs[I2C_CMD_REG] & I2C_CMD_WITH_STOP) {
+                i2c_end_transfer(bus);
+                i2c->regs[I2C_EXTD_STAT_REG] &=
+                    ~(I2C_EXTD_STAT_I2C_BUSY | I2C_EXTD_STAT_SELF_BUSY);
+            }
+        } else {
+            i2c->regs[I2C_STAT_REG] &= ~I2C_STAT_CMD_COMP;
+        }
+    }
+
+    /*
+     * Status and interrupt registers have nearly the same layout.
+     */
+    i2c->regs[I2C_INTR_RAW_COND_REG] = i2c->regs[I2C_STAT_REG] >> 16;
+    i2c->regs[I2C_INTR_COND_REG] =
+        i2c->regs[I2C_INTR_RAW_COND_REG] & i2c->regs[I2C_INTR_MASK_REG];
+
+    qemu_set_irq(i2c->psi_irq, i2c->regs[I2C_INTR_COND_REG] != 0);
+}
+
+static void pnv_i2c_fifo_update_count(PnvI2C *i2c)
+{
+    uint64_t stat = i2c->regs[I2C_STAT_REG];
+
+    i2c->regs[I2C_STAT_REG] = SETFIELD(I2C_STAT_FIFO_ENTRY_COUNT, stat,
+                                       fifo8_num_used(&i2c->fifo));
+}
+
+static void pnv_i2c_frontend_update(PnvI2C *i2c)
+{
+    uint64_t residual_end = i2c->regs[I2C_RESIDUAL_LEN_REG];
+    uint16_t front_end = GETFIELD(I2C_RESIDUAL_FRONT_END, residual_end);
+
+    i2c->regs[I2C_RESIDUAL_LEN_REG] =
+        SETFIELD(I2C_RESIDUAL_FRONT_END, residual_end, front_end - 1);
+}
+
+static void pnv_i2c_fifo_flush(PnvI2C *i2c)
+{
+    I2CBus *bus = pnv_i2c_get_bus(i2c);
+    uint8_t data;
+    int ret;
+
+    if (!bus) {
+        qemu_log_mask(LOG_GUEST_ERROR, "I2C: invalid port\n");
+        return;
+    }
+    if (!i2c_bus_busy(bus)) {
+        return;
+    }
+
+    if (i2c->regs[I2C_CMD_REG] & I2C_CMD_READ_NOT_WRITE) {
+        if (fifo8_is_full(&i2c->fifo)) {
+            return;
+        }
+
+        data = i2c_recv(bus);
+        fifo8_push(&i2c->fifo, data);
+    } else {
+        if (fifo8_is_empty(&i2c->fifo)) {
+            return;
+        }
+
+        data = fifo8_pop(&i2c->fifo);
+        ret = i2c_send(bus, data);
+        if (ret) {
+            i2c->regs[I2C_STAT_REG] |= I2C_STAT_NACK_RCVD_ERR;
+            i2c_end_transfer(bus);
+        }
+    }
+
+    pnv_i2c_fifo_update_count(i2c);
+    pnv_i2c_frontend_update(i2c);
+}
+
+static void pnv_i2c_handle_cmd(PnvI2C *i2c, uint64_t val)
+{
+    I2CBus *bus = pnv_i2c_get_bus(i2c);
+    uint8_t addr = GETFIELD(I2C_CMD_DEV_ADDR, val);
+    int recv = !!(val & I2C_CMD_READ_NOT_WRITE);
+    uint32_t len_bytes = GETFIELD(I2C_CMD_LEN_BYTES, val);
+
+    if (!(val & I2C_CMD_WITH_START) && !(val & I2C_CMD_WITH_ADDR) &&
+        !(val & I2C_CMD_WITH_STOP) && !len_bytes) {
+        i2c->regs[I2C_STAT_REG] |= I2C_STAT_INVALID_CMD;
+        qemu_log_mask(LOG_GUEST_ERROR, "I2C: invalid command 0x%"PRIx64"\n",
+                      val);
+        return;
+    }
+
+    if (!(i2c->regs[I2C_STAT_REG] & I2C_STAT_CMD_COMP)) {
+        i2c->regs[I2C_STAT_REG] |= I2C_STAT_INVALID_CMD;
+        qemu_log_mask(LOG_GUEST_ERROR, "I2C: command in progress\n");
+        return;
+    }
+
+    if (!bus) {
+        qemu_log_mask(LOG_GUEST_ERROR, "I2C: invalid port\n");
+        return;
+    }
+
+    i2c->regs[I2C_RESIDUAL_LEN_REG] =
+        SETFIELD(I2C_RESIDUAL_FRONT_END, 0ull, len_bytes) |
+        SETFIELD(I2C_RESIDUAL_BACK_END, 0ull, len_bytes);
+
+    if (val & I2C_CMD_WITH_START) {
+        if (i2c_start_transfer(bus, addr, recv)) {
+            i2c->regs[I2C_STAT_REG] |= I2C_STAT_NACK_RCVD_ERR;
+        } else {
+            i2c->regs[I2C_EXTD_STAT_REG] |=
+                (I2C_EXTD_STAT_I2C_BUSY | I2C_EXTD_STAT_SELF_BUSY);
+            pnv_i2c_fifo_flush(i2c);
+        }
+    }
+}
+
+static void pnv_i2c_backend_update(PnvI2C *i2c)
+{
+    uint64_t residual_end = i2c->regs[I2C_RESIDUAL_LEN_REG];
+    uint16_t back_end = GETFIELD(I2C_RESIDUAL_BACK_END, residual_end);
+
+    if (!back_end) {
+        i2c->regs[I2C_STAT_REG] |= I2C_STAT_BKEND_ACCESS_ERR;
+        return;
+    }
+
+    i2c->regs[I2C_RESIDUAL_LEN_REG] =
+        SETFIELD(I2C_RESIDUAL_BACK_END, residual_end, back_end - 1);
+}
+
+static void pnv_i2c_fifo_in(PnvI2C *i2c)
+{
+    uint8_t data = GETFIELD(I2C_FIFO, i2c->regs[I2C_FIFO_REG]);
+    I2CBus *bus = pnv_i2c_get_bus(i2c);
+
+    if (!bus) {
+        qemu_log_mask(LOG_GUEST_ERROR, "I2C: invalid port\n");
+        return;
+    }
+
+    if (!i2c_bus_busy(bus)) {
+        i2c->regs[I2C_STAT_REG] |= I2C_STAT_INVALID_CMD;
+        qemu_log_mask(LOG_GUEST_ERROR, "I2C: no command in progress\n");
+        return;
+    }
+
+    if (i2c->regs[I2C_CMD_REG] & I2C_CMD_READ_NOT_WRITE) {
+        i2c->regs[I2C_STAT_REG] |= I2C_STAT_INVALID_CMD;
+        qemu_log_mask(LOG_GUEST_ERROR, "I2C: read command in progress\n");
+        return;
+    }
+
+    if (fifo8_is_full(&i2c->fifo)) {
+        if (!(i2c->regs[I2C_MODE_REG] & I2C_MODE_PACING_ALLOW)) {
+            i2c->regs[I2C_STAT_REG] |= I2C_STAT_BKEND_OVERRUN_ERR;
+        }
+        return;
+    }
+
+    fifo8_push(&i2c->fifo, data);
+    pnv_i2c_fifo_update_count(i2c);
+    pnv_i2c_backend_update(i2c);
+    pnv_i2c_fifo_flush(i2c);
+}
+
+static void pnv_i2c_fifo_out(PnvI2C *i2c)
+{
+    uint8_t data;
+    I2CBus *bus = pnv_i2c_get_bus(i2c);
+
+    if (!bus) {
+        qemu_log_mask(LOG_GUEST_ERROR, "I2C: invalid port\n");
+        return;
+    }
+
+    if (!i2c_bus_busy(bus)) {
+        i2c->regs[I2C_STAT_REG] |= I2C_STAT_INVALID_CMD;
+        qemu_log_mask(LOG_GUEST_ERROR, "I2C: no command in progress\n");
+        return;
+    }
+
+    if (!(i2c->regs[I2C_CMD_REG] & I2C_CMD_READ_NOT_WRITE)) {
+        i2c->regs[I2C_STAT_REG] |= I2C_STAT_INVALID_CMD;
+        qemu_log_mask(LOG_GUEST_ERROR, "I2C: write command in progress\n");
+        return;
+    }
+
+    if (fifo8_is_empty(&i2c->fifo)) {
+        if (!(i2c->regs[I2C_MODE_REG] & I2C_MODE_PACING_ALLOW)) {
+            i2c->regs[I2C_STAT_REG] |= I2C_STAT_BKEND_OVERRUN_ERR;
+        }
+        return;
+    }
+
+    data = fifo8_pop(&i2c->fifo);
+
+    i2c->regs[I2C_FIFO_REG] = SETFIELD(I2C_FIFO, 0ull, data);
+    pnv_i2c_fifo_update_count(i2c);
+    pnv_i2c_backend_update(i2c);
+}
+
+static uint64_t pnv_i2c_xscom_read(void *opaque, hwaddr addr,
+                                   unsigned size)
+{
+    PnvI2C *i2c = PNV_I2C(opaque);
+    uint32_t offset = addr >> 3;
+    uint64_t val = -1;
+    int i;
+
+    switch (offset) {
+    case I2C_STAT_REG:
+        val = i2c->regs[offset];
+        break;
+
+    case I2C_FIFO_REG:
+        pnv_i2c_fifo_out(i2c);
+        val = i2c->regs[offset];
+        break;
+
+    case I2C_PORT_BUSY_REG: /* compute busy bit for each port  */
+        val = 0;
+        for (i = 0; i < i2c->num_busses; i++) {
+            val |= i2c_bus_busy(i2c->busses[i]) << i;
+        }
+        break;
+
+    case I2C_CMD_REG:
+    case I2C_MODE_REG:
+    case I2C_WATERMARK_REG:
+    case I2C_INTR_MASK_REG:
+    case I2C_INTR_RAW_COND_REG:
+    case I2C_INTR_COND_REG:
+    case I2C_EXTD_STAT_REG:
+    case I2C_RESIDUAL_LEN_REG:
+        val = i2c->regs[offset];
+        break;
+    default:
+        i2c->regs[I2C_STAT_REG] |= I2C_STAT_INVALID_CMD;
+        qemu_log_mask(LOG_GUEST_ERROR, "I2C: read at register: 0x%"
+                      HWADDR_PRIx "\n", addr >> 3);
+    }
+
+    pnv_i2c_update_irq(i2c);
+
+    return val;
+}
+
+static void pnv_i2c_xscom_write(void *opaque, hwaddr addr,
+                                uint64_t val, unsigned size)
+{
+    PnvI2C *i2c = PNV_I2C(opaque);
+    uint32_t offset = addr >> 3;
+
+    switch (offset) {
+    case I2C_MODE_REG:
+        {
+            i2c->regs[offset] = val;
+            I2CBus *bus = pnv_i2c_get_bus(i2c);
+            if (!bus) {
+                qemu_log_mask(LOG_GUEST_ERROR, "I2C: invalid port\n");
+                return;
+            }
+            if (i2c_bus_busy(bus)) {
+                i2c->regs[I2C_STAT_REG] |= I2C_STAT_INVALID_CMD;
+                qemu_log_mask(LOG_GUEST_ERROR, "I2C: command in progress\n");
+            }
+        }
+        break;
+
+    case I2C_CMD_REG:
+        i2c->regs[offset] = val;
+        pnv_i2c_handle_cmd(i2c, val);
+        break;
+
+    case I2C_FIFO_REG:
+        i2c->regs[offset] = val;
+        pnv_i2c_fifo_in(i2c);
+        break;
+
+    case I2C_WATERMARK_REG:
+        i2c->regs[offset] = val;
+        break;
+
+    case I2C_RESET_I2C_REG:
+        i2c->regs[I2C_MODE_REG] = 0;
+        i2c->regs[I2C_CMD_REG] = 0;
+        i2c->regs[I2C_WATERMARK_REG] = 0;
+        i2c->regs[I2C_INTR_MASK_REG] = 0;
+        i2c->regs[I2C_INTR_COND_REG] = 0;
+        i2c->regs[I2C_INTR_RAW_COND_REG] = 0;
+        i2c->regs[I2C_STAT_REG] = 0;
+        i2c->regs[I2C_RESIDUAL_LEN_REG] = 0;
+        i2c->regs[I2C_EXTD_STAT_REG] &=
+            (I2C_EXTD_STAT_FIFO_SIZE | I2C_EXTD_STAT_I2C_VERSION);
+        break;
+
+    case I2C_RESET_ERRORS:
+        i2c->regs[I2C_STAT_REG] &= ~I2C_STAT_ANY_ERR;
+        i2c->regs[I2C_RESIDUAL_LEN_REG] = 0;
+        i2c->regs[I2C_EXTD_STAT_REG] &=
+            (I2C_EXTD_STAT_FIFO_SIZE | I2C_EXTD_STAT_I2C_VERSION);
+        fifo8_reset(&i2c->fifo);
+        break;
+
+    case I2C_INTR_MASK_REG:
+        i2c->regs[offset] = val;
+        break;
+
+    case I2C_INTR_MASK_OR_REG:
+        i2c->regs[I2C_INTR_MASK_REG] |= val;
+        break;
+
+    case I2C_INTR_MASK_AND_REG:
+        i2c->regs[I2C_INTR_MASK_REG] &= val;
+        break;
+
+    case I2C_PORT_BUSY_REG:
+    case I2C_SET_S_SCL_REG:
+    case I2C_RESET_S_SCL_REG:
+    case I2C_SET_S_SDA_REG:
+    case I2C_RESET_S_SDA_REG:
+        i2c->regs[offset] = val;
+        break;
+    default:
+        i2c->regs[I2C_STAT_REG] |= I2C_STAT_INVALID_CMD;
+        qemu_log_mask(LOG_GUEST_ERROR, "I2C: write at register: 0x%"
+                      HWADDR_PRIx " val=0x%"PRIx64"\n", addr >> 3, val);
+    }
+
+    pnv_i2c_update_irq(i2c);
+}
+
+static const MemoryRegionOps pnv_i2c_xscom_ops = {
+    .read = pnv_i2c_xscom_read,
+    .write = pnv_i2c_xscom_write,
+    .valid.min_access_size = 8,
+    .valid.max_access_size = 8,
+    .impl.min_access_size = 8,
+    .impl.max_access_size = 8,
+    .endianness = DEVICE_BIG_ENDIAN,
+};
+
+static int pnv_i2c_bus_dt_xscom(PnvI2C *i2c, void *fdt,
+                                int offset, int index)
+{
+    int i2c_bus_offset;
+    const char i2c_compat[] =
+        "ibm,opal-i2c\0ibm,power8-i2c-port\0ibm,power9-i2c-port";
+    g_autofree char *i2c_port_name = NULL;
+    g_autofree char *name = g_strdup_printf("i2c-bus@%x", index);
+
+    i2c_bus_offset = fdt_add_subnode(fdt, offset, name);
+    _FDT(i2c_bus_offset);
+
+    _FDT((fdt_setprop_cell(fdt, i2c_bus_offset, "reg", index)));
+    _FDT((fdt_setprop_cell(fdt, i2c_bus_offset, "#address-cells", 1)));
+    _FDT((fdt_setprop_cell(fdt, i2c_bus_offset, "#size-cells", 0)));
+    _FDT(fdt_setprop(fdt, i2c_bus_offset, "compatible", i2c_compat,
+                     sizeof(i2c_compat)));
+    _FDT((fdt_setprop_cell(fdt, i2c_bus_offset, "bus-frequency", 400000)));
+
+    i2c_port_name = g_strdup_printf("p8_%08x_e%dp%d", i2c->chip->chip_id,
+                                    i2c->engine, index);
+    _FDT(fdt_setprop_string(fdt, i2c_bus_offset, "ibm,port-name",
+                            i2c_port_name));
+    return 0;
+}
+
+#define XSCOM_BUS_FREQUENCY 466500000
+#define I2C_CLOCK_FREQUENCY (XSCOM_BUS_FREQUENCY / 4)
+
+static int pnv_i2c_dt_xscom(PnvXScomInterface *dev, void *fdt,
+                            int offset)
+{
+    PnvI2C *i2c = PNV_I2C(dev);
+    int i2c_offset;
+    const char i2c_compat[] = "ibm,power8-i2cm\0ibm,power9-i2cm";
+    uint32_t i2c_pcba = PNV9_XSCOM_I2CM_BASE +
+        i2c->engine * PNV9_XSCOM_I2CM_SIZE;
+    uint32_t reg[2] = {
+        cpu_to_be32(i2c_pcba),
+        cpu_to_be32(PNV9_XSCOM_I2CM_SIZE)
+    };
+    int i;
+    g_autofree char *name = g_strdup_printf("i2cm@%x", i2c_pcba);
+
+    i2c_offset = fdt_add_subnode(fdt, offset, name);
+    _FDT(i2c_offset);
+
+    _FDT(fdt_setprop(fdt, i2c_offset, "reg", reg, sizeof(reg)));
+
+    _FDT((fdt_setprop_cell(fdt, i2c_offset, "#address-cells", 1)));
+    _FDT((fdt_setprop_cell(fdt, i2c_offset, "#size-cells", 0)));
+    _FDT(fdt_setprop(fdt, i2c_offset, "compatible", i2c_compat,
+                     sizeof(i2c_compat)));
+    _FDT((fdt_setprop_cell(fdt, i2c_offset, "chip-engine#", i2c->engine)));
+    _FDT((fdt_setprop_cell(fdt, i2c_offset, "clock-frequency",
+                           I2C_CLOCK_FREQUENCY)));
+
+    for (i = 0; i < i2c->num_busses; i++) {
+        pnv_i2c_bus_dt_xscom(i2c, fdt, i2c_offset, i);
+    }
+    return 0;
+}
+
+static void pnv_i2c_reset(void *dev)
+{
+    PnvI2C *i2c = PNV_I2C(dev);
+
+    memset(i2c->regs, 0, sizeof(i2c->regs));
+
+    i2c->regs[I2C_STAT_REG] = I2C_STAT_CMD_COMP;
+    i2c->regs[I2C_EXTD_STAT_REG] =
+        SETFIELD(I2C_EXTD_STAT_FIFO_SIZE, 0ull, PNV_I2C_FIFO_SIZE) |
+        SETFIELD(I2C_EXTD_STAT_I2C_VERSION, 0ull, 23); /* last version */
+
+    fifo8_reset(&i2c->fifo);
+}
+
+static void pnv_i2c_realize(DeviceState *dev, Error **errp)
+{
+    PnvI2C *i2c = PNV_I2C(dev);
+    int i;
+
+    assert(i2c->chip);
+
+    pnv_xscom_region_init(&i2c->xscom_regs, OBJECT(i2c), &pnv_i2c_xscom_ops,
+                          i2c, "xscom-i2c", PNV9_XSCOM_I2CM_SIZE);
+
+    i2c->busses = g_new(I2CBus *, i2c->num_busses);
+    for (i = 0; i < i2c->num_busses; i++) {
+        char name[32];
+
+        snprintf(name, sizeof(name), TYPE_PNV_I2C ".%d", i);
+        i2c->busses[i] = i2c_init_bus(dev, name);
+    }
+
+    fifo8_create(&i2c->fifo, PNV_I2C_FIFO_SIZE);
+
+    qemu_register_reset(pnv_i2c_reset, dev);
+
+    qdev_init_gpio_out(DEVICE(dev), &i2c->psi_irq, 1);
+}
+
+static Property pnv_i2c_properties[] = {
+    DEFINE_PROP_LINK("chip", PnvI2C, chip, TYPE_PNV_CHIP, PnvChip *),
+    DEFINE_PROP_UINT32("engine", PnvI2C, engine, 1),
+    DEFINE_PROP_UINT32("num-busses", PnvI2C, num_busses, 1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pnv_i2c_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PnvXScomInterfaceClass *xscomc = PNV_XSCOM_INTERFACE_CLASS(klass);
+
+    xscomc->dt_xscom = pnv_i2c_dt_xscom;
+
+    dc->desc = "PowerNV I2C";
+    dc->realize = pnv_i2c_realize;
+    device_class_set_props(dc, pnv_i2c_properties);
+}
+
+static const TypeInfo pnv_i2c_info = {
+    .name          = TYPE_PNV_I2C,
+    .parent        = TYPE_DEVICE,
+    .instance_size = sizeof(PnvI2C),
+    .class_init    = pnv_i2c_class_init,
+    .interfaces    = (InterfaceInfo[]) {
+        { TYPE_PNV_XSCOM_INTERFACE },
+        { }
+    }
+};
+
+static void pnv_i2c_register_types(void)
+{
+    type_register_static(&pnv_i2c_info);
+}
+
+type_init(pnv_i2c_register_types);
diff --git a/include/hw/ppc/pnv_i2c.h b/include/hw/ppc/pnv_i2c.h
new file mode 100644
index 0000000000..1a37730f1e
--- /dev/null
+++ b/include/hw/ppc/pnv_i2c.h
@@ -0,0 +1,38 @@
+/*
+ * QEMU PowerPC PowerNV Processor I2C model
+ *
+ * Copyright (c) 2019-2023, IBM Corporation.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef PPC_PNV_I2C_H
+#define PPC_PNV_I2C_H
+
+#include "hw/ppc/pnv.h"
+#include "hw/i2c/i2c.h"
+#include "qemu/fifo8.h"
+
+#define TYPE_PNV_I2C "pnv-i2c"
+#define PNV_I2C(obj) OBJECT_CHECK(PnvI2C, (obj), TYPE_PNV_I2C)
+
+#define PNV_I2C_REGS 0x20
+
+typedef struct PnvI2C {
+    DeviceState parent;
+
+    struct PnvChip *chip;
+
+    qemu_irq psi_irq;
+
+    uint64_t regs[PNV_I2C_REGS];
+    uint32_t engine;
+    uint32_t num_busses;
+    I2CBus **busses;
+
+    MemoryRegion xscom_regs;
+
+    Fifo8 fifo;
+} PnvI2C;
+
+#endif /* PPC_PNV_I2C_H */
diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h
index 35b19610f7..056392ab60 100644
--- a/include/hw/ppc/pnv_xscom.h
+++ b/include/hw/ppc/pnv_xscom.h
@@ -90,6 +90,9 @@ struct PnvXScomInterfaceClass {
     ((uint64_t)(((core) & 0x1C) + 0x40) << 22)
 #define PNV9_XSCOM_EQ_SIZE        0x100000
 
+#define PNV9_XSCOM_I2CM_BASE      0xa0000
+#define PNV9_XSCOM_I2CM_SIZE      0x1000
+
 #define PNV9_XSCOM_OCC_BASE       PNV_XSCOM_OCC_BASE
 #define PNV9_XSCOM_OCC_SIZE       0x8000
 
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PULL 5/9] ppc/pnv: Connect I2C controller model to powernv9 chip
  2023-11-07 20:47 [PULL 0/9] ppc queue Daniel Henrique Barboza
                   ` (3 preceding siblings ...)
  2023-11-07 20:48 ` [PULL 4/9] ppc/pnv: Add an I2C controller model Daniel Henrique Barboza
@ 2023-11-07 20:48 ` Daniel Henrique Barboza
  2023-11-07 20:48 ` [PULL 6/9] ppc/pnv: Connect PNV I2C controller to powernv10 Daniel Henrique Barboza
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Daniel Henrique Barboza @ 2023-11-07 20:48 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-ppc, danielhb413, peter.maydell, Cédric Le Goater,
	Glenn Miles

From: Cédric Le Goater <clg@kaod.org>

Wires up three I2C controller instances to the powernv9 chip
XSCOM address space.

Each controller instance is wired up to a single I2C bus of
its own.  No other I2C devices are connected to the buses
at this time.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
[milesg: Split wiring from addition of model itself]
[milesg: Added new commit message]
[milesg: Moved hardcoded attributes into PnvChipClass]
[milesg: Removed TODO comment for I2C]
Signed-off-by: Glenn Miles <milesg@linux.vnet.ibm.com>
Acked-by: Daniel Henrique Barboza <danielhb413@gmail.com>
Message-ID: <20231016222013.3739530-3-milesg@linux.vnet.ibm.com>
Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
 hw/ppc/pnv.c              | 28 ++++++++++++++++++++++++++++
 include/hw/ppc/pnv_chip.h |  8 ++++++++
 2 files changed, 36 insertions(+)

diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index c0e34fffbc..bb4d00e266 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -1432,6 +1432,10 @@ static void pnv_chip_power9_instance_init(Object *obj)
         object_initialize_child(obj, "pec[*]", &chip9->pecs[i],
                                 TYPE_PNV_PHB4_PEC);
     }
+
+    for (i = 0; i < pcc->i2c_num_engines; i++) {
+        object_initialize_child(obj, "i2c[*]", &chip9->i2c[i], TYPE_PNV_I2C);
+    }
 }
 
 static void pnv_chip_quad_realize_one(PnvChip *chip, PnvQuad *eq,
@@ -1504,6 +1508,7 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
     PnvChip *chip = PNV_CHIP(dev);
     Pnv9Psi *psi9 = &chip9->psi;
     Error *local_err = NULL;
+    int i;
 
     /* XSCOM bridge is first */
     pnv_xscom_init(chip, PNV9_XSCOM_SIZE, PNV9_XSCOM_BASE(chip));
@@ -1602,6 +1607,27 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
         error_propagate(errp, local_err);
         return;
     }
+
+    /*
+     * I2C
+     */
+    for (i = 0; i < pcc->i2c_num_engines; i++) {
+        Object *obj =  OBJECT(&chip9->i2c[i]);
+
+        object_property_set_int(obj, "engine", i + 1, &error_fatal);
+        object_property_set_int(obj, "num-busses", pcc->i2c_num_ports,
+                                &error_fatal);
+        object_property_set_link(obj, "chip", OBJECT(chip), &error_abort);
+        if (!qdev_realize(DEVICE(obj), NULL, errp)) {
+            return;
+        }
+        pnv_xscom_add_subregion(chip, PNV9_XSCOM_I2CM_BASE +
+                               chip9->i2c[i].engine * PNV9_XSCOM_I2CM_SIZE,
+                                &chip9->i2c[i].xscom_regs);
+        qdev_connect_gpio_out(DEVICE(&chip9->i2c[i]), 0,
+                              qdev_get_gpio_in(DEVICE(&chip9->psi),
+                                               PSIHB9_IRQ_SBE_I2C));
+    }
 }
 
 static uint32_t pnv_chip_power9_xscom_pcba(PnvChip *chip, uint64_t addr)
@@ -1629,6 +1655,8 @@ static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
     k->xscom_pcba = pnv_chip_power9_xscom_pcba;
     dc->desc = "PowerNV Chip POWER9";
     k->num_pecs = PNV9_CHIP_MAX_PEC;
+    k->i2c_num_engines = PNV9_CHIP_MAX_I2C;
+    k->i2c_num_ports = PNV9_CHIP_MAX_I2C_PORTS;
 
     device_class_set_parent_realize(dc, pnv_chip_power9_realize,
                                     &k->parent_realize);
diff --git a/include/hw/ppc/pnv_chip.h b/include/hw/ppc/pnv_chip.h
index 53e1d921d7..90cfbad1a5 100644
--- a/include/hw/ppc/pnv_chip.h
+++ b/include/hw/ppc/pnv_chip.h
@@ -9,6 +9,7 @@
 #include "hw/ppc/pnv_psi.h"
 #include "hw/ppc/pnv_sbe.h"
 #include "hw/ppc/pnv_xive.h"
+#include "hw/ppc/pnv_i2c.h"
 #include "hw/sysbus.h"
 
 OBJECT_DECLARE_TYPE(PnvChip, PnvChipClass,
@@ -86,6 +87,10 @@ struct Pnv9Chip {
 
 #define PNV9_CHIP_MAX_PEC 3
     PnvPhb4PecState pecs[PNV9_CHIP_MAX_PEC];
+
+#define PNV9_CHIP_MAX_I2C 3
+#define PNV9_CHIP_MAX_I2C_PORTS 1
+    PnvI2C      i2c[PNV9_CHIP_MAX_I2C];
 };
 
 /*
@@ -130,6 +135,9 @@ struct PnvChipClass {
     uint32_t     num_pecs;
     uint32_t     num_phbs;
 
+    uint32_t     i2c_num_engines;
+    uint32_t     i2c_num_ports;
+
     DeviceRealize parent_realize;
 
     uint32_t (*core_pir)(PnvChip *chip, uint32_t core_id);
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PULL 6/9] ppc/pnv: Connect PNV I2C controller to powernv10
  2023-11-07 20:47 [PULL 0/9] ppc queue Daniel Henrique Barboza
                   ` (4 preceding siblings ...)
  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 ` 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
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Daniel Henrique Barboza @ 2023-11-07 20:48 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-ppc, danielhb413, peter.maydell, Glenn Miles,
	Cédric Le Goater

From: Glenn Miles <milesg@linux.vnet.ibm.com>

Wires up four I2C controller instances to the powernv10 chip
XSCOM address space.

Each controller instance is wired up to two I2C buses of
its own.  No other I2C devices are connected to the buses
at this time.

Signed-off-by: Glenn Miles <milesg@linux.vnet.ibm.com>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
Message-ID: <20231017221434.810363-1-milesg@linux.vnet.ibm.com>
Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
 hw/ppc/pnv.c               | 29 +++++++++++++++++++++++++++++
 include/hw/ppc/pnv_chip.h  |  4 ++++
 include/hw/ppc/pnv_xscom.h |  3 +++
 3 files changed, 36 insertions(+)

diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index bb4d00e266..ae8e0b45cd 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -1684,6 +1684,10 @@ static void pnv_chip_power10_instance_init(Object *obj)
         object_initialize_child(obj, "pec[*]", &chip10->pecs[i],
                                 TYPE_PNV_PHB5_PEC);
     }
+
+    for (i = 0; i < pcc->i2c_num_engines; i++) {
+        object_initialize_child(obj, "i2c[*]", &chip10->i2c[i], TYPE_PNV_I2C);
+    }
 }
 
 static void pnv_chip_power10_quad_realize(Pnv10Chip *chip10, Error **errp)
@@ -1742,6 +1746,7 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp)
     PnvChip *chip = PNV_CHIP(dev);
     Pnv10Chip *chip10 = PNV10_CHIP(dev);
     Error *local_err = NULL;
+    int i;
 
     /* XSCOM bridge is first */
     pnv_xscom_init(chip, PNV10_XSCOM_SIZE, PNV10_XSCOM_BASE(chip));
@@ -1847,6 +1852,28 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp)
         error_propagate(errp, local_err);
         return;
     }
+
+
+    /*
+     * I2C
+     */
+    for (i = 0; i < pcc->i2c_num_engines; i++) {
+        Object *obj =  OBJECT(&chip10->i2c[i]);
+
+        object_property_set_int(obj, "engine", i + 1, &error_fatal);
+        object_property_set_int(obj, "num-busses", pcc->i2c_num_ports,
+                                &error_fatal);
+        object_property_set_link(obj, "chip", OBJECT(chip), &error_abort);
+        if (!qdev_realize(DEVICE(obj), NULL, errp)) {
+            return;
+        }
+        pnv_xscom_add_subregion(chip, PNV10_XSCOM_I2CM_BASE +
+                                chip10->i2c[i].engine * PNV10_XSCOM_I2CM_SIZE,
+                                &chip10->i2c[i].xscom_regs);
+        qdev_connect_gpio_out(DEVICE(&chip10->i2c[i]), 0,
+                              qdev_get_gpio_in(DEVICE(&chip10->psi),
+                                               PSIHB9_IRQ_SBE_I2C));
+    }
 }
 
 static uint32_t pnv_chip_power10_xscom_pcba(PnvChip *chip, uint64_t addr)
@@ -1874,6 +1901,8 @@ static void pnv_chip_power10_class_init(ObjectClass *klass, void *data)
     k->xscom_pcba = pnv_chip_power10_xscom_pcba;
     dc->desc = "PowerNV Chip POWER10";
     k->num_pecs = PNV10_CHIP_MAX_PEC;
+    k->i2c_num_engines = PNV10_CHIP_MAX_I2C;
+    k->i2c_num_ports = PNV10_CHIP_MAX_I2C_PORTS;
 
     device_class_set_parent_realize(dc, pnv_chip_power10_realize,
                                     &k->parent_realize);
diff --git a/include/hw/ppc/pnv_chip.h b/include/hw/ppc/pnv_chip.h
index 90cfbad1a5..5815d96ecf 100644
--- a/include/hw/ppc/pnv_chip.h
+++ b/include/hw/ppc/pnv_chip.h
@@ -120,6 +120,10 @@ struct Pnv10Chip {
 
 #define PNV10_CHIP_MAX_PEC 2
     PnvPhb4PecState pecs[PNV10_CHIP_MAX_PEC];
+
+#define PNV10_CHIP_MAX_I2C 4
+#define PNV10_CHIP_MAX_I2C_PORTS 2
+    PnvI2C       i2c[PNV10_CHIP_MAX_I2C];
 };
 
 #define PNV10_PIR2FUSEDCORE(pir) (((pir) >> 3) & 0xf)
diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h
index 056392ab60..f5becbab41 100644
--- a/include/hw/ppc/pnv_xscom.h
+++ b/include/hw/ppc/pnv_xscom.h
@@ -152,6 +152,9 @@ struct PnvXScomInterfaceClass {
 #define PNV10_XSCOM_PSIHB_BASE     0x3011D00
 #define PNV10_XSCOM_PSIHB_SIZE     0x100
 
+#define PNV10_XSCOM_I2CM_BASE      PNV9_XSCOM_I2CM_BASE
+#define PNV10_XSCOM_I2CM_SIZE      PNV9_XSCOM_I2CM_SIZE
+
 #define PNV10_XSCOM_OCC_BASE       PNV9_XSCOM_OCC_BASE
 #define PNV10_XSCOM_OCC_SIZE       PNV9_XSCOM_OCC_SIZE
 
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PULL 7/9] ppc/pnv: Fix number of I2C engines and ports for power9/10
  2023-11-07 20:47 [PULL 0/9] ppc queue Daniel Henrique Barboza
                   ` (5 preceding siblings ...)
  2023-11-07 20:48 ` [PULL 6/9] ppc/pnv: Connect PNV I2C controller to powernv10 Daniel Henrique Barboza
@ 2023-11-07 20:48 ` Daniel Henrique Barboza
  2023-11-07 20:48 ` [PULL 8/9] hw/pci-host: Update PHB5 XSCOM registers Daniel Henrique Barboza
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Daniel Henrique Barboza @ 2023-11-07 20:48 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-ppc, danielhb413, peter.maydell, Glenn Miles,
	Cédric Le Goater

From: Glenn Miles <milesg@linux.vnet.ibm.com>

Power9 is supposed to have 4 PIB-connected I2C engines with the
following number of ports on each engine:

    0: 2
    1: 13
    2: 2
    3: 2

Power10 also has 4 engines but has the following number of ports
on each engine:

    0: 14
    1: 14
    2: 2
    3: 16

Current code assumes that they all have the same (maximum) number.
This can be a problem if software expects to see a certain number
of ports present (Power Hypervisor seems to care).

Fixed this by adding separate tables for power9 and power10 that
map the I2C controller number to the number of I2C buses that should
be attached for that engine.

Reviewed-by: Cédric Le Goater <clg@kaod.org>
Signed-off-by: Glenn Miles <milesg@linux.vnet.ibm.com>
Message-ID: <20231025152714.956664-1-milesg@linux.vnet.ibm.com>
Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
 hw/ppc/pnv.c              | 12 ++++++++----
 include/hw/ppc/pnv_chip.h |  6 ++----
 2 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index ae8e0b45cd..9c29727337 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -1615,7 +1615,8 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
         Object *obj =  OBJECT(&chip9->i2c[i]);
 
         object_property_set_int(obj, "engine", i + 1, &error_fatal);
-        object_property_set_int(obj, "num-busses", pcc->i2c_num_ports,
+        object_property_set_int(obj, "num-busses",
+                                pcc->i2c_ports_per_engine[i],
                                 &error_fatal);
         object_property_set_link(obj, "chip", OBJECT(chip), &error_abort);
         if (!qdev_realize(DEVICE(obj), NULL, errp)) {
@@ -1640,6 +1641,7 @@ static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
     PnvChipClass *k = PNV_CHIP_CLASS(klass);
+    static const int i2c_ports_per_engine[PNV9_CHIP_MAX_I2C] = {2, 13, 2, 2};
 
     k->chip_cfam_id = 0x220d104900008000ull; /* P9 Nimbus DD2.0 */
     k->cores_mask = POWER9_CORE_MASK;
@@ -1656,7 +1658,7 @@ static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
     dc->desc = "PowerNV Chip POWER9";
     k->num_pecs = PNV9_CHIP_MAX_PEC;
     k->i2c_num_engines = PNV9_CHIP_MAX_I2C;
-    k->i2c_num_ports = PNV9_CHIP_MAX_I2C_PORTS;
+    k->i2c_ports_per_engine = i2c_ports_per_engine;
 
     device_class_set_parent_realize(dc, pnv_chip_power9_realize,
                                     &k->parent_realize);
@@ -1861,7 +1863,8 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp)
         Object *obj =  OBJECT(&chip10->i2c[i]);
 
         object_property_set_int(obj, "engine", i + 1, &error_fatal);
-        object_property_set_int(obj, "num-busses", pcc->i2c_num_ports,
+        object_property_set_int(obj, "num-busses",
+                                pcc->i2c_ports_per_engine[i],
                                 &error_fatal);
         object_property_set_link(obj, "chip", OBJECT(chip), &error_abort);
         if (!qdev_realize(DEVICE(obj), NULL, errp)) {
@@ -1886,6 +1889,7 @@ static void pnv_chip_power10_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
     PnvChipClass *k = PNV_CHIP_CLASS(klass);
+    static const int i2c_ports_per_engine[PNV10_CHIP_MAX_I2C] = {14, 14, 2, 16};
 
     k->chip_cfam_id = 0x120da04900008000ull; /* P10 DD1.0 (with NX) */
     k->cores_mask = POWER10_CORE_MASK;
@@ -1902,7 +1906,7 @@ static void pnv_chip_power10_class_init(ObjectClass *klass, void *data)
     dc->desc = "PowerNV Chip POWER10";
     k->num_pecs = PNV10_CHIP_MAX_PEC;
     k->i2c_num_engines = PNV10_CHIP_MAX_I2C;
-    k->i2c_num_ports = PNV10_CHIP_MAX_I2C_PORTS;
+    k->i2c_ports_per_engine = i2c_ports_per_engine;
 
     device_class_set_parent_realize(dc, pnv_chip_power10_realize,
                                     &k->parent_realize);
diff --git a/include/hw/ppc/pnv_chip.h b/include/hw/ppc/pnv_chip.h
index 5815d96ecf..0ab5c42308 100644
--- a/include/hw/ppc/pnv_chip.h
+++ b/include/hw/ppc/pnv_chip.h
@@ -88,8 +88,7 @@ struct Pnv9Chip {
 #define PNV9_CHIP_MAX_PEC 3
     PnvPhb4PecState pecs[PNV9_CHIP_MAX_PEC];
 
-#define PNV9_CHIP_MAX_I2C 3
-#define PNV9_CHIP_MAX_I2C_PORTS 1
+#define PNV9_CHIP_MAX_I2C 4
     PnvI2C      i2c[PNV9_CHIP_MAX_I2C];
 };
 
@@ -122,7 +121,6 @@ struct Pnv10Chip {
     PnvPhb4PecState pecs[PNV10_CHIP_MAX_PEC];
 
 #define PNV10_CHIP_MAX_I2C 4
-#define PNV10_CHIP_MAX_I2C_PORTS 2
     PnvI2C       i2c[PNV10_CHIP_MAX_I2C];
 };
 
@@ -140,7 +138,7 @@ struct PnvChipClass {
     uint32_t     num_phbs;
 
     uint32_t     i2c_num_engines;
-    uint32_t     i2c_num_ports;
+    const int    *i2c_ports_per_engine;
 
     DeviceRealize parent_realize;
 
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PULL 8/9] hw/pci-host: Update PHB5 XSCOM registers
  2023-11-07 20:47 [PULL 0/9] ppc queue Daniel Henrique Barboza
                   ` (6 preceding siblings ...)
  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 ` 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
  9 siblings, 0 replies; 11+ messages in thread
From: Daniel Henrique Barboza @ 2023-11-07 20:48 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-ppc, danielhb413, peter.maydell, Saif Abrar,
	Cédric Le Goater, Harsh Prateek Bora

From: Saif Abrar <saif.abrar@linux.vnet.ibm.com>

Add new XSCOM registers introduced in PHB5.
Apply bit-masks within xscom-write methods.
Bit-masks specified using PPC_BITMASK macro.

Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
Reviewed-by: Harsh Prateek Bora <harshpb@linux.ibm.com>
Message-ID: <20231016175948.10869-1-saif.abrar@linux.vnet.ibm.com>
Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
 hw/pci-host/pnv_phb4.c              | 46 ++++++++++++++++++-----------
 hw/pci-host/pnv_phb4_pec.c          | 33 +++++++++++++++++----
 include/hw/pci-host/pnv_phb4.h      |  2 +-
 include/hw/pci-host/pnv_phb4_regs.h |  4 ++-
 4 files changed, 60 insertions(+), 25 deletions(-)

diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
index 37c7afc18c..075499d36d 100644
--- a/hw/pci-host/pnv_phb4.c
+++ b/hw/pci-host/pnv_phb4.c
@@ -855,7 +855,7 @@ static uint64_t pnv_pec_stk_nest_xscom_read(void *opaque, hwaddr addr,
     PnvPHB4 *phb = PNV_PHB4(opaque);
     uint32_t reg = addr >> 3;
 
-    /* TODO: add list of allowed registers and error out if not */
+    /* All registers are read-able */
     return phb->nest_regs[reg];
 }
 
@@ -1000,7 +1000,7 @@ static void pnv_pec_stk_nest_xscom_write(void *opaque, hwaddr addr,
 
     switch (reg) {
     case PEC_NEST_STK_PCI_NEST_FIR:
-        phb->nest_regs[PEC_NEST_STK_PCI_NEST_FIR] = val;
+        phb->nest_regs[PEC_NEST_STK_PCI_NEST_FIR] = val & PPC_BITMASK(0, 27);
         break;
     case PEC_NEST_STK_PCI_NEST_FIR_CLR:
         phb->nest_regs[PEC_NEST_STK_PCI_NEST_FIR] &= val;
@@ -1009,7 +1009,8 @@ static void pnv_pec_stk_nest_xscom_write(void *opaque, hwaddr addr,
         phb->nest_regs[PEC_NEST_STK_PCI_NEST_FIR] |= val;
         break;
     case PEC_NEST_STK_PCI_NEST_FIR_MSK:
-        phb->nest_regs[PEC_NEST_STK_PCI_NEST_FIR_MSK] = val;
+        phb->nest_regs[PEC_NEST_STK_PCI_NEST_FIR_MSK] = val &
+                                                        PPC_BITMASK(0, 27);
         break;
     case PEC_NEST_STK_PCI_NEST_FIR_MSKC:
         phb->nest_regs[PEC_NEST_STK_PCI_NEST_FIR_MSK] &= val;
@@ -1019,7 +1020,7 @@ static void pnv_pec_stk_nest_xscom_write(void *opaque, hwaddr addr,
         break;
     case PEC_NEST_STK_PCI_NEST_FIR_ACT0:
     case PEC_NEST_STK_PCI_NEST_FIR_ACT1:
-        phb->nest_regs[reg] = val;
+        phb->nest_regs[reg] = val & PPC_BITMASK(0, 27);
         break;
     case PEC_NEST_STK_PCI_NEST_FIR_WOF:
         phb->nest_regs[reg] = 0;
@@ -1030,7 +1031,7 @@ static void pnv_pec_stk_nest_xscom_write(void *opaque, hwaddr addr,
         /* Flag error ? */
         break;
     case PEC_NEST_STK_PBCQ_MODE:
-        phb->nest_regs[reg] = val & 0xff00000000000000ull;
+        phb->nest_regs[reg] = val & PPC_BITMASK(0, 7);
         break;
     case PEC_NEST_STK_MMIO_BAR0:
     case PEC_NEST_STK_MMIO_BAR0_MASK:
@@ -1041,28 +1042,33 @@ static void pnv_pec_stk_nest_xscom_write(void *opaque, hwaddr addr,
              PEC_NEST_STK_BAR_EN_MMIO1)) {
             phb_pec_error(pec, "Changing enabled BAR unsupported");
         }
-        phb->nest_regs[reg] = val & 0xffffffffff000000ull;
+        phb->nest_regs[reg] = val & PPC_BITMASK(0, 39);
         break;
     case PEC_NEST_STK_PHB_REGS_BAR:
         if (phb->nest_regs[PEC_NEST_STK_BAR_EN] & PEC_NEST_STK_BAR_EN_PHB) {
             phb_pec_error(pec, "Changing enabled BAR unsupported");
         }
-        phb->nest_regs[reg] = val & 0xffffffffffc00000ull;
+        phb->nest_regs[reg] = val & PPC_BITMASK(0, 41);
         break;
     case PEC_NEST_STK_INT_BAR:
         if (phb->nest_regs[PEC_NEST_STK_BAR_EN] & PEC_NEST_STK_BAR_EN_INT) {
             phb_pec_error(pec, "Changing enabled BAR unsupported");
         }
-        phb->nest_regs[reg] = val & 0xfffffff000000000ull;
+        phb->nest_regs[reg] = val & PPC_BITMASK(0, 27);
         break;
     case PEC_NEST_STK_BAR_EN:
-        phb->nest_regs[reg] = val & 0xf000000000000000ull;
+        phb->nest_regs[reg] = val & PPC_BITMASK(0, 3);
         pnv_pec_phb_update_map(phb);
         break;
     case PEC_NEST_STK_DATA_FRZ_TYPE:
-    case PEC_NEST_STK_PBCQ_TUN_BAR:
         /* Not used for now */
-        phb->nest_regs[reg] = val;
+        phb->nest_regs[reg] = val & PPC_BITMASK(0, 27);
+        break;
+    case PEC_NEST_STK_PBCQ_SPARSE_PAGE:
+        phb->nest_regs[reg] = val & PPC_BITMASK(3, 5);
+        break;
+    case PEC_NEST_STK_PBCQ_CACHE_INJ:
+        phb->nest_regs[reg] = val & PPC_BITMASK(0, 7);
         break;
     default:
         qemu_log_mask(LOG_UNIMP, "phb4_pec: nest_xscom_write 0x%"HWADDR_PRIx
@@ -1086,7 +1092,7 @@ static uint64_t pnv_pec_stk_pci_xscom_read(void *opaque, hwaddr addr,
     PnvPHB4 *phb = PNV_PHB4(opaque);
     uint32_t reg = addr >> 3;
 
-    /* TODO: add list of allowed registers and error out if not */
+    /* All registers are read-able */
     return phb->pci_regs[reg];
 }
 
@@ -1095,10 +1101,9 @@ static void pnv_pec_stk_pci_xscom_write(void *opaque, hwaddr addr,
 {
     PnvPHB4 *phb = PNV_PHB4(opaque);
     uint32_t reg = addr >> 3;
-
     switch (reg) {
     case PEC_PCI_STK_PCI_FIR:
-        phb->pci_regs[reg] = val;
+        phb->pci_regs[reg] = val & PPC_BITMASK(0, 5);
         break;
     case PEC_PCI_STK_PCI_FIR_CLR:
         phb->pci_regs[PEC_PCI_STK_PCI_FIR] &= val;
@@ -1107,7 +1112,7 @@ static void pnv_pec_stk_pci_xscom_write(void *opaque, hwaddr addr,
         phb->pci_regs[PEC_PCI_STK_PCI_FIR] |= val;
         break;
     case PEC_PCI_STK_PCI_FIR_MSK:
-        phb->pci_regs[reg] = val;
+        phb->pci_regs[reg] = val & PPC_BITMASK(0, 5);
         break;
     case PEC_PCI_STK_PCI_FIR_MSKC:
         phb->pci_regs[PEC_PCI_STK_PCI_FIR_MSK] &= val;
@@ -1117,20 +1122,25 @@ static void pnv_pec_stk_pci_xscom_write(void *opaque, hwaddr addr,
         break;
     case PEC_PCI_STK_PCI_FIR_ACT0:
     case PEC_PCI_STK_PCI_FIR_ACT1:
-        phb->pci_regs[reg] = val;
+        phb->pci_regs[reg] = val & PPC_BITMASK(0, 5);
         break;
     case PEC_PCI_STK_PCI_FIR_WOF:
         phb->pci_regs[reg] = 0;
         break;
     case PEC_PCI_STK_ETU_RESET:
-        phb->pci_regs[reg] = val & 0x8000000000000000ull;
+        phb->pci_regs[reg] = val & PPC_BIT(0);
         /* TODO: Implement reset */
         break;
     case PEC_PCI_STK_PBAIB_ERR_REPORT:
         break;
     case PEC_PCI_STK_PBAIB_TX_CMD_CRED:
+        phb->pci_regs[reg] = val &
+                                 ((PPC_BITMASK(0, 2) | PPC_BITMASK(10, 18)
+                                   | PPC_BITMASK(26, 34) | PPC_BITMASK(41, 50)
+                                   | PPC_BITMASK(58, 63)));
+        break;
     case PEC_PCI_STK_PBAIB_TX_DAT_CRED:
-        phb->pci_regs[reg] = val;
+        phb->pci_regs[reg] = val & (PPC_BITMASK(33, 34) | PPC_BITMASK(44, 47));
         break;
     default:
         qemu_log_mask(LOG_UNIMP, "phb4_pec_stk: pci_xscom_write 0x%"HWADDR_PRIx
diff --git a/hw/pci-host/pnv_phb4_pec.c b/hw/pci-host/pnv_phb4_pec.c
index 3b2850f7a3..ce8e228f98 100644
--- a/hw/pci-host/pnv_phb4_pec.c
+++ b/hw/pci-host/pnv_phb4_pec.c
@@ -34,7 +34,7 @@ static uint64_t pnv_pec_nest_xscom_read(void *opaque, hwaddr addr,
     PnvPhb4PecState *pec = PNV_PHB4_PEC(opaque);
     uint32_t reg = addr >> 3;
 
-    /* TODO: add list of allowed registers and error out if not */
+    /* All registers are readable */
     return pec->nest_regs[reg];
 }
 
@@ -45,18 +45,36 @@ static void pnv_pec_nest_xscom_write(void *opaque, hwaddr addr,
     uint32_t reg = addr >> 3;
 
     switch (reg) {
-    case PEC_NEST_PBCQ_HW_CONFIG:
     case PEC_NEST_DROP_PRIO_CTRL:
+        pec->nest_regs[reg] = val & PPC_BITMASK(0, 25);
+        break;
     case PEC_NEST_PBCQ_ERR_INJECT:
+        pec->nest_regs[reg] = val & PPC_BITMASK(0, 11);
+        break;
     case PEC_NEST_PCI_NEST_CLK_TRACE_CTL:
+        pec->nest_regs[reg] = val & PPC_BITMASK(0, 16);
+        break;
     case PEC_NEST_PBCQ_PMON_CTRL:
+        pec->nest_regs[reg] = val & PPC_BITMASK(0, 37);
+        break;
     case PEC_NEST_PBCQ_PBUS_ADDR_EXT:
+        pec->nest_regs[reg] = val & PPC_BITMASK(0, 6);
+        break;
     case PEC_NEST_PBCQ_PRED_VEC_TIMEOUT:
-    case PEC_NEST_CAPP_CTRL:
+        pec->nest_regs[reg] = val & PPC_BITMASK(0, 15);
+        break;
     case PEC_NEST_PBCQ_READ_STK_OVR:
+        pec->nest_regs[reg] = val & PPC_BITMASK(0, 48);
+        break;
     case PEC_NEST_PBCQ_WRITE_STK_OVR:
     case PEC_NEST_PBCQ_STORE_STK_OVR:
+        pec->nest_regs[reg] = val & PPC_BITMASK(0, 24);
+        break;
     case PEC_NEST_PBCQ_RETRY_BKOFF_CTRL:
+        pec->nest_regs[reg] = val & PPC_BITMASK(0, 41);
+        break;
+    case PEC_NEST_PBCQ_HW_CONFIG:
+    case PEC_NEST_CAPP_CTRL:
         pec->nest_regs[reg] = val;
         break;
     default:
@@ -81,7 +99,7 @@ static uint64_t pnv_pec_pci_xscom_read(void *opaque, hwaddr addr,
     PnvPhb4PecState *pec = PNV_PHB4_PEC(opaque);
     uint32_t reg = addr >> 3;
 
-    /* TODO: add list of allowed registers and error out if not */
+    /* All registers are readable */
     return pec->pci_regs[reg];
 }
 
@@ -93,8 +111,13 @@ static void pnv_pec_pci_xscom_write(void *opaque, hwaddr addr,
 
     switch (reg) {
     case PEC_PCI_PBAIB_HW_CONFIG:
+        pec->pci_regs[reg] = val & PPC_BITMASK(0, 42);
+        break;
+    case PEC_PCI_PBAIB_HW_OVR:
+        pec->pci_regs[reg] = val & PPC_BITMASK(0, 15);
+        break;
     case PEC_PCI_PBAIB_READ_STK_OVR:
-        pec->pci_regs[reg] = val;
+        pec->pci_regs[reg] = val & PPC_BITMASK(0, 48);
         break;
     default:
         phb_pec_error(pec, "%s @0x%"HWADDR_PRIx"=%"PRIx64"\n", __func__,
diff --git a/include/hw/pci-host/pnv_phb4.h b/include/hw/pci-host/pnv_phb4.h
index 2d026db9a3..3212e68160 100644
--- a/include/hw/pci-host/pnv_phb4.h
+++ b/include/hw/pci-host/pnv_phb4.h
@@ -117,7 +117,7 @@ struct PnvPHB4 {
     MemoryRegion pci_regs_mr;
 
     /* Nest registers */
-#define PHB4_PEC_NEST_STK_REGS_COUNT  0x17
+#define PHB4_PEC_NEST_STK_REGS_COUNT  0x18
     uint64_t nest_regs[PHB4_PEC_NEST_STK_REGS_COUNT];
     MemoryRegion nest_regs_mr;
 
diff --git a/include/hw/pci-host/pnv_phb4_regs.h b/include/hw/pci-host/pnv_phb4_regs.h
index 4a0d3b28ef..bea96f4d91 100644
--- a/include/hw/pci-host/pnv_phb4_regs.h
+++ b/include/hw/pci-host/pnv_phb4_regs.h
@@ -77,10 +77,12 @@
 #define   PEC_NEST_STK_BAR_EN_PHB               PPC_BIT(2)
 #define   PEC_NEST_STK_BAR_EN_INT               PPC_BIT(3)
 #define PEC_NEST_STK_DATA_FRZ_TYPE      0x15
-#define PEC_NEST_STK_PBCQ_TUN_BAR       0x16
+#define PEC_NEST_STK_PBCQ_SPARSE_PAGE   0x16 /* P10 */
+#define PEC_NEST_STK_PBCQ_CACHE_INJ     0x17 /* P10 */
 
 /* XSCOM PCI global registers */
 #define PEC_PCI_PBAIB_HW_CONFIG         0x00
+#define PEC_PCI_PBAIB_HW_OVR            0x01
 #define PEC_PCI_PBAIB_READ_STK_OVR      0x02
 
 /* XSCOM PCI per-stack registers */
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PULL 9/9] ppc: qtest already exports qtest_rtas_call()
  2023-11-07 20:47 [PULL 0/9] ppc queue Daniel Henrique Barboza
                   ` (7 preceding siblings ...)
  2023-11-07 20:48 ` [PULL 8/9] hw/pci-host: Update PHB5 XSCOM registers Daniel Henrique Barboza
@ 2023-11-07 20:48 ` Daniel Henrique Barboza
  2023-11-08 14:20 ` [PULL 0/9] ppc queue Stefan Hajnoczi
  9 siblings, 0 replies; 11+ messages in thread
From: Daniel Henrique Barboza @ 2023-11-07 20:48 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-ppc, danielhb413, peter.maydell, Juan Quintela,
	Cédric Le Goater

From: Juan Quintela <quintela@redhat.com>

Having two functions with the same name is a bad idea.  As spapr only
uses the function locally, made it static.

When you compile with clang, you get this compilation error:

/usr/bin/ld: tests/qtest/libqos/libqos.fa.p/.._libqtest.c.o: in function `qtest_rtas_call':
/scratch/qemu/clang/full/all/../../../../../mnt/code/qemu/full/tests/qtest/libqtest.c:1195: multiple definition of `qtest_rtas_call'; libqemu-ppc64-softmmu.fa.p/hw_ppc_spapr_rtas.c.o:/scratch/qemu/clang/full/all/../../../../../mnt/code/qemu/full/hw/ppc/spapr_rtas.c:536: first defined here
clang-16: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.
make: *** [Makefile:162: run-ninja] Error 1

Signed-off-by: Juan Quintela <quintela@redhat.com>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
Message-ID: <20231030163834.4638-1-quintela@redhat.com>
[dhb: remove 'spapr_rtas.h' include from spapr_rtas.c]
Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
 hw/ppc/spapr_rtas.c         |  5 ++---
 include/hw/ppc/spapr_rtas.h | 10 ----------
 2 files changed, 2 insertions(+), 13 deletions(-)
 delete mode 100644 include/hw/ppc/spapr_rtas.h

diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c
index 26c384b261..f329693c55 100644
--- a/hw/ppc/spapr_rtas.c
+++ b/hw/ppc/spapr_rtas.c
@@ -38,7 +38,6 @@
 
 #include "hw/ppc/spapr.h"
 #include "hw/ppc/spapr_vio.h"
-#include "hw/ppc/spapr_rtas.h"
 #include "hw/ppc/spapr_cpu_core.h"
 #include "hw/ppc/ppc.h"
 
@@ -531,8 +530,8 @@ target_ulong spapr_rtas_call(PowerPCCPU *cpu, SpaprMachineState *spapr,
     return H_PARAMETER;
 }
 
-uint64_t qtest_rtas_call(char *cmd, uint32_t nargs, uint64_t args,
-                         uint32_t nret, uint64_t rets)
+static uint64_t qtest_rtas_call(char *cmd, uint32_t nargs, uint64_t args,
+                                uint32_t nret, uint64_t rets)
 {
     int token;
 
diff --git a/include/hw/ppc/spapr_rtas.h b/include/hw/ppc/spapr_rtas.h
deleted file mode 100644
index 383611f10f..0000000000
--- a/include/hw/ppc/spapr_rtas.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef HW_SPAPR_RTAS_H
-#define HW_SPAPR_RTAS_H
-/*
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-uint64_t qtest_rtas_call(char *cmd, uint32_t nargs, uint64_t args,
-                         uint32_t nret, uint64_t rets);
-#endif /* HW_SPAPR_RTAS_H */
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PULL 0/9] ppc queue
  2023-11-07 20:47 [PULL 0/9] ppc queue Daniel Henrique Barboza
                   ` (8 preceding siblings ...)
  2023-11-07 20:48 ` [PULL 9/9] ppc: qtest already exports qtest_rtas_call() Daniel Henrique Barboza
@ 2023-11-08 14:20 ` Stefan Hajnoczi
  9 siblings, 0 replies; 11+ messages in thread
From: Stefan Hajnoczi @ 2023-11-08 14:20 UTC (permalink / raw)
  To: Daniel Henrique Barboza; +Cc: qemu-devel, qemu-ppc, danielhb413, peter.maydell

[-- Attachment #1: Type: text/plain, Size: 115 bytes --]

Applied, thanks.

Please update the changelog at https://wiki.qemu.org/ChangeLog/8.2 for any user-visible changes.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2023-11-08 14:23 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-11-07 20:47 [PULL 0/9] ppc queue Daniel Henrique Barboza
2023-11-07 20:47 ` [PULL 1/9] hw/pci-host: Add emulation of Mai Logic Articia S Daniel Henrique Barboza
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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).