All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Cédric Le Goater" <clg@kaod.org>
To: David Gibson <david@gibson.dropbear.id.au>
Cc: qemu-ppc@nongnu.org, qemu-devel@nongnu.org,
	"Cédric Le Goater" <clg@kaod.org>
Subject: [Qemu-devel] [PATCH v2 06/15] ppc/pnv: add a LPC Controller model for POWER9
Date: Thu,  7 Mar 2019 23:35:39 +0100	[thread overview]
Message-ID: <20190307223548.20516-7-clg@kaod.org> (raw)
In-Reply-To: <20190307223548.20516-1-clg@kaod.org>

The LPC Controller on POWER9 is very similar to the one found on
POWER8 but accesses are now done via on MMIOs, without the XSCOM and
ECCB logic. The device tree is populated differently so we add a
specific POWER9 routine for the purpose.

SerIRQ routing is yet to be done.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---

 Changes in v2:

 - defined a 'dt_isa_nodename' for the POWER9 chip

 include/hw/ppc/pnv.h     |   4 +
 include/hw/ppc/pnv_lpc.h |   9 ++
 hw/ppc/pnv.c             |  22 ++++-
 hw/ppc/pnv_lpc.c         | 200 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 234 insertions(+), 1 deletion(-)

diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
index c81f157f41a9..1cd1ad622d0b 100644
--- a/include/hw/ppc/pnv.h
+++ b/include/hw/ppc/pnv.h
@@ -87,6 +87,7 @@ typedef struct Pnv9Chip {
     /*< public >*/
     PnvXive      xive;
     Pnv9Psi      psi;
+    PnvLpcController lpc;
 } Pnv9Chip;
 
 typedef struct PnvChipClass {
@@ -234,6 +235,9 @@ void pnv_bmc_powerdown(IPMIBmc *bmc);
 #define PNV9_XIVE_PC_SIZE            0x0000001000000000ull
 #define PNV9_XIVE_PC_BASE(chip)      PNV9_CHIP_BASE(chip, 0x0006018000000000ull)
 
+#define PNV9_LPCM_SIZE               0x0000000100000000ull
+#define PNV9_LPCM_BASE(chip)         PNV9_CHIP_BASE(chip, 0x0006030000000000ull)
+
 #define PNV9_PSIHB_SIZE              0x0000000000100000ull
 #define PNV9_PSIHB_BASE(chip)        PNV9_CHIP_BASE(chip, 0x0006030203000000ull)
 
diff --git a/include/hw/ppc/pnv_lpc.h b/include/hw/ppc/pnv_lpc.h
index f3f24419b19a..242b18081caa 100644
--- a/include/hw/ppc/pnv_lpc.h
+++ b/include/hw/ppc/pnv_lpc.h
@@ -27,6 +27,9 @@
 #define TYPE_PNV8_LPC TYPE_PNV_LPC "-POWER8"
 #define PNV8_LPC(obj) OBJECT_CHECK(PnvLpcController, (obj), TYPE_PNV8_LPC)
 
+#define TYPE_PNV9_LPC TYPE_PNV_LPC "-POWER9"
+#define PNV9_LPC(obj) OBJECT_CHECK(PnvLpcController, (obj), TYPE_PNV9_LPC)
+
 typedef struct PnvLpcController {
     DeviceState parent;
 
@@ -85,6 +88,12 @@ typedef struct PnvLpcClass {
     DeviceRealize parent_realize;
 } PnvLpcClass;
 
+/*
+ * Old compilers error on typdef forward declarations. Keep them happy.
+ */
+struct PnvChip;
+
 ISABus *pnv_lpc_isa_create(PnvLpcController *lpc, bool use_cpld, Error **errp);
+int pnv_dt_lpc(struct PnvChip *chip, void *fdt, int root_offset);
 
 #endif /* _PPC_PNV_LPC_H */
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 6625562d276d..918fae057b5c 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -306,6 +306,8 @@ static void pnv_chip_power9_dt_populate(PnvChip *chip, void *fdt)
     if (chip->ram_size) {
         pnv_dt_memory(fdt, chip->chip_id, chip->ram_start, chip->ram_size);
     }
+
+    pnv_dt_lpc(chip, fdt, 0);
 }
 
 static void pnv_dt_rtc(ISADevice *d, void *fdt, int lpc_off)
@@ -547,7 +549,8 @@ static ISABus *pnv_chip_power8nvl_isa_create(PnvChip *chip, Error **errp)
 
 static ISABus *pnv_chip_power9_isa_create(PnvChip *chip, Error **errp)
 {
-    return NULL;
+    Pnv9Chip *chip9 = PNV9_CHIP(chip);
+    return pnv_lpc_isa_create(&chip9->lpc, false, errp);
 }
 
 static ISABus *pnv_isa_create(PnvChip *chip, Error **errp)
@@ -948,6 +951,11 @@ static void pnv_chip_power9_instance_init(Object *obj)
                             TYPE_PNV9_PSI, &error_abort, NULL);
     object_property_add_const_link(OBJECT(&chip9->psi), "chip", obj,
                                    &error_abort);
