summaryrefslogtreecommitdiff
path: root/chip/npcx/clock.c
diff options
context:
space:
mode:
authorMulin Chao <mlchao@nuvoton.com>2016-01-29 18:03:20 +0800
committerchrome-bot <chrome-bot@chromium.org>2016-02-06 01:57:58 -0800
commitf700e3bb0ea187bae315ff925f59c8eab05fb446 (patch)
tree1a0b6eba415c58d906299f554c9d6b0b1e415e79 /chip/npcx/clock.c
parent4ec554dd8fbdd47871dcd04374fb04018b24b7b5 (diff)
downloadchrome-ec-f700e3bb0ea187bae315ff925f59c8eab05fb446.tar.gz
nuc: Add support for CONFIG_LOW_POWER_S0.
To get better power consumption in S0, we add FW support for CONFIG_LOW_POWER_S0. Before entering deep idle in S0, we must enable Host interrupt to wake up EC if it needs to service LPC bus. This version also add a new bit of sleep_mask (SLEEP_MASK_FAN) in system.h to prevent EC enter deep idle if fan's duty isn't zero. Normally, the freq of PWM fan is 25 kHz. It means we must select apb2 clock as the source clock of PWM fan. Or fan would stop when ec enters deep idle because of no PWM signal. In hwtimer.c, we reset the preload counter to maximum value in ITEI32's ISR since preload counter is changed by __hw_clock_source_set all the time. We also found there're no event set if it's deadline is over 32 bits but current source clock isn't. To prevent ec doesn't wake-up in deep-idle even if ITIM32 expires, FW set an event for ITIM32 after process_timers(). Modified sources: 1. wheatley/board.h: Add CONFIG_LOW_POWER_S0 definition. 2. clock.c: Enable Host interrupt for LPC. 3. clock.c: Disable LP_WK_CTL for better power consumption. 4. gpio.c: Add ISR for Host interrupt. 5. uart.c: Introduce bit 6 of USTAT to make sure transmitting is completed. 6. register.h: Add uart_clear_pending_wakeup function. 7. hwtimer.c: Fixed watchdog issue when ITIM32 is closed to overflow. 8. fan.c: Enable deep sleep if duty cycle is zero. 9. include/system.h: Add SLEEP_MASK_FAN for fan control loop. 10. core/cortex-m/task.c: Add "isb" to flash the garbage data in the instruction pipeline. BUG=chrome-os-partner:34346 TEST=make buildall -j; test nuvoton IC specific drivers BRANCH=none Change-Id: Ibe3630d0d68cf3f32206adb2afa1b5958916a2be Signed-off-by: Mulin Chao <mlchao@nuvoton.com> Reviewed-on: https://chromium-review.googlesource.com/324651 Reviewed-by: Shawn N <shawnn@chromium.org>
Diffstat (limited to 'chip/npcx/clock.c')
-rw-r--r--chip/npcx/clock.c44
1 files changed, 34 insertions, 10 deletions
diff --git a/chip/npcx/clock.c b/chip/npcx/clock.c
index 9eeb06efc0..ae5080b6d4 100644
--- a/chip/npcx/clock.c
+++ b/chip/npcx/clock.c
@@ -205,10 +205,14 @@ void clock_uart2gpio(void)
{
/* Is pimux to UART? */
if (npcx_is_uart()) {
+ /* Flush tx before enter deep idle */
+ uart_tx_flush();
/* Change pinmux to GPIO and disable UART IRQ */
task_disable_irq(NPCX_IRQ_UART);
/* Set to GPIO */
npcx_uart2gpio();
+ /* Clear pending wakeup */
+ uart_clear_pending_wakeup();
/* Enable MIWU for GPIO (UARTRX) */
uart_enable_wakeup(1);
}
@@ -243,7 +247,8 @@ void __idle(void)
#else
timestamp_t t0, t1;
- uint32_t next_evt_us, evt_count;
+ uint32_t next_evt_us;
+ uint16_t evt_count;
/*
* Initialize console in use to true and specify the console expire
@@ -274,13 +279,14 @@ void __idle(void)
CLEAR_BIT(NPCX_PDOUT(0), 0);
#endif
idle_dsleep_cnt++;
- /* Set instant wake up mode */
- SET_BIT(NPCX_ENIDL_CTL, NPCX_ENIDL_CTL_LP_WK_CTL);
- /* Set deep idle - instant wake-up mode */
- NPCX_PMCSR = IDLE_PARAMS;
+ /* Enable Host access wakeup */
+ SET_BIT(NPCX_WKEN(MIWU_TABLE_0, MIWU_GROUP_5), 6);
+
/* UART-rx(console) become to GPIO (NONE INT mode) */
clock_uart2gpio();
+ /* Set deep idle - instant wake-up mode */
+ NPCX_PMCSR = IDLE_PARAMS;
/* Get current counter value of event timer */
evt_count = __hw_clock_event_count();
@@ -289,22 +295,40 @@ void __idle(void)
/* Get time delay cause of deep idle */
next_evt_us = __hw_clock_get_sleep_time(evt_count);
+ /*
+ * Clear PMCSR manually in case there's wake-up between
+ * setting it and wfi.
+ */
+ NPCX_PMCSR = 0;
/* GPIO back to UART-rx (console) */
clock_gpio2uart();
- /* Fast forward timer according to wake-up timer. */
- t1.val = t0.val + next_evt_us;
/* Record time spent in deep sleep. */
idle_dsleep_time_us += next_evt_us;
- force_time(t1);
+
+ /* Fast forward timer according to wake-up timer. */
+ t1.val = t0.val + next_evt_us;
+ /* Leave overflow situation for ITIM32 */
+ if (t1.le.hi == t0.le.hi)
+ force_time(t1);
} else {
#if DEBUG_CLK
/* Use GPIO to indicate NORMAL mode */
SET_BIT(NPCX_PDOUT(0), 0);
#endif
idle_sleep_cnt++;
- /* normal idle : wait for interrupt */
- asm("wfi");
+ /*
+ * Normal idle : wait for interrupt
+ * TODO (ML): Workaround method for wfi issue.
+ * Please see task.c for more detail
+ */
+ asm ("push {r0-r5}\n"
+ "ldr r0, =0x100A8000\n"
+ "wfi\n"
+ "ldm r0, {r0-r5}\n"
+ "pop {r0-r5}\n"
+ "isb\n"
+ );
}
/*