summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarco Chen <marcochen@google.com>2020-07-17 14:50:42 +0800
committerCommit Bot <commit-bot@chromium.org>2020-09-11 01:46:24 +0000
commit585dd16a32ab67f2bd6ef2134f77adb287fca155 (patch)
treec1ee3d6f31ea6a8244d170a946711685ab875fc8
parentfd13ea525b40d38d3d0ae56dd23f098b3f867605 (diff)
downloadchrome-ec-585dd16a32ab67f2bd6ef2134f77adb287fca155.tar.gz
ps8xxx: support multiple chips in the runtime
BUG=b:159082424 BRANCH=none TEST=verify the same EC image can work on devices with PS8751 or PS8755 for src / snk roles. Signed-off-by: Marco Chen <marcochen@chromium.org> Change-Id: I3a743666a4ccbcae37ecb6f0d6657122cf9c5a69 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2304237 Reviewed-by: Jett Rink <jettrink@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2393406 Tested-by: Devin Lu <Devin.Lu@quantatw.com> Reviewed-by: Edward Hill <ecgh@chromium.org> Commit-Queue: Edward Hill <ecgh@chromium.org>
-rw-r--r--driver/tcpm/ps8xxx.c320
-rw-r--r--driver/tcpm/ps8xxx.h56
-rw-r--r--include/config.h37
3 files changed, 298 insertions, 115 deletions
diff --git a/driver/tcpm/ps8xxx.c b/driver/tcpm/ps8xxx.c
index e7e561e4ae..c6e1cc671b 100644
--- a/driver/tcpm/ps8xxx.c
+++ b/driver/tcpm/ps8xxx.c
@@ -15,6 +15,7 @@
*/
#include "common.h"
+#include "console.h"
#include "ps8xxx.h"
#include "tcpci.h"
#include "tcpm.h"
@@ -38,17 +39,200 @@
#endif
+#ifdef CONFIG_USB_PD_TCPM_PS8751
+/* PS8751 cannot run with PD 3.0 (see b/148554997 for details) */
+#if defined(CONFIG_USB_PD_REV30)
+#error "PS8751 cannot run with PD 3.0. Fall back to using PD 2.0"
+#endif
+
+#endif /* CONFIG_USB_PD_TCPM_PS8751 */
+
+#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args)
+#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args)
+
+/*
+ * The product_id per ports here is expected to be set in callback function -
+ * .init of tcpm_drv by calling board_get_ps8xxx_product_id().
+ *
+ * In case of CONFIG_USB_PD_TCPM_MULTI_PS8XXX enabled, board code should
+ * override the board_get_ps8xxx_product_id() for getting the correct id.
+ */
+static uint16_t product_id[CONFIG_USB_PD_PORT_COUNT];
+
/*
* timestamp of the next possible toggle to ensure the 2-ms spacing
* between IRQ_HPD.
*/
static uint64_t hpd_deadline[CONFIG_USB_PD_PORT_COUNT];
+#if defined(CONFIG_USB_PD_TCPM_PS8705) || \
+ defined(CONFIG_USB_PD_TCPM_PS8751) || \
+ defined(CONFIG_USB_PD_TCPM_PS8755) || \
+ defined(CONFIG_USB_PD_TCPM_PS8805)
+/*
+ * DCI is enabled by default and burns about 40 mW when the port is in
+ * USB2 mode or when a C-to-A dongle is attached, so force it off.
+ */
+
+static int ps8xxx_addr_dci_disable(int port, int i2c_addr, int i2c_reg)
+{
+ int status;
+ int dci;
+
+ status = tcpc_addr_read(port, i2c_addr, i2c_reg, &dci);
+ if (status != EC_SUCCESS)
+ return status;
+ if ((dci & PS8XXX_REG_MUX_USB_DCI_CFG_MODE_MASK) !=
+ PS8XXX_REG_MUX_USB_DCI_CFG_MODE_OFF) {
+ dci &= ~PS8XXX_REG_MUX_USB_DCI_CFG_MODE_MASK;
+ dci |= PS8XXX_REG_MUX_USB_DCI_CFG_MODE_OFF;
+ if (tcpc_addr_write(port, i2c_addr, i2c_reg, dci) != EC_SUCCESS)
+ return status;
+ }
+ return EC_SUCCESS;
+}
+#endif /* CONFIG_USB_PD_TCPM_PS875[15] || CONFIG_USB_PD_TCPM_PS8[78]05 */
+
+#if defined(CONFIG_USB_PD_TCPM_PS8705) || \
+ defined(CONFIG_USB_PD_TCPM_PS8755) || \
+ defined(CONFIG_USB_PD_TCPM_PS8805)
+static int ps8705_dci_disable(int port)
+{
+ int p1_addr;
+ int p3_addr;
+ int regval;
+ int rv;
+
+ /* Enable access to debug pages. */
+ p3_addr = tcpc_config[port].i2c_info.addr_flags;
+ rv = tcpc_addr_read(port, p3_addr, PS8XXX_REG_I2C_DEBUGGING_ENABLE,
+ &regval);
+ if (rv)
+ return rv;
+
+ rv = tcpc_addr_write(port, p3_addr, PS8XXX_REG_I2C_DEBUGGING_ENABLE,
+ PS8XXX_REG_I2C_DEBUGGING_ENABLE_ON);
+
+ /* Disable Auto DCI */
+ p1_addr = PS8751_P3_TO_P1_FLAGS(p3_addr);
+ rv = ps8xxx_addr_dci_disable(port, p1_addr,
+ PS8XXX_P1_REG_MUX_USB_DCI_CFG);
+
+ /*
+ * PS8705/PS8755/PS8805 will automatically re-assert bit:0 on the
+ * PS8XXX_REG_I2C_DEBUGGING_ENABLE register.
+ */
+ return rv;
+}
+#endif /* CONFIG_USB_PD_TCPM_PS8755 || CONFIG_USB_PD_TCPM_PS8[78]05 */
+
+#ifdef CONFIG_USB_PD_TCPM_PS8751
+static int ps8751_dci_disable(int port)
+{
+ int p3_addr;
+
+ p3_addr = tcpc_config[port].i2c_info.addr_flags;
+ return ps8xxx_addr_dci_disable(port, p3_addr,
+ PS8751_REG_MUX_USB_DCI_CFG);
+}
+#endif /* CONFIG_USB_PD_TCPM_PS8751 */
+
+#ifdef CONFIG_USB_PD_TCPM_PS8815
+static int ps8815_dci_disable(int port)
+{
+ /* DCI is disabled on the ps8815 */
+ return EC_SUCCESS;
+}
+#endif /* CONFIG_USB_PD_TCPM_PS8815 */
+
+enum ps8xxx_variant_regs {
+ REG_FIRST_INDEX = 0,
+ /* NOTE: The rev will read as 0x00 if the FW has malfunctioned. */
+ REG_FW_VER = REG_FIRST_INDEX,
+ REG_MAX_COUNT,
+};
+
+struct ps8xxx_variant_map {
+ int product_id;
+ int (*dci_disable_ptr)(int port);
+ int reg_map[REG_MAX_COUNT];
+};
+
+/*
+ * variant_map here is leveraged to lookup from ps8xxx_variant_regs to i2c
+ * register and corresponding dci_disable function based on product_id.
+ */
+static struct ps8xxx_variant_map variant_map[] = {
+#ifdef CONFIG_USB_PD_TCPM_PS8705
+ {
+ PS8705_PRODUCT_ID,
+ ps8705_dci_disable,
+ {
+ [REG_FW_VER] = 0x82,
+ }
+ },
+#endif
+#ifdef CONFIG_USB_PD_TCPM_PS8751
+ {
+ PS8751_PRODUCT_ID,
+ ps8751_dci_disable,
+ {
+ [REG_FW_VER] = 0x90,
+ }
+ },
+#endif
+#ifdef CONFIG_USB_PD_TCPM_PS8755
+ {
+ PS8755_PRODUCT_ID,
+ ps8705_dci_disable,
+ {
+ [REG_FW_VER] = 0x82,
+ }
+ },
+#endif
+#ifdef CONFIG_USB_PD_TCPM_PS8805
+ {
+ PS8805_PRODUCT_ID,
+ ps8705_dci_disable,
+ {
+ [REG_FW_VER] = 0x82,
+ }
+ },
+#endif
+#ifdef CONFIG_USB_PD_TCPM_PS8815
+ {
+ PS8815_PRODUCT_ID,
+ ps8815_dci_disable,
+ {
+ [REG_FW_VER] = 0x82,
+ }
+ },
+#endif
+};
+
+static int get_reg_by_product(const int port,
+ const enum ps8xxx_variant_regs reg)
+{
+ int i;
+
+ if (reg < REG_FIRST_INDEX || reg >= REG_MAX_COUNT)
+ return INT32_MAX;
+
+ for (i = 0; i < ARRAY_SIZE(variant_map); i++) {
+ if (product_id[port] ==
+ variant_map[i].product_id) {
+ return variant_map[i].reg_map[reg];
+ }
+ }
+
+ CPRINTS("%s: failed to get register number by product_id.", __func__);
+ return INT32_MAX;
+}
+
static int dp_set_hpd(int port, int enable)
{
int reg;
int rv;
-
rv = mux_read(port, MUX_IN_HPD_ASSERTION_REG, &reg);
if (rv)
return rv;
@@ -58,13 +242,10 @@ static int dp_set_hpd(int port, int enable)
reg &= ~IN_HPD;
return mux_write(port, MUX_IN_HPD_ASSERTION_REG, reg);
}
-
static int dp_set_irq(int port, int enable)
{
-
int reg;
int rv;
-
rv = mux_read(port, MUX_IN_HPD_ASSERTION_REG, &reg);
if (rv)
return rv;
@@ -75,6 +256,33 @@ static int dp_set_irq(int port, int enable)
return mux_write(port, MUX_IN_HPD_ASSERTION_REG, reg);
}
+__overridable
+uint16_t board_get_ps8xxx_product_id(int port)
+{
+ /* Board supporting multiple chip sources in ps8xxx.c MUST override this
+ * function to judge the real chip source for this board. For example,
+ * SKU ID / strappings / provisioning in the factory can be the ways.
+ */
+
+ if (IS_ENABLED(CONFIG_USB_PD_TCPM_MULTI_PS8XXX)) {
+ CPRINTS("%s: board should override this function.", __func__);
+ return 0;
+ } else if (IS_ENABLED(CONFIG_USB_PD_TCPM_PS8705)) {
+ return PS8705_PRODUCT_ID;
+ } else if (IS_ENABLED(CONFIG_USB_PD_TCPM_PS8751)) {
+ return PS8751_PRODUCT_ID;
+ } else if (IS_ENABLED(CONFIG_USB_PD_TCPM_PS8755)) {
+ return PS8755_PRODUCT_ID;
+ } else if (IS_ENABLED(CONFIG_USB_PD_TCPM_PS8805)) {
+ return PS8805_PRODUCT_ID;
+ } else if (IS_ENABLED(CONFIG_USB_PD_TCPM_PS8815)) {
+ return PS8815_PRODUCT_ID;
+ }
+
+ CPRINTS("%s: Any new product id is not defined here?", __func__);
+ return 0;
+}
+
void ps8xxx_tcpc_update_hpd_status(int port, int hpd_lvl, int hpd_irq)
{
dp_set_hpd(port, hpd_lvl);
@@ -127,8 +335,9 @@ static int ps8xxx_tcpm_release(int port)
{
int version;
int status;
+ int reg = get_reg_by_product(port, REG_FW_VER);
- status = tcpc_read(port, FW_VER_REG, &version);
+ status = tcpc_read(port, reg, &version);
if (status != 0) {
/* wait for chip to wake up */
msleep(10);
@@ -141,26 +350,35 @@ static int ps8xxx_get_chip_info(int port, int live,
struct ec_response_pd_chip_info_v1 **chip_info)
{
int val;
+ int reg;
int rv = tcpci_get_chip_info(port, live, chip_info);
if (rv)
return rv;
if (!live) {
+ product_id[port] = board_get_ps8xxx_product_id(port);
(*chip_info)->vendor_id = PS8XXX_VENDOR_ID;
- (*chip_info)->product_id = PS8XXX_PRODUCT_ID;
+ (*chip_info)->product_id = product_id[port];
}
if ((*chip_info)->fw_version_number == 0 ||
(*chip_info)->fw_version_number == -1 || live) {
- rv = tcpc_read(port, FW_VER_REG, &val);
-
- if (rv)
+ reg = get_reg_by_product(port, REG_FW_VER);
+ rv = tcpc_read(port, reg, &val);
+ if (rv != EC_SUCCESS)
return rv;
(*chip_info)->fw_version_number = val;
}
+ /* Treat unexpected values as error (FW not initiated from reset) */
+ if (live && (
+ (*chip_info)->vendor_id != PS8XXX_VENDOR_ID ||
+ (*chip_info)->product_id != board_get_ps8xxx_product_id(port) ||
+ (*chip_info)->fw_version_number == 0))
+ return EC_ERROR_UNKNOWN;
+
#if defined(CONFIG_USB_PD_TCPM_PS8751) && \
defined(CONFIG_USB_PD_VBUS_DETECT_TCPC)
/*
@@ -173,91 +391,25 @@ static int ps8xxx_get_chip_info(int port, int live,
return rv;
}
-
-#if defined(CONFIG_USB_PD_TCPM_PS8705) || \
- defined(CONFIG_USB_PD_TCPM_PS8751) || \
- defined(CONFIG_USB_PD_TCPM_PS8755) || \
- defined(CONFIG_USB_PD_TCPM_PS8805)
-/*
- * DCI is enabled by default and burns about 40 mW when the port is in
- * USB2 mode or when a C-to-A dongle is attached, so force it off.
- */
-
-static int ps8xxx_addr_dci_disable(int port, int i2c_addr, int i2c_reg)
-{
- int status;
- int dci;
-
- status = tcpc_addr_read(port, i2c_addr, i2c_reg, &dci);
- if (status != EC_SUCCESS)
- return status;
- if ((dci & PS8XXX_REG_MUX_USB_DCI_CFG_MODE_MASK) !=
- PS8XXX_REG_MUX_USB_DCI_CFG_MODE_OFF) {
- dci &= ~PS8XXX_REG_MUX_USB_DCI_CFG_MODE_MASK;
- dci |= PS8XXX_REG_MUX_USB_DCI_CFG_MODE_OFF;
- if (tcpc_addr_write(port, i2c_addr, i2c_reg, dci) != EC_SUCCESS)
- return status;
- }
- return EC_SUCCESS;
-}
-#endif /* CONFIG_USB_PD_TCPM_PS875[15] || CONFIG_USB_PD_TCPM_PS8[78]05 */
-
-#if defined(CONFIG_USB_PD_TCPM_PS8705) || \
- defined(CONFIG_USB_PD_TCPM_PS8755) || \
- defined(CONFIG_USB_PD_TCPM_PS8805)
-static int ps8xxx_dci_disable(int port)
-{
- int p1_addr;
- int p3_addr;
- int regval;
- int rv;
-
- /* Enable access to debug pages. */
- p3_addr = tcpc_config[port].i2c_info.addr_flags;
- rv = tcpc_addr_read(port, p3_addr, PS8XXX_REG_I2C_DEBUGGING_ENABLE,
- &regval);
- if (rv)
- return rv;
-
- rv = tcpc_addr_write(port, p3_addr, PS8XXX_REG_I2C_DEBUGGING_ENABLE,
- PS8XXX_REG_I2C_DEBUGGING_ENABLE_ON);
-
- /* Disable Auto DCI */
- p1_addr = PS8751_P3_TO_P1_FLAGS(p3_addr);
- rv = ps8xxx_addr_dci_disable(port, p1_addr,
- PS8XXX_P1_REG_MUX_USB_DCI_CFG);
-
- /*
- * PS8705/PS8755/PS8805 will automatically re-assert bit:0 on the
- * PS8XXX_REG_I2C_DEBUGGING_ENABLE register.
- */
- return rv;
-}
-#endif /* CONFIG_USB_PD_TCPM_PS8755 || CONFIG_USB_PD_TCPM_PS8[78]05 */
-
-#ifdef CONFIG_USB_PD_TCPM_PS8751
static int ps8xxx_dci_disable(int port)
{
- int p3_addr;
+ int i;
- p3_addr = tcpc_config[port].i2c_info.addr_flags;
- return ps8xxx_addr_dci_disable(port, p3_addr,
- PS8751_REG_MUX_USB_DCI_CFG);
-}
-#endif /* CONFIG_USB_PD_TCPM_PS8751 */
+ for (i = 0; i < ARRAY_SIZE(variant_map); i++) {
+ if (product_id[port] == variant_map[i].product_id)
+ return variant_map[i].dci_disable_ptr(port);
+ }
-#ifdef CONFIG_USB_PD_TCPM_PS8815
-static int ps8xxx_dci_disable(int port)
-{
- /* DCI is disabled on the ps8815 */
- return EC_SUCCESS;
+ CPRINTS("%s: failed to get dci_disable function pointers.", __func__);
+ return EC_ERROR_INVAL;
}
-#endif /* CONFIG_USB_PD_TCPM_PS8815 */
static int ps8xxx_tcpm_init(int port)
{
int status;
+ product_id[port] = board_get_ps8xxx_product_id(port);
+
status = tcpci_tcpm_init(port);
if (status != EC_SUCCESS)
return status;
diff --git a/driver/tcpm/ps8xxx.h b/driver/tcpm/ps8xxx.h
index 77bf076fa2..806d264a23 100644
--- a/driver/tcpm/ps8xxx.h
+++ b/driver/tcpm/ps8xxx.h
@@ -49,51 +49,49 @@
#define PS8XXX_P1_REG_MUX_USB_DCI_CFG 0x4B
+/* NOTE: The Product ID will read as 0x8803 if the firmware has malfunctioned in
+ * 8705, 8755 and 8805.
+ */
+#define PS8705_PRODUCT_ID 0x8705
+#define PS8751_PRODUCT_ID 0x8751
+#define PS8755_PRODUCT_ID 0x8755
+#define PS8805_PRODUCT_ID 0x8805
+#define PS8815_PRODUCT_ID 0x8815
+
#if defined(CONFIG_USB_PD_TCPM_PS8751)
/* Vendor defined registers */
-#define PS8XXX_PRODUCT_ID 0x8751
-
-#define FW_VER_REG 0x90
#define PS8XXX_REG_VENDOR_ID_L 0x00
#define PS8XXX_REG_VENDOR_ID_H 0x01
#define PS8XXX_REG_MUX_DP_EQ_CONFIGURATION 0xD3
#define PS8XXX_REG_MUX_USB_C2SS_EQ 0xE7
#define PS8XXX_REG_MUX_USB_C2SS_HS_THRESHOLD 0xE8
#define PS8751_REG_MUX_USB_DCI_CFG 0xED
+#endif
-#elif defined(CONFIG_USB_PD_TCPM_PS8755)
-/* Vendor defined registers */
-/* NOTE: The Product ID will read as 0x8803 if the firmware has malfunctioned */
-#define PS8XXX_PRODUCT_ID 0x8755
-
-#define FW_VER_REG 0x82
-
-#elif defined(CONFIG_USB_PD_TCPM_PS8705)
-/* Vendor defined registers */
-/* NOTE: The Product ID will read as 0x8803 if the firmware has malfunctioned */
-#define PS8XXX_PRODUCT_ID 0x8705
-
-/* NOTE: The revision will read as 0x00 if the firmware has malfunctioned. */
-#define FW_VER_REG 0x82
-
-#elif defined(CONFIG_USB_PD_TCPM_PS8805)
-/* Vendor defined registers */
-/* NOTE: The Product ID will read as 0x8803 if the firmware has malfunctioned */
-#define PS8XXX_PRODUCT_ID 0x8805
-
-#define FW_VER_REG 0x82
-
-#elif defined(CONFIG_USB_PD_TCPM_PS8815)
+#if defined(CONFIG_USB_PD_TCPM_PS8815)
/* Vendor defined registers */
-#define PS8XXX_PRODUCT_ID 0x8815
-
-#define FW_VER_REG 0x82
+#define PS8815_P1_REG_HW_REVISION 0xF0
#endif
extern const struct tcpm_drv ps8xxx_tcpm_drv;
void ps8xxx_tcpc_update_hpd_status(int port, int hpd_lvl, int hpd_irq);
+/**
+ * Board specific callback to judge and provide which chip source of PS8XXX
+ * series supported by this driver per specific port.
+ *
+ * If the board supports only one single source then there is no nencessary to
+ * provide the __override version.
+ *
+ * If board supports two sources or above (with CONFIG_USB_PD_TCPM_MULTI_PS8XXX)
+ * then the __override version is mandatory.
+ *
+ * @param port TCPC port number.
+ */
+__override_proto
+uint16_t board_get_ps8xxx_product_id(int port);
+
#ifdef CONFIG_CMD_I2C_STRESS_TEST_TCPC
extern struct i2c_stress_test_dev ps8xxx_i2c_stress_test_dev;
#endif /* defined(CONFIG_CMD_I2C_STRESS_TEST_TCPC) */
diff --git a/include/config.h b/include/config.h
index eefa780003..3d7f3dad4e 100644
--- a/include/config.h
+++ b/include/config.h
@@ -3398,13 +3398,24 @@
#undef CONFIG_USB_PD_TCPM_ANX741X
#undef CONFIG_USB_PD_TCPM_ANX7447
#undef CONFIG_USB_PD_TCPM_ANX7688
+#undef CONFIG_USB_PD_TCPM_MT6370
+#undef CONFIG_USB_PD_TCPM_TUSB422
+
+/* PS8XXX series are all supported by a single driver with a build time config
+ * listed below (CONFIG_USB_PD_TCPM_PS*) defined to enable the specific product.
+ *
+ * If a board with the same EC FW is expected to support multiple products here
+ * then CONFIG_USB_PD_TCPM_MULTI_PS8XXX MUST be defined then we can enable more
+ * than one product config to support them in the runtime. In this case, board
+ * is responsible to override function of board_get_ps8xxx_product_id in order
+ * to provide the product id per port.
+ */
+#undef CONFIG_USB_PD_TCPM_MULTI_PS8XXX
#undef CONFIG_USB_PD_TCPM_PS8751
#undef CONFIG_USB_PD_TCPM_PS8755
#undef CONFIG_USB_PD_TCPM_PS8705
#undef CONFIG_USB_PD_TCPM_PS8805
#undef CONFIG_USB_PD_TCPM_PS8815
-#undef CONFIG_USB_PD_TCPM_MT6370
-#undef CONFIG_USB_PD_TCPM_TUSB422
/*
* Adds an EC console command to erase the ANX7447 OCM flash.
@@ -4361,5 +4372,27 @@
#error "CONFIG_DPTF_MULTI_PROFILE can be set only when CONFIG_DPTF is set."
#endif /* CONFIG_DPTF_MULTI_PROFILE && !CONFIG_DPTF */
+#if defined(CONFIG_USB_PD_TCPM_MULTI_PS8XXX)
+#if defined(CONFIG_USB_PD_TCPM_PS8705) + \
+ defined(CONFIG_USB_PD_TCPM_PS8751) + \
+ defined(CONFIG_USB_PD_TCPM_PS8755) + \
+ defined(CONFIG_USB_PD_TCPM_PS8805) + \
+ defined(CONFIG_USB_PD_TCPM_PS8815) < 2
+#error "Must select 2 CONFIG_USB_PD_TCPM_PS8* or above if " \
+ "CONFIG_USB_PD_TCPM_MULTI_PS8XXX is defined."
+#endif
+#endif /* CONFIG_USB_PD_TCPM_MULTI_PS8XXX */
+
+#if defined(CONFIG_USB_PD_TCPM_PS8705) + \
+ defined(CONFIG_USB_PD_TCPM_PS8751) + \
+ defined(CONFIG_USB_PD_TCPM_PS8755) + \
+ defined(CONFIG_USB_PD_TCPM_PS8805) + \
+ defined(CONFIG_USB_PD_TCPM_PS8815) > 1
+#if !defined(CONFIG_USB_PD_TCPM_MULTI_PS8XXX)
+#error "CONFIG_USB_PD_TCPM_MULTI_PS8XXX MUST be defined if more than one " \
+ "CONFIG_USB_PD_TCPM_PS8* are intended to support in a board."
+#endif
+#endif /* defined(CONFIG_USB_PD_TCPM_PS8705) + ... */
+
#endif /* __CROS_EC_CONFIG_H */