diff options
author | Keith Short <keithshort@chromium.org> | 2020-11-16 15:08:47 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-11-18 00:13:25 +0000 |
commit | 867fe225cbd2321bf07241213c43692b7bf122c4 (patch) | |
tree | 3c2197c63d10275fcc1ef0b32ef4db85cc0318b5 /driver | |
parent | ef1ebb6ee64a3e070057c50d87046a095971ccc5 (diff) | |
download | chrome-ec-867fe225cbd2321bf07241213c43692b7bf122c4.tar.gz |
ps8815: Add a delay after writes to ROLE_CONTROL
The PS8815 can corrupt the transmit buffer. Add a delay following writes
to the ROLE_CONTROL register to workaround the corruption until a new
revision of the chip is available.
BUG=b:171430855
BRANCH=firmware-volteer-13521.B-master
TEST=make buildalls
TEST=Connect DP+USB monitor to Delbin. Perform repeated power role swaps
and verify no corrupted PS_RDY packets.
Signed-off-by: Keith Short <keithshort@chromium.org>
Change-Id: If887af58b0a7c3f27df879156e0f234f88db14ed
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2544803
Reviewed-by: Aseda Aboagye <aaboagye@chromium.org>
Reviewed-by: Abe Levkoy <alevkoy@chromium.org>
Diffstat (limited to 'driver')
-rw-r--r-- | driver/tcpm/ps8xxx.c | 79 | ||||
-rw-r--r-- | driver/tcpm/ps8xxx.h | 3 |
2 files changed, 77 insertions, 5 deletions
diff --git a/driver/tcpm/ps8xxx.c b/driver/tcpm/ps8xxx.c index ebfe43d916..b24141c4f0 100644 --- a/driver/tcpm/ps8xxx.c +++ b/driver/tcpm/ps8xxx.c @@ -61,6 +61,16 @@ static uint16_t product_id[CONFIG_USB_PD_PORT_MAX_COUNT]; /* + * Revisions A1 and A0 of the PS8815 can corrupt the transmit buffer when + * updating the transmit buffer within 1ms of writing the ROLE_CONTROL + * register. When this version of silicon is detected, add a 1ms delay before + * all writes to the transmit buffer. + * + * See b/171430855 for details. + */ +static bool ps8815_role_control_delay[CONFIG_USB_PD_PORT_MAX_COUNT]; + +/* * timestamp of the next possible toggle to ensure the 2-ms spacing * between IRQ_HPD. */ @@ -352,6 +362,23 @@ static int ps8xxx_tcpm_release(int port) } #ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE +static int ps8xxx_set_role_ctrl(int port, enum tcpc_drp drp, + enum tcpc_rp_value rp, enum tcpc_cc_pull pull) +{ + int rv; + + rv = tcpci_set_role_ctrl(port, drp, rp, pull); + + /* + * b/171430855 delay 1 ms after ROLE_CONTROL updates to prevent + * transmit buffer corruption + */ + if (ps8815_role_control_delay[port]) + msleep(1); + + return rv; +} + static int ps8xxx_tcpc_drp_toggle(int port) { int rv; @@ -376,7 +403,7 @@ static int ps8xxx_tcpc_drp_toggle(int port) } /* Set auto drp toggle, starting with the opposite pull */ - rv |= tcpci_set_role_ctrl(port, TYPEC_DRP, TYPEC_RP_USB, + rv |= ps8xxx_set_role_ctrl(port, TYPEC_DRP, TYPEC_RP_USB, opposite_pull); /* Set Look4Connection command */ @@ -506,12 +533,44 @@ static int ps8xxx_dci_disable(int port) return EC_ERROR_INVAL; } +__maybe_unused static void ps8815_transmit_buffer_workaround_check(int port) +{ + int p1_addr; + int val; + int status; + + ps8815_role_control_delay[port] = false; + + if (product_id[port] != PS8815_PRODUCT_ID) + return; + + /* P1 registers are always accessible on PS8815 */ + p1_addr = PS8751_P3_TO_P1_FLAGS(tcpc_config[port].i2c_info.addr_flags); + + status = tcpc_addr_read16(port, p1_addr, PS8815_P1_REG_HW_REVISION, + &val); + if (status != EC_SUCCESS) + return; + + switch (val) { + case 0x0a00: + case 0x0a01: + ps8815_role_control_delay[port] = true; + break; + default: + break; + } +} + static int ps8xxx_tcpm_init(int port) { int status; product_id[port] = board_get_ps8xxx_product_id(port); + if (IS_ENABLED(CONFIG_USB_PD_TCPM_PS8815)) + ps8815_transmit_buffer_workaround_check(port); + status = tcpci_tcpm_init(port); if (status != EC_SUCCESS) return status; @@ -552,6 +611,22 @@ static int ps8751_get_gcc(int port, enum tcpc_cc_voltage_status *cc1, } #endif +static int ps8xxx_tcpm_set_cc(int port, int pull) +{ + int rv; + + rv = tcpci_tcpm_set_cc(port, pull); + + /* + * b/171430855 delay 1 ms after ROLE_CONTROL updates to prevent + * transmit buffer corruption + */ + if (ps8815_role_control_delay[port]) + msleep(1); + + return rv; +} + static int ps8xxx_tcpm_get_cc(int port, enum tcpc_cc_voltage_status *cc1, enum tcpc_cc_voltage_status *cc2) { @@ -571,7 +646,7 @@ const struct tcpm_drv ps8xxx_tcpm_drv = { .check_vbus_level = &tcpci_tcpm_check_vbus_level, #endif .select_rp_value = &tcpci_tcpm_select_rp_value, - .set_cc = &tcpci_tcpm_set_cc, + .set_cc = &ps8xxx_tcpm_set_cc, .set_polarity = &tcpci_tcpm_set_polarity, #ifdef CONFIG_USB_PD_DECODE_SOP .sop_prime_disable = &tcpci_tcpm_sop_prime_disable, diff --git a/driver/tcpm/ps8xxx.h b/driver/tcpm/ps8xxx.h index 788e2f2655..6ef1cd9d90 100644 --- a/driver/tcpm/ps8xxx.h +++ b/driver/tcpm/ps8xxx.h @@ -89,12 +89,9 @@ #define PS8751_REG_MUX_USB_DCI_CFG 0xED #endif -#if defined(CONFIG_USB_PD_TCPM_PS8815) /* Vendor defined registers */ #define PS8815_P1_REG_HW_REVISION 0xF0 -#endif - extern const struct tcpm_drv ps8xxx_tcpm_drv; /** |