+
+    object_initialize_child(obj, "lpc",  &chip9->lpc, sizeof(chip9->lpc),
+                            TYPE_PNV9_LPC, &error_abort, NULL);
+    object_property_add_const_link(OBJECT(&chip9->lpc), "psi",
+                                   OBJECT(&chip9->psi), &error_abort);
 }
 
 static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
@@ -992,6 +1000,18 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
     }
     pnv_xscom_add_subregion(chip, PNV9_XSCOM_PSIHB_BASE,
                             &PNV_PSI(psi9)->xscom_regs);
+
+    /* LPC */
+    object_property_set_bool(OBJECT(&chip9->lpc), true, "realized", &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
+    memory_region_add_subregion(get_system_memory(), PNV9_LPCM_BASE(chip),
+                                &chip9->lpc.xscom_regs);
+
+    chip->dt_isa_nodename = g_strdup_printf("/lpcm-opb@%" PRIx64 "/lpc@0",
+                                            (uint64_t) PNV9_LPCM_BASE(chip));
 }
 
 static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
diff --git a/hw/ppc/pnv_lpc.c b/hw/ppc/pnv_lpc.c
index 3c509a30a0af..6df694e0abc1 100644
--- a/hw/ppc/pnv_lpc.c
+++ b/hw/ppc/pnv_lpc.c
@@ -118,6 +118,100 @@ static int pnv_lpc_dt_xscom(PnvXScomInterface *dev, void *fdt, int xscom_offset)
     return 0;
 }
 
