summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMary Ruthven <mruthven@chromium.org>2022-01-21 10:25:45 -0600
committerCommit Bot <commit-bot@chromium.org>2022-01-26 22:32:40 +0000
commit12d62b7996952bb8108af286e312481cecad02a1 (patch)
tree1f074644a12d7946714560e6d8d7aa58c3e206d2
parenta65cd8208381364b523f00baae1478c714512acf (diff)
downloadchrome-ec-12d62b7996952bb8108af286e312481cecad02a1.tar.gz
add vendor command to disable deep sleep
Add a vendor command to disable deep sleep the next time TPM_RST_L is asserted. Normally cr50 enters deep sleep whenever TPM_RST_L is asserted. New boards want to disable deep sleep during certain power states. This vendor command allows the AP to disable deep sleep for the next suspend cycle. When deep sleep is disabled, cr50 modifies TPM_RST_L to be WAKE_HIGH and sets it back to WAKE_LOW after TPM_RST_L is deasserted, so TPM_RST_L doesn't constantly wake cr50 from regular sleep. This uses 248 bytes BUG=b:214479456 TEST=manual # Check G3 resume works ok. # Disable Deep Sleep from the AP. The vendor command is 59 # (0x3b) trunks_send --raw 80010000000c20000000003b ccdstate DS Dis: on AP > shutdown -P now ... [454.992733 Block DS] ccdstate DS Dis: on pinmux 40060018: DIOM3 0 IN WAKE_HIGH idle idle action: sleep # Verify cr50 starts cycling through sleep spinner at two ticks # a second. EC > powerbtn # check the cr50 console ... Aï¿œUART on] 10/ 1 [102.484012 Missed edge] [102.484352 deferred_tpm_rst_isr] [102.484580 AP on] [102.484779 set TPM wake] [102.484981 tpm_reset_request(0, 0)] [102.485279 tpm_reset_now(0)] [547.928375 AP on] [547.928615 set TPM wake] pinmux 40060018: DIOM3 0 IN WAKE_LOW # Disable Deep Sleep from the AP. The vendor command is 59 # (0x3b) trunks_send --raw 80010000000c20000000003b ccdstate DS Dis: on ecrst pulse ... [602.638427 AP on] [547.928615 set TPM wake] [602.638668 tpm_reset_request(0, 0)] ... ccdstate DS Dis: off # Check S3 resume works ok. # Use AP commands to enter S3 AP > trunks_send --raw 80010000000c20000000003b AP > echo deep > /sys/power/mem_sleep AP > echo mem > /sys/power/state 10\ 1 [243.409412 dis DS] 1|[249.536811 tpm_rst_asserted] [250.537197 AP off] [250.537631 Block DS] # Wake the AP with a power button press from the EC EC > powerbtn # verify cr50 prints "Missed edge", but the device resumes ok. 1/ 10- 1 [270.112655 Missed edge] [270.113037 deferred_tpm_rst_isr] [270.113315 AP on] [270.113529 set TPM wake] [270.113712 tpm_reset_request(0, 0)] [270.114013 tpm_reset_now(0)] [270.116996 tpm_init] tpm_manufactured: manufactured [270.118301 tpm_reset_now: done] [270.156967 PinWeaver: Loading Tree!] [270.189353 Skipping commit] Change-Id: I96049a9d38b5c66acad9c73628f588f4cf6b2b3f Signed-off-by: Mary Ruthven <mruthven@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3406587 Reviewed-by: Vadim Bendebury <vbendeb@chromium.org> Commit-Queue: Vadim Bendebury <vbendeb@chromium.org>
-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,
};