diff options
author | Mary Ruthven <mruthven@chromium.org> | 2016-08-18 18:35:45 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2016-09-16 17:43:32 -0700 |
commit | 17aa84b8b8ce45005d9672d22874bb42c511ac4b (patch) | |
tree | 493cfe6a670cee1eb3095c2425897714553ebf45 | |
parent | 7f507212c1a3aa56a42d41f2d5b6be053903ea0d (diff) | |
download | chrome-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.c | 33 | ||||
-rw-r--r-- | board/cr50/board.h | 1 | ||||
-rw-r--r-- | chip/g/idle.c | 39 |
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); |