diff options
author | Marco Chen <marcochen@google.com> | 2020-07-17 14:50:42 +0800 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-08-14 06:51:01 +0000 |
commit | d4013027f0f1c95397363b21761085c0d08a6825 (patch) | |
tree | 0325f662346eebabc75a124940f084ace7249e2f | |
parent | c7bf1bd094828785d4444a01e54ca703bfc5c797 (diff) | |
download | chrome-ec-d4013027f0f1c95397363b21761085c0d08a6825.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>
-rw-r--r-- | driver/tcpm/ps8xxx.c | 321 | ||||
-rw-r--r-- | driver/tcpm/ps8xxx.h | 56 | ||||
-rw-r--r-- | include/config.h | 39 |
3 files changed, 297 insertions, 119 deletions
diff --git a/driver/tcpm/ps8xxx.c b/driver/tcpm/ps8xxx.c index 9c65048c39..713977b1e7 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" @@ -47,12 +48,186 @@ #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_MAX_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_MAX_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, + ®val); + 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) +{ + if (reg < REG_FIRST_INDEX || reg >= REG_MAX_COUNT) + return INT32_MAX; + + for (int 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(const struct usb_mux *me, int enable) { int reg; @@ -83,6 +258,33 @@ static int dp_set_irq(const struct usb_mux *me, int enable) return mux_write(me, 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(const struct usb_mux *me, int hpd_lvl, int hpd_irq) { @@ -138,8 +340,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); @@ -160,8 +363,8 @@ static int ps8xxx_tcpc_drp_toggle(int port) * Detection if the partner already presents pull. Now starts with * the opposite pull. Check b/149570002. */ - if (IS_ENABLED(CONFIG_USB_PD_TCPM_PS8805) || - IS_ENABLED(CONFIG_USB_PD_TCPM_PS8815)) { + if (product_id[port] == PS8805_PRODUCT_ID || + product_id[port] == PS8815_PRODUCT_ID) { /* Check CC_STATUS for the current pull */ rv = tcpc_read(port, TCPC_REG_CC_STATUS, &status); if (status & TCPC_REG_CC_STATUS_CONNECT_RESULT_MASK) { @@ -226,27 +429,31 @@ 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 != EC_SUCCESS) 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) { #ifdef CONFIG_USB_PD_TCPM_PS8815_FORCE_DID - if (chip_info->device_id == 0x0001) { + if (chip_info->product_id == PS8815_PRODUCT_ID && + chip_info->device_id == 0x0001) { rv = ps8815_make_device_id(port, &val); if (rv != EC_SUCCESS) return rv; chip_info->device_id = val; } #endif - rv = tcpc_read(port, FW_VER_REG, &val); + reg = get_reg_by_product(port, REG_FW_VER); + rv = tcpc_read(port, reg, &val); if (rv != EC_SUCCESS) return rv; @@ -256,7 +463,7 @@ static int ps8xxx_get_chip_info(int port, int live, /* Treat unexpected values as error (FW not initiated from reset) */ if (live && ( chip_info->vendor_id != PS8XXX_VENDOR_ID || - chip_info->product_id != PS8XXX_PRODUCT_ID || + chip_info->product_id != board_get_ps8xxx_product_id(port) || chip_info->fw_version_number == 0)) return EC_ERROR_UNKNOWN; @@ -287,90 +494,23 @@ static int ps8xxx_enter_low_power_mode(int port) } #endif -#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, - ®val); - 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; - - 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 (int 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; @@ -411,14 +551,21 @@ static int ps8751_get_gcc(int port, enum tcpc_cc_voltage_status *cc1, } #endif +static int ps8xxx_tcpm_get_cc(int port, enum tcpc_cc_voltage_status *cc1, + enum tcpc_cc_voltage_status *cc2) +{ +#ifdef CONFIG_USB_PD_TCPM_PS8751 + if (product_id[port] == PS8751_PRODUCT_ID) + return ps8751_get_gcc(port, cc1, cc2); +#endif + + return tcpci_tcpm_get_cc(port, cc1, cc2); +} + const struct tcpm_drv ps8xxx_tcpm_drv = { .init = &ps8xxx_tcpm_init, .release = &ps8xxx_tcpm_release, -#ifdef CONFIG_USB_PD_TCPM_PS8751 - .get_cc = &ps8751_get_gcc, -#else - .get_cc = &tcpci_tcpm_get_cc, -#endif + .get_cc = &ps8xxx_tcpm_get_cc, #ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC .check_vbus_level = &tcpci_tcpm_check_vbus_level, #endif diff --git a/driver/tcpm/ps8xxx.h b/driver/tcpm/ps8xxx.h index 2dcf13e5e6..788e2f2655 100644 --- a/driver/tcpm/ps8xxx.h +++ b/driver/tcpm/ps8xxx.h @@ -69,11 +69,17 @@ #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 @@ -81,39 +87,31 @@ #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; + +/** + * 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); + void ps8xxx_tcpc_update_hpd_status(const struct usb_mux *me, int hpd_lvl, int hpd_irq); diff --git a/include/config.h b/include/config.h index 79aa880e4c..6b9af1479a 100644 --- a/include/config.h +++ b/include/config.h @@ -4089,14 +4089,25 @@ #undef CONFIG_USB_PD_TCPM_ANX7447 #undef CONFIG_USB_PD_TCPM_ANX7688 #undef CONFIG_USB_PD_TCPM_NCT38XX +#undef CONFIG_USB_PD_TCPM_MT6370 +#undef CONFIG_USB_PD_TCPM_TUSB422 +#undef CONFIG_USB_PD_TCPM_RAA489000 + +/* 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 -#undef CONFIG_USB_PD_TCPM_RAA489000 /* * Defined automatically by chip and depends on chip. This guards the onboard @@ -5618,4 +5629,26 @@ #undef CONFIG_KEYBOARD_VIVALDI #endif +#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 */ |