aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristophe Lombard <clombard@linux.vnet.ibm.com>2021-10-14 17:56:52 +0200
committerVasant Hegde <hegdevasant@linux.vnet.ibm.com>2021-10-19 12:26:01 +0530
commitfaea2419754c0a455b6cf32a5fa58c72fa75083b (patch)
tree38b93fdbabb1799da7b369bb454a86e16af5b46e
parent768f67e686e5691a6d6d956f625ce455d3b48fb5 (diff)
downloadskiboot-faea2419754c0a455b6cf32a5fa58c72fa75083b.zip
skiboot-faea2419754c0a455b6cf32a5fa58c72fa75083b.tar.gz
skiboot-faea2419754c0a455b6cf32a5fa58c72fa75083b.tar.bz2
rainier: detect pau devices
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@linux.vnet.ibm.com> Signed-off-by: Vasant Hegde <hegdevasant@linux.vnet.ibm.com>
-rw-r--r--include/pau.h3
-rw-r--r--include/platform.h5
-rw-r--r--platforms/astbmc/rainier.c239
3 files changed, 247 insertions, 0 deletions
diff --git a/include/pau.h b/include/pau.h
index 2a26a65..e946e0f 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 6fafddb..db0c086 100644
--- a/include/platform.h
+++ b/include/platform.h
@@ -69,6 +69,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 17d9fe2..3e21e1b 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,6 +100,227 @@ 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,
+ bool *presence)
+{
+ int64_t rc = OPAL_SUCCESS;
+ uint8_t detect;
+
+ /* 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;
+ *presence = false;
+ rc = i2c_request_send(dev->i2c_bus_id,
+ platform.ocapi->i2c_dev_addr,
+ SMBUS_READ, 0x00, 1,
+ &detect, 1, 120);
+
+ /* LED0 (bit 0): a high level no card is plugged */
+ if (!rc && !(detect & platform.ocapi->i2c_predetect_pin))
+ *presence = true;
+
+ return rc;
+}
+
+static void rainier_pau_device_detect(struct pau *pau)
+{
+ struct pau_dev *dev;
+ bool presence;
+ 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, &presence);
+ if (!rc && presence)
+ dev->type = PAU_DEV_TYPE_OPENCAPI;
+ }
+
+ dt_add_property_u64(dev->dn, "ibm,link-speed", 25000000000ull);
+ }
+}
+
+static void rainier_pau_create_i2c_bus(void)
+{
+ struct dt_node *xscom, *i2cm, *i2c_bus;
+
+ prlog(PR_DEBUG, "PLAT: Adding I2C bus device node for PAU reset\n");
+ dt_for_each_compatible(dt_root, xscom, "ibm,xscom") {
+ i2cm = dt_find_by_name(xscom, "i2cm@a1000");
+ if (!i2cm) {
+ prlog(PR_DEBUG, "PLAT: Adding master @a1000\n");
+ i2cm = dt_new(xscom, "i2cm@a1000");
+ dt_add_property_cells(i2cm, "reg", 0xa1000, 0x1000);
+ dt_add_property_strings(i2cm, "compatible",
+ "ibm,power8-i2cm", "ibm,power9-i2cm");
+ dt_add_property_cells(i2cm, "#size-cells", 0x0);
+ dt_add_property_cells(i2cm, "#address-cells", 0x1);
+ dt_add_property_cells(i2cm, "chip-engine#", 0x1);
+ dt_add_property_cells(i2cm, "clock-frequency", 0x7735940);
+ }
+
+ i2c_bus = dt_find_by_name(i2cm, "i2c-bus@0");
+ if (!i2c_bus) {
+ prlog(PR_DEBUG, "PLAT: Adding bus 0 to master @a1000\n");
+ i2c_bus = dt_new_addr(i2cm, "i2c-bus", 0);
+ dt_add_property_cells(i2c_bus, "reg", 0);
+ dt_add_property_cells(i2c_bus, "bus-frequency", 0x61a80);
+ dt_add_property_strings(i2c_bus, "compatible",
+ "ibm,opal-i2c",
+ "ibm,power8-i2c-port",
+ "ibm,power9-i2c-port",
+ "ibm,power10-i2c-port");
+ }
+
+ i2c_bus = dt_find_by_name(i2cm, "i2c-bus@1");
+ if (!i2c_bus) {
+ prlog(PR_DEBUG, "PLAT: Adding bus 1 to master @a1000\n");
+ i2c_bus = dt_new_addr(i2cm, "i2c-bus", 1);
+ dt_add_property_cells(i2c_bus, "reg", 1);
+ dt_add_property_cells(i2c_bus, "bus-frequency", 0x61a80);
+ dt_add_property_strings(i2c_bus, "compatible",
+ "ibm,opal-i2c",
+ "ibm,power8-i2c-port",
+ "ibm,power9-i2c-port",
+ "ibm,power10-i2c-port");
+ }
+ }
+}
+
static void rainier_init(void)
{
astbmc_init();
@@ -118,9 +340,24 @@ static bool rainier_probe(void)
/* Setup UART for use by OPAL (Linux hvc) */
uart_set_console_policy(UART_CONSOLE_OPAL);
+ /* create i2c entries for PAU */
+ rainier_pau_create_i2c_bus();
+
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 */
+ /* As previously for NPU/NPU2, we use indirect functions for
+ * this platform to reset the device. This makes the code more
+ * generic in PAU.
+ */
+ .i2c_assert_reset = rainier_i2c_assert_reset,
+ .i2c_deassert_reset = rainier_i2c_deassert_reset,
+};
+
DECLARE_PLATFORM(rainier) = {
.name = "Rainier",
.probe = rainier_probe,
@@ -131,6 +368,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,
};