[Skiboot] [PATCH 07/28] lpc: Add basic P9 LPC read/write ops

Benjamin Herrenschmidt benh at kernel.crashing.org
Thu Jul 7 11:49:58 AEST 2016


We still need to review interrupts handling etc...

Also update the example device-tree for SIMICS

Signed-off-by: Benjamin Herrenschmidt <benh at kernel.crashing.org>
---
 hw/lpc.c       | 132 ++++++++++++++++++++++++++++++++++++++++++++++-----------
 include/chip.h |   1 +
 2 files changed, 108 insertions(+), 25 deletions(-)

diff --git a/hw/lpc.c b/hw/lpc.c
index 1e81eeb..5f37ba6 100644
--- a/hw/lpc.c
+++ b/hw/lpc.c
@@ -129,6 +129,24 @@ static uint32_t lpc_fw_opb_base 	= 0xf0000000;
 static uint32_t lpc_reg_opb_base 	= 0xc0012000;
 static uint32_t opb_master_reg_base 	= 0xc0010000;
 
+static int64_t opb_mmio_write(struct proc_chip *chip, uint32_t addr, uint32_t data,
+			      uint32_t sz)
+{
+	switch (sz) {
+	case 1:
+		out_8(chip->lpc_mbase + addr, data);
+		return OPAL_SUCCESS;
+	case 2:
+		out_be16(chip->lpc_mbase + addr, data);
+		return OPAL_SUCCESS;
+	case 4:
+		out_be32(chip->lpc_mbase + addr, data);
+		return OPAL_SUCCESS;
+	}
+	prerror("LPC: Invalid data size %d\n", sz);
+	return OPAL_PARAMETER;
+}
+
 static int64_t opb_write(struct proc_chip *chip, uint32_t addr, uint32_t data,
 			 uint32_t sz)
 {
@@ -136,6 +154,9 @@ static int64_t opb_write(struct proc_chip *chip, uint32_t addr, uint32_t data,
 	int64_t rc, tout;
 	uint64_t data_reg;
 
+	if (chip->lpc_mbase)
+		return opb_mmio_write(chip, addr, data, sz);
+
 	switch(sz) {
 	case 1:
 		data_reg = ((uint64_t)data) << 56;
@@ -190,12 +211,33 @@ static int64_t opb_write(struct proc_chip *chip, uint32_t addr, uint32_t data,
 	return OPAL_HARDWARE;
 }
 
+static int64_t opb_mmio_read(struct proc_chip *chip, uint32_t addr, uint32_t *data,
+			     uint32_t sz)
+{
+	switch (sz) {
+	case 1:
+		*data = in_8(chip->lpc_mbase + addr);
+		return OPAL_SUCCESS;
+	case 2:
+		*data = in_be16(chip->lpc_mbase + addr);
+		return OPAL_SUCCESS;
+	case 4:
+		*data = in_be32(chip->lpc_mbase + addr);
+		return OPAL_SUCCESS;
+	}
+	prerror("LPC: Invalid data size %d\n", sz);
+	return OPAL_PARAMETER;
+}
+
 static int64_t opb_read(struct proc_chip *chip, uint32_t addr, uint32_t *data,
 		        uint32_t sz)
 {
 	uint64_t ctl = ECCB_CTL_MAGIC | ECCB_CTL_READ, stat;
 	int64_t rc, tout;
 
+	if (chip->lpc_mbase)
+		return opb_mmio_read(chip, addr, data, sz);
+
 	if (sz != 1 && sz != 2 && sz != 4) {
 		prerror("Invalid data size %d\n", sz);
 		return OPAL_PARAMETER;
@@ -378,7 +420,7 @@ static int64_t __lpc_write(uint32_t chip_id, enum OpalLPCAddressType addr_type,
 	uint32_t opb_base;
 	int64_t rc;
 
-	if (!chip || !chip->lpc_xbase)
+	if (!chip || (!chip->lpc_xbase && !chip->lpc_mbase))
 		return OPAL_PARAMETER;
 
 	lock(&chip->lpc_lock);
@@ -437,7 +479,7 @@ static int64_t __lpc_read(uint32_t chip_id, enum OpalLPCAddressType addr_type,
 	uint32_t opb_base;
 	int64_t rc;
 
-	if (!chip || !chip->lpc_xbase)
+	if (!chip || (!chip->lpc_xbase && !chip->lpc_mbase))
 		return OPAL_PARAMETER;
 
 	lock(&chip->lpc_lock);
@@ -697,7 +739,7 @@ void lpc_interrupt(uint32_t chip_id)
 	int rc;
 
 	/* No initialized LPC controller on that chip */
-	if (!chip->lpc_xbase)
+	if (!chip || (!chip->lpc_xbase && !chip->lpc_mbase))
 		return;
 
 	lock(&chip->lpc_lock);
@@ -752,35 +794,75 @@ void lpc_all_interrupts(uint32_t chip_id)
 	unlock(&chip->lpc_lock);
 }
 
-void lpc_init(void)
+static void lpc_init_chip_p8(struct dt_node *xn)
+ {
+	uint32_t gcid = dt_get_chip_id(xn);
+	struct proc_chip *chip;
+
+	chip = get_chip(gcid);
+	assert(chip);
+
+	chip->lpc_xbase = dt_get_address(xn, 0, NULL);
+	chip->lpc_fw_idsel = 0xff;
+	chip->lpc_fw_rdsz = 0xff;
+	init_lock(&chip->lpc_lock);
+
+	if (lpc_default_chip_id < 0 ||
+	    dt_has_node_property(xn, "primary", NULL)) {
+		lpc_default_chip_id = chip->id;
+	}
+
+	prlog(PR_NOTICE, "Bus on chip %d, access via XSCOM, PCB_Addr=0x%x\n",
+	      chip->id, chip->lpc_xbase);
+
+	lpc_init_interrupts(chip);
+	if (chip->type == PROC_CHIP_P8_NAPLES)
+		dt_add_property(xn, "interrupt-controller", NULL, 0);
+}
+
+static void lpc_init_chip_p9(struct dt_node *opb_node)
 {
-	struct dt_node *xn;
-	bool has_lpc = false;
+	uint32_t gcid = dt_get_chip_id(opb_node);
+	struct proc_chip *chip;
+	u64 addr;
 
-	dt_for_each_compatible(dt_root, xn, "ibm,power8-lpc") {
-		uint32_t gcid = dt_get_chip_id(xn);
-		struct proc_chip *chip;
+	chip = get_chip(gcid);
+	assert(chip);
 
-		chip = get_chip(gcid);
-		assert(chip);
+	/* Grab OPB base address */
+	addr = dt_prop_get_cell(opb_node, "ranges", 1);
+	addr <<= 32;
+	addr |= dt_prop_get_cell(opb_node, "ranges", 2);
 
-		chip->lpc_xbase = dt_get_address(xn, 0, NULL);
-		chip->lpc_fw_idsel = 0xff;
-		chip->lpc_fw_rdsz = 0xff;
-		init_lock(&chip->lpc_lock);
+	chip->lpc_mbase = (void *)addr;
+	chip->lpc_fw_idsel = 0xff;
+	chip->lpc_fw_rdsz = 0xff;
+	init_lock(&chip->lpc_lock);
 
-		if (lpc_default_chip_id < 0 ||
-		    dt_has_node_property(xn, "primary", NULL)) {
-			lpc_default_chip_id = chip->id;
-		}
+	if (lpc_default_chip_id < 0 ||
+	    dt_has_node_property(opb_node, "primary", NULL)) {
+		lpc_default_chip_id = chip->id;
+	}
 
-		prlog(PR_NOTICE, "Bus on chip %d PCB_Addr=0x%x\n",
-					chip->id, chip->lpc_xbase);
-		has_lpc = true;
+	prlog(PR_NOTICE, "Bus on chip %d, access via MMIO @%p\n",
+	       chip->id, chip->lpc_mbase);
+
+	// XXX TODO
+	//lpc_init_interrupts(chip);
+}
 
-		lpc_init_interrupts(chip);
-		if (chip->type == PROC_CHIP_P8_NAPLES)
-			dt_add_property(xn, "interrupt-controller", NULL, 0);
+void lpc_init(void)
+{
+	struct dt_node *xn;
+	bool has_lpc = false;
+
+	dt_for_each_compatible(dt_root, xn, "ibm,power8-lpc") {
+		lpc_init_chip_p8(xn);
+		has_lpc = true;
+	}
+	dt_for_each_compatible(dt_root, xn, "ibm,power9-lpcm-opb") {
+		lpc_init_chip_p9(xn);
+		has_lpc = true;
 	}
 	if (lpc_default_chip_id >= 0)
 		prlog(PR_NOTICE, "Default bus on chip %d\n",
diff --git a/include/chip.h b/include/chip.h
index 1f31a13..f62c964 100644
--- a/include/chip.h
+++ b/include/chip.h
@@ -170,6 +170,7 @@ struct proc_chip {
 
 	/* Used by hw/lpc.c */
 	uint32_t		lpc_xbase;
+	void			*lpc_mbase;
 	struct lock		lpc_lock;
 	uint8_t			lpc_fw_idsel;
 	uint8_t			lpc_fw_rdsz;
-- 
2.7.4



More information about the Skiboot mailing list