qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[RFC PATCH 2/3] hw/peci: add PECI support for NPCM7xx BMCs


From: Titus Rwantare
Subject: [RFC PATCH 2/3] hw/peci: add PECI support for NPCM7xx BMCs
Date: Tue, 6 Sep 2022 22:05:51 +0000

This allows BMC firmware for npcm7xx BMCs to talk to a PECI client
in qemu.

Signed-off-by: Titus Rwantare <titusr@google.com>
Reviewed-by: Patrick Venture <venture@google.com>
---
 MAINTAINERS                    |   3 +-
 hw/arm/Kconfig                 |   1 +
 hw/arm/npcm7xx.c               |   9 ++
 hw/peci/meson.build            |   1 +
 hw/peci/npcm7xx_peci.c         | 204 +++++++++++++++++++++++++++++++++
 hw/peci/trace-events           |   5 +
 include/hw/arm/npcm7xx.h       |   2 +
 include/hw/peci/npcm7xx_peci.h |  37 ++++++
 8 files changed, 261 insertions(+), 1 deletion(-)
 create mode 100644 hw/peci/npcm7xx_peci.c
 create mode 100644 include/hw/peci/npcm7xx_peci.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 14ab29679d..f87dfe5bfa 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2959,7 +2959,7 @@ R: Paolo Bonzini <pbonzini@redhat.com>
 R: Bandan Das <bsd@redhat.com>
 R: Stefan Hajnoczi <stefanha@redhat.com>
 R: Thomas Huth <thuth@redhat.com>
-R: Darren Kenny <darren.kenny@oracle.com> 
+R: Darren Kenny <darren.kenny@oracle.com>
 R: Qiuhao Li <Qiuhao.Li@outlook.com>
 S: Maintained
 F: tests/qtest/fuzz/
@@ -3218,6 +3218,7 @@ S: Maintained
 F: hw/peci/peci-core.c
 F: hw/peci/peci-client.c
 F: include/hw/peci/peci.h
+F: hw/peci/npcm7xx_peci.c
 
 Firmware schema specifications
 M: Philippe Mathieu-Daudé <f4bug@amsat.org>
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 15fa79afd3..cb38c6c88f 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -408,6 +408,7 @@ config NPCM7XX
     select SSI
     select UNIMP
     select PCA954X
+    select PECI
 
 config FSL_IMX25
     bool
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
index d85cc02765..d408dd7eb4 100644
--- a/hw/arm/npcm7xx.c
+++ b/hw/arm/npcm7xx.c
@@ -45,6 +45,7 @@
 #define NPCM7XX_CLK_BA          (0xf0801000)
 #define NPCM7XX_MC_BA           (0xf0824000)
 #define NPCM7XX_RNG_BA          (0xf000b000)
+#define NPCM7XX_PECI_BA         (0xf0100000)
 
 /* USB Host modules */
 #define NPCM7XX_EHCI_BA         (0xf0806000)
@@ -83,6 +84,7 @@ enum NPCM7xxInterrupt {
     NPCM7XX_UART1_IRQ,
     NPCM7XX_UART2_IRQ,
     NPCM7XX_UART3_IRQ,
+    NPCM7XX_PECI_IRQ            = 6,
     NPCM7XX_EMC1RX_IRQ          = 15,
     NPCM7XX_EMC1TX_IRQ,
     NPCM7XX_MMC_IRQ             = 26,
@@ -445,6 +447,7 @@ static void npcm7xx_init(Object *obj)
     }
 
     object_initialize_child(obj, "mmc", &s->mmc, TYPE_NPCM7XX_SDHCI);
+    object_initialize_child(obj, "peci", &s->peci, TYPE_NPCM7XX_PECI);
 }
 
 static void npcm7xx_realize(DeviceState *dev, Error **errp)
@@ -715,6 +718,12 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
     sysbus_connect_irq(SYS_BUS_DEVICE(&s->mmc), 0,
             npcm7xx_irq(s, NPCM7XX_MMC_IRQ));
 
+     /* PECI */
+    sysbus_realize(SYS_BUS_DEVICE(&s->peci), &error_abort);
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->peci), 0, NPCM7XX_PECI_BA);
+    sysbus_connect_irq(SYS_BUS_DEVICE(&s->peci), 0,
+                       npcm7xx_irq(s, NPCM7XX_PECI_IRQ));
+
     create_unimplemented_device("npcm7xx.shm",          0xc0001000,   4 * KiB);
     create_unimplemented_device("npcm7xx.vdmx",         0xe0800000,   4 * KiB);
     create_unimplemented_device("npcm7xx.pcierc",       0xe1000000,  64 * KiB);
