summaryrefslogtreecommitdiff
path: root/chip/it83xx
diff options
context:
space:
mode:
authorDino Li <Dino.Li@ite.com.tw>2016-09-21 11:21:15 +0800
committerchrome-bot <chrome-bot@chromium.org>2016-09-21 19:37:17 -0700
commit0174d4f85bc83d9081c39de1d5399cab45c61a72 (patch)
treebcbd9a3b40e347822a7e864d23dd3e97f095bcef /chip/it83xx
parentc5d03154ee5e5d49d6d1c731dd22a551e1e6c04c (diff)
downloadchrome-ec-0174d4f85bc83d9081c39de1d5399cab45c61a72.tar.gz
it83xx: EC sleep mode for system hibernate
The typical power consumption in sleep mode is 65uA. IT83xx uses deep doze mode for low power idle task. The typical power consumption in this state is 280uA (depends on EC tasks, it should be more) and the wake up time is in microsecond. We are using deep doze mode for low power idle task instead of sleep mode is because the wake up time will be 6ms more. While in system hibernate (EC sleep mode), EC won't wake up frequently so we can keep the power consumption at 65uA. Signed-off-by: Dino Li <dino.li@ite.com.tw> BRANCH=none BUG=none TEST=- hibernate 0 [1|999999] - hibernate [1|5|10|600] - hibernate then press power button. - hibernate then lid open. Change-Id: I94884c010264f01ede4950c6bb1b0a444d7b1e6d Reviewed-on: https://chromium-review.googlesource.com/383332 Commit-Ready: Dino Li <dino0303@gmail.com> Tested-by: Dino Li <dino0303@gmail.com> Reviewed-by: Shawn N <shawnn@chromium.org>
Diffstat (limited to 'chip/it83xx')
-rw-r--r--chip/it83xx/clock.c59
-rw-r--r--chip/it83xx/intc.h2
-rw-r--r--chip/it83xx/registers.h4
-rw-r--r--chip/it83xx/system.c21
-rw-r--r--chip/it83xx/watchdog.c5
5 files changed, 74 insertions, 17 deletions
diff --git a/chip/it83xx/clock.c b/chip/it83xx/clock.c
index ab542aae6e..c353c7b326 100644
--- a/chip/it83xx/clock.c
+++ b/chip/it83xx/clock.c
@@ -10,6 +10,8 @@
#include "console.h"
#include "hwtimer.h"
#include "hwtimer_chip.h"
+#include "intc.h"
+#include "irq_chip.h"
#include "registers.h"
#include "system.h"
#include "task.h"
@@ -31,6 +33,7 @@ static int idle_doze_cnt;
static int idle_sleep_cnt;
static uint64_t total_idle_sleep_time_us;
static int allow_sleep;
+static uint32_t ec_sleep;
/*
* Fixed amount of time to keep the console in use flag true after boot in
* order to give a permanent window in which the heavy sleep mode is not used.
@@ -348,10 +351,66 @@ static int clock_allow_low_power_idle(void)
return 1;
}
+int clock_ec_wake_from_sleep(void)
+{
+ return ec_sleep;
+}
+
+void __enter_hibernate(uint32_t seconds, uint32_t microseconds)
+{
+ int i;
+
+ /* disable all interrupts */
+ interrupt_disable();
+ for (i = 0; i < IT83XX_IRQ_COUNT; i++) {
+ chip_disable_irq(i);
+ chip_clear_pending_irq(i);
+ }
+ /* bit5: watchdog is disabled. */
+ IT83XX_ETWD_ETWCTRL |= (1 << 5);
+ /* Setup GPIOs for hibernate */
+ if (board_hibernate_late)
+ board_hibernate_late();
+
+ if (seconds || microseconds) {
+ /* At least 1 ms for hibernate. */
+ uint64_t c = (seconds * 1000 + microseconds / 1000 + 1) * 1024;
+
+ uint64divmod(&c, 1000);
+ /* enable a 56-bit timer and clock source is 1.024 KHz */
+ ext_timer_stop(FREE_EXT_TIMER_L, 1);
+ ext_timer_stop(FREE_EXT_TIMER_H, 1);
+ IT83XX_ETWD_ETXPSR(FREE_EXT_TIMER_L) = EXT_PSR_1P024K_HZ;
+ IT83XX_ETWD_ETXPSR(FREE_EXT_TIMER_H) = EXT_PSR_1P024K_HZ;
+ IT83XX_ETWD_ETXCNTLR(FREE_EXT_TIMER_L) = c & 0xffffff;
+ IT83XX_ETWD_ETXCNTLR(FREE_EXT_TIMER_H) = (c >> 24) & 0xffffffff;
+ ext_timer_start(FREE_EXT_TIMER_H, 1);
+ ext_timer_start(FREE_EXT_TIMER_L, 0);
+ }
+
+ for (i = 0; i < hibernate_wake_pins_used; ++i)
+ gpio_enable_interrupt(hibernate_wake_pins[i]);
+
+ /* EC sleep */
+ ec_sleep = 1;
+ clock_ec_pll_ctrl(EC_PLL_SLEEP);
+ interrupt_enable();
+ /* standby instruction */
+ asm("standby wake_grant");
+
+ /* we should never reach that point */
+ while (1)
+ ;
+}
+
void clock_sleep_mode_wakeup_isr(void)
{
uint32_t st_us, c;
+ /* trigger a reboot if wake up EC from sleep mode (system hibernate) */
+ if (clock_ec_wake_from_sleep())
+ system_reset(SYSTEM_RESET_HARD);
+
if (IT83XX_ECPM_PLLCTRL == EC_PLL_DEEP_DOZE) {
clock_ec_pll_ctrl(EC_PLL_DOZE);
diff --git a/chip/it83xx/intc.h b/chip/it83xx/intc.h
index 73c69b3c96..129f5b63bf 100644
--- a/chip/it83xx/intc.h
+++ b/chip/it83xx/intc.h
@@ -21,5 +21,7 @@ void peci_interrupt(void);
void i2c_interrupt(int port);
int gpio_clear_pending_interrupt(enum gpio_signal signal);
void clock_sleep_mode_wakeup_isr(void);
+int clock_ec_wake_from_sleep(void);
+void __enter_hibernate(uint32_t seconds, uint32_t microseconds);
#endif /* __CROS_EC_INTC_H */
diff --git a/chip/it83xx/registers.h b/chip/it83xx/registers.h
index b46151cbdb..a90b5b72f2 100644
--- a/chip/it83xx/registers.h
+++ b/chip/it83xx/registers.h
@@ -1224,6 +1224,10 @@ enum usbpd_port {
USBPD_PORT_COUNT,
};
+/* Wake pin definitions, defined at board-level */
+extern const enum gpio_signal hibernate_wake_pins[];
+extern const int hibernate_wake_pins_used;
+
/* --- MISC (not implemented yet) --- */
#define IT83XX_PS2_BASE 0x00F01700
diff --git a/chip/it83xx/system.c b/chip/it83xx/system.c
index 64d6c09157..fee95f2611 100644
--- a/chip/it83xx/system.c
+++ b/chip/it83xx/system.c
@@ -10,6 +10,7 @@
#include "ec2i_chip.h"
#include "flash.h"
#include "host_command.h"
+#include "intc.h"
#include "registers.h"
#include "system.h"
#include "task.h"
@@ -17,23 +18,6 @@
#include "version.h"
#include "watchdog.h"
-void __no_hibernate(uint32_t seconds, uint32_t microseconds)
-{
-#ifdef CONFIG_COMMON_RUNTIME
- /*
- * Hibernate not implemented on this platform.
- *
- * Until then, treat this as a request to hard-reboot.
- */
- cprints(CC_SYSTEM, "hibernate not supported, so rebooting");
- cflush();
- system_reset(SYSTEM_RESET_HARD);
-#endif
-}
-
-void __enter_hibernate(uint32_t seconds, uint32_t microseconds)
- __attribute__((weak, alias("__no_hibernate")));
-
void system_hibernate(uint32_t seconds, uint32_t microseconds)
{
#ifdef CONFIG_HOSTCMD_PD
@@ -142,6 +126,9 @@ void system_reset(int flags)
else
save_flags |= RESET_FLAG_SOFT;
+ if (clock_ec_wake_from_sleep())
+ save_flags |= RESET_FLAG_HIBERNATE;
+
/* Store flags to battery backed RAM. */
BRAM_RESET_FLAGS = save_flags >> 24;
BRAM_RESET_FLAGS1 = (save_flags >> 16) & 0xff;
diff --git a/chip/it83xx/watchdog.c b/chip/it83xx/watchdog.c
index 6c15afc60a..1bbba6ceb3 100644
--- a/chip/it83xx/watchdog.c
+++ b/chip/it83xx/watchdog.c
@@ -63,8 +63,13 @@ int watchdog_init(void)
/* Set WDT key match enabled and WDT clock to use ET1PSR. */
IT83XX_ETWD_ETWCFG = 0x30;
+#ifdef CONFIG_HIBERNATE
+ /* bit4: watchdog can be stopped. */
+ IT83XX_ETWD_ETWCTRL |= (1 << 4);
+#else
/* Specify that watchdog cannot be stopped. */
IT83XX_ETWD_ETWCTRL = 0x00;
+#endif
/* Start WDT_EXT_TIMER (CONFIG_AUX_TIMER_PERIOD_MS ms). */
ext_timer_ms(WDT_EXT_TIMER, EXT_PSR_32P768K_HZ, 1, 1,