summaryrefslogtreecommitdiff
path: root/chip/mchp/clock.c
diff options
context:
space:
mode:
Diffstat (limited to 'chip/mchp/clock.c')
-rw-r--r--chip/mchp/clock.c780
1 files changed, 0 insertions, 780 deletions
diff --git a/chip/mchp/clock.c b/chip/mchp/clock.c
deleted file mode 100644
index 362025ee1c..0000000000
--- a/chip/mchp/clock.c
+++ /dev/null
@@ -1,780 +0,0 @@
-/* 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 us */
-#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;
-}
-
-/*
- * MEC170x and MEC152x have the same 32 KHz clock enable hardware.
- * MEC172x 32 KHz clock configuration is different and includes
- * hardware to check the crystal before switching and to monitor
- * the 32 KHz input if desired.
- */
-#ifdef CHIP_FAMILY_MEC172X
-/* 32 KHz crystal connected in parallel */
-static inline void config_32k_src_crystal(void)
-{
- MCHP_VBAT_CSS = MCHP_VBAT_CSS_XTAL_EN
- | MCHP_VBAT_CSS_SRC_XTAL;
-}
-
-/* 32 KHz source is 32KHZ_IN pin which must be configured */
-static inline void config_32k_src_se_input(void)
-{
- MCHP_VBAT_CSS = MCHP_VBAT_CSS_SIL32K_EN
- | MCHP_VBAT_CSS_SRC_SWPS;
-}
-
-static inline void config_32k_src_sil_osc(void)
-{
- MCHP_VBAT_CSS = MCHP_VBAT_CSS_SIL32K_EN;
-}
-
-#else
-static void config_32k_src_crystal(void)
-{
- MCHP_VBAT_CE = MCHP_VBAT_CE_XOSEL_PAR
- | MCHP_VBAT_CE_ALWAYS_ON_32K_SRC_CRYSTAL;
-}
-
-/* 32 KHz source is 32KHZ_IN pin which must be configured */
-static inline void config_32k_src_se_input(void)
-{
- MCHP_VBAT_CE = MCHP_VBAT_CE_32K_DOMAIN_32KHZ_IN_PIN
- | MCHP_VBAT_CE_ALWAYS_ON_32K_SRC_INT;
-}
-
-static inline void config_32k_src_sil_osc(void)
-{
- MCHP_VBAT_CE = ~(MCHP_VBAT_CE_32K_DOMAIN_32KHZ_IN_PIN
- | MCHP_VBAT_CE_ALWAYS_ON_32K_SRC_CRYSTAL);
-}
-#endif
-
-/** 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)
-{
- if (IS_ENABLED(CONFIG_CLOCK_SRC_EXTERNAL))
- if (IS_ENABLED(CONFIG_CLOCK_CRYSTAL))
- config_32k_src_crystal();
- else
- /* 32KHz 50% duty waveform on 32KHZ_IN pin */
- config_32k_src_se_input();
- else
- /* Use internal silicon 32KHz OSC */
- config_32k_src_sil_osc();
-
- /* Wait for PLL to lock onto 32KHz source (OSC_LOCK == 1) */
- while (!(MCHP_PCR_CHIP_OSC_ID & 0x100))
- ;
-}
-
-/**
- * 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 = MCHP_PCR_CLK_CTL_12MHZ;
-}
-DECLARE_HOOK(HOOK_INIT,
- clock_turbo_disable,
- HOOK_PRIO_INIT_VBOOT_HASH + 1);
-
-/**
- * initialization of Hibernation timer 0
- * 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.
- */
-void htimer_init(void)
-{
- MCHP_PCR_SLP_DIS_DEV(MCHP_PCR_HTMR0);
- MCHP_HTIMER_PRELOAD(0) = 0; /* disable at beginning */
- MCHP_INT_SOURCE(MCHP_HTIMER_GIRQ) = MCHP_HTIMER_GIRQ_BIT(0);
- MCHP_INT_ENABLE(MCHP_HTIMER_GIRQ) = MCHP_HTIMER_GIRQ_BIT(0);
-
- 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.
- * Control register bit[0] selects the divider.
- * 0 is divide by 1 for 30.5 us per LSB for a maximum of
- * 65535 * 30.5 us = 1998817.5 us or 32.786 counts per second
- * 1 is divide by 4096 for 0.125 s per LSB for a maximum of ~2 hours.
- * 65535 * 0.125 s ~ 8192 s = 2.27 hours
- */
-void system_set_htimer_alarm(uint32_t seconds,
- uint32_t microseconds)
-{
- uint32_t hcnt, ns;
- uint8_t hctrl;
-
- MCHP_HTIMER_PRELOAD(0) = 0; /* disable */
-
- if (microseconds > 1000000ul) {
- ns = (microseconds / 1000000ul);
- microseconds %= 1000000ul;
- if ((0xfffffffful - seconds) > ns)
- seconds += ns;
- else
- seconds = 0xfffffffful;
- }
-
- if (seconds > 1) {
- hcnt = (seconds << 3); /* divide by 0.125 */
- if (hcnt > 0xfffful)
- hcnt = 0xfffful;
- hctrl = 1;
- } else {
- /*
- * approximate(~2% error) as seconds is 0 or 1
- * seconds / 30.5e-6 + microseconds / 30.5
- */
- hcnt = (seconds << 15) + (microseconds >> 5) +
- (microseconds >> 10);
- hctrl = 0;
- }
-
- MCHP_HTIMER_CONTROL(0) = hctrl;
- MCHP_HTIMER_PRELOAD(0) = hcnt;
-}
-
-#ifdef CONFIG_LOW_POWER_IDLE
-
-/**
- * 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) us 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]);
-}
-#else
-static __maybe_unused void print_pcr_regs(void) {}
-static __maybe_unused void print_ecia_regs(void) {}
-static __maybe_unused void save_regs(void) {}
-static __maybe_unused void print_saved_regs(void) {}
-#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-M4) 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)
-{
- /* 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 |= BIT(2);
-
- /* Stop timers */
- MCHP_TMR32_CTL(0) &= ~1;
- MCHP_TMR32_CTL(1) &= ~1;
-#ifdef CONFIG_WATCHDOG_HELP
- MCHP_TMR16_CTL(0) &= ~1;
- MCHP_INT_DISABLE(MCHP_TMR16_GIRQ) =
- MCHP_TMR16_GIRQ_BIT(0);
- MCHP_INT_SOURCE(MCHP_TMR16_GIRQ) =
- MCHP_TMR16_GIRQ_BIT(0);
-#endif
- 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);
-
-#ifdef CONFIG_WATCHDOG
- /* Stop watchdog */
- MCHP_WDG_CTL &= ~1;
-#endif
-
-
-#ifdef CONFIG_HOSTCMD_ESPI
- MCHP_INT_SOURCE(22) = MCHP_INT22_WAKE_ONLY_ESPI;
- MCHP_INT_ENABLE(22) = MCHP_INT22_WAKE_ONLY_ESPI;
-#else
- MCHP_INT_SOURCE(22) = MCHP_INT22_WAKE_ONLY_LPC;
- MCHP_INT_ENABLE(22) = MCHP_INT22_WAKE_ONLY_LPC;
-#endif
-
-#ifdef CONFIG_ADC
- /*
- * Clear ADC activate bit. If a conversion is in progress the
- * ADC block will not enter low power until the conversion is
- * complete.
- */
- MCHP_ADC_CTRL &= ~1;
-#endif
-
- /* stop Port80 capture timer */
-#ifndef CHIP_FAMILY_MEC172X
- MCHP_P80_ACTIVATE(0) = 0;
-#endif
-
- /*
- * 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)
-{
- MCHP_PCR_SYS_SLP_CTL = 0x00; /* default */
-
- /* Disable assertion of DeepSleep signal when core executes WFI */
- CPU_SCB_SYSCTRL &= ~BIT(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_HOSTCMD_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 Port 80 capture */
-#ifndef CHIP_FAMILY_MEC172X
- MCHP_P80_ACTIVATE(0) = 1;
-#endif
-
-#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 = BIT(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 initializations and have gone to sleep.
- */
- CPRINTS("MEC 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("MEC Disable console "
- "in deep sleep");
- }
-
-
- /* 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 sleep capable, UART/console
- * readiness is final decision factor of
- * heavy sleep of EC.
- */
- if (uart_ready_for_deepsleep) {
-
- idle_dsleep_cnt++;
-
- /*
- * configure 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 execution.
- */
- 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-enable 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);
-
- if (IS_ENABLED(CONFIG_MCHP_DEEP_SLP_DEBUG))
- print_pcr_regs(); /* debug */
-
- 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 heavy sleep mode.\nUse 'off' to "
- "allow deep sleep to use heavy sleep whenever conditions "
- "allow.\n"
- "Give a timeout value for the console in use timeout.\n"
- "See also 'sleep mask'.");
-#endif /* CONFIG_LOW_POWER_IDLE */