diff --git a/hw/peci/meson.build b/hw/peci/meson.build
index 01cfa95abe..ee033eb915 100644
--- a/hw/peci/meson.build
+++ b/hw/peci/meson.build
@@ -1 +1,2 @@
 softmmu_ss.add(when: 'CONFIG_PECI', if_true: files('peci-core.c', 
'peci-client.c'))
+softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_peci.c'))
diff --git a/hw/peci/npcm7xx_peci.c b/hw/peci/npcm7xx_peci.c
new file mode 100644
index 0000000000..17a2642898
--- /dev/null
+++ b/hw/peci/npcm7xx_peci.c
@@ -0,0 +1,204 @@
+/*
+ * Nuvoton NPCM7xx PECI Module
+ *
+ * Copyright 2021 Google LLC
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/peci/npcm7xx_peci.h"
+#include "qemu/bitops.h"
+#include "qemu/log.h"
+#include "qemu/units.h"
+#include "trace.h"
+
+#define PECI_CTL_STS            0
+#define     PECI_CTL_STS_DONE_EN      BIT(6)
+#define     PECI_CTL_STS_ABRT_ERR     BIT(4)
+#define     PECI_CTL_STS_CRC_ERR      BIT(3)
+#define     PECI_CTL_STS_DONE         BIT(1)
+#define     PECI_CTL_STS_START_BUSY   BIT(0)
+#define PECI_RD_LENGTH          0x4
+#define PECI_ADDR               0x8
+#define PECI_CMD                0xC
+#define PECI_CTL2               0x10
+#define PECI_WR_LENGTH          0x1C
+#define PECI_PDDR               0x2C
+#define PECI_DAT_INOUT(reg)    (0x100 + (reg) * 4)
+
+static uint64_t npcm7xx_peci_read(void *opaque, hwaddr offset, unsigned size)
+{
+    NPCM7xxPECIState *ps = NPCM7XX_PECI(opaque);
+    uint8_t ret = 0;
+
+    if (!ps->bus->num_clients) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: no peci clients added to board\n",
+                      __func__);
+        return 0;
+    }
+
+    qemu_irq_lower(ps->irq);
+
+    switch (offset) {
+    case PECI_CTL_STS:
+        ret = ps->status;
+        break;
+
+    case PECI_RD_LENGTH:
+        ret = ps->pcmd.rd_length;
+        break;
+
+    case PECI_ADDR:
+        ret = ps->pcmd.addr;
+        break;
+
+    case PECI_CMD:
+        ret = ps->pcmd.cmd;
+        break;
+
+    case PECI_CTL2:
+        ret = ps->ctl2;
+        break;
+
+    case PECI_WR_LENGTH:
+        ret = ps->pcmd.wr_length;
+        break;
+
+    case PECI_PDDR:
+        qemu_log_mask(LOG_UNIMP, "%s: PECI PDDR is unimplemented.\n", 
__func__);
+        ret = ps->pddr;  /* undoc register */
+        break;
+
+    case PECI_DAT_INOUT(0) ... PECI_DAT_INOUT(63):
+        ret = ps->pcmd.tx[(offset - PECI_DAT_INOUT(0)) / 4];
+        break;
+
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: unknown register 0x%lx\n",
+                      __func__, offset);
+        ret = 0xff;
+        break;
+    }
+    trace_npcm7xx_peci_read(offset, ret);
+    return ret;
+}
+
+static void npcm7xx_peci_write(void *opaque, hwaddr offset, uint64_t input,
+                               unsigned size)
+{
+    NPCM7xxPECIState *ps = NPCM7XX_PECI(opaque);
+    uint8_t data = input & 0xff;
+
+    trace_npcm7xx_peci_write(offset, input);
+
+    /* ignore writes if the bus has not been populated */
+    if (!ps->bus->num_clients) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: no peci clients added to board\n",
+                      __func__);
+        return;
+    }
+
+    switch (offset) {
+    case PECI_CTL_STS:
+        ps->status = data;
+        /* STS_START busy is set by the bmc when the request is written */
+        if (data & PECI_CTL_STS_START_BUSY) {
+            if (!peci_handle_cmd(ps->bus, &(ps->pcmd))) {
+                ps->status |= PECI_CTL_STS_ABRT_ERR;
+            }
+            ps->status |= PECI_CTL_STS_DONE;
+            ps->status &= ~PECI_CTL_STS_START_BUSY;
+            qemu_irq_raise(ps->irq);
+        }
+        break;
+
+    case PECI_RD_LENGTH:
+        ps->pcmd.rd_length = data;
+        break;
+
+    case PECI_ADDR:
+        ps->pcmd.addr = data;
+        break;
+
+    case PECI_CMD:
+        ps->pcmd.cmd = data;
+        break;
+
+    case PECI_CTL2:
+        ps->ctl2 = data;
+        break;
+
+    case PECI_WR_LENGTH:
+        ps->pcmd.wr_length = data;
+        break;
+
+    case PECI_PDDR:
+        ps->pddr = data;
+        break;
+
+    case PECI_DAT_INOUT(0) ... PECI_DAT_INOUT(63):
+        ps->pcmd.rx[(offset - PECI_DAT_INOUT(0)) / 4] = data;
+        break;
+
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: to unknown register 0x%lx : 0x%lx\n",
+                      __func__, offset, input);
+        return;
+    }
+
+}
+
+static void npcm7xx_peci_reset(Object *obj, ResetType type)
+{
+    NPCM7xxPECIState *ps = NPCM7XX_PECI(obj);
+
+    ps->status = PECI_CTL_STS_DONE_EN;
+}
+
+static const MemoryRegionOps npcm7xx_peci_ops = {
+    .read = npcm7xx_peci_read,
+    .write = npcm7xx_peci_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 1,
+        .min_access_size = 1,
+        .unaligned = false,
+    },
+};
+
+static void npcm7xx_peci_realize(DeviceState *dev, Error **errp)
+{
+    NPCM7xxPECIState *ps = NPCM7XX_PECI(dev);
+    SysBusDevice *sbd = &ps->parent;
+
+    memory_region_init_io(&ps->iomem, OBJECT(ps), &npcm7xx_peci_ops, ps,
+                          TYPE_NPCM7XX_PECI, 4 * KiB);
+
+    sysbus_init_mmio(sbd, &ps->iomem);
+    sysbus_init_irq(sbd, &ps->irq);
+
+    ps->bus = peci_bus_create(DEVICE(ps));
+}
+
+static void npcm7xx_peci_class_init(ObjectClass *klass, void *data)
+{
+    ResettableClass *rc = RESETTABLE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->desc = "NPCM7xx PECI Module";
+    dc->realize = npcm7xx_peci_realize;
+    rc->phases.enter = npcm7xx_peci_reset;
+}
+
+static const TypeInfo npcm7xx_peci_types[] = {
+    {
+        .name = TYPE_NPCM7XX_PECI,
+        .parent = TYPE_SYS_BUS_DEVICE,
+        .instance_size = sizeof(NPCM7xxPECIState),
+        .class_init = npcm7xx_peci_class_init,
+    },
+};
+
+DEFINE_TYPES(npcm7xx_peci_types)
diff --git a/hw/peci/trace-events b/hw/peci/trace-events
index f90c998dd9..a895b21f7b 100644
--- a/hw/peci/trace-events
+++ b/hw/peci/trace-events
@@ -3,3 +3,8 @@
 # peci-core.c
 peci_handle_cmd(const char* s, uint8_t addr) "%s @ 0x%02" PRIx8
 peci_rd_pkg_cfg(const char* s) "%s"
