mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-07 16:11:43 +00:00
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:
@@ -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);
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user