diff options
author | Caveh Jalali <caveh@chromium.org> | 2021-08-10 02:41:58 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2021-08-17 23:12:04 +0000 |
commit | cd73e503e98aac047a319aab95710d3dd8422eb0 (patch) | |
tree | 0c13ef0918507c75c988852a8104da8e17e58f0e /driver/tcpm | |
parent | f89340eed3f35f9de9b6aaca83d5628893b95562 (diff) | |
download | chrome-ec-cd73e503e98aac047a319aab95710d3dd8422eb0.tar.gz |
ps8xxx: Wait for chip to wake up from LPM
The ps8815 can take up to 50ms to fully wake up from sleep/low power
mode. When the chip is asleep, the 1st I2C transaction will fail but the
chip will begin to wake up within 10ms. After this delay, I2C
transactions succeed, but the firmware is still not fully
operational. The way to check if the firmware is ready, is to poll the
firmware register for a non-zero value.
BRANCH=none
BUG=b:195087071,b:186189039
TEST=buildall passes
Change-Id: If047fc122d7f61ed5fc361f97b47180e5cf08970
Signed-off-by: Caveh Jalali <caveh@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3084331
Reviewed-by: Keith Short <keithshort@chromium.org>
Diffstat (limited to 'driver/tcpm')
-rw-r--r-- | driver/tcpm/ps8xxx.c | 52 |
1 files changed, 51 insertions, 1 deletions
diff --git a/driver/tcpm/ps8xxx.c b/driver/tcpm/ps8xxx.c index c75103688b..cab795ef09 100644 --- a/driver/tcpm/ps8xxx.c +++ b/driver/tcpm/ps8xxx.c @@ -58,6 +58,8 @@ #define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) #define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) +#define PS8XXX_I2C_RECOVERY_DELAY_MS 10 + /* * 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(). @@ -290,7 +292,7 @@ static struct ps8xxx_variant_map variant_map[] = { }; static int get_reg_by_product(const int port, - const enum ps8xxx_variant_regs reg) + const enum ps8xxx_variant_regs reg) { int i; @@ -569,6 +571,48 @@ static int ps8815_make_device_id(int port, int *id) } #endif +/* + * The ps8815 can take up to 50ms (FW_INIT_DELAY_MS) to fully wake up + * from sleep/low power mode - specially when it contains an application + * block firmware update. When the chip is asleep, the 1st I2C + * transaction will fail but the chip will begin to wake up within 10ms + * (I2C_RECOVERY_DELAY_MS). After this delay, I2C transactions succeed, + * but the firmware is still not fully operational. The way to check if + * the firmware is ready, is to poll the firmware register for a + * non-zero value. This logic applies to all ps8xxx family members + * supported by this driver. + */ + +static int ps8xxx_lpm_recovery_delay(int port) +{ + int val; + int status; + int fw_reg; + timestamp_t deadline; + + fw_reg = get_reg_by_product(port, REG_FW_VER); + + deadline = get_time(); + deadline.val += PS8815_FW_INIT_DELAY_MS * 1000; + + val = 0; + for (;;) { + status = tcpc_read(port, fw_reg, &val); + if (status != EC_SUCCESS) { + /* wait for chip to wake up */ + msleep(PS8XXX_I2C_RECOVERY_DELAY_MS); + continue; + } + if (val != 0) + break; + msleep(1); + if (timestamp_expired(deadline, NULL)) + return EC_ERROR_TIMEOUT; + } + + return EC_SUCCESS; +} + static int ps8xxx_get_chip_info(int port, int live, struct ec_response_pd_chip_info_v1 *chip_info) { @@ -726,6 +770,12 @@ static int ps8xxx_tcpm_init(int port) product_id[port] = board_get_ps8xxx_product_id(port); + status = ps8xxx_lpm_recovery_delay(port); + if (status != EC_SUCCESS) { + CPRINTS("C%d: init: LPM recovery failed", port); + return status; + } + if (IS_ENABLED(CONFIG_USB_PD_TCPM_PS8815)) { status = ps8815_transmit_buffer_workaround_check(port); if (status != EC_SUCCESS) |