summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/falco/board.c9
-rw-r--r--board/falco/board.h2
-rw-r--r--board/peppy/board.c9
-rw-r--r--board/peppy/board.h2
-rw-r--r--board/slippy/board.c9
-rw-r--r--board/slippy/board.h2
-rw-r--r--chip/lm4/clock.c132
-rw-r--r--chip/lm4/gpio.c12
-rw-r--r--chip/lm4/jtag.c28
-rw-r--r--chip/lm4/uart.c73
-rw-r--r--chip/stm32/clock-stm32f.c8
-rw-r--r--common/console.c7
-rw-r--r--common/system_common.c26
-rw-r--r--common/uart_buffering.c5
-rw-r--r--include/clock.h5
-rw-r--r--include/gpio.h12
-rw-r--r--include/jtag.h12
-rw-r--r--include/system.h21
-rw-r--r--include/uart.h32
19 files changed, 384 insertions, 22 deletions
diff --git a/board/falco/board.c b/board/falco/board.c
index e6efae41c2..486239ae82 100644
--- a/board/falco/board.c
+++ b/board/falco/board.c
@@ -17,6 +17,7 @@
#include "gpio.h"
#include "host_command.h"
#include "i2c.h"
+#include "jtag.h"
#include "keyboard_scan.h"
#include "lid_switch.h"
#include "lm4_adc.h"
@@ -27,6 +28,7 @@
#include "temp_sensor.h"
#include "temp_sensor_g781.h"
#include "timer.h"
+#include "uart.h"
#include "util.h"
/* GPIO signal list. Must match order from enum gpio_signal. */
@@ -62,6 +64,11 @@ const struct gpio_info gpio_list[] = {
switch_interrupt},
{"WP_L", LM4_GPIO_A, (1<<4), GPIO_INT_BOTH,
switch_interrupt},
+ {"JTAG_TCK", LM4_GPIO_C, (1<<0), GPIO_DEFAULT,
+ jtag_interrupt},
+ {"UART0_RX", LM4_GPIO_A, (1<<0), GPIO_PULL_UP|
+ GPIO_INT_BOTH_DSLEEP,
+ uart_deepsleep_interrupt},
/* Other inputs */
{"FAN_ALERT_L", LM4_GPIO_B, (1<<0), GPIO_INPUT, NULL},
@@ -127,7 +134,7 @@ BUILD_ASSERT(ARRAY_SIZE(gpio_list) == GPIO_COUNT);
/* Pins with alternate functions */
const struct gpio_alt_func gpio_alt_funcs[] = {
- {GPIO_A, 0x03, 1, MODULE_UART}, /* UART0 */
+ {GPIO_A, 0x03, 1, MODULE_UART, GPIO_PULL_UP}, /* UART0 */
{GPIO_A, 0x40, 3, MODULE_I2C}, /* I2C1 SCL */
{GPIO_A, 0x80, 3, MODULE_I2C, GPIO_OPEN_DRAIN}, /* I2C1 SDA */
{GPIO_B, 0x04, 3, MODULE_I2C}, /* I2C0 SCL */
diff --git a/board/falco/board.h b/board/falco/board.h
index 5587506464..a42b5c3dd2 100644
--- a/board/falco/board.h
+++ b/board/falco/board.h
@@ -89,6 +89,8 @@ enum gpio_signal {
GPIO_PCH_EDP_VDD_EN, /* PCH wants EDP enabled */
GPIO_RECOVERY_L, /* Recovery signal from servo */
GPIO_WP_L, /* Write protect input */
+ GPIO_JTAG_TCK, /* JTAG clock input */
+ GPIO_UART0_RX, /* UART0 RX input */
/* Other inputs */
GPIO_FAN_ALERT_L, /* From thermal sensor */
diff --git a/board/peppy/board.c b/board/peppy/board.c
index f3f2376dd1..57c0a75f9e 100644
--- a/board/peppy/board.c
+++ b/board/peppy/board.c
@@ -15,6 +15,7 @@
#include "gpio.h"
#include "host_command.h"
#include "i2c.h"
+#include "jtag.h"
#include "keyboard_scan.h"
#include "lid_switch.h"
#include "lm4_adc.h"
@@ -25,6 +26,7 @@
#include "temp_sensor.h"
#include "temp_sensor_g781.h"
#include "timer.h"
+#include "uart.h"
#include "util.h"
/* GPIO signal list. Must match order from enum gpio_signal. */
@@ -60,6 +62,11 @@ const struct gpio_info gpio_list[] = {
switch_interrupt},
{"WP_L", LM4_GPIO_A, (1<<4), GPIO_INT_BOTH,
switch_interrupt},
+ {"JTAG_TCK", LM4_GPIO_C, (1<<0), GPIO_DEFAULT,
+ jtag_interrupt},
+ {"UART0_RX", LM4_GPIO_A, (1<<0), GPIO_PULL_UP|
+ GPIO_INT_BOTH_DSLEEP,
+ uart_deepsleep_interrupt},
/* Other inputs */
{"FAN_ALERT_L", LM4_GPIO_B, (1<<0), GPIO_INPUT, NULL},
@@ -126,7 +133,7 @@ BUILD_ASSERT(ARRAY_SIZE(gpio_list) == GPIO_COUNT);
/* Pins with alternate functions */
const struct gpio_alt_func gpio_alt_funcs[] = {
- {GPIO_A, 0x03, 1, MODULE_UART}, /* UART0 */
+ {GPIO_A, 0x03, 1, MODULE_UART, GPIO_PULL_UP}, /* UART0 */
{GPIO_B, 0x04, 3, MODULE_I2C}, /* I2C0 SCL */
{GPIO_B, 0x08, 3, MODULE_I2C, GPIO_OPEN_DRAIN}, /* I2C0 SDA */
{GPIO_B, 0x40, 3, MODULE_I2C}, /* I2C5 SCL */
diff --git a/board/peppy/board.h b/board/peppy/board.h
index 94d6efa0ff..5f602bb826 100644
--- a/board/peppy/board.h
+++ b/board/peppy/board.h
@@ -90,6 +90,8 @@ enum gpio_signal {
GPIO_PCH_EDP_VDD_EN, /* PCH wants EDP enabled */
GPIO_RECOVERY_L, /* Recovery signal from servo */
GPIO_WP_L, /* Write protect input */
+ GPIO_JTAG_TCK, /* JTAG clock input */
+ GPIO_UART0_RX, /* UART0 RX input */
/* Other inputs */
GPIO_FAN_ALERT_L, /* From thermal sensor */
diff --git a/board/slippy/board.c b/board/slippy/board.c
index fc170c76f9..bee38b3451 100644
--- a/board/slippy/board.c
+++ b/board/slippy/board.c
@@ -15,6 +15,7 @@
#include "gpio.h"
#include "host_command.h"
#include "i2c.h"
+#include "jtag.h"
#include "keyboard_scan.h"
#include "lid_switch.h"
#include "lm4_adc.h"
@@ -25,6 +26,7 @@
#include "temp_sensor.h"
#include "temp_sensor_g781.h"
#include "timer.h"
+#include "uart.h"
#include "util.h"
/* GPIO signal list. Must match order from enum gpio_signal. */
@@ -60,6 +62,11 @@ const struct gpio_info gpio_list[] = {
switch_interrupt},
{"WP_L", LM4_GPIO_A, (1<<4), GPIO_INT_BOTH,
switch_interrupt},
+ {"JTAG_TCK", LM4_GPIO_C, (1<<0), GPIO_DEFAULT,
+ jtag_interrupt},
+ {"UART0_RX", LM4_GPIO_A, (1<<0), GPIO_PULL_UP|
+ GPIO_INT_BOTH_DSLEEP,
+ uart_deepsleep_interrupt},
/* Other inputs */
{"FAN_ALERT_L", LM4_GPIO_B, (1<<0), GPIO_INPUT, NULL},
@@ -124,7 +131,7 @@ BUILD_ASSERT(ARRAY_SIZE(gpio_list) == GPIO_COUNT);
/* Pins with alternate functions */
const struct gpio_alt_func gpio_alt_funcs[] = {
- {GPIO_A, 0x03, 1, MODULE_UART}, /* UART0 */
+ {GPIO_A, 0x03, 1, MODULE_UART, GPIO_PULL_UP}, /* UART0 */
{GPIO_B, 0x04, 3, MODULE_I2C}, /* I2C0 SCL */
{GPIO_B, 0x08, 3, MODULE_I2C, GPIO_OPEN_DRAIN}, /* I2C0 SDA */
{GPIO_B, 0x40, 3, MODULE_I2C}, /* I2C5 SCL */
diff --git a/board/slippy/board.h b/board/slippy/board.h
index fb88f4826e..532b9394b8 100644
--- a/board/slippy/board.h
+++ b/board/slippy/board.h
@@ -88,6 +88,8 @@ enum gpio_signal {
GPIO_PCH_EDP_VDD_EN, /* PCH wants EDP enabled */
GPIO_RECOVERY_L, /* Recovery signal from servo */
GPIO_WP_L, /* Write protect input */
+ GPIO_JTAG_TCK, /* JTAG clock input */
+ GPIO_UART0_RX, /* UART0 RX input */
/* Other inputs */
GPIO_FAN_ALERT_L, /* From thermal sensor */
diff --git a/chip/lm4/clock.c b/chip/lm4/clock.c
index 478cb796eb..bbd2e503d1 100644
--- a/chip/lm4/clock.c
+++ b/chip/lm4/clock.c
@@ -16,6 +16,7 @@
#include "system.h"
#include "task.h"
#include "timer.h"
+#include "uart.h"
#include "util.h"
#include "watchdog.h"
@@ -27,9 +28,11 @@
/*
* Length of time for the processor to wake up from deep sleep. Actual
- * measurement gives anywhere from 75-200us, so this is conservative.
+ * measurement gives anywhere up to 780us, depending on the mode it is coming
+ * out of. The datasheet gives a maximum of 846us, for coming out of deep
+ * sleep in our worst case deep sleep mode.
*/
-#define DEEP_SLEEP_RECOVER_TIME_USEC 300
+#define DEEP_SLEEP_RECOVER_TIME_USEC 850
/* Low power idle statistics */
#ifdef CONFIG_LOW_POWER_IDLE
@@ -37,6 +40,15 @@ static int idle_sleep_cnt;
static int idle_dsleep_cnt;
static uint64_t idle_dsleep_time_us;
static int dsleep_recovery_margin_us = 1000000;
+
+/*
+ * Fixed amount of time to keep the console in use flag true after boot in
+ * order to give a permanent window in which the low speed clock is not used.
+ */
+#define CONSOLE_IN_USE_ON_BOOT_TIME (15*SECOND)
+
+static int console_in_use_timeout_sec = 60;
+static timestamp_t console_expire_time;
#endif
static int freq;
@@ -207,12 +219,23 @@ void clock_disable_peripheral(uint32_t offset, uint32_t mask, uint32_t mode)
#ifdef CONFIG_LOW_POWER_IDLE
+void clock_refresh_console_in_use(void)
+{
+ disable_sleep(SLEEP_MASK_CONSOLE);
+
+ /* Set console in use expire time. */
+ console_expire_time = get_time();
+ console_expire_time.val += console_in_use_timeout_sec * SECOND;
+
+}
+
/* Low power idle task. Executed when no tasks are ready to be scheduled. */
void __idle(void)
{
timestamp_t t0, t1, rtc_t0, rtc_t1;
int next_delay = 0;
int time_for_dsleep, margin_us;
+ int use_lfiosc;
/* Enable the hibernate IRQ used to wake up from deep sleep */
system_enable_hib_interrupt();
@@ -220,6 +243,17 @@ void __idle(void)
/* Set SRAM and flash power management to 'low power' in deep sleep. */
LM4_SYSTEM_DSLPPWRCFG = 0x23;
+ /* Enable JTAG interrupt which will notify us when JTAG is in use. */
+ gpio_enable_interrupt(GPIO_JTAG_TCK);
+
+ /*
+ * Initialize console in use to true and specify the console expire
+ * time in order to give a fixed window on boot in which the low speed
+ * clock will not be used in idle.
+ */
+ disable_sleep(SLEEP_MASK_CONSOLE);
+ console_expire_time.val = get_time().val + CONSOLE_IN_USE_ON_BOOT_TIME;
+
/*
* Print when the idle task starts. This is the lowest priority task,
* so this only starts once all other tasks have gotten a chance to do
@@ -243,10 +277,50 @@ void __idle(void)
time_for_dsleep = next_delay > (DEEP_SLEEP_RECOVER_TIME_USEC +
HIB_SET_RTC_MATCH_DELAY_USEC);
- if (!sleep_mask && time_for_dsleep) {
+ if (DEEP_SLEEP_ALLOWED && time_for_dsleep) {
/* Deep-sleep in STOP mode. */
idle_dsleep_cnt++;
+ /* Check if the console use has expired. */
+ if ((sleep_mask & SLEEP_MASK_CONSOLE) &&
+ t0.val > console_expire_time.val) {
+ /* Enable low speed deep sleep. */
+ enable_sleep(SLEEP_MASK_CONSOLE);
+
+ /*
+ * Wait one clock before checking if low speed
+ * deep sleep is allowed to give time for
+ * sleep mask to update.
+ */
+ clock_wait_cycles(1);
+
+ if (LOW_SPEED_DEEP_SLEEP_ALLOWED)
+ CPRINTF("[%T Disabling console in "
+ "deep sleep]\n");
+ }
+
+ /*
+ * Determine if we should use the LFIOSC (30kHz) or the
+ * PIOSC (16MHz) for the clock in deep sleep. Use the
+ * LFIOSC only if the sleep mask specifies that low
+ * speed sleep is allowed, the console UART TX is not
+ * busy, and the console UART buffer is empty.
+ */
+ use_lfiosc = LOW_SPEED_DEEP_SLEEP_ALLOWED &&
+ !uart_tx_in_progress() && uart_buffer_empty();
+
+ /* Set the deep sleep clock register. */
+ LM4_SYSTEM_DSLPCLKCFG = use_lfiosc ? 0x32 : 0x10;
+
+ /*
+ * If using low speed (LFIOSC) clock, disable console.
+ * This will also convert the console RX pin to a GPIO
+ * and set an edge interrupt to wake us from deep sleep
+ * if any action occurs on console.
+ */
+ if (use_lfiosc)
+ uart_enter_dsleep();
+
/* Set deep sleep bit. */
CPU_SCB_SYSCTRL |= 0x4;
@@ -274,6 +348,10 @@ void __idle(void)
t1.val = t0.val + (rtc_t1.val - rtc_t0.val);
force_time(t1);
+ /* If using low speed clock, re-enable the console. */
+ if (use_lfiosc)
+ uart_exit_dsleep();
+
/* Record time spent in deep sleep. */
idle_dsleep_time_us += (rtc_t1.val - rtc_t0.val);
@@ -615,5 +693,53 @@ DECLARE_CONSOLE_COMMAND(idlestats, command_idle_stats,
"",
"Print last idle stats",
NULL);
+
+/**
+ * Configure deep sleep clock settings.
+ */
+static int command_dsleepmask(int argc, char **argv)
+{
+ int v;
+
+ if (argc > 1) {
+ if (parse_bool(argv[1], &v)) {
+ /*
+ * Force deep sleep not to use low speed clock or
+ * allow it to use the low speed clock.
+ */
+ if (v)
+ disable_sleep(SLEEP_MASK_FORCE_NO_LOW_SPEED);
+ else
+ enable_sleep(SLEEP_MASK_FORCE_NO_LOW_SPEED);
+ } else {
+ /* Set console in use timeout. */
+ char *e;
+ v = strtoi(argv[1], &e, 10);
+ if (*e)
+ return EC_ERROR_PARAM1;
+
+ console_in_use_timeout_sec = v;
+
+ /* Refresh console in use to use new timeout. */
+ clock_refresh_console_in_use();
+ }
+ }
+
+ ccprintf("Sleep mask: %08x\n", sleep_mask);
+ ccprintf("Console in use timeout: %d sec\n",
+ console_in_use_timeout_sec);
+ ccprintf("DSLPCLKCFG register: 0x%08x\n", LM4_SYSTEM_DSLPCLKCFG);
+
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(dsleepmask, command_dsleepmask,
+ "[ on | off | <timeout> sec]",
+ "Deep sleep clock settings:\nUse 'on' to force deep "
+ "sleep not to use low speed clock.\nUse 'off' to "
+ "allow deep sleep to auto-select using the low speed "
+ "clock.\n"
+ "Give a timeout value for the console in use timeout.\n"
+ "See also 'sleepmask'.",
+ NULL);
#endif /* CONFIG_LOW_POWER_IDLE */
diff --git a/chip/lm4/gpio.c b/chip/lm4/gpio.c
index 8708ab637e..b8dc0f6570 100644
--- a/chip/lm4/gpio.c
+++ b/chip/lm4/gpio.c
@@ -156,6 +156,18 @@ int gpio_enable_interrupt(enum gpio_signal signal)
return EC_SUCCESS;
}
+int gpio_disable_interrupt(enum gpio_signal signal)
+{
+ const struct gpio_info *g = gpio_list + signal;
+
+ /* Fail if no interrupt handler */
+ if (!g->irq_handler)
+ return EC_ERROR_UNKNOWN;
+
+ LM4_GPIO_IM(g->port) &= ~g->mask;
+ return EC_SUCCESS;
+}
+
#ifdef CONFIG_LOW_POWER_IDLE
/**
* Convert GPIO port to a mask that can be used to set the
diff --git a/chip/lm4/jtag.c b/chip/lm4/jtag.c
index 6b59d7fead..a3867aa0f6 100644
--- a/chip/lm4/jtag.c
+++ b/chip/lm4/jtag.c
@@ -4,14 +4,15 @@
*/
#include "clock.h"
+#include "gpio.h"
#include "jtag.h"
#include "registers.h"
+#include "system.h"
void jtag_pre_init(void)
{
/* Enable clocks to GPIO block C in run and sleep modes. */
- clock_enable_peripheral(CGC_OFFSET_GPIO, 0x0004,
- CGC_MODE_RUN | CGC_MODE_SLEEP);
+ clock_enable_peripheral(CGC_OFFSET_GPIO, 0x0004, CGC_MODE_ALL);
/*
* Ensure PC0:3 are set to JTAG function. They should be set this way
@@ -35,7 +36,30 @@ void jtag_pre_init(void)
LM4_GPIO_DEN(LM4_GPIO_C) |= 0x0f;
LM4_GPIO_PUR(LM4_GPIO_C) |= 0x0f;
+ /* Set interrupt on either edge of the JTAG signals */
+ LM4_GPIO_IS(LM4_GPIO_C) &= ~0x0f;
+ LM4_GPIO_IBE(LM4_GPIO_C) |= 0x0f;
+
/* Re-lock commit register */
LM4_GPIO_CR(LM4_GPIO_C) &= ~0x0f;
LM4_GPIO_LOCK(LM4_GPIO_C) = 0;
}
+
+#ifdef CONFIG_LOW_POWER_IDLE
+void jtag_interrupt(enum gpio_signal signal)
+{
+ /*
+ * This interrupt is the first sign someone is trying to use
+ * the JTAG. Disable slow speed sleep so that the JTAG action
+ * can take place.
+ */
+ disable_sleep(SLEEP_MASK_JTAG);
+
+ /*
+ * Once we get this interrupt, disable it from occurring again
+ * to avoid repeated interrupts when debugging via JTAG.
+ */
+ gpio_disable_interrupt(GPIO_JTAG_TCK);
+}
+#endif /* CONFIG_LOW_POWER_IDLE */
+
diff --git a/chip/lm4/uart.c b/chip/lm4/uart.c
index 7fd7101b70..8e593f7c65 100644
--- a/chip/lm4/uart.c
+++ b/chip/lm4/uart.c
@@ -69,6 +69,12 @@ int uart_tx_ready(void)
return !(LM4_UART_FR(0) & 0x20);
}
+int uart_tx_in_progress(void)
+{
+ /* Transmit is in progress if the TX busy bit is set. */
+ return LM4_UART_FR(0) & 0x08;
+}
+
int uart_rx_available(void)
{
return !(LM4_UART_FR(0) & 0x10);
@@ -192,7 +198,7 @@ void uart_init(void)
* UART in run and sleep modes.
*/
mask |= 1;
- clock_enable_peripheral(CGC_OFFSET_UART, mask, CGC_MODE_DSLEEP);
+ clock_enable_peripheral(CGC_OFFSET_UART, mask, CGC_MODE_ALL);
#ifdef CONFIG_UART_HOST
mask |= (1 << CONFIG_UART_HOST);
@@ -217,6 +223,71 @@ void uart_init(void)
init_done = 1;
}
+#ifdef CONFIG_LOW_POWER_IDLE
+void uart_enter_dsleep(void)
+{
+ const struct gpio_info g = gpio_list[GPIO_UART0_RX];
+
+ /* Disable the UART0 module interrupt. */
+ task_disable_irq(LM4_IRQ_UART0);
+
+ /* Disable UART0 peripheral in deep sleep. */
+ clock_disable_peripheral(CGC_OFFSET_UART, 0x1, CGC_MODE_DSLEEP);
+
+ /*
+ * Set the UART0 RX pin to be a generic GPIO with the flags defined
+ * in the board.c file.
+ */
+ gpio_set_flags_by_mask(g.port, g.mask, g.flags);
+ gpio_set_alternate_function(g.port, g.mask, -1);
+
+ /* Clear any pending GPIO interrupts on the UART0 RX pin. */
+ LM4_GPIO_ICR(g.port) = g.mask;
+
+ /* Enable GPIO interrupts on the UART0 RX pin. */
+ gpio_enable_interrupt(GPIO_UART0_RX);
+}
+
+void uart_exit_dsleep(void)
+{
+ const struct gpio_info g = gpio_list[GPIO_UART0_RX];
+
+ /*
+ * If the UART0 RX GPIO interrupt has not fired, then no edge has been
+ * detected. Disable the GPIO interrupt so that switching the pin over
+ * to a UART pin doesn't inadvertently cause a GPIO edge interrupt.
+ * Note: we can't disable this interrupt if it has already fired
+ * because then the IRQ will not get called.
+ */
+ if (!(LM4_GPIO_MIS(g.port) & g.mask))
+ gpio_disable_interrupt(GPIO_UART0_RX);
+
+ /* Configure UART0 pins for use in UART peripheral. */
+ gpio_config_module(MODULE_UART, 1);
+
+ /* Clear pending interrupts on UART peripheral and enable interrupts. */
+ uart_clear_rx_fifo(0);
+ task_enable_irq(LM4_IRQ_UART0);
+
+ /* Enable UART0 peripheral in deep sleep */
+ clock_enable_peripheral(CGC_OFFSET_UART, 0x1, CGC_MODE_DSLEEP);
+}
+
+void uart_deepsleep_interrupt(enum gpio_signal signal)
+{
+ /*
+ * Activity seen on UART RX pin while UART was disabled for deep sleep.
+ * The console won't see that character because the UART is disabled,
+ * so we need to inform the clock module of UART activity ourselves.
+ */
+ clock_refresh_console_in_use();
+
+ /* Disable interrupts on UART0 RX pin to avoid repeated interrupts. */
+ gpio_disable_interrupt(GPIO_UART0_RX);
+}
+#endif /* CONFIG_LOW_POWER_IDLE */
+
+
/*****************************************************************************/
/* COMx functions */
diff --git a/chip/stm32/clock-stm32f.c b/chip/stm32/clock-stm32f.c
index 23db9f1f44..11b426a42f 100644
--- a/chip/stm32/clock-stm32f.c
+++ b/chip/stm32/clock-stm32f.c
@@ -177,6 +177,10 @@ void __enter_hibernate(uint32_t seconds, uint32_t microseconds)
#ifdef CONFIG_LOW_POWER_IDLE
+void clock_refresh_console_in_use(void)
+{
+}
+
#ifdef CONFIG_FORCE_CONSOLE_RESUME
static void enable_serial_wakeup(int enable)
{
@@ -192,7 +196,7 @@ static void enable_serial_wakeup(int enable)
} else {
/* serial port wake up : don't go back to sleep */
if (STM32_EXTI_PR & (1 << 10))
- disable_sleep(SLEEP_MASK_FORCE);
+ disable_sleep(SLEEP_MASK_FORCE_NO_DSLEEP);
/* restore keyboard external IT on PC10 */
STM32_AFIO_EXTICR(10 / 4) = save_exticr;
}
@@ -216,7 +220,7 @@ void __idle(void)
t0 = get_time();
next_delay = __hw_clock_event_get() - t0.le.lo;
- if (!sleep_mask && (next_delay > STOP_MODE_LATENCY)) {
+ if (DEEP_SLEEP_ALLOWED && (next_delay > STOP_MODE_LATENCY)) {
/* deep-sleep in STOP mode */
enable_serial_wakeup(1);
diff --git a/common/console.c b/common/console.c
index 78fd96a7c7..f310ef41a7 100644
--- a/common/console.c
+++ b/common/console.c
@@ -4,7 +4,7 @@
*/
/* Console module for Chrome EC */
-
+#include "clock.h"
#include "console.h"
#include "link_defs.h"
#include "system.h"
@@ -519,6 +519,11 @@ static void console_handle_char(int c)
void console_has_input(void)
{
+#ifdef CONFIG_LOW_POWER_IDLE
+ /* Notify the clock module that the console is in use. */
+ clock_refresh_console_in_use();
+#endif
+
/* Wake up the console task */
task_wake(TASK_ID_CONSOLE);
}
diff --git a/common/system_common.c b/common/system_common.c
index 778a7ef672..d651fd7579 100644
--- a/common/system_common.c
+++ b/common/system_common.c
@@ -758,15 +758,23 @@ DECLARE_CONSOLE_COMMAND(syslock, command_system_lock,
*/
static int command_sleepmask(int argc, char **argv)
{
- int off;
+ int v;
if (argc >= 2) {
- off = strtoi(argv[1], NULL, 10);
-
- if (off)
- disable_sleep(SLEEP_MASK_FORCE);
- else
- enable_sleep(SLEEP_MASK_FORCE);
+ if (parse_bool(argv[1], &v)) {
+ if (v)
+ disable_sleep(SLEEP_MASK_FORCE_NO_DSLEEP);
+ else
+ enable_sleep(SLEEP_MASK_FORCE_NO_DSLEEP);
+ } else {
+ char *e;
+ v = strtoi(argv[1], &e, 10);
+ if (*e)
+ return EC_ERROR_PARAM1;
+
+ /* Set sleep mask directly. */
+ sleep_mask = v;
+ }
}
ccprintf("sleep mask: %08x\n", sleep_mask);
@@ -774,8 +782,8 @@ static int command_sleepmask(int argc, char **argv)
return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(sleepmask, command_sleepmask,
- "[<sleep_mask>]",
- "Display/force sleep mask",
+ "[ on | off | <sleep_mask>]",
+ "Display/force sleep mask.\nSee also 'dsleepmask'.",
NULL);
#endif
diff --git a/common/uart_buffering.c b/common/uart_buffering.c
index 2ccb967e81..fee325d5b4 100644
--- a/common/uart_buffering.c
+++ b/common/uart_buffering.c
@@ -246,6 +246,11 @@ int uart_getc(void)
return c;
}
+int uart_buffer_empty(void)
+{
+ return tx_buf_head == tx_buf_tail;
+}
+
int uart_gets(char *dest, int size)
{
int got = 0;
diff --git a/include/clock.h b/include/clock.h
index 2f14ffc62b..f94da36e34 100644
--- a/include/clock.h
+++ b/include/clock.h
@@ -65,4 +65,9 @@ void clock_enable_peripheral(uint32_t offset, uint32_t mask, uint32_t mode);
*/
void clock_disable_peripheral(uint32_t offset, uint32_t mask, uint32_t mode);
+/**
+ * Notify the clock module that the UART for the console is in use.
+ */
+void clock_refresh_console_in_use(void);
+
#endif /* __CROS_EC_CLOCK_H */
diff --git a/include/gpio.h b/include/gpio.h
index b3861ede08..f984822175 100644
--- a/include/gpio.h
+++ b/include/gpio.h
@@ -165,6 +165,18 @@ void gpio_set_level(enum gpio_signal signal, int value);
int gpio_enable_interrupt(enum gpio_signal signal);
/**
+ * Disable interrupts for the signal.
+ *
+ * The signal must have been defined with
+ * an interrupt handler. Normally called by the module which handles the
+ * interrupt, if it doesn't want to process interrupts.
+ *
+ * @param signal Signal to disable interrupts for
+ * @return EC_SUCCESS, or non-zero if error.
+ */
+int gpio_disable_interrupt(enum gpio_signal signal);
+
+/**
* Set flags for GPIO(s) by port and mask.
*
* Use gpio_set_flags() to set flags for an individual GPIO by id.
diff --git a/include/jtag.h b/include/jtag.h
index 690158b4ec..9c7835dfd0 100644
--- a/include/jtag.h
+++ b/include/jtag.h
@@ -15,4 +15,16 @@
*/
void jtag_pre_init(void);
+#ifdef CONFIG_LOW_POWER_IDLE
+/**
+ * Interrupt handler for JTAG clock.
+ *
+ * @param signal Signal which triggered the interrupt.
+ */
+void jtag_interrupt(enum gpio_signal signal);
+#else
+#define jtag_interrupt NULL
+#endif
+
+
#endif /* __CROS_EC_JTAG_H */
diff --git a/include/system.h b/include/system.h
index 0c2936a33c..cf936d64bf 100644
--- a/include/system.h
+++ b/include/system.h
@@ -284,13 +284,25 @@ void system_enable_hib_interrupt(void);
/* Low power modes for idle API */
enum {
+ /*
+ * Sleep masks to prevent going in to deep sleep.
+ */
SLEEP_MASK_AP_RUN = (1 << 0), /* the main CPU is running */
SLEEP_MASK_UART = (1 << 1), /* UART communication on-going */
SLEEP_MASK_I2C = (1 << 2), /* I2C master communication on-going */
SLEEP_MASK_CHARGING = (1 << 3), /* Charging loop on-going */
SLEEP_MASK_USB_PWR = (1 << 4), /* USB power loop on-going */
- SLEEP_MASK_FORCE = (1 << 31), /* Force disabling low power modes */
+ SLEEP_MASK_FORCE_NO_DSLEEP = (1 << 15), /* Force disable. */
+
+
+ /*
+ * Sleep masks to prevent using slow speed clock in deep sleep.
+ */
+ SLEEP_MASK_JTAG = (1 << 16), /* JTAG is in use. */
+ SLEEP_MASK_CONSOLE = (1 << 17), /* Console is in use. */
+
+ SLEEP_MASK_FORCE_NO_LOW_SPEED = (1 << 31) /* Force disable. */
};
/*
@@ -299,6 +311,13 @@ enum {
*/
extern uint32_t sleep_mask;
+/*
+ * Macros to use to get whether deep sleep is allowed or whether
+ * low speed deep sleep is allowed.
+ */
+#define DEEP_SLEEP_ALLOWED (!(sleep_mask & 0x0000ffff))
+#define LOW_SPEED_DEEP_SLEEP_ALLOWED (!(sleep_mask & 0xffff0000))
+
/**
* Enable low power sleep mask. For low power sleep to take affect, all masks
* in the sleep mask enum above must be enabled.
diff --git a/include/uart.h b/include/uart.h
index 05d4aee036..d98d9eb48e 100644
--- a/include/uart.h
+++ b/include/uart.h
@@ -127,6 +127,11 @@ void uart_tx_flush(void);
int uart_tx_ready(void);
/**
+ * Return non-zero if a transmit is in progress.
+ */
+int uart_tx_in_progress(void);
+
+/**
* Return non-zero if the UART has a character available to read.
*/
int uart_rx_available(void);
@@ -187,6 +192,33 @@ int uart_tx_stopped(void);
*/
void uart_process(void);
+/**
+ * Return boolean expressing whether UART buffer is empty or not.
+ */
+int uart_buffer_empty(void);
+
+/**
+ * Disable the EC console UART and convert the UART RX pin to a generic GPIO
+ * with an edge detect interrupt.
+ */
+void uart_enter_dsleep(void);
+
+/**
+ * Enable the EC console UART after a uart_enter_dsleep().
+ */
+void uart_exit_dsleep(void);
+
+#ifdef CONFIG_LOW_POWER_IDLE
+/**
+ * Interrupt handler for UART RX pin transition in deep sleep.
+ *
+ * @param signal Signal which triggered the interrupt.
+ */
+void uart_deepsleep_interrupt(enum gpio_signal signal);
+#else
+#define uart_deepsleep_interrupt NULL
+#endif
+
/*
* COMx functions
*/