+/* POWER9 only */
+int pnv_dt_lpc(PnvChip *chip, void *fdt, int root_offset)
+{
+    const char compat[] = "ibm,power9-lpcm-opb\0simple-bus";
+    const char lpc_compat[] = "ibm,power9-lpc\0ibm,lpc";
+    char *name;
+    int offset, lpcm_offset;
+    uint64_t lpcm_addr = PNV9_LPCM_BASE(chip);
+    uint32_t opb_ranges[8] = { 0,
+                               cpu_to_be32(lpcm_addr >> 32),
+                               cpu_to_be32((uint32_t)lpcm_addr),
+                               cpu_to_be32(PNV9_LPCM_SIZE / 2),
+                               cpu_to_be32(PNV9_LPCM_SIZE / 2),
+                               cpu_to_be32(lpcm_addr >> 32),
+                               cpu_to_be32(PNV9_LPCM_SIZE / 2),
+                               cpu_to_be32(PNV9_LPCM_SIZE / 2),
+    };
+    uint32_t opb_reg[4] = { cpu_to_be32(lpcm_addr >> 32),
+                            cpu_to_be32((uint32_t)lpcm_addr),
+                            cpu_to_be32(PNV9_LPCM_SIZE >> 32),
+                            cpu_to_be32((uint32_t)PNV9_LPCM_SIZE),
+    };
+    uint32_t reg[2];
+
+    /*
+     * OPB bus
+     */
+    name = g_strdup_printf("lpcm-opb@%"PRIx64, lpcm_addr);
+    lpcm_offset = fdt_add_subnode(fdt, root_offset, name);
+    _FDT(lpcm_offset);
+    g_free(name);
+
+    _FDT((fdt_setprop(fdt, lpcm_offset, "reg", opb_reg, sizeof(opb_reg))));
+    _FDT((fdt_setprop_cell(fdt, lpcm_offset, "#address-cells", 1)));
+    _FDT((fdt_setprop_cell(fdt, lpcm_offset, "#size-cells", 1)));
+    _FDT((fdt_setprop(fdt, lpcm_offset, "compatible", compat, sizeof(compat))));
+    _FDT((fdt_setprop_cell(fdt, lpcm_offset, "ibm,chip-id", chip->chip_id)));
+    _FDT((fdt_setprop(fdt, lpcm_offset, "ranges", opb_ranges,
+                      sizeof(opb_ranges))));
+
+    /*
+     * OPB Master registers
+     */
+    name = g_strdup_printf("opb-master@%x", LPC_OPB_REGS_OPB_ADDR);
+    offset = fdt_add_subnode(fdt, lpcm_offset, name);
+    _FDT(offset);
+    g_free(name);
+
+    reg[0] = cpu_to_be32(LPC_OPB_REGS_OPB_ADDR);
+    reg[1] = cpu_to_be32(LPC_OPB_REGS_OPB_SIZE);
+    _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg))));
+    _FDT((fdt_setprop_string(fdt, offset, "compatible",
+                             "ibm,power9-lpcm-opb-master")));
+
+    /*
+     * OPB arbitrer registers
+     */
+    name = g_strdup_printf("opb-arbitrer@%x", LPC_OPB_REGS_OPBA_ADDR);
+    offset = fdt_add_subnode(fdt, lpcm_offset, name);
+    _FDT(offset);
+    g_free(name);
+
+    reg[0] = cpu_to_be32(LPC_OPB_REGS_OPBA_ADDR);
+    reg[1] = cpu_to_be32(LPC_OPB_REGS_OPBA_SIZE);
+    _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg))));
+    _FDT((fdt_setprop_string(fdt, offset, "compatible",
+                             "ibm,power9-lpcm-opb-arbiter")));
+
+    /*
+     * LPC Host Controller registers
+     */
+    name = g_strdup_printf("lpc-controller@%x", LPC_HC_REGS_OPB_ADDR);
+    offset = fdt_add_subnode(fdt, lpcm_offset, name);
+    _FDT(offset);
+    g_free(name);
+
+    reg[0] = cpu_to_be32(LPC_HC_REGS_OPB_ADDR);
+    reg[1] = cpu_to_be32(LPC_HC_REGS_OPB_SIZE);
+    _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg))));
+    _FDT((fdt_setprop_string(fdt, offset, "compatible",
+                             "ibm,power9-lpc-controller")));
+
+    name = g_strdup_printf("lpc@0");
+    offset = fdt_add_subnode(fdt, lpcm_offset, name);
+    _FDT(offset);
+    g_free(name);
+    _FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 2)));
+    _FDT((fdt_setprop_cell(fdt, offset, "#size-cells", 1)));
+    _FDT((fdt_setprop(fdt, offset, "compatible", lpc_compat,
+                      sizeof(lpc_compat))));
+
+    return 0;
+}
+
 /*
  * These read/write handlers of the OPB address space should be common
  * with the P9 LPC Controller which uses direct MMIOs.
@@ -242,6 +336,74 @@ static const MemoryRegionOps pnv_lpc_xscom_ops = {
     .endianness = DEVICE_BIG_ENDIAN,
 };
 
+static uint64_t pnv_lpc_mmio_read(void *opaque, hwaddr addr, unsigned size)
+{
+    PnvLpcController *lpc = PNV_LPC(opaque);
+    uint64_t val = 0;
+    uint32_t opb_addr = addr & ECCB_CTL_ADDR_MASK;
+    MemTxResult result;
+
+    switch (size) {
+    case 4:
+        val = address_space_ldl(&lpc->opb_as, opb_addr, MEMTXATTRS_UNSPECIFIED,
+                                &result);
+        break;
+    case 1:
+        val = address_space_ldub(&lpc->opb_as, opb_addr, MEMTXATTRS_UNSPECIFIED,
+                                 &result);
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "OPB read failed at @0x%"
+                      HWADDR_PRIx " invalid size %d\n", addr, size);
+        return 0;
+    }
+
+    if (result != MEMTX_OK) {
+        qemu_log_mask(LOG_GUEST_ERROR, "OPB read failed at @0x%"
+                      HWADDR_PRIx "\n", addr);
+    }
+
+    return val;
+}
+
+static void pnv_lpc_mmio_write(void *opaque, hwaddr addr,
+                                uint64_t val, unsigned size)
+{
+    PnvLpcController *lpc = PNV_LPC(opaque);
+    uint32_t opb_addr = addr & ECCB_CTL_ADDR_MASK;
+    MemTxResult result;
+
+    switch (size) {
+    case 4:
+        address_space_stl(&lpc->opb_as, opb_addr, val, MEMTXATTRS_UNSPECIFIED,
+                          &result);
+         break;
+    case 1:
+        address_space_stb(&lpc->opb_as, opb_addr, val, MEMTXATTRS_UNSPECIFIED,
+                          &result);
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "OPB write failed at @0x%"
+                      HWADDR_PRIx " invalid size %d\n", addr, size);
+        return;
+    }
+
+    if (result != MEMTX_OK) {
+        qemu_log_mask(LOG_GUEST_ERROR, "OPB write failed at @0x%"
+                      HWADDR_PRIx "\n", addr);
+    }
+}
+
+static const MemoryRegionOps pnv_lpc_mmio_ops = {
+    .read = pnv_lpc_mmio_read,
+    .write = pnv_lpc_mmio_write,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_BIG_ENDIAN,
+};
+
 static void pnv_lpc_eval_irqs(PnvLpcController *lpc)
 {
     bool lpc_to_opb_irq = false;
@@ -465,6 +627,43 @@ static const TypeInfo pnv_lpc_power8_info = {
     }
 };
 
+static void pnv_lpc_power9_realize(DeviceState *dev, Error **errp)
+{
+    PnvLpcController *lpc = PNV_LPC(dev);
+    PnvLpcClass *plc = PNV_LPC_GET_CLASS(dev);
+    Error *local_err = NULL;
+
+    plc->parent_realize(dev, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
+
+    /* P9 uses a MMIO region */
+    memory_region_init_io(&lpc->xscom_regs, OBJECT(lpc), &pnv_lpc_mmio_ops,
+                          lpc, "lpcm", PNV9_LPCM_SIZE);
+}
+
+static void pnv_lpc_power9_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PnvLpcClass *plc = PNV_LPC_CLASS(klass);
+
+    dc->desc = "PowerNV LPC Controller POWER9";
+
+    plc->psi_irq = PSIHB9_IRQ_LPCHC;
+
+    device_class_set_parent_realize(dc, pnv_lpc_power9_realize,
+                                    &plc->parent_realize);
+}
+
+static const TypeInfo pnv_lpc_power9_info = {
+    .name          = TYPE_PNV9_LPC,
+    .parent        = TYPE_PNV_LPC,
+    .instance_size = sizeof(PnvLpcController),
+    .class_init    = pnv_lpc_power9_class_init,
+};
+
 static void pnv_lpc_realize(DeviceState *dev, Error **errp)
 {
     PnvLpcController *lpc = PNV_LPC(dev);
@@ -540,6 +739,7 @@ static void pnv_lpc_register_types(void)
 {
     type_register_static(&pnv_lpc_info);
     type_register_static(&pnv_lpc_power8_info);
+    type_register_static(&pnv_lpc_power9_info);
 }
 
 type_init(pnv_lpc_register_types)
-- 
2.20.1

  parent reply	other threads:[~2019-03-07 22:36 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-03-07 22:35 [Qemu-devel] [PATCH v2 00/15] ppc: add POWER9 support to the PowerNV platform Cédric Le Goater
2019-03-07 22:35 ` [Qemu-devel] [PATCH v2 01/15] ppc/pnv: add a PSI bridge class model Cédric Le Goater
2019-03-07 23:57   ` David Gibson
2019-03-07 22:35 ` [Qemu-devel] [PATCH v2 02/15] ppc/pnv: add a PSI bridge model for POWER9 Cédric Le Goater
2019-03-07 23:58   ` David Gibson
2019-03-07 22:35 ` [Qemu-devel] [PATCH v2 03/15] ppc/pnv: lpc: fix OPB address ranges Cédric Le Goater
2019-03-07 23:59   ` David Gibson
2019-03-07 22:35 ` [Qemu-devel] [PATCH v2 04/15] ppc/pnv: add a LPC Controller class model Cédric Le Goater
2019-03-07 23:59   ` David Gibson
2019-03-07 22:35 ` [Qemu-devel] [PATCH v2 05/15] ppc/pnv: add a 'dt_isa_nodename' to the chip Cédric Le Goater
2019-03-08  0:01   ` David Gibson
2019-03-08  6:55     ` Cédric Le Goater
2019-03-08 11:08       ` David Gibson
2019-03-07 22:35 ` Cédric Le Goater [this message]
2019-03-08  0:28   ` [Qemu-devel] [PATCH v2 06/15] ppc/pnv: add a LPC Controller model for POWER9 David Gibson
2019-03-07 22:35 ` [Qemu-devel] [PATCH v2 07/15] ppc/pnv: add SerIRQ routing registers Cédric Le Goater
2019-03-08  0:28   ` David Gibson
2019-03-07 22:35 ` [Qemu-devel] [PATCH v2 08/15] ppc/pnv: add a OCC model class Cédric Le Goater
2019-03-08  0:29   ` David Gibson
2019-03-07 22:35 ` [Qemu-devel] [PATCH v2 09/15] ppc/pnv: add a OCC model for POWER9 Cédric Le Goater
2019-03-08  0:30   ` David Gibson
2019-03-07 22:35 ` [Qemu-devel] [PATCH v2 10/15] ppc/pnv: extend XSCOM core support " Cédric Le Goater
2019-03-08  0:31   ` David Gibson
2019-03-07 22:35 ` [Qemu-devel] [PATCH v2 11/15] ppc/pnv: POWER9 XSCOM quad support Cédric Le Goater
2019-03-08  0:32   ` David Gibson
2019-03-07 22:35 ` [Qemu-devel] [PATCH v2 12/15] ppc/pnv: activate XSCOM tests for POWER9 Cédric Le Goater
2019-03-08  0:33   ` David Gibson
2019-03-07 22:35 ` [Qemu-devel] [PATCH v2 13/15] ppc/pnv: add more dummy XSCOM addresses Cédric Le Goater
2019-03-08  0:56   ` David Gibson
2019-03-07 22:35 ` [Qemu-devel] [PATCH v2 14/15] ppc/pnv: add a "ibm, opal/power-mgt" device tree node on POWER9 Cédric Le Goater
2019-03-08  0:58   ` David Gibson
2019-03-07 22:35 ` [Qemu-devel] [PATCH v2 15/15] target/ppc: add HV support for POWER9 Cédric Le Goater
2019-03-08  0:59   ` David Gibson

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to=20190307223548.20516-7-clg@kaod.org \
    --to=clg@kaod.org \
    --cc=david@gibson.dropbear.id.au \
    --cc=qemu-devel@nongnu.org \
    --cc=qemu-ppc@nongnu.org \
    /path/to/YOUR_REPLY

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

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