it8380dev: fix clock module

1. Implement deep doze mode for CONFIG_LOW_POWER_IDLE.

Signed-off-by: Dino Li <dino.li@ite.com.tw>

BRANCH=none
BUG=none
TEST=test the following items in deep doze mode.
     1. WUI interrupts wake-up OK. (For example, power button, lid,
        uart rx, keyboard ksi, and so on)
     2. LPC access interrupt wake-up OK.
     3. Enabled Hook debug, no warning message received (48hrs).

Change-Id: I8702a112632cb6c1c0fa75d682badf272130a7d4
Reviewed-on: https://chromium-review.googlesource.com/307060
Commit-Ready: Dino Li <dino.li@ite.com.tw>
Tested-by: Dino Li <dino.li@ite.com.tw>
Reviewed-by: Randall Spangler <rspangler@chromium.org>
This commit is contained in:
Dino Li
2015-10-20 16:55:43 +08:00
committed by chrome-bot
parent 9acd84460e
commit 19c1e9905d
12 changed files with 399 additions and 37 deletions

View File

@@ -23,8 +23,10 @@
#include "registers.h"
#include "spi.h"
#include "switch.h"
#include "system.h"
#include "task.h"
#include "timer.h"
#include "uart.h"
#include "util.h"
#include "gpio_list.h"
@@ -173,7 +175,11 @@ BUILD_ASSERT(ARRAY_SIZE(pnpcfg_settings) == EC2I_SETTING_COUNT);
/* Initialize board. */
static void board_init(void)
{
/*
* Default no low power idle for EVB,
* use console command "sleepmask" to enable it if necessary.
*/
disable_sleep(SLEEP_MASK_FORCE_NO_DSLEEP);
}
DECLARE_HOOK(HOOK_INIT, board_init, HOOK_PRIO_DEFAULT);

View File

@@ -9,16 +9,17 @@
#define __CROS_EC_BOARD_H
/* Optional features */
#undef CHIP_FAMILY_IT839X
#define CHIP_FAMILY_IT839X
#define CONFIG_BATTERY_SMART
#define CONFIG_FANS 1
#undef CONFIG_IT83XX_KEYBOARD_KSI_WUC_INT
#define CONFIG_IT83XX_KEYBOARD_KSI_WUC_INT
#define CONFIG_IT83XX_LPC_ACCESS_INT
#define CONFIG_IT83XX_PECI_WITH_INTERRUPT
#define CONFIG_IT83XX_SMCLK2_ON_GPC7
#define CONFIG_KEYBOARD_BOARD_CONFIG
#define CONFIG_KEYBOARD_PROTOCOL_8042
#define CONFIG_LOW_POWER_IDLE
#define CONFIG_PECI_TJMAX 100
#define CONFIG_POWER_BUTTON
/* Use CS0 of SSPI */

View File

