diff options
author | Scott Worley <scott.worley@microchip.corp-partner.google.com> | 2017-12-20 17:08:09 -0500 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2017-12-28 12:35:07 -0800 |
commit | 4e9588ddcffb9315b0a74ac62121efb76b7b2202 (patch) | |
tree | d1ce8cea735b68c5e43f7631af2e90026006df58 /chip/mchp/clock.c | |
parent | c334f648bd644f5e72e841458fdac6796efa1ceb (diff) | |
download | chrome-ec-4e9588ddcffb9315b0a74ac62121efb76b7b2202.tar.gz |
ec_chip_mchp: Add MCHP chip folder
BRANCH=none
BUG=
TEST=Review only. Committing small pieces until
all code passes review.
Change-Id: I9d16f95314a7c97b11c4fe61602c6db2621e6024
Signed-off-by: Scott Worley <scott.worley@microchip.corp-partner.google.com>
Diffstat (limited to 'chip/mchp/clock.c')
-rw-r--r-- | chip/mchp/clock.c | 763 |
1 files changed, 763 insertions, 0 deletions
diff --git a/chip/mchp/clock.c b/chip/mchp/clock.c new file mode 100644 index 0000000000..d0df0240f9 --- /dev/null +++ b/chip/mchp/clock.c @@ -0,0 +1,763 @@ +/* Copyright 2017 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 "tfdp_chip.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 + +#define HTIMER_DIV_1_US_MAX (1998848) +#define HTIMER_DIV_1_1SEC (0x8012) + +/* 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; + +#ifdef CONFIG_MCHP_DEEP_SLP_DEBUG +static uint32_t pcr_slp_en[MCHP_PCR_SLP_RST_REG_MAX]; +static uint32_t pcr_clk_req[MCHP_PCR_SLP_RST_REG_MAX]; +static uint32_t ecia_result[MCHP_INT_GIRQ_NUM]; +#endif + +/* + * 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; +} + +/** clock_init + * @note + * MCHP MEC implements 4 control bits in the VBAT Clock Enable register. + * It also implements an internal silicon 32KHz +/- 2% oscillator powered + * by VBAT. + * b[3] = XOSEL 0=parallel, 1=single-ended + * b[2] = 32KHZ_SOURCE specifies source of always-on clock domain + * 0=internal silicon oscillator + * 1=crystal XOSEL pin(s) + * b[1] = EXT_32K use always-on clock domain or external 32KHZ_IN pin + * 0=32K source is always-on clock domain + * 1=32K source is 32KHZ_IN pin (GPIO 0165) + * b[0] = 32K_SUPPRESS + * 0=32K clock domain stays enabled if VTR is off. Powered by VBAT + * 1=32K clock domain is disabled if VTR is off. + * Set b[3] based on CONFIG_CLOCK_CRYSTAL + * Set b[2:0] = 100b + * b[0]=0 32K clock domain always on (requires VBAT if VTR is off) + * b[1]=0 32K source is the 32K clock domain NOT the 32KHZ_IN pin + * b[2]=1 If activity detected on crystal pins switch 32K input from + * internal silicon oscillator to XOSEL pin(s) based on b[3]. + */ +void clock_init(void) +{ + int __attribute__((unused)) dummy; + + trace0(0, MEC, 0, "Clock Init"); + +#ifdef CONFIG_CLOCK_CRYSTAL + /* XOSEL: 0 = Parallel resonant crystal */ + MCHP_VBAT_CE &= ~(1ul << 3); + +#else + /* XOSEL: 1 = Single ended clock source */ + MCHP_VBAT_CE |= (1ul << 3); +#endif + + /* 32K clock enable */ + MCHP_VBAT_CE = (MCHP_VBAT_CE & ~(0x03)) | (1ul << 2); + +#ifdef CONFIG_CLOCK_CRYSTAL + /* Wait for crystal to stabilize (OSC_LOCK == 1) */ + while (!(MCHP_PCR_CHIP_OSC_ID & 0x100)) + ; +#endif + trace0(0, MEC, 0, "PLL OSC is Locked"); +#ifndef LFW + dummy = shared_mem_size(); + trace11(0, MEC, 0, "Shared Memory size = 0x%08x", (uint32_t)dummy); +#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 */ + MCHP_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 timer0 + * Clear PCR sleep enable. + * GIRQ=21, aggregator bit = 1, Direct NVIC = 112 + * NVIC direct connect interrupts are used for all peripherals + * (exception GPIO's) then the MCHP_INT_BLK_EN GIRQ bit should not be + * set. + */ +static void htimer_init(void) +{ + MCHP_PCR_SLP_DIS_DEV(MCHP_PCR_HTMR0); + MCHP_INT_ENABLE(MCHP_HTIMER_GIRQ) = + MCHP_HTIMER_GIRQ_BIT(0); + MCHP_HTIMER_PRELOAD(0) = 0; /* disable at beginning */ + + task_enable_irq(MCHP_IRQ_HTIMER0); +} + +/** + * 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 + * @note hibernation timer input clock is 32.768KHz and has two + * divider values. + * Control register bit[0] selects the divider. + * 0 is divide by 1 for 30.5us per LSB for a maximum of ~2 seconds. + * 1 is divide by 4096 for 0.125s per LSB for a maximum of ~2 hours. + */ +static void system_set_htimer_alarm(uint32_t seconds, + uint32_t microseconds) +{ + uint32_t hcnt; + + if (microseconds >= 1000000) { + seconds += microseconds / 1000000; + microseconds -= (microseconds / 1000000) * 1000000; + } + + if (seconds || microseconds) { + + /* if (seconds > 2) { */ + if (seconds > 1) { + /* count from 2 sec to 2 hrs, mec1322 sec 18.10.2 */ + ASSERT(seconds <= 0xffff / 8); + /* 0.125(=1/8) per clock */ + MCHP_HTIMER_CONTROL(0) = 1; + /* (number of counts to be loaded) + * = seconds * ( 8 clocks per second ) + * + microseconds / 125000 + * ---> (0 if (microseconds < 125000) + */ + hcnt = (seconds * 8 + microseconds / 125000); + + } else { /* count up to 2 sec. */ + /* 30.5(= 2/61) usec */ + MCHP_HTIMER_CONTROL(0) = 0; + + /* (number of counts to be loaded) + * = (total microseconds) / 30.5; + */ + hcnt = (seconds * 1000000 + microseconds) * + 2 / 61; + } + + MCHP_HTIMER_PRELOAD(0) = hcnt; + } +} + +/** + * return time slept in micro-seconds + */ +static timestamp_t system_get_htimer(void) +{ + uint16_t count; + timestamp_t time; + + count = MCHP_HTIMER_COUNT(0); + + + if (MCHP_HTIMER_CONTROL(0) == 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) +{ + MCHP_HTIMER_PRELOAD(0) = 0; + MCHP_INT_SOURCE(MCHP_HTIMER_GIRQ) = + MCHP_HTIMER_GIRQ_BIT(0); +} + +#ifdef CONFIG_MCHP_DEEP_SLP_DEBUG +static void print_pcr_regs(void) +{ + int i; + + trace0(0, MEC, 0, "Current PCR registers"); + for (i = 0; i < 5; i++) { + trace12(0, MEC, 0, "REG SLP_EN[%d] = 0x%08X", + i, MCHP_PCR_SLP_EN(i)); + trace12(0, MEC, 0, "REG CLK_REQ[%d] = 0x%08X", + i, MCHP_PCR_CLK_REQ(i)); + } +} + +static void print_ecia_regs(void) +{ + int i; + + trace0(0, MEC, 0, "Current GIRQn.Result registers"); + for (i = MCHP_INT_GIRQ_FIRST; + i <= MCHP_INT_GIRQ_LAST; i++) + trace12(0, MEC, 0, "GIRQ[%d].Result = 0x%08X", + i, MCHP_INT_RESULT(i)); +} + +static void save_regs(void) +{ + int i; + + for (i = 0; i < MCHP_PCR_SLP_RST_REG_MAX; i++) { + pcr_slp_en[i] = MCHP_PCR_SLP_EN(i); + pcr_clk_req[i] = MCHP_PCR_CLK_REQ(i); + } + + for (i = 0; i < MCHP_INT_GIRQ_NUM; i++) + ecia_result[i] = + MCHP_INT_RESULT(MCHP_INT_GIRQ_FIRST + i); +} + +static void print_saved_regs(void) +{ + int i; + + trace0(0, BRD, 0, "Before sleep saved registers"); + for (i = 0; i < MCHP_PCR_SLP_RST_REG_MAX; i++) { + trace12(0, BRD, 0, "PCR_SLP_EN[%d] = 0x%08X", + i, pcr_slp_en[i]); + trace12(0, BRD, 0, "PCR_CLK_REQ[%d] = 0x%08X", + i, pcr_clk_req[i]); + } + + for (i = 0; i < MCHP_INT_GIRQ_NUM; i++) + trace12(0, BRD, 0, "GIRQ[%d].Result = 0x%08X", + (i+MCHP_INT_GIRQ_FIRST), ecia_result[i]); +} +#endif /* #ifdef CONFIG_MCHP_DEEP_SLP_DEBUG */ + +/** + * This is MCHP specific and equivalent to ARM Cortex's + * 'DeepSleep' via system control block register, CPU_SCB_SYSCTRL + * MCHP has new SLP_ALL feature. + * When SLP_ALL is enabled and HW sees sleep entry trigger from CPU. + * 1. HW saves PCR.SLP_EN registers + * 2. HW sets all PCR.SLP_EN bits to 1. + * 3. System sleeps + * 4. wake event wakes system + * 5. HW restores original values of all PCR.SLP_EN registers + * NOTE1: Current RTOS core (Cortex-Mx) does not use SysTick timer. + * We can leave code to disable it but do not re-enable on wake. + * NOTE2: Some peripherals will not sleep until outstanding transactions + * are complete: I2C, DMA, GPSPI, QMSPI, etc. + * NOTE3: Security blocks do not fully implement HW sleep therefore their + * sleep enables must be manually set/restored. + * + */ +static void prepare_for_deep_sleep(void) +{ + trace0(0, MEC, 0, "Prepare for Deep Sleep"); + + /* sysTick timer */ + CPU_NVIC_ST_CTRL &= ~ST_ENABLE; + CPU_NVIC_ST_CTRL &= ~ST_COUNTFLAG; + + CPU_NVIC_ST_CTRL &= ~ST_TICKINT; /* SYS_TICK_INT_DISABLE */ + + /* Enable assertion of DeepSleep signals + * from the core when core enters sleep. + */ + CPU_SCB_SYSCTRL |= (1 << 2); + + /* Stop timers */ + MCHP_TMR32_CTL(0) &= ~1; + MCHP_TMR32_CTL(1) &= ~1; + MCHP_TMR16_CTL(0) &= ~1; + MCHP_INT_DISABLE(MCHP_TMR32_GIRQ) = + MCHP_TMR32_GIRQ_BIT(0) + + MCHP_TMR32_GIRQ_BIT(1); + MCHP_INT_SOURCE(MCHP_TMR32_GIRQ) = + MCHP_TMR32_GIRQ_BIT(0) + + MCHP_TMR32_GIRQ_BIT(1); + MCHP_INT_DISABLE(MCHP_TMR16_GIRQ) = + MCHP_TMR16_GIRQ_BIT(0); + MCHP_INT_SOURCE(MCHP_TMR16_GIRQ) = + MCHP_TMR16_GIRQ_BIT(0); + +#ifdef CONFIG_WATCHDOG + /* Stop watchdog */ + MCHP_WDG_CTL &= ~1; +#endif + + +#ifdef CONFIG_ESPI + #ifdef CONFIG_POWER_S0IX + MCHP_INT_SOURCE(22) = MCHP_INT22_WAKE_ONLY_ESPI; + MCHP_INT_ENABLE(22) = MCHP_INT22_WAKE_ONLY_ESPI; + #else + MCHP_ESPI_ACTIVATE &= ~1; + #endif +#else + #ifdef CONFIG_POWER_S0IX + MCHP_INT_SOURCE(22) = MCHP_INT22_WAKE_ONLY_LPC; + MCHP_INT_ENABLE(22) = MCHP_INT22_WAKE_ONLY_LPC; + #else + MCHP_LPC_ACT |= 1; + #endif +#endif + +#ifdef CONFIG_ADC + /* + * Clear ADC activate bit. If a conversion is in progress the + * ADC block will not enter low power until the converstion is + * complete. + */ + MCHP_ADC_CTRL &= ~1; +#endif + + /* stop Port80 capture timer */ + MCHP_P80_ACTIVATE(0) = 0; + + /* + * Clear SLP_EN bit(s) for wake sources. + * Currently only Hibernation timer 0. + * GPIO pins can always wake. + */ + MCHP_PCR_SLP_EN3 &= ~(MCHP_PCR_SLP_EN3_HTMR0); + +#ifdef CONFIG_PWM + pwm_keep_awake(); /* clear sleep enables of active PWM's */ +#else + /* Disable 100 Khz clock */ + MCHP_PCR_SLOW_CLK_CTL &= 0xFFFFFC00; +#endif + +#ifdef CONFIG_CHIPSET_DEBUG + /* Disable JTAG and preserve mode */ + /* MCHP_EC_JTAG_EN &= ~(MCHP_JTAG_ENABLE); */ +#endif + + /* call board level */ +#ifdef CONFIG_BOARD_DEEP_SLEEP + board_prepare_for_deep_sleep(); +#endif + +#ifdef CONFIG_MCHP_DEEP_SLP_DEBUG + save_regs(); +#endif +} + +static void resume_from_deep_sleep(void) +{ + trace0(0, MEC, 0, "resume_from_deep_sleep"); + + MCHP_PCR_SYS_SLP_CTL = 0x00; /* default */ + + /* Disable assertion of DeepSleep signal when core executes WFI */ + CPU_SCB_SYSCTRL &= ~(1 << 2); + +#ifdef CONFIG_MCHP_DEEP_SLP_DEBUG + print_saved_regs(); + print_pcr_regs(); + print_ecia_regs(); +#endif + +#ifdef CONFIG_CHIPSET_DEBUG + MCHP_EC_JTAG_EN |= (MCHP_JTAG_ENABLE); +#endif + + MCHP_PCR_SLOW_CLK_CTL |= 0x1e0; + + /* call board level */ +#ifdef CONFIG_BOARD_DEEP_SLEEP + board_resume_from_deep_sleep(); +#endif + /* + * re-enable hibernation timer 0 PCR.SLP_EN to + * reduce power. + */ + MCHP_PCR_SLP_EN3 |= (MCHP_PCR_SLP_EN3_HTMR0); + +#ifdef CONFIG_ESPI + #ifdef CONFIG_POWER_S0IX + MCHP_INT_DISABLE(22) = MCHP_INT22_WAKE_ONLY_ESPI; + MCHP_INT_SOURCE(22) = MCHP_INT22_WAKE_ONLY_ESPI; + #else + MCHP_ESPI_ACTIVATE |= 1; + #endif +#else + #ifdef CONFIG_POWER_S0IX + MCHP_INT_DISABLE(22) = MCHP_INT22_WAKE_ONLY_LPC; + MCHP_INT_SOURCE(22) = MCHP_INT22_WAKE_ONLY_LPC; + #else + MCHP_LPC_ACT |= 1; + #endif +#endif + + /* re-enable Port80 capture */ + MCHP_P80_ACTIVATE(0) = 1; + +#ifdef CONFIG_ADC + MCHP_ADC_CTRL |= 1; +#endif + + /* Enable timer */ + MCHP_TMR32_CTL(0) |= 1; + MCHP_TMR32_CTL(1) |= 1; + MCHP_TMR16_CTL(0) |= 1; + MCHP_INT_ENABLE(MCHP_TMR32_GIRQ) = + MCHP_TMR32_GIRQ_BIT(0) + + MCHP_TMR32_GIRQ_BIT(1); + MCHP_INT_ENABLE(MCHP_TMR16_GIRQ) = + MCHP_TMR16_GIRQ_BIT(0); + + /* Enable watchdog */ +#ifdef CONFIG_WATCHDOG +#ifdef CONFIG_CHIPSET_DEBUG + /* enable WDG stall on active JTAG and do not start */ + MCHP_WDG_CTL = (1 << 4); +#else + MCHP_WDG_CTL |= 1; +#endif +#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("MEC1701 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) { + trace0(0, MEC, 0, "Enough time for Deep Sleep"); + /* + * 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("MEC1701 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 MCHP's heavy sleep mode requires all + * blocks to be sleepable, UART/console's + * readiness is final decision factor of + * heavy sleep of EC. + */ + if (uart_ready_for_deepsleep) { + + idle_dsleep_cnt++; + + /* + * config UART Rx as GPIO wakeup + * interrupt source + */ + uart_enter_dsleep(); + + /* MCHP 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); + + /* set sleep all just before WFI */ + MCHP_PCR_SYS_SLP_CTL |= + MCHP_PCR_SYS_SLP_HEAVY; + MCHP_PCR_SYS_SLP_CTL |= + MCHP_PCR_SYS_SLP_ALL; + + } else { + idle_sleep_cnt++; + } + + /* Wait for interrupt: goes into deep sleep. */ + asm("dsb"); + asm("wfi"); + asm("isb"); + asm("nop"); + + 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 + */ + +#ifdef CONFIG_MCHP_DEEP_SLP_DEBUG +static void print_pcr_regs(void) +{ + int i; + + ccprintf("PCR regs before WFI\n"); + for (i = 0; i < 5; i++) { + ccprintf("PCR SLP_EN[%d] = 0x%08X\n", pcr_slp_en[i]); + ccprintf("PCR CLK_REQ[%d] = 0x%08X\n", pcr_clk_req[i]); + } +} +#endif + +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): %.6ld(s)\n", + total_idle_dsleep_time_us); + ccprintf("Total time on: %.6lds\n\n", + ts.val); + +#ifdef CONFIG_MCHP_DEEP_SLP_DEBUG + print_pcr_regs(); /* debug */ +#endif + 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 deepsleep 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 */ |