[Skiboot] [PATCH 04/16] [PATCH 04/16] opencapi5: rainier detect device

Christophe Lombard clombard at linux.vnet.ibm.com
Fri Aug 20 19:45:45 AEST 2021


Update the platform_ocapi structure to store Rainier platform-specific
values for detecting and resetting OpenCAPI devices via the module
I2C (PCA9553)
The unique number I2C bus ID associated to each OpenCapi device
is get from the I2C port and engine.
(De)Assert a reset and detect an OpenCapi device is available through
the I2C bus id and address.

Signed-off-by: Christophe Lombard <clombard at linux.vnet.ibm.com>
---
 include/pau.h              |   3 +
 include/platform.h         |   5 +
 platforms/astbmc/rainier.c | 181 +++++++++++++++++++++++++++++++++++++
 3 files changed, 189 insertions(+)

diff --git a/include/pau.h b/include/pau.h
index 75e7b8d5..d91ffa6d 100644
--- a/include/pau.h
+++ b/include/pau.h
@@ -24,6 +24,9 @@ struct pau_dev {
 	uint32_t		index;
 	struct dt_node		*dn;
 
+	/* Associated I2C information */
+	uint8_t			i2c_bus_id;
+
 	/* Associated PHY information */
 	uint32_t		pau_unit; /* 0,3,4,5,6,7 */
 	uint32_t		odl_index;
diff --git a/include/platform.h b/include/platform.h
index d25e9ef4..26fb852a 100644
--- a/include/platform.h
+++ b/include/platform.h
@@ -70,6 +70,11 @@ struct platform_ocapi {
 	uint8_t i2c_presence_brick5;	/* I2C pin to read for presence on brick 5 */
 	bool odl_phy_swap;		/* Swap ODL1 to use brick 2 rather than
 					 * brick 1 lanes */
+	uint8_t i2c_dev_addr;		/* I2C device address */
+	uint8_t i2c_intreset_pin;	/* I2C pin to write to reset */
+	uint8_t i2c_predetect_pin;	/* I2C pin to read for presence */
+	int64_t (*i2c_assert_reset)(uint8_t i2c_bus_id);
+	int64_t (*i2c_deassert_reset)(uint8_t i2c_bus_id);
 	const char *(*ocapi_slot_label)(uint32_t chip_id, uint32_t brick_index);
 	const struct ocapi_phy_setup *phy_setup;
 };
diff --git a/platforms/astbmc/rainier.c b/platforms/astbmc/rainier.c
index 17d9fe2b..b9fd53b8 100644
--- a/platforms/astbmc/rainier.c
+++ b/platforms/astbmc/rainier.c
@@ -6,6 +6,7 @@
 #include <skiboot.h>
 #include <device.h>
 #include <ipmi.h>
+#include <pau.h>
 #include <chip.h>
 #include <i2c.h>
 #include <timebase.h>
@@ -99,8 +100,178 @@ static void rainier_init_slot_power(void)
 	}
 }
 
