summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMary Ruthven <mruthven@google.com>2019-01-30 10:51:00 -0800
committerchrome-bot <chrome-bot@chromium.org>2019-03-06 06:50:59 -0800
commit70b2257b4c9d22847574a5128332787909934043 (patch)
treeaf60b75af829840465a9b07cd71d14f34aefba20
parent94388feaf11a1aaca22311138b1060db592aa669 (diff)
downloadchrome-ec-70b2257b4c9d22847574a5128332787909934043.tar.gz
cr50: use interrupts for ap_state
The ap_state machine as is is pretty hard to modify as it's implemented now. The state machine has to have certain states set at certain points to handle AP detection properly and it is very slow to detect AP off. It takes a second and it will only detect AP off if TPM_RST_L stays asserted for 1 second. This change modifies ap_state.c to use interrupts instead of polling, so it can detect when the AP is off immediately and wont miss any resets. This is required for the new closed loop reset feature. Cr50 has to be able to detect all AP resets and it can't take 1 second for cr50 to determine the AP is off. We used polling because we had to use APTX_CR50RX to detect AP state for a while. The UART level changes a lot. Processing all of the interrupts really impacted CCD uart, so we couldn't use interrupts to detect the state. We had to poll. AP UART isn't used to detect AP state anymore on any platforms, so it's ok to switch to interrupts now. APTX_CR50RX is still used for ap uart detection in ap_uart_state.c. This change doesn't modify that at all. BUG=b:123544145 BRANCH=cr50 TEST=Make sure suspend and reboot stress tests still work on a bob and a soraka. Check that Cr50 detects the AP state correctly. Change-Id: I80eb97aecffe460b7857e66e7204a55b72c9dd47 Signed-off-by: Mary Ruthven <mruthven@google.com> Reviewed-on: https://chromium-review.googlesource.com/1446999 Commit-Ready: Mary Ruthven <mruthven@chromium.org> Tested-by: Mary Ruthven <mruthven@chromium.org> Reviewed-by: Vadim Bendebury <vbendeb@chromium.org>
-rw-r--r--board/cr50/ap_state.c96
-rw-r--r--board/cr50/board.c19
-rw-r--r--board/cr50/board.h1
-rw-r--r--board/cr50/gpio.inc6
4 files changed, 55 insertions, 67 deletions
diff --git a/board/cr50/ap_state.c b/board/cr50/ap_state.c
index d4f549940a..32064ae07c 100644
--- a/board/cr50/ap_state.c
+++ b/board/cr50/ap_state.c
@@ -22,8 +22,7 @@ void print_ap_state(void)
int ap_is_on(void)
{
- /* Debouncing and on are both still on */
- return (state == DEVICE_STATE_DEBOUNCING || state == DEVICE_STATE_ON);
+ return state == DEVICE_STATE_ON;
}
/**
@@ -47,9 +46,10 @@ static void set_state(enum device_state new_state)
}
/**
- * Set AP to the off state
+ * Set AP to the off state. Disable functionality that should only be available
+ * when the AP is on.
*/
-static void set_ap_off(void)
+static void deferred_set_ap_off(void)
{
CPRINTS("AP off");
set_state(DEVICE_STATE_OFF);
@@ -77,12 +77,14 @@ static void set_ap_off(void)
if (board_deep_sleep_allowed())
enable_deep_sleep();
}
+DECLARE_DEFERRED(deferred_set_ap_off);
/**
* Move the AP to the ON state
*/
void set_ap_on(void)
{
+ hook_call_deferred(&deferred_set_ap_off_data, -1);
CPRINTS("AP on");
set_state(DEVICE_STATE_ON);
@@ -99,62 +101,48 @@ void set_ap_on(void)
disable_deep_sleep();
}
-/**
- * Detect state machine
+/*
+ * If TPM_RST_L is asserted, the AP is in reset. Disable all AP functionality
+ * in 1 second if it remains asserted.
*/
-static void ap_detect(void)
+void tpm_rst_asserted(enum gpio_signal unused)
{
- /* Handle detecting device */
- if (gpio_get_level(GPIO_TPM_RST_L)) {
- /*
- * It is important to check if the AP is already 'on' here, so
- * we don't call tpm_rst_deasserted() when the AP is already on.
- *
- * If we were debouncing ON->OFF, cancel debouncing and go back
- * to the ON state.
- */
- if (state == DEVICE_STATE_DEBOUNCING)
- set_state(DEVICE_STATE_ON);
- /* If AP is already on, nothing needs to be done */
- if (state == DEVICE_STATE_ON)
- return;
-
- /*
- * The platform reset handler has not run yet; otherwise, it
- * would have already turned the AP on and we wouldn't get here.
- *
- * This can happen if the hook task calls ap_detect() before
- * deferred_tpm_rst_isr(). In this case, the deferred handler is
- * already pending so calling the ISR has no effect.
- *
- * But we may actually have missed the edge. In that case,
- * calling the ISR makes sure we don't miss the reset. It will
- * call set_ap_on() to move the AP to the ON state.
- */
- CPRINTS("AP detect calling tpm_rst_deasserted()");
- tpm_rst_deasserted(GPIO_TPM_RST_L);
- return;
- }
+ CPRINTS("%s", __func__);
- /* TPM_RST_L is asserted. If we're already off, done. */
- if (state == DEVICE_STATE_OFF)
- return;
+ /*
+ * It's possible the signal is being pulsed. Wait 1 second to disable
+ * functionality, so it's more likely the AP is fully off and not being
+ * reset.
+ */
+ hook_call_deferred(&deferred_set_ap_off_data, SECOND);
- /* If we were debouncing, we're now sure we're off */
- if (state == DEVICE_STATE_DEBOUNCING ||
- state == DEVICE_STATE_INIT_DEBOUNCING) {
- set_ap_off();
- return;
- }
+ set_state(DEVICE_STATE_DEBOUNCING);
+}
+/**
+ * Check the initial AP state.
+ */
+static void init_ap_detect(void)
+{
+ /* Enable interrupts for AP state detection */
+ gpio_enable_interrupt(GPIO_TPM_RST_L);
+ gpio_enable_interrupt(GPIO_DETECT_TPM_RST_L_ASSERTED);
/*
- * Otherwise, we were on before and haven't detected the AP off. We
- * don't know if thats because the AP is actually off, or because the
- * TPM_RST_L signal is being pulsed for a short reset. Start debouncing.
+ * Enable TPM reset GPIO interrupt.
+ *
+ * If the TPM_RST_L signal is already high when cr50 wakes up or
+ * transitions to high before we are able to configure the gpio then we
+ * will have missed the edge and the tpm reset isr will not get
+ * called. Check that we haven't already missed the rising edge. If we
+ * have alert tpm_rst_isr.
*/
- if (state == DEVICE_STATE_INIT)
- set_state(DEVICE_STATE_INIT_DEBOUNCING);
+ if (gpio_get_level(GPIO_TPM_RST_L))
+ tpm_rst_deasserted(GPIO_TPM_RST_L);
else
- set_state(DEVICE_STATE_DEBOUNCING);
+ tpm_rst_asserted(GPIO_TPM_RST_L);
}
-DECLARE_HOOK(HOOK_SECOND, ap_detect, HOOK_PRIO_DEFAULT);
+/*
+ * TPM_RST_L isn't setup until board_init. Make sure init_ap_detect happens
+ * after that.
+ */
+DECLARE_HOOK(HOOK_INIT, init_ap_detect, HOOK_PRIO_DEFAULT + 1);
diff --git a/board/cr50/board.c b/board/cr50/board.c
index e7e19a4577..3aa3693f16 100644
--- a/board/cr50/board.c
+++ b/board/cr50/board.c
@@ -582,7 +582,10 @@ static void configure_board_specific_gpios(void)
*/
if (board_use_plt_rst()) {
/* Use plt_rst_l as the tpm reset signal. */
+ /* Select for TPM_RST_L */
GWRITE(PINMUX, GPIO1_GPIO0_SEL, GC_PINMUX_DIOM3_SEL);
+ /* Select for DETECT_TPM_RST_L_ASSERTED */
+ GWRITE(PINMUX, GPIO1_GPIO4_SEL, GC_PINMUX_DIOM3_SEL);
/* Enable the input */
GWRITE_FIELD(PINMUX, DIOM3_CTL, IE, 1);
@@ -604,7 +607,10 @@ static void configure_board_specific_gpios(void)
GWRITE_FIELD(PINMUX, EXITEN0, DIOM3, 1);
} else {
/* Use sys_rst_l as the tpm reset signal. */
+ /* Select for TPM_RST_L */
GWRITE(PINMUX, GPIO1_GPIO0_SEL, GC_PINMUX_DIOM0_SEL);
+ /* Select for DETECT_TPM_RST_L_ASSERTED */
+ GWRITE(PINMUX, GPIO1_GPIO4_SEL, GC_PINMUX_DIOM0_SEL);
/* Enable the input */
GWRITE_FIELD(PINMUX, DIOM0_CTL, IE, 1);
@@ -738,19 +744,6 @@ static void board_init(void)
check_board_id_mismatch();
/*
- * Enable TPM reset GPIO interrupt.
- *
- * If the TPM_RST_L signal is already high when cr50 wakes up or
- * transitions to high before we are able to configure the gpio then we
- * will have missed the edge and the tpm reset isr will not get
- * called. Check that we haven't already missed the rising edge. If we
- * have alert tpm_rst_isr.
- */
- gpio_enable_interrupt(GPIO_TPM_RST_L);
- if (gpio_get_level(GPIO_TPM_RST_L))
- hook_call_deferred(&deferred_tpm_rst_isr_data, 0);
-
- /*
* Start monitoring AC detect to wake Cr50 from deep sleep. This is
* needed to detect RDD cable changes in deep sleep. AC detect is also
* used for battery cutoff software support on detachable devices.
diff --git a/board/cr50/board.h b/board/cr50/board.h
index 527dcd3e01..352afdc04f 100644
--- a/board/cr50/board.h
+++ b/board/cr50/board.h
@@ -244,6 +244,7 @@ void ec_detect_asserted(enum gpio_signal signal);
void ec_tx_cr50_rx(enum gpio_signal signal);
void servo_detect_asserted(enum gpio_signal signal);
void tpm_rst_deasserted(enum gpio_signal signal);
+void tpm_rst_asserted(enum gpio_signal signal);
void post_reboot_request(void);
diff --git a/board/cr50/gpio.inc b/board/cr50/gpio.inc
index b686fe008a..cd9348fd2c 100644
--- a/board/cr50/gpio.inc
+++ b/board/cr50/gpio.inc
@@ -67,6 +67,12 @@ GPIO_INT(DETECT_EC_UART, PIN(1, 2), GPIO_INT_HIGH, ec_detect_asserted)
*/
GPIO_INT(DETECT_SERVO, PIN(1, 3), GPIO_INT_HIGH | GPIO_PULL_DOWN,
servo_detect_asserted)
+/*
+ * Whan TPM_RST_L is asserted, the AP is in reset. Use this for detecting when
+ * the AP is off.
+ */
+GPIO_INT(DETECT_TPM_RST_L_ASSERTED, PIN(1, 4), GPIO_INT_FALLING,
+ tpm_rst_asserted)
/*****************************************************************************/
/* NON STANDARD INTERRUPT GPIOs - handlers defined and configured in board.c */