diff options
-rw-r--r-- | board/falco/board.c | 9 | ||||
-rw-r--r-- | board/falco/board.h | 2 | ||||
-rw-r--r-- | board/peppy/board.c | 9 | ||||
-rw-r--r-- | board/peppy/board.h | 2 | ||||
-rw-r--r-- | board/slippy/board.c | 9 | ||||
-rw-r--r-- | board/slippy/board.h | 2 | ||||
-rw-r--r-- | chip/lm4/clock.c | 132 | ||||
-rw-r--r-- | chip/lm4/gpio.c | 12 | ||||
-rw-r--r-- | chip/lm4/jtag.c | 28 | ||||
-rw-r--r-- | chip/lm4/uart.c | 73 | ||||
-rw-r--r-- | chip/stm32/clock-stm32f.c | 8 | ||||
-rw-r--r-- | common/console.c | 7 | ||||
-rw-r--r-- | common/system_common.c | 26 | ||||
-rw-r--r-- | common/uart_buffering.c | 5 | ||||
-rw-r--r-- | include/clock.h | 5 | ||||
-rw-r--r-- | include/gpio.h | 12 | ||||
-rw-r--r-- | include/jtag.h | 12 | ||||
-rw-r--r-- | include/system.h | 21 | ||||
-rw-r--r-- | include/uart.h | 32 |
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 */ |