summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMary Ruthven <mruthven@chromium.org>2016-08-18 18:35:45 -0700
committerchrome-bot <chrome-bot@chromium.org>2016-09-16 17:43:32 -0700
commit17aa84b8b8ce45005d9672d22874bb42c511ac4b (patch)
tree493cfe6a670cee1eb3095c2425897714553ebf45
parent7f507212c1a3aa56a42d41f2d5b6be053903ea0d (diff)
downloadchrome-ec-17aa84b8b8ce45005d9672d22874bb42c511ac4b.tar.gz
cr50: enable deep sleep on chipset shutdown
On CHIPSET_SHUTDOWN set the idle_action to deep sleep. If sleep is enabled it will go into deep sleep. If not it will wait until sleep is sleep is enabled. This change also sets the idle_action to IDLE_DEFAULT when resuming from deep sleep or during init. Before cr50 kept track of the previous idle state in a PWRDN register and then used that state during the next resume. If we went into deep sleep, on resume we want the idle action to be reset to sleep and then only enter deep sleep if we have detected the AP is off. BUG=chrome-os-partner:56100 BUG=chrome-os-partner:55747 BRANCH=none TEST=manual run 'poweroff' on the AP and see that cr50 enables deep sleep verify that even if the ap is powered off it doesn't prevent ccd from working and when suzyq is unplugged cr50 will go into deep sleep After running poweroff on the AP wait a while and run powerbtn on the EC. Verify the system can boot up fully without going into recovery. Do this on gru and reef. Change-Id: I07f5a9d85dd0467cd22e499d4261c75caf653563 Signed-off-by: Mary Ruthven <mruthven@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/373139 Reviewed-by: Bill Richardson <wfrichar@chromium.org>
-rw-r--r--board/cr50/board.c33
-rw-r--r--board/cr50/board.h1
-rw-r--r--chip/g/idle.c39
3 files changed, 55 insertions, 18 deletions
diff --git a/board/cr50/board.c b/board/cr50/board.c
index 575d3511dd..c80c2f3930 100644
--- a/board/cr50/board.c
+++ b/board/cr50/board.c
@@ -123,7 +123,12 @@ void pmu_wakeup_interrupt(void)
*/
delay_sleep_by(3 * MINUTE);
- if (!gpio_get_level(GPIO_SYS_RST_L_IN))
+ /*
+ * If sys_rst_l is configured to wake on low and the signal is
+ * low then call sys_rst_asserted
+ */
+ if (!gpio_get_level(GPIO_SYS_RST_L_IN) &&
+ GREAD_FIELD(PINMUX, EXITINV0, DIOM0))
sys_rst_asserted(GPIO_SYS_RST_L_IN);
}
@@ -138,6 +143,32 @@ void pmu_wakeup_interrupt(void)
}
DECLARE_IRQ(GC_IRQNUM_PMU_INTR_WAKEUP_INT, pmu_wakeup_interrupt, 1);
+void board_configure_deep_sleep_wakepins(void)
+{
+ /*
+ * Disable the i2c and spi slave wake sources since the TPM is
+ * not being used and reenable them in their init functions on
+ * resume.
+ */
+ GWRITE_FIELD(PINMUX, EXITEN0, DIOA12, 0); /* SPS_CS_L */
+ /* TODO remove i2cs wake event */
+
+ /*
+ * Whether it is a short pulse or long one waking on the rising edge is
+ * fine because the goal of sys_rst is to reset the TPM and after
+ * resuming from deep sleep the TPM will be reset. Cr50 doesn't need to
+ * read the low value and then reset.
+ *
+ * Configure cr50 to resume on the rising edge of sys_rst_l
+ */
+ /* Disable sys_rst_l as a wake pin */
+ GWRITE_FIELD(PINMUX, EXITEN0, DIOM0, 0);
+ /* Reconfigure and reenable it. */
+ GWRITE_FIELD(PINMUX, EXITEDGE0, DIOM0, 1); /* edge sensitive */
+ GWRITE_FIELD(PINMUX, EXITINV0, DIOM0, 0); /* wake on high */
+ GWRITE_FIELD(PINMUX, EXITEN0, DIOM0, 1); /* enable powerdown exit */
+}
+
static void init_interrupts(void)
{
int i;
diff --git a/board/cr50/board.h b/board/cr50/board.h
index de0ced7d36..c7814e5b36 100644
--- a/board/cr50/board.h
+++ b/board/cr50/board.h
@@ -123,6 +123,7 @@ enum usb_spi {
USB_SPI_EC,
};
+void board_configure_deep_sleep_wakepins(void);
/* Interrupt handler */
void sys_rst_asserted(enum gpio_signal signal);
void device_state_on(enum gpio_signal signal);
diff --git a/chip/g/idle.c b/chip/g/idle.c
index d1250115f2..5486cebaa9 100644
--- a/chip/g/idle.c
+++ b/chip/g/idle.c
@@ -5,6 +5,7 @@
#include "common.h"
#include "console.h"
+#include "hooks.h"
#include "hwtimer.h"
#include "rdd.h"
#include "registers.h"
@@ -101,13 +102,8 @@ static void prepare_to_sleep(void)
/* Clear upcoming events. They don't matter in deep sleep */
__hw_clock_event_clear();
- /*
- * Disable the i2c and spi slave wake sources since the TPM is
- * not being used and reenable them in their init functions on
- * resume.
- */
- GWRITE_FIELD(PINMUX, EXITEN0, DIOA12, 0); /* SPS_CS_L */
- /* TODO remove i2cs wake event */
+ /* Configure pins for deep sleep */
+ board_configure_deep_sleep_wakepins();
/*
* Preserve some state prior to deep sleep. Pretty much all we
@@ -115,8 +111,6 @@ static void prepare_to_sleep(void)
* reinitialized on resume.
*/
GREG32(PMU, PWRDN_SCRATCH18) = GR_USB_DCFG;
- /* And the idle action */
- GREG32(PMU, PWRDN_SCRATCH17) = idle_action;
/* Latch the pinmux values */
GREG32(PINMUX, HOLD) = 1;
@@ -166,22 +160,33 @@ void clock_refresh_console_in_use(void)
delay_sleep_by(10 * SECOND);
}
+void disable_deep_sleep(void)
+{
+ idle_action = IDLE_DEFAULT;
+}
+DECLARE_HOOK(HOOK_CHIPSET_RESUME, disable_deep_sleep, HOOK_PRIO_DEFAULT);
+
+void enable_deep_sleep(void)
+{
+ idle_action = IDLE_DEEP_SLEEP;
+}
+DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, enable_deep_sleep, HOOK_PRIO_DEFAULT);
+
/* Custom idle task, executed when no tasks are ready to be scheduled. */
void __idle(void)
{
int sleep_ok, sleep_delay_passed, next_evt_us;
/*
- * This register is preserved across soft reboots, but not hard. It
- * defaults to zero, which is how we can tell whether this is the
- * preserved value or not. We only need to remember it because we might
- * change it with the console command.
+ * On init or resume from deep sleep set the idle action to default. If
+ * it should be something else it will be determined during runtime.
+ *
+ * Before changing idle_action check that it is not already set. It is
+ * possible that HOOK_CHIPSET_RESUME or SHUTDOWN were triggered before
+ * this and set the idle_action.
*/
- idle_action = GREG32(PMU, PWRDN_SCRATCH17);
- if (idle_action == DONT_KNOW || idle_action >= NUM_CHOICES) {
+ if (!idle_action)
idle_action = IDLE_DEFAULT;
- GREG32(PMU, PWRDN_SCRATCH17) = idle_action;
- }
/* Disable sleep until 3 minutes after init */
delay_sleep_by(3 * MINUTE);