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
---
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_SIZE0x0010ull
#define PNV9_XIVE_PC_BASE(chip) PNV9_CHIP_BASE(chip,
0x00060180ull)
+#define PNV9_LPCM_SIZE 0x0001ull
+#define PNV9_LPCM_BASE(chip) PNV9_CHIP_BASE(chip,
0x00060300ull)
+
#define PNV9_PSIHB_SIZE 0x0010ull
#define PNV9_PSIHB_BASE(chip)PNV9_CHIP_BASE(chip,
0x000603020300ull)
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(>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, _abort, NULL);
object_property_add_const_link(OBJECT(>psi), "chip", obj,
_abort);
+
+object_initialize_child(obj, "lpc", >lpc, sizeof(chip9->lpc),
+TYPE_PNV9_LPC, _abort, NULL);
+object_property_add_const_link(OBJECT(>lpc), "psi",
+ OBJECT(>psi), _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,
_PSI(psi9)->xscom_regs);
+
+/* LPC */
+object_property_set_bool(OBJECT(>lpc), true, "realized",
_err);
+if (local_err) {
+error_propagate(errp, local_err);
+return;
+}
+memory_region_add_subregion(get_system_memory(), PNV9_LPCM_BASE(chip),
+>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,
+