summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMary Ruthven <mruthven@chromium.org>2022-04-15 12:34:23 -0500
committerChromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com>2022-04-25 21:02:09 +0000
commit901bd36869257d4e5fadf6e5d63dea998c9300a1 (patch)
tree203736d5f28f864e70169245a5a6530b47a2df64
parenta2e434d6c70f605b89cfe403dfc64ed2bd430cc3 (diff)
downloadchrome-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>
-rw-r--r--board/cr50/ap_state.c36
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.
*/