+
+# npcm7xx_peci.c
+npcm7xx_peci_cmd(uint64_t cmd) "cmd: 0x%04" PRIx64
+npcm7xx_peci_read(uint64_t offset, uint64_t value) "offset: 0x%04" PRIx64 " 
value: 0x%08" PRIx64
+npcm7xx_peci_write(uint64_t offset, uint64_t value) "offset: 0x%04" PRIx64 " 
value: 0x%08" PRIx64
diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h
index ce593235d9..9e7cf8b774 100644
--- a/include/hw/arm/npcm7xx.h
+++ b/include/hw/arm/npcm7xx.h
@@ -30,6 +30,7 @@
 #include "hw/misc/npcm7xx_rng.h"
 #include "hw/net/npcm7xx_emc.h"
 #include "hw/nvram/npcm7xx_otp.h"
+#include "hw/peci/npcm7xx_peci.h"
 #include "hw/timer/npcm7xx_timer.h"
 #include "hw/ssi/npcm7xx_fiu.h"
 #include "hw/usb/hcd-ehci.h"
@@ -105,6 +106,7 @@ typedef struct NPCM7xxState {
     NPCM7xxFIUState     fiu[2];
     NPCM7xxEMCState     emc[2];
     NPCM7xxSDHCIState   mmc;
+    NPCM7xxPECIState    peci;
 } NPCM7xxState;
 
 #define TYPE_NPCM7XX    "npcm7xx"
diff --git a/include/hw/peci/npcm7xx_peci.h b/include/hw/peci/npcm7xx_peci.h
new file mode 100644
index 0000000000..421f445041
--- /dev/null
+++ b/include/hw/peci/npcm7xx_peci.h
@@ -0,0 +1,37 @@
+/*
+ * Nuvoton NPCM7xx PECI Module
+ *
+ * Copyright 2021 Google LLC
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef NPCM7XX_PECI_H
+#define NPCM7XX_PECI_H
+
+#include "exec/memory.h"
+#include "hw/irq.h"
+#include "hw/peci/peci.h"
+#include "hw/sysbus.h"
+
+typedef struct NPCM7xxPECIState {
+    SysBusDevice parent;
+
+    MemoryRegion iomem;
+
+    PECIBus      *bus;
+    qemu_irq      irq;
+
+    PECICmd       pcmd;
+
+    /* Registers */
+    uint8_t       status;
+    uint8_t       ctl2;
+    uint8_t       pddr;
+} NPCM7xxPECIState;
+
+#define TYPE_NPCM7XX_PECI "npcm7xx-peci"
+#define NPCM7XX_PECI(obj)                                               \
+    OBJECT_CHECK(NPCM7xxPECIState, (obj), TYPE_NPCM7XX_PECI)
+
+#endif /* NPCM7XX_PECI_H */
-- 
2.37.2.789.g6183377224-goog




reply via email to

[Prev in Thread] Current Thread [Next in Thread]