@@ -9,6 +9,9 @@ GPIO_INT(POWER_BUTTON_L, PIN(E, 4), GPIO_INT_BOTH | GPIO_PULL_UP, power_button
GPIO_INT(PCH_PLTRST_L, PIN(E, 3), GPIO_INT_BOTH | GPIO_PULL_UP, lpcrst_interrupt)
GPIO_INT(LID_OPEN, PIN(E, 2), GPIO_INT_BOTH | GPIO_PULL_DOWN, lid_interrupt)
GPIO_INT(WP_L, PIN(E, 1), GPIO_INT_BOTH, switch_interrupt) /* Write protect input */
#ifdef CONFIG_LOW_POWER_IDLE
GPIO_INT(UART1_RX, PIN(B, 0), GPIO_INT_FALLING, uart_deepsleep_interrupt) /* UART1 RX input */
#endif
GPIO(CAPS_LED, PIN(H, 1), GPIO_OUT_LOW)
GPIO(SCRO_LED, PIN(H, 2), GPIO_OUT_LOW)

View File

@@ -8,15 +8,42 @@
#include "clock.h"
#include "common.h"
#include "console.h"
#include "hwtimer.h"
#include "hwtimer_chip.h"
#include "registers.h"
#include "system.h"
#include "task.h"
#include "timer.h"
#include "uart.h"
#include "util.h"
/* Console output macros. */
#define CPUTS(outstr) cputs(CC_CLOCK, outstr)
#define CPRINTS(format, args...) cprints(CC_CLOCK, format, ## args)
#ifdef CONFIG_LOW_POWER_IDLE
#define SLEEP_SET_HTIMER_DELAY_USEC 250
#define SLEEP_FTIMER_SKIP_USEC (HOOK_TICK_INTERVAL * 2)
static timestamp_t sleep_mode_t0;
static timestamp_t sleep_mode_t1;
static int idle_doze_cnt;
static int idle_sleep_cnt;
static uint64_t total_idle_sleep_time_us;
static int allow_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.
*/
#define CONSOLE_IN_USE_ON_BOOT_TIME (15*SECOND)
static int console_in_use_timeout_sec = 5;
static timestamp_t console_expire_time;
/* clock source is 32.768KHz */
#define TIMER_32P768K_CNT_TO_US(cnt) ((cnt) * 32768 / 1000)
#define TIMER_CNT_8M_32P768K(cnt) (((cnt) / 262) + 1)
#endif /*CONFIG_LOW_POWER_IDLE */
static int freq;
struct clock_gate_ctrl {
@@ -49,6 +76,9 @@ void clock_init(void)
/* Turn off auto clock gating. */
IT83XX_ECPM_AUTOCG = 0x00;
/* Default doze mode */
IT83XX_ECPM_PLLCTRL = EC_PLL_DOZE;
}
int clock_get_freq(void)
@@ -100,3 +130,239 @@ void clock_disable_peripheral(uint32_t offset, uint32_t mask, uint32_t mode)
*reg |= reg_mask | tmp_mask;
}
#ifdef CONFIG_LOW_POWER_IDLE
void clock_refresh_console_in_use(void)
{
/* Set console in use expire time. */
console_expire_time = get_time();
console_expire_time.val += console_in_use_timeout_sec * SECOND;
}
static void clock_event_timer_clock_change(enum ext_timer_clock_source clock,
uint32_t count)
{
IT83XX_ETWD_ETXCTRL(EVENT_EXT_TIMER) &= ~(1 << 0);
IT83XX_ETWD_ETXPSR(EVENT_EXT_TIMER) = clock;
IT83XX_ETWD_ETXCNTLR(EVENT_EXT_TIMER) = count;
IT83XX_ETWD_ETXCTRL(EVENT_EXT_TIMER) |= 0x3;
}
static void clock_htimer_enable(void)
{
uint32_t c;
/* disable free running interrupt */
task_disable_irq(et_ctrl_regs[FREE_EXT_TIMER_H].irq);
task_disable_irq(et_ctrl_regs[FREE_EXT_TIMER_L].irq);
/* change event timer clock source to 32.768 KHz */
c = TIMER_CNT_8M_32P768K(IT83XX_ETWD_ETXCNTOR(EVENT_EXT_TIMER));
clock_event_timer_clock_change(EXT_PSR_32P768K_HZ, c);
}
static int clock_allow_low_power_idle(void)
{
if (!(IT83XX_ETWD_ETXCTRL(EVENT_EXT_TIMER) & (1 << 0)))
return 0;
if (*et_ctrl_regs[EVENT_EXT_TIMER].isr &
et_ctrl_regs[EVENT_EXT_TIMER].mask)
return 0;
if (EVENT_TIMER_COUNT_TO_US(IT83XX_ETWD_ETXCNTOR(EVENT_EXT_TIMER)) <
SLEEP_SET_HTIMER_DELAY_USEC)
return 0;
if (TIMER_L_COUNT_TO_US(IT83XX_ETWD_ETXCNTOR(FREE_EXT_TIMER_L)) <
SLEEP_SET_HTIMER_DELAY_USEC)
return 0;
sleep_mode_t0 = get_time();
if ((sleep_mode_t0.le.lo > (0xffffffff - SLEEP_FTIMER_SKIP_USEC)) ||
(sleep_mode_t0.le.lo < SLEEP_FTIMER_SKIP_USEC))
return 0;
if (sleep_mode_t0.val < console_expire_time.val)
return 0;
return 1;
}
static void clock_ec_pll_ctrl(enum ec_pll_ctrl mode)
{
IT83XX_ECPM_PLLCTRL = mode;
#ifdef CHIP_FAMILY_IT839X
/* for deep doze / sleep mode */
IT83XX_ECPM_PLLCTRL = mode;
#endif
asm volatile ("dsb");
}
void clock_sleep_mode_wakeup_isr(void)
{
uint32_t st_us, c;
if (IT83XX_ECPM_PLLCTRL != EC_PLL_DOZE) {
clock_ec_pll_ctrl(EC_PLL_DOZE);
/* update free running timer */
c = 0xffffffff - IT83XX_ETWD_ETXCNTOR(LOW_POWER_EXT_TIMER);
st_us = TIMER_32P768K_CNT_TO_US(c);
sleep_mode_t1.val = sleep_mode_t0.val + st_us;
/*
* When TIMER_L underflow, and because the observation value
* equals to counter setting register, we need a window of
* 64us (at minimum) to reset the value of TIMER_L back to
* 0xfffff8(TIMER_L_COUNT_TO_US(0xffffffff))
*/
c = TIMER_L_US_TO_COUNT(0xffffffff - sleep_mode_t1.le.lo);
if (TIMER_L_COUNT_TO_US(c) < 64) {
sleep_mode_t1.le.lo |= 0x3F;
sleep_mode_t1.le.lo &= ~(1 << 6);
}
__hw_clock_source_set(sleep_mode_t1.le.lo);
/* reset event timer and clock source is 8 MHz */
clock_event_timer_clock_change(EXT_PSR_8M_HZ, 0xffffffff);
task_clear_pending_irq(et_ctrl_regs[EVENT_EXT_TIMER].irq);
process_timers(0);
/* disable uart wui */
uart_exit_dsleep();
/* Record time spent in sleep. */
total_idle_sleep_time_us += st_us;
}
}
/**
* Low power idle task. Executed when no tasks are ready to be scheduled.
*/
void __idle(void)
{
console_expire_time.val = get_time().val + CONSOLE_IN_USE_ON_BOOT_TIME;
/* init hw timer and clock source is 32.768 KHz */
ext_timer_ms(LOW_POWER_EXT_TIMER, EXT_PSR_32P768K_HZ, 1, 0,
0xffffffff, 1, 1);
#if defined(CONFIG_LPC) && defined(CONFIG_IT83XX_LPC_ACCESS_INT)
IT83XX_WUC_WUESR4 = 0xff;
task_clear_pending_irq(IT83XX_IRQ_WKINTAD);
/* bit2, wake-up enable for LPC access */
IT83XX_WUC_WUENR4 |= (1 << 2);
#endif
/*
* 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
* their task inits and have gone to sleep.
*/
CPRINTS("low power idle task started");
while (1) {
#if defined(CONFIG_LPC) && defined(CONFIG_IT83XX_LPC_ACCESS_INT)
BRAM_LPC_ACCESS = LPC_ACCESS_INT_BUSY;
/* LPC access interrupt pending. */
if (IT83XX_WUC_WUESR4 & (1 << 2)) {
task_enable_irq(IT83XX_IRQ_WKINTAD);
continue;
}
BRAM_LPC_ACCESS = 0;
task_enable_irq(IT83XX_IRQ_WKINTAD);
#endif
allow_sleep = 0;
if (DEEP_SLEEP_ALLOWED)
allow_sleep = clock_allow_low_power_idle();
if (allow_sleep) {
interrupt_disable();
/* reset low power mode hw timer */
IT83XX_ETWD_ETXCTRL(LOW_POWER_EXT_TIMER) |= (1 << 1);
sleep_mode_t0 = get_time();
/* enable uart wui */
uart_enter_dsleep();
/* enable hw timer for deep doze / sleep mode wake-up */
clock_htimer_enable();
/* deep doze mode */
clock_ec_pll_ctrl(EC_PLL_DEEP_DOZE);
interrupt_enable();
/* standby instruction */
asm("standby wake_grant");
idle_sleep_cnt++;
} else {
/* doze mode */
clock_ec_pll_ctrl(EC_PLL_DOZE);
/* standby instruction */
asm("standby wake_grant");
idle_doze_cnt++;
}
}
}
#endif /* CONFIG_LOW_POWER_IDLE */
#ifdef CONFIG_LOW_POWER_IDLE
/**
* Print low power idle statistics
*/
static int command_idle_stats(int argc, char **argv)
{
timestamp_t ts = get_time();
ccprintf("Num idle calls that doze: %d\n", idle_doze_cnt);
ccprintf("Num idle calls that sleep: %d\n", idle_sleep_cnt);
ccprintf("Total Time spent in sleep(sec): %.6ld(s)\n",
total_idle_sleep_time_us);
ccprintf("Total time on: %.6lds\n\n", ts.val);
return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(idlestats, command_idle_stats,
"",
"Print last idle stats",
NULL);
/**
* Configure deep sleep clock settings.
*/
static int command_dsleep(int argc, char **argv)
{
int v;
if (argc > 1) {
if (parse_bool(argv[1], &v)) {
/*
* Force deep sleep not to use heavy sleep mode or
* allow it to use the heavy sleep mode.
*/
if (v) /* 'on' */
disable_sleep(SLEEP_MASK_FORCE_NO_LOW_SPEED);
else /* 'off' */
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);
return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(dsleep, command_dsleep,
"[ on | off | <timeout> sec]",
"Deep sleep clock settings:\n"
"Use 'on' to force deep sleep NOT to enter heavysleep mode.\n"
"Use 'off' to allow deep sleep to use heavysleep whenever\n"
"conditions allow.\n"
"Give a timeout value for the console in use timeout.\n"
"See also 'sleepmask'.",
NULL);
#endif /* CONFIG_LOW_POWER_IDLE */

View File

@@ -91,6 +91,7 @@
#define CONFIG_FW_RESET_VECTOR
/* Optional features present on this chip */
#define CHIP_FAMILY_IT83XX
#define CONFIG_ADC
#define CONFIG_EC2I
#define CONFIG_I2C

View File

@@ -378,6 +378,18 @@ int gpio_disable_interrupt(enum gpio_signal signal)
return EC_SUCCESS;
}
int gpio_clear_pending_interrupt(enum gpio_signal signal)
{
int irq = gpio_to_irq(gpio_list[signal].port, gpio_list[signal].mask);
if (irq == -1)
return EC_ERROR_UNKNOWN;
*(wuesr(gpio_irqs[irq].wuc_group)) = gpio_irqs[irq].wuc_mask;
task_clear_pending_irq(irq);
return EC_SUCCESS;
}
void gpio_pre_init(void)
{
const struct gpio_info *g = gpio_list;

View File

@@ -56,52 +56,36 @@
* 8 MHz 32-bit timer to handle events.
*/
#define TIMER_COUNT_1US_SHIFT 3
/* Combinational mode, microseconds to timer counter setting register */
#define TIMER_H_US_TO_COUNT(us) ((us) >> (24 - TIMER_COUNT_1US_SHIFT))
#define TIMER_L_US_TO_COUNT(us) (((us) << TIMER_COUNT_1US_SHIFT) & 0x00ffffff)
/* Free running timer counter observation value to microseconds */
#define TIMER_H_COUNT_TO_US(cnt) ((~(cnt)) << (24 - TIMER_COUNT_1US_SHIFT))
#define TIMER_L_COUNT_TO_US(cnt) (((cnt) & 0x00ffffff) >> TIMER_COUNT_1US_SHIFT)
/* Microseconds to event timer counter setting register */
#define EVENT_TIMER_US_TO_COUNT(us) ((us) << TIMER_COUNT_1US_SHIFT)
/* Event timer counter observation value to microseconds */
#define EVENT_TIMER_COUNT_TO_US(cnt) ((cnt) >> TIMER_COUNT_1US_SHIFT)
#define TIMER_H_CNT_COMP TIMER_H_US_TO_COUNT(0xffffffff)
#define TIMER_L_CNT_COMP TIMER_L_US_TO_COUNT(0xffffffff)
#define MS_TO_COUNT(hz, ms) ((hz) * (ms) / 1000)
const struct ext_timer_ctrl_t et_ctrl_regs[] = {
{&IT83XX_INTC_IELMR19, &IT83XX_INTC_IPOLR19, 0x08,
{&IT83XX_INTC_IELMR19, &IT83XX_INTC_IPOLR19, &IT83XX_INTC_ISR19, 0x08,
IT83XX_IRQ_EXT_TIMER3},
{&IT83XX_INTC_IELMR19, &IT83XX_INTC_IPOLR19, 0x10,
{&IT83XX_INTC_IELMR19, &IT83XX_INTC_IPOLR19, &IT83XX_INTC_ISR19, 0x10,
IT83XX_IRQ_EXT_TIMER4},
{&IT83XX_INTC_IELMR19, &IT83XX_INTC_IPOLR19, 0x20,
{&IT83XX_INTC_IELMR19, &IT83XX_INTC_IPOLR19, &IT83XX_INTC_ISR19, 0x20,
IT83XX_IRQ_EXT_TIMER5},
{&IT83XX_INTC_IELMR19, &IT83XX_INTC_IPOLR19, 0x40,
{&IT83XX_INTC_IELMR19, &IT83XX_INTC_IPOLR19, &IT83XX_INTC_ISR19, 0x40,
IT83XX_IRQ_EXT_TIMER6},
{&IT83XX_INTC_IELMR19, &IT83XX_INTC_IPOLR19, 0x80,
{&IT83XX_INTC_IELMR19, &IT83XX_INTC_IPOLR19, &IT83XX_INTC_ISR19, 0x80,
IT83XX_IRQ_EXT_TIMER7},
{&IT83XX_INTC_IELMR10, &IT83XX_INTC_IPOLR10, 0x01,
{&IT83XX_INTC_IELMR10, &IT83XX_INTC_IPOLR10, &IT83XX_INTC_ISR10, 0x01,
IT83XX_IRQ_EXT_TMR8},
};
BUILD_ASSERT(ARRAY_SIZE(et_ctrl_regs) == EXT_TIMER_COUNT);
static void free_run_timer_config_counter(uint32_t us)
{
/* bit0, timer stop */
IT83XX_ETWD_ETXCTRL(FREE_EXT_TIMER_L) &= ~(1 << 0);
/*
* microseconds to timer counter,
* timer 3(TIMER_L) and 4(TIMER_H) combinational mode
*/
IT83XX_ETWD_ETXCNTLR(FREE_EXT_TIMER_H) = TIMER_H_US_TO_COUNT(us);
IT83XX_ETWD_ETXCNTLR(FREE_EXT_TIMER_L) = TIMER_L_US_TO_COUNT(us);
/* bit1, timer re-start */
IT83XX_ETWD_ETXCTRL(FREE_EXT_TIMER_L) |= (1 << 1);
/* bit[0,1], timer start and reset */
IT83XX_ETWD_ETXCTRL(FREE_EXT_TIMER_L) |= 3;
}
static void free_run_timer_clear_pending_isr(void)
@@ -174,9 +158,9 @@ void __hw_clock_source_set(uint32_t ts)
ext_timer_ms(FREE_EXT_TIMER_L, EXT_PSR_8M_HZ, 1, 1,
TIMER_L_US_TO_COUNT(start_us), 1, 1);
} else {
free_run_timer_clear_pending_isr();
/* set timer counter only */
free_run_timer_config_counter(start_us);
free_run_timer_clear_pending_isr();
task_enable_irq(et_ctrl_regs[FREE_EXT_TIMER_H].irq);
task_enable_irq(et_ctrl_regs[FREE_EXT_TIMER_L].irq);
}
@@ -282,10 +266,13 @@ static void __hw_clock_source_irq(void)
* 0xfffff8(TIMER_L_COUNT_TO_US(0xffffffff)).
*/
if (IT83XX_ETWD_ETXCNTLR(FREE_EXT_TIMER_H)) {
/* bit0, timer stop */
IT83XX_ETWD_ETXCTRL(FREE_EXT_TIMER_L) &= ~(1 << 0);
IT83XX_ETWD_ETXCNTLR(FREE_EXT_TIMER_L) =
TIMER_L_US_TO_COUNT(0xffffffff);
IT83XX_ETWD_ETXCNTLR(FREE_EXT_TIMER_H) -= 1;
IT83XX_ETWD_ETXCTRL(FREE_EXT_TIMER_L) |= (1 << 1);
/* bit[0,1], timer start and reset */
IT83XX_ETWD_ETXCTRL(FREE_EXT_TIMER_L) |= 3;
update_exc_start_time();
} else {
free_run_timer_overflow();

View File

@@ -8,11 +8,30 @@
#ifndef __CROS_EC_HWTIMER_CHIP_H
#define __CROS_EC_HWTIMER_CHIP_H
#define TIMER_COUNT_1US_SHIFT 3
/* Combinational mode, microseconds to timer counter setting register */
#define TIMER_H_US_TO_COUNT(us) ((us) >> (24 - TIMER_COUNT_1US_SHIFT))
#define TIMER_L_US_TO_COUNT(us) (((us) << TIMER_COUNT_1US_SHIFT) & 0x00ffffff)
/* Free running timer counter observation value to microseconds */
#define TIMER_H_COUNT_TO_US(cnt) ((~(cnt)) << (24 - TIMER_COUNT_1US_SHIFT))
#define TIMER_L_COUNT_TO_US(cnt) (((cnt) & 0x00ffffff) >> TIMER_COUNT_1US_SHIFT)
/* Microseconds to event timer counter setting register */
#define EVENT_TIMER_US_TO_COUNT(us) ((us) << TIMER_COUNT_1US_SHIFT)
/* Event timer counter observation value to microseconds */
#define EVENT_TIMER_COUNT_TO_US(cnt) ((cnt) >> TIMER_COUNT_1US_SHIFT)
#define TIMER_H_CNT_COMP TIMER_H_US_TO_COUNT(0xffffffff)
#define TIMER_L_CNT_COMP TIMER_L_US_TO_COUNT(0xffffffff)
#define FREE_EXT_TIMER_L EXT_TIMER_3
#define FREE_EXT_TIMER_H EXT_TIMER_4
#define FAN_CTRL_EXT_TIMER EXT_TIMER_5
#define EVENT_EXT_TIMER EXT_TIMER_6
#define WDT_EXT_TIMER EXT_TIMER_7
#define LOW_POWER_EXT_TIMER EXT_TIMER_8
enum ext_timer_clock_source {
EXT_PSR_32P768K_HZ = 0,
@@ -35,7 +54,7 @@ enum ext_timer_sel {
EXT_TIMER_6,
/* For WDT capture important state information before being reset */
EXT_TIMER_7,
/* reserved */
/* HW timer for low power mode */
EXT_TIMER_8,
EXT_TIMER_COUNT,
};
@@ -43,6 +62,7 @@ enum ext_timer_sel {
struct ext_timer_ctrl_t {
volatile uint8_t *mode;
volatile uint8_t *polarity;
volatile uint8_t *isr;
uint8_t mask;
uint8_t irq;
};
@@ -52,6 +72,7 @@ void ext_timer_start(enum ext_timer_sel ext_timer, int en_irq);
void ext_timer_stop(enum ext_timer_sel ext_timer, int dis_irq);
void fan_ext_timer_interrupt(void);
void update_exc_start_time(void);
/**
* Config a external timer.
*

View File

@@ -18,5 +18,7 @@ void pm5_ibf_interrupt(void);
void lpcrst_interrupt(enum gpio_signal signal);
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);
#endif /* __CROS_EC_INTC_H */

View File

@@ -581,6 +581,12 @@ enum {
#define IT83XX_ECPM_CGCTRL4R_OFF 0x09
#define IT83XX_ECPM_PLLCTRL REG8(IT83XX_ECPM_BASE+0x03)
enum ec_pll_ctrl {
EC_PLL_DOZE = 0,
EC_PLL_SLEEP = 1,
EC_PLL_DEEP_DOZE = 3,
};
#define IT83XX_ECPM_AUTOCG REG8(IT83XX_ECPM_BASE+0x04)
#define IT83XX_ECPM_PLLFREQR REG8(IT83XX_ECPM_BASE+0x06)
#define IT83XX_ECPM_PLLCSS REG8(IT83XX_ECPM_BASE+0x08)

View File

@@ -9,6 +9,7 @@
#include "common.h"
#include "console.h"
#include "gpio.h"
#include "intc.h"
#include "registers.h"
#include "system.h"
#include "task.h"
@@ -178,6 +179,27 @@ static void host_uart_config(void)
}
#endif
#ifdef CONFIG_LOW_POWER_IDLE
void uart_enter_dsleep(void)
{
gpio_clear_pending_interrupt(GPIO_UART1_RX);
gpio_enable_interrupt(GPIO_UART1_RX);
}
void uart_exit_dsleep(void)
{
gpio_disable_interrupt(GPIO_UART1_RX);
gpio_clear_pending_interrupt(GPIO_UART1_RX);
}
void uart_deepsleep_interrupt(enum gpio_signal signal)
{
clock_refresh_console_in_use();
/* Disable interrupts on UART1 RX pin to avoid repeated interrupts. */
gpio_disable_interrupt(GPIO_UART1_RX);
}
#endif /* CONFIG_LOW_POWER_IDLE */
void uart_init(void)
{
/* reset uart before config it */

View File

@@ -9,6 +9,8 @@
#include "common.h"
#include "console.h"
#include "cpu.h"
#include "hwtimer_chip.h"
#include "intc.h"
#include "irq_chip.h"
#include "link_defs.h"
#include "registers.h"
@@ -58,6 +60,10 @@ static uint64_t exc_total_time; /* Total time in exceptions */
static uint32_t svc_calls; /* Number of service calls */
static uint32_t task_switches; /* Number of times active task changed */
static uint32_t irq_dist[CONFIG_IRQ_COUNT]; /* Distribution of IRQ calls */
#if defined(CONFIG_LOW_POWER_IDLE) && defined(CHIP_FAMILY_IT83XX)
static uint32_t exc_current_fth;
static uint32_t exc_current_ftl;
#endif
#endif
extern int __task_start(void);
@@ -92,8 +98,10 @@ void __idle(void)
task_enable_irq(IT83XX_IRQ_WKINTAD);
#endif
#ifdef CHIP_FAMILY_IT83XX
/* doze mode */
IT83XX_ECPM_PLLCTRL = 0x00;
IT83XX_ECPM_PLLCTRL = EC_PLL_DOZE;
#endif
asm volatile ("dsb");
/*
* Wait for the next irq event. This stops the CPU clock
@@ -341,6 +349,10 @@ void update_exc_start_time(void)
{
#ifdef CONFIG_TASK_PROFILING
exc_start_time = get_time().val;
#if defined(CONFIG_LOW_POWER_IDLE) && defined(CHIP_FAMILY_IT83XX)
exc_current_fth = IT83XX_ETWD_ETXCNTOR(FREE_EXT_TIMER_H);
exc_current_ftl = IT83XX_ETWD_ETXCNTOR(FREE_EXT_TIMER_L);
#endif
#endif
}
@@ -348,15 +360,20 @@ void start_irq_handler(void)
{
#ifdef CONFIG_TASK_PROFILING
int irq;
#endif
/* save r0, r1, and r2 for syscall */
asm volatile ("smw.adm $r0, [$sp], $r2, 0");
#if defined(CONFIG_LOW_POWER_IDLE) && defined(CHIP_FAMILY_IT83XX)
clock_sleep_mode_wakeup_isr();
#endif
#ifdef CONFIG_TASK_PROFILING
update_exc_start_time();
irq = get_sw_int();
#ifdef CHIP_FAMILY_IT83XX
if (!irq)
irq = IT83XX_INTC_AIVCT - 16;
#endif
/*
* Track IRQ distribution. No need for atomic add, because an IRQ
@@ -364,10 +381,9 @@ void start_irq_handler(void)
*/
if ((irq > 0) && (irq < ARRAY_SIZE(irq_dist)))
irq_dist[irq]++;
#endif
/* restore r0, r1, and r2 */
asm volatile ("lmw.bim $r0, [$sp], $r2, 0");
#endif
}
void end_irq_handler(void)
@@ -375,6 +391,9 @@ void end_irq_handler(void)
#ifdef CONFIG_TASK_PROFILING
uint64_t t, p;
#if defined(CONFIG_LOW_POWER_IDLE) && defined(CHIP_FAMILY_IT83XX)
uint32_t c;
#endif
/*
* save r0 and fp (fp for restore r0-r5, r15, fp, lp and sp
* while interrupt exit.
@@ -382,6 +401,13 @@ void end_irq_handler(void)
asm volatile ("smw.adm $r0, [$sp], $r0, 8");
t = get_time().val;
#if defined(CONFIG_LOW_POWER_IDLE) && defined(CHIP_FAMILY_IT83XX)
if (exc_current_fth != IT83XX_ETWD_ETXCNTOR(FREE_EXT_TIMER_H)) {
c = (IT83XX_ETWD_ETXCNTLR(FREE_EXT_TIMER_L) + exc_current_ftl) -
IT83XX_ETWD_ETXCNTOR(FREE_EXT_TIMER_L);
t = exc_start_time + (c >> TIMER_COUNT_1US_SHIFT);
}
#endif
p = t - exc_start_time;
exc_total_time += p;
@@ -478,12 +504,20 @@ void task_enable_all_tasks(void)
void task_enable_irq(int irq)
{
uint32_t int_mask = get_int_mask();
interrupt_disable();
chip_enable_irq(irq);
set_int_mask(int_mask);
}
void task_disable_irq(int irq)
{
uint32_t int_mask = get_int_mask();
interrupt_disable();
chip_disable_irq(irq);
set_int_mask(int_mask);
}
void task_clear_pending_irq(int irq)
@@ -494,6 +528,7 @@ void task_clear_pending_irq(int irq)
void task_trigger_irq(int irq)
{
int cpu_int = chip_trigger_irq(irq);
if (cpu_int > 0) {
sw_int_num = irq;
__schedule(0, 0, cpu_int);