diff options
Diffstat (limited to 'chip/mec1322/clock.c')
-rw-r--r-- | chip/mec1322/clock.c | 484 |
1 files changed, 0 insertions, 484 deletions
diff --git a/chip/mec1322/clock.c b/chip/mec1322/clock.c deleted file mode 100644 index ce07284891..0000000000 --- a/chip/mec1322/clock.c +++ /dev/null @@ -1,484 +0,0 @@ -/* Copyright 2013 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* Clocks and power management settings */ - -#include "clock.h" -#include "common.h" -#include "console.h" -#include "cpu.h" -#include "hooks.h" -#include "hwtimer.h" -#include "pwm.h" -#include "pwm_chip.h" -#include "registers.h" -#include "shared_mem.h" -#include "system.h" -#include "task.h" -#include "timer.h" -#include "uart.h" -#include "util.h" -#include "vboot_hash.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 -/* Recovery time for HvySlp2 is 0 usec */ -#define HEAVY_SLEEP_RECOVER_TIME_USEC 75 - -#define SET_HTIMER_DELAY_USEC 200 - -static int idle_sleep_cnt; -static int idle_dsleep_cnt; -static uint64_t total_idle_dsleep_time_us; - -/* - * 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 = 60; -static timestamp_t console_expire_time; -#endif /*CONFIG_LOW_POWER_IDLE */ - -static int freq = 48000000; - -void clock_wait_cycles(uint32_t cycles) -{ - asm volatile("1: subs %0, #1\n" - " bne 1b\n" : "+r"(cycles)); -} - -int clock_get_freq(void) -{ - return freq; -} - -void clock_init(void) -{ -#ifdef CONFIG_CLOCK_CRYSTAL - /* XOSEL: 0 = Parallel resonant crystal */ - MEC1322_VBAT_CE &= ~0x1; -#else - /* XOSEL: 1 = Single ended clock source */ - MEC1322_VBAT_CE |= 0x1; -#endif - - /* 32K clock enable */ - MEC1322_VBAT_CE |= 0x2; - -#ifdef CONFIG_CLOCK_CRYSTAL - /* Wait for crystal to stabilize (OSC_LOCK == 1) */ - while (!(MEC1322_PCR_CHIP_OSC_ID & 0x100)) - ; -#endif -} - -/** - * Speed through boot + vboot hash calculation, dropping our processor clock - * only after vboot hashing is completed. - */ -static void clock_turbo_disable(void); -DECLARE_DEFERRED(clock_turbo_disable); - -static void clock_turbo_disable(void) -{ -#ifdef CONFIG_VBOOT_HASH - if (vboot_hash_in_progress()) - hook_call_deferred(&clock_turbo_disable_data, 100 * MSEC); - else -#endif - /* Use 12 MHz processor clock for power savings */ - MEC1322_PCR_PROC_CLK_CTL = 4; -} -DECLARE_HOOK(HOOK_INIT, clock_turbo_disable, HOOK_PRIO_INIT_VBOOT_HASH + 1); - -#ifdef CONFIG_LOW_POWER_IDLE -/** - * initialization of Hibernation timer - */ -static void htimer_init(void) -{ - MEC1322_INT_BLK_EN |= BIT(17); - MEC1322_INT_ENABLE(17) |= BIT(20); /* GIRQ=17, aggregator bit = 20 */ - MEC1322_HTIMER_PRELOAD = 0; /* disable at beginning */ - - task_enable_irq(MEC1322_IRQ_HTIMER); -} - -/** - * Use hibernate module to set up an htimer interrupt at a given - * time from now - * - * @param seconds Number of seconds before htimer interrupt - * @param microseconds Number of microseconds before htimer interrupt - */ -static void system_set_htimer_alarm(uint32_t seconds, uint32_t microseconds) -{ - if (seconds || microseconds) { - - if (seconds > 2) { - /* count from 2 sec to 2 hrs, mec1322 sec 18.10.2 */ - ASSERT(seconds <= 0xffff / 8); - MEC1322_HTIMER_CONTROL = 1; /* 0.125(=1/8) per clock */ - /* (number of counts to be loaded) - * = seconds * ( 8 clocks per second ) - * + microseconds / 125000 - * ---> (0 if (microseconds < 125000) - */ - MEC1322_HTIMER_PRELOAD = - (seconds * 8 + microseconds / 125000); - - } else { /* count up to 2 sec. */ - - MEC1322_HTIMER_CONTROL = 0; /* 30.5(= 2/61) usec */ - - /* (number of counts to be loaded) - * = (total microseconds) / 30.5; - */ - MEC1322_HTIMER_PRELOAD = - (seconds * 1000000 + microseconds) * 2 / 61; - } - } -} - -/** - * return time slept in micro-seconds - */ -static timestamp_t system_get_htimer(void) -{ - uint16_t count; - timestamp_t time; - - count = MEC1322_HTIMER_COUNT; - - - if (MEC1322_HTIMER_CONTROL == 1) /* if > 2 sec */ - /* 0.125 sec per count */ - time.le.lo = (uint32_t)(count * 125000); - else /* if < 2 sec */ - /* 30.5(=61/2)usec per count */ - time.le.lo = (uint32_t)(count * 61 / 2); - - time.le.hi = 0; - - return time; /* in uSec */ -} - -/** - * Disable and clear hibernation timer interrupt - */ -static void system_reset_htimer_alarm(void) -{ - MEC1322_HTIMER_PRELOAD = 0; -} - -/** - * This is mec1322 specific and equivalent to ARM Cortex's - * 'DeepSleep' via system control block register, CPU_SCB_SYSCTRL - */ -static void prepare_for_deep_sleep(void) -{ - uint32_t ec_slp_en = MEC1322_PCR_EC_SLP_EN | - MEC1322_PCR_EC_SLP_EN_SLEEP; - - /* sysTick timer */ - CPU_NVIC_ST_CTRL &= ~ST_ENABLE; - CPU_NVIC_ST_CTRL &= ~ST_COUNTFLAG; - - /* Disable JTAG */ - MEC1322_EC_JTAG_EN &= ~1; - /* Power down ADC VREF, ADC_VREF overrides ADC_CTRL. */ - MEC1322_EC_ADC_VREF_PD |= 1; - - /* Stop watchdog */ - MEC1322_WDG_CTL &= ~1; - - /* Stop timers */ - MEC1322_TMR32_CTL(0) &= ~1; - MEC1322_TMR32_CTL(1) &= ~1; - MEC1322_TMR16_CTL(0) &= ~1; - - MEC1322_PCR_CHIP_SLP_EN |= 0x3; -#ifdef CONFIG_PWM - if (pwm_get_keep_awake_mask()) - ec_slp_en &= ~pwm_get_keep_awake_mask(); - else -#endif - /* Disable 100 Khz clock */ - MEC1322_PCR_SLOW_CLK_CTL &= 0xFFFFFC00; - - MEC1322_PCR_EC_SLP_EN = ec_slp_en; - MEC1322_PCR_HOST_SLP_EN |= MEC1322_PCR_HOST_SLP_EN_SLEEP; - MEC1322_PCR_EC_SLP_EN2 |= MEC1322_PCR_EC_SLP_EN2_SLEEP; - -#ifndef CONFIG_POWER_S0IX - MEC1322_LPC_ACT = 0x0; -#endif - - MEC1322_PCR_SYS_SLP_CTL = 0x2; /* heavysleep 2 */ - - CPU_NVIC_ST_CTRL &= ~ST_TICKINT; /* SYS_TICK_INT_DISABLE */ -} - -static void resume_from_deep_sleep(void) -{ - CPU_NVIC_ST_CTRL |= ST_TICKINT; /* SYS_TICK_INT_ENABLE */ - CPU_NVIC_ST_CTRL |= ST_ENABLE; - - MEC1322_EC_JTAG_EN = 1; - MEC1322_EC_ADC_VREF_PD &= ~1; - /* ADC_VREF_PD overrides ADC_CTRL ! */ - - /* Enable timer */ - MEC1322_TMR32_CTL(0) |= 1; - MEC1322_TMR32_CTL(1) |= 1; - MEC1322_TMR16_CTL(0) |= 1; - - /* Enable watchdog */ - MEC1322_WDG_CTL |= 1; - - MEC1322_PCR_SLOW_CLK_CTL |= 0x1e0; - MEC1322_PCR_CHIP_SLP_EN &= ~0x3; - MEC1322_PCR_EC_SLP_EN &= MEC1322_PCR_EC_SLP_EN_WAKE; - MEC1322_PCR_HOST_SLP_EN &= MEC1322_PCR_HOST_SLP_EN_WAKE; - MEC1322_PCR_EC_SLP_EN2 &= MEC1322_PCR_EC_SLP_EN2_WAKE; - - MEC1322_PCR_SYS_SLP_CTL = 0xF8; /* default */ - -#ifndef CONFIG_POWER_S0IX - /* Enable LPC */ - MEC1322_LPC_ACT |= 1; -#endif -} - - -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; - timestamp_t t1; - timestamp_t ht_t1; - uint32_t next_delay; - uint32_t max_sleep_time; - int time_for_dsleep; - int uart_ready_for_deepsleep; - - htimer_init(); /* hibernation timer initialize */ - - 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 - * their task inits and have gone to sleep. - */ - CPRINTS("low power idle task started"); - - while (1) { - /* Disable interrupts */ - interrupt_disable(); - - t0 = get_time(); /* uSec */ - - /* __hw_clock_event_get() is next programmed timer event */ - next_delay = __hw_clock_event_get() - t0.le.lo; - - time_for_dsleep = next_delay > (HEAVY_SLEEP_RECOVER_TIME_USEC + - SET_HTIMER_DELAY_USEC); - - max_sleep_time = next_delay - HEAVY_SLEEP_RECOVER_TIME_USEC; - - /* check if there enough time for deep sleep */ - if (DEEP_SLEEP_ALLOWED && time_for_dsleep) { - - - /* - * Check if the console use has expired and console - * sleep is masked by GPIO(UART-RX) interrupt. - */ - if ((sleep_mask & SLEEP_MASK_CONSOLE) && - t0.val > console_expire_time.val) { - /* allow console to sleep. */ - enable_sleep(SLEEP_MASK_CONSOLE); - - /* - * Wait one clock before checking if heavy sleep - * is allowed to give time for sleep mask - * to be updated. - */ - clock_wait_cycles(1); - - if (LOW_SPEED_DEEP_SLEEP_ALLOWED) - CPRINTS("Disable console in deepsleep"); - } - - - /* UART is not being used */ - uart_ready_for_deepsleep = LOW_SPEED_DEEP_SLEEP_ALLOWED - && !uart_tx_in_progress() - && uart_buffer_empty(); - - /* - * Since MEC1322's heavysleep modes requires all block - * to be sleepable, UART/console's readiness is final - * decision factor of heavysleep of EC. - */ - if (uart_ready_for_deepsleep) { - - idle_dsleep_cnt++; - - /* - * config UART Rx as GPIO wakeup interrupt - * source - */ - uart_enter_dsleep(); - - /* MEC1322 specific deep-sleep mode */ - prepare_for_deep_sleep(); - - /* - * 'max_sleep_time' value should be big - * enough so that hibernation timer's interrupt - * triggers only after 'wfi' completes its - * excution. - */ - max_sleep_time -= (get_time().le.lo - t0.le.lo); - - /* setup/enable htimer wakeup interrupt */ - system_set_htimer_alarm(0, max_sleep_time); - } else { - idle_sleep_cnt++; - } - - /* Wait for interrupt: goes into deep sleep. */ - asm("wfi"); - - if (uart_ready_for_deepsleep) { - - resume_from_deep_sleep(); - - /* - * Fast forward timer according to htimer - * counter: - * Since all blocks including timers will be in - * sleep mode, timers stops except hibernate - * timer. - * And system schedule timer should be corrected - * after wakeup by either hibernate timer or - * GPIO_UART_RX interrupt. - */ - ht_t1 = system_get_htimer(); - - /* disable/clear htimer wakeup interrupt */ - system_reset_htimer_alarm(); - - t1.val = t0.val + - (uint64_t)(max_sleep_time - ht_t1.le.lo); - - force_time(t1); - - /* re-eanble UART */ - uart_exit_dsleep(); - - /* Record time spent in deep sleep. */ - total_idle_dsleep_time_us += - (uint64_t)(max_sleep_time - ht_t1.le.lo); - } - - } else { /* CPU 'Sleep' mode */ - - idle_sleep_cnt++; - - asm("wfi"); - - } - - interrupt_enable(); - } /* while(1) */ -} - -#ifdef CONFIG_CMD_IDLE_STATS -/** - * Print low power idle statistics - */ -static int command_idle_stats(int argc, char **argv) -{ - timestamp_t ts = get_time(); - - ccprintf("Num idle calls that sleep: %d\n", idle_sleep_cnt); - ccprintf("Num idle calls that deep-sleep: %d\n", idle_dsleep_cnt); - - ccprintf("Total Time spent in deep-sleep(sec): %.6lld(s)\n", - total_idle_dsleep_time_us); - ccprintf("Total time on: %.6llds\n\n", ts.val); - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(idlestats, command_idle_stats, - "", - "Print last idle stats"); -#endif /* defined(CONFIG_CMD_IDLE_STATS) */ - -/** - * 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:\nUse 'on' to force deep " - "sleep NOT to enter heavysleep mode.\nUse 'off' to " - "allow deep sleep to use heavysleep whenever conditions" - "allow.\n" - "Give a timeout value for the console in use timeout.\n" - "See also 'sleepmask'."); -#endif /* CONFIG_LOW_POWER_IDLE */ |