+static int64_t rainier_i2c_assert_reset(uint8_t i2c_bus_id)
+{
+	uint8_t data;
+	int64_t rc = OPAL_SUCCESS;
+
+	/*
+	 * Set the i2c reset pin in output mode (9553 device)
+	 * To write a register:
+	 *   puti2c pu 0 0|1 C4 <data> <offset> 1,
+	 *   with data being a 2-nibble hex value and offset being the
+	 *   register offset from the datasheet
+	 *
+	 * puti2c (-p1) 0 0|1 C4 51 5 1	     0		: i2c engine
+	 *				     0|1	: i2c_port
+	 *				     C4 (C4 > 1 = 62) : Address
+	 *				     51		: data
+	 *				     5		: register (offset)
+	 *				     1		: offset byte
+	 *
+	 * 7.3.6 LS0 - LED selector register: default value 0x55
+	 * bit 1:0 01* LED0 selected  (OpenCapi card)
+	 *
+	 * offset 0x05, register name: LS0, Fct: LED selector
+	 * see Table 4. Control register definition (PCA9553)
+	 */
+	data = 0x51;
+	rc = i2c_request_send(i2c_bus_id,
+			      platform.ocapi->i2c_dev_addr,
+			      SMBUS_WRITE, 0x5, 1,
+			      &data, sizeof(data), 120);
+
+	return rc;
+}
+
+static int64_t rainier_i2c_deassert_reset(uint8_t i2c_bus_id)
+{
+	uint8_t data;
+	int64_t rc = OPAL_SUCCESS;
+
+	/* puti2c (-p1) 0 0|1 C4 55 <offset> 1
+	 *
+	 * offset 0x05, register name: LS0, Fct: LED selector
+	 * see Table 4. Control register definition (PCA9553)
+	 */
+	data = 0x55;
+	rc = i2c_request_send(i2c_bus_id,
+			      platform.ocapi->i2c_dev_addr,
+			      SMBUS_WRITE, 0x5, 1,
+			      &data, sizeof(data), 120);
+
+	return rc;
+}
+
+static int get_i2c_info(struct pau_dev *dev, int *engine, int *port)
+{
+	uint32_t chip_id = dev->pau->chip_id;
+	uint32_t pau_index = dev->pau->index;
+	uint32_t link = dev->index;
+
+	switch (chip_id) {
+	case 0:
+	case 4:
+		/*
+		 * OP3: links 0 and 1 on chip 0
+		 *      link 0 only on chip 4
+		 */
+		if (pau_index == 1) {
+			if (link == 1 && chip_id == 4)
+				return -1;
+			*engine = 1;
+			*port = link;
+			return 0;
+		}
+		break;
+	case 2:
+	case 6:
+		/*
+		 * OP0: links 0 and 1 on chip 2
+		 *      link 1 only on chip 6
+		 */
+		if (pau_index == 0) {
+			if (link == 0 && chip_id == 6)
+				return -1;
+			*engine = 1;
+			*port = link;
+			return 0;
+		}
+		break;
+	}
+	return -1;
+}
+
+static void rainier_i2c_presence_init(struct pau_dev *dev)
+{
+	char port_name[17];
+	struct dt_node *np;
+	int engine, port;
+
+	/* Find I2C port */
+	if (dev->i2c_bus_id)
+		return;
+
+	if (get_i2c_info(dev, &engine, &port))
+		return;
+
+	snprintf(port_name, sizeof(port_name), "p8_%08x_e%dp%d",
+		 dev->pau->chip_id, engine, port);
+
+	dt_for_each_compatible(dt_root, np, "ibm,power10-i2c-port") {
+		if (streq(port_name, dt_prop_get(np, "ibm,port-name"))) {
+			dev->i2c_bus_id = dt_prop_get_u32(np, "ibm,opal-id");
+			break;
+		}
+	}
+}
+
+static int64_t rainier_i2c_dev_detect(struct pau_dev *dev,
+				      uint8_t *detect)
+{
+	int64_t rc = OPAL_SUCCESS;
+
+	/* Read the presence value
+	 * geti2c (-p1) pu 0 0|1 C4 1 <offset> 1
+	 *
+	 * offset 0x00, register name: INPUT, Fct: input register
+	 * see Table 4. Control register definition (PCA9553)
+	 */
+	*detect = 0x00;
+	rc = i2c_request_send(dev->i2c_bus_id,
+			      platform.ocapi->i2c_dev_addr,
+			      SMBUS_READ, 0x00, 1,
+			      detect, 1, 120);
+
+	return rc;
+}
+
+static void rainier_pau_device_detect(struct pau *pau)
+{
+	struct pau_dev *dev;
+	uint8_t detect;
+	int64_t rc;
+
+	/* OpenCapi devices are possibly connected on Optical link pair:
+	 * OP0 or OP3
+	 * pau_index	Interface Link - OPxA/B
+	 * 0		OPT0 -- PAU0
+	 *		OPT1 -- no PAU, SMP only
+	 *		OPT2 -- no PAU, SMP only
+	 * 1		OPT3 -- PAU3
+	 * 2		OPT4 -- PAU4 by default, but can be muxed to use PAU5 - N/A on Rainier
+	 * 3		OPT5 -- PAU5 by default, but can be muxed to use PAU4 - N/A on Rainier
+	 * 4		OPT6 -- PAU6 by default, but can be muxed to use PAU7 - N/A on Rainier
+	 * 5		OPT7 -- PAU7 by default, but can be muxed to use PAU6 - N/A on Rainier
+	 */
+	pau_for_each_dev(dev, pau) {
+		dev->type = PAU_DEV_TYPE_UNKNOWN;
+
+		rainier_i2c_presence_init(dev);
+		if (dev->i2c_bus_id) {
+			rc = rainier_i2c_dev_detect(dev, &detect);
+			/* LED0 (bit 0): a high level no card is plugged */
+			if (!rc && !(detect & platform.ocapi->i2c_predetect_pin))
+				dev->type = PAU_DEV_TYPE_OPENCAPI;
+		}
+
+		dt_add_property_u64(dev->dn, "ibm,link-speed", 25000000000ull);
+	}
+}
+
 static void rainier_init(void)
 {
+
 	astbmc_init();
 	rainier_init_slot_power();
 }
@@ -121,6 +292,14 @@ static bool rainier_probe(void)
 	return true;
 }
 
+static struct platform_ocapi rainier_ocapi = {
+	.i2c_dev_addr		= 0x62, /* C4 >> 1 */
+	.i2c_intreset_pin	= 0x02, /* PIN 2 - LED1 - INT/RESET */
+	.i2c_predetect_pin	= 0x01, /* PIN 1 - LED0 - PRE-DETECT */
+	.i2c_assert_reset	= rainier_i2c_assert_reset,
+	.i2c_deassert_reset	= rainier_i2c_deassert_reset,
+};
+
 DECLARE_PLATFORM(rainier) = {
 	.name			= "Rainier",
 	.probe			= rainier_probe,
@@ -131,6 +310,8 @@ DECLARE_PLATFORM(rainier) = {
 	.cec_power_down         = astbmc_ipmi_power_down,
 	.cec_reboot             = astbmc_ipmi_reboot,
 	.elog_commit		= ipmi_elog_commit,
+	.pau_device_detect	= rainier_pau_device_detect,
+	.ocapi			= &rainier_ocapi,
 	.exit			= astbmc_exit,
 	.terminate		= ipmi_terminate,
 };
-- 
2.31.1



More information about the Skiboot mailing list