diff options
author | Mary Ruthven <mruthven@chromium.org> | 2022-04-15 12:34:23 -0500 |
---|---|---|
committer | Chromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com> | 2022-04-25 21:02:09 +0000 |
commit | 901bd36869257d4e5fadf6e5d63dea998c9300a1 (patch) | |
tree | 203736d5f28f864e70169245a5a6530b47a2df64 /board | |
parent | a2e434d6c70f605b89cfe403dfc64ed2bd430cc3 (diff) | |
download | chrome-ec-901bd36869257d4e5fadf6e5d63dea998c9300a1.tar.gz |
ap_state: poll TPM_RST_L in case cr50 missed an edge.
New boards generate very short pulses on TPM_RST_L. They deassert
TPM_RST_L and then quickly reassert it. Most processing is not done in
the assert/deassert interrupts. The interrupts schedule deferred
functions to reset the TPM and set the AP state.
tpm_rst_asserted sets the AP state to debouncing and schedules
deferred_set_ap_off_data for a second later.
tpm_rst_deasserted schedules a deferred_tpm_rst_isr call ASAP.
deferred_tpm_rst_isr sets the AP state to on and cancels any pending
deferred_set_ap_off calls. If there's a short period where the AP is
off, cr50 won't enable deep sleep or disable the TPM, it'll be in the
debouncing state until the rising edge, and then the AP will be set back
to on.
The issue with short pulses is cr50 doesn't fully process
deferred_tpm_rst_isr before the tpm_rst_asserted interrupt is
triggered.
tpm_rst_deasserted is triggered which schedules deferred_tpm_rst_isr
tpm_rst_asserted is triggered which schedules deferred_set_ap_off
deferred_tpm_rst_isr is processed which sets the AP state to on and
cancels deferred_set_ap_off.
Even though tpm_rst_asserted happened after tpm_rst_deasserted cr50
process set_ap_on which cancels the pending set_ap_off call. Cr50 gets
left with the AP state on even though tpm_rst_asserted was the last
interrupt. This change adds polling to catch this state after a second,
so cr50 can enable deep sleep.
BUG=b:226680127
TEST=manual
reset the AP on hoglin. check for appoll messages
run firmware_Cr50DeviceState on hatch
comment out enabling the TPM_RST_L interrupt handlers.
verify cr50 eventually gets to the correct ap state.
Change-Id: Ib100d4019a1e65cc4c5ce699d268f65884b4f009
Signed-off-by: Mary Ruthven <mruthven@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3597031
Reviewed-by: Vadim Bendebury <vbendeb@chromium.org>
Diffstat (limited to 'board')
-rw-r--r-- | board/cr50/ap_state.c | 36 |
1 files changed, 36 insertions, 0 deletions
diff --git a/board/cr50/ap_state.c b/board/cr50/ap_state.c index 1dfd73af32..115f067c50 100644 --- a/board/cr50/ap_state.c +++ b/board/cr50/ap_state.c @@ -117,6 +117,17 @@ static void set_state(enum device_state new_state) */ static void deferred_set_ap_off(void) { + /* + * It's important cr50 keeps INT_AP_L enabled whenever the AP is on. + * Check if TPM_RST_L is still asserted before touching the AP state or + * the INT_AP_L signal. It shouldn't be possible for TPM_RST_L to be + * deasserted in set_ap_off. Check the level just to be safe. + * Block the AP state change if it's deasserted. + */ + if (gpio_get_level(GPIO_TPM_RST_L)) { + CPRINTS("AP: ovrd"); + return; + } CPRINTS("AP off"); set_state(DEVICE_STATE_OFF); @@ -254,6 +265,31 @@ void board_closed_loop_reset(void) tpm_rst_asserted(GPIO_TPM_RST_L); } +static void poll_ap_state(void) +{ + /* + * High means the AP is on. If cr50 thinks the AP is off, it missed an + * interrupt. Trigger the deasserted interrupt. + */ + if (gpio_get_level(GPIO_TPM_RST_L)) { + /* + * If cr50 thinks the AP is off while TPM_RST_L is high, it + * missed a falling edge interrupt. Trigger it. + */ + if (!ap_is_on()) { + CPRINTS("appoll: R-"); + tpm_rst_deasserted(GPIO_TPM_RST_L); + } + } else if (ap_is_on()) { + /* + * If cr50 thinks the AP is on while TPM_RST_L is low, it missed + * a falling edge interrupt. Trigger it. + */ + CPRINTS("appoll: -F"); + tpm_rst_asserted(GPIO_TPM_RST_L); + } +} +DECLARE_HOOK(HOOK_SECOND, poll_ap_state, HOOK_PRIO_DEFAULT); /** * Check the initial AP state. */ |