summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/cr50/ap_state.c70
-rw-r--r--board/cr50/board.c2
-rw-r--r--board/cr50/board.h1
-rw-r--r--common/extension.c1
-rw-r--r--include/tpm_vendor_cmds.h8
5 files changed, 81 insertions, 1 deletions
diff --git a/board/cr50/ap_state.c b/board/cr50/ap_state.c
index 97b08acbb3..79506b2a2e 100644
--- a/board/cr50/ap_state.c
+++ b/board/cr50/ap_state.c
@@ -6,6 +6,7 @@
*/
#include "ap_ro_integrity_check.h"
#include "ec_commands.h"
+#include "extension.h"
#include "gpio.h"
#include "hooks.h"
#include "registers.h"
@@ -15,9 +16,11 @@
#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ## args)
static enum device_state state = DEVICE_STATE_INIT;
+static bool disable_ds_temp;
void print_ap_state(void)
{
+ ccprintf("DS Dis: %s\n", disable_ds_temp ? "on" : "off");
ccprintf("AP: %s\n", device_state_name(state));
}
@@ -26,6 +29,46 @@ int ap_is_on(void)
return state == DEVICE_STATE_ON;
}
+void pmu_check_tpm_rst(void)
+{
+ /*
+ * disable_ds_temp modifies the GPIO_TPM_RST_L wake settings to
+ * WAKE_HIGH. With that setting it's possible to miss a rising edge.
+ * If TPM_RST_L is high, but the ap state isn't on, cr50 missed the
+ * edge. Trigger the interrupt manually.
+ */
+ if (disable_ds_temp && !ap_is_on() &&
+ gpio_get_level(GPIO_TPM_RST_L)) {
+ tpm_rst_deasserted(GPIO_TPM_RST_L);
+ CPRINTS("Missed edge");
+ }
+}
+
+/*
+ * Disable deep sleep during the next TPM_RST_L pulse
+ *
+ * Normally cr50 enters deep sleep while TPM_RST_L is asserted. This vendor
+ * command can be used to disable deep sleep the next time TPM_RST_L is
+ * asserted.
+ *
+ * This can be run on any board with any CCD state.
+ */
+static enum vendor_cmd_rc vc_ds_disable_temp(enum vendor_cmd_cc code,
+ void *buf,
+ size_t input_size,
+ size_t *response_size)
+{
+ *response_size = 0;
+ if (input_size)
+ return VENDOR_RC_BOGUS_ARGS;
+
+ disable_ds_temp = true;
+ CPRINTS("dis DS");
+
+ return VENDOR_RC_SUCCESS;
+}
+DECLARE_VENDOR_COMMAND(VENDOR_CC_DS_DIS_TEMP, vc_ds_disable_temp);
+
/**
* Set the AP state.
*
@@ -75,8 +118,17 @@ static void deferred_set_ap_off(void)
* Note: Presence of platform reset is a poor indicator of deep sleep
* support. It happens to be correlated with ARM vs x86 at present.
*/
- if (board_deep_sleep_allowed())
+ if (disable_ds_temp) {
+ CPRINTS("Block DS");
+ disable_deep_sleep();
+ /*
+ * TPM_RST_L will stay asserted until the system resumes.
+ * Wake from sleep when it goes high.
+ */
+ gpio_set_wakepin(GPIO_TPM_RST_L, GPIO_HIB_WAKE_HIGH);
+ } else if (board_deep_sleep_allowed()) {
enable_deep_sleep();
+ }
}
DECLARE_DEFERRED(deferred_set_ap_off);
@@ -100,6 +152,22 @@ void set_ap_on(void)
if (board_deep_sleep_allowed())
disable_deep_sleep();
+
+
+ /*
+ * Restore TPM_RST_L wake low now that TPM_RST_L has been
+ * deasserted. Only change the TPM_RST_L wake setting if cr50 blocked
+ * deep sleep.
+ */
+ if (disable_ds_temp) {
+ CPRINTS("set TPM wake");
+ gpio_set_wakepin(GPIO_TPM_RST_L, GPIO_HIB_WAKE_LOW);
+ }
+ /*
+ * disable_ds_temp only survives one TPM_RST_L pulse. Clear it when
+ * the AP turns back on.
+ */
+ disable_ds_temp = false;
}
static uint8_t waiting_for_ap_reset;
diff --git a/board/cr50/board.c b/board/cr50/board.c
index 4f0ea7b66a..323b7d4d71 100644
--- a/board/cr50/board.c
+++ b/board/cr50/board.c
@@ -552,6 +552,8 @@ void pmu_wakeup_interrupt(void)
if (wakeup_src & GC_PMU_EXITPD_SRC_PIN_PD_EXIT_MASK) {
reset_wake_logic();
+ pmu_check_tpm_rst();
+
/*
* Delay sleep long enough for a SPI periph transaction to start
* or for the system to be reset.
diff --git a/board/cr50/board.h b/board/cr50/board.h
index 1e9e0f72d3..a42df3038f 100644
--- a/board/cr50/board.h
+++ b/board/cr50/board.h
@@ -395,6 +395,7 @@ void print_ap_uart_state(void);
void print_ec_state(void);
void print_servo_state(void);
+void pmu_check_tpm_rst(void);
int ap_is_on(void);
int ap_uart_is_on(void);
int ec_is_on(void);
diff --git a/common/extension.c b/common/extension.c
index 055cfcb031..92e4798dce 100644
--- a/common/extension.c
+++ b/common/extension.c
@@ -36,6 +36,7 @@ uint32_t extension_route_command(struct vendor_cmd_params *p)
case VENDOR_CC_ENDORSEMENT_SEED:
case VENDOR_CC_RESET_EC:
case VENDOR_CC_POP_LOG_ENTRY:
+ case VENDOR_CC_DS_DIS_TEMP:
#endif /* defined(CR50_DEV) */
case EXTENSION_POST_RESET: /* Always need to reset. */
case VENDOR_CC_CCD:
diff --git a/include/tpm_vendor_cmds.h b/include/tpm_vendor_cmds.h
index 73647eca5a..a59c81e10f 100644
--- a/include/tpm_vendor_cmds.h
+++ b/include/tpm_vendor_cmds.h
@@ -157,6 +157,14 @@ enum vendor_cmd_cc {
VENDOR_CC_AP_RO_VALIDATE = 58,
+ /*
+ * Vendor command to disable deep sleep during the next TPM_RST_L
+ * assertion. Cr50 used to use 22 to do this. It can't reuse that
+ * because some old boards still send it, and deep sleep shouldn't
+ * be disabled on those boards.
+ */
+ VENDOR_CC_DS_DIS_TEMP = 59,
+
LAST_VENDOR_COMMAND = 65535,
};