summaryrefslogtreecommitdiff
path: root/chip/stm32/clock-stm32f3.c
diff options
context:
space:
mode:
authorTom Hughes <tomhughes@chromium.org>2022-09-21 14:08:36 -0700
committerTom Hughes <tomhughes@chromium.org>2022-09-22 12:59:38 -0700
commitc453fd704268ef72de871b0c5ac7a989de662334 (patch)
treefcf6ce5810f9ff9e3c8cce434812dd75492269ed /chip/stm32/clock-stm32f3.c
parent6c1587ca70f558b4f96b3f0b18ad8b027d3ba99d (diff)
parent28712dae9d7ed1e694f7622cc083afa71090d4d5 (diff)
downloadchrome-ec-c453fd704268ef72de871b0c5ac7a989de662334.tar.gz
Merge remote-tracking branch cros/main into firmware-fpmcu-dartmonkey-releasefirmware-fpmcu-dartmonkey-release
Generated by: ./util/update_release_branch.py --board dartmonkey --relevant_paths_file ./util/fingerprint-relevant-paths.txt firmware-fpmcu-dartmonkey-release Relevant changes: git log --oneline 6c1587ca70..28712dae9d -- board/nocturne_fp board/dartmonkey common/fpsensor docs/fingerprint driver/fingerprint util/getversion.sh ded9307b79 util/getversion.sh: Fix version when not in a git repo 956055e692 board: change Google USB vendor info 71b2ef709d Update license boilerplate text in source code files 33e11afda0 Revert "fpsensor: Build fpsensor source file with C++" c8d0360723 fpsensor: Build fpsensor source file with C++ bc113abd53 fpsensor: Fix g++ compiler error 150a58a0dc fpsensor: Fix fp_set_sensor_mode return type b33b5ce85b fpsensor: Remove nested designators for C++ compatibility 2e864b2539 tree-wide: const-ify argv for console commands 56d8b360f9 test: Add test for get ikm failure when seed not set 3a3d6c3690 test: Add test for fpsensor trivial key failure 233e6bbd08 fpsensor_crypto: Abstract calls to hmac_SHA256 0a041b285b docs/fingerprint: Typo correction c03fab67e2 docs/fingerprint: Fix the path of fputils.py 0b5d4baf5a util/getversion.sh: Fix empty file list handling 6e128fe760 FPMCU dev board environment with Satlab 3eb29b6aa5 builtin: Move ssize_t to sys/types.h 345d62ebd1 docs/fingerprint: Update power numbers for latest dartmonkey release c25ffdb316 common: Conditionally support printf %l and %i modifiers 9a3c514b45 test: Add a test to check if the debugger is connected 54e603413f Move standard library tests to their own file 43fa6b4bf8 docs/fingerprint: Update power numbers for latest bloonchipper release 25536f9a84 driver/fingerprint/fpc/bep/fpc_sensor_spi.c: Format with clang-format 4face99efd driver/fingerprint/fpc/libfp/fpc_sensor_pal.h: Format with clang-format 738de2b575 trng: Rename rand to trng_rand 14b8270edd docs/fingerprint: Update dragonclaw power numbers 0b268f93d1 driver/fingerprint/fpc/libfp/fpc_private.c: Format with clang-format f80da163f2 driver/fingerprint/fpc/libfp/fpc_private.h: Format with clang-format a0751778f4 board/nocturne_fp/ro_workarounds.c: Format with clang-format 5e9c85c9b1 driver/fingerprint/fpc/libfp/fpc_sensor_pal.c: Format with clang-format c1f9dd3cf8 driver/fingerprint/fpc/libfp/fpc_bio_algorithm.h: Format with clang-format eb1e1bed8d driver/fingerprint/fpc/libfp/fpc1145_private.h: Format with clang-format 6e7b611821 driver/fingerprint/fpc/bep/fpc_bio_algorithm.h: Format with clang-format e0589cd5e2 driver/fingerprint/fpc/bep/fpc1035_private.h: Format with clang-format 58f0246dbe board/nocturne_fp/board_ro.c: Format with clang-format 7905e556a0 common/fpsensor/fpsensor_crypto.c: Format with clang-format 21289d170c driver/fingerprint/fpc/bep/fpc1025_private.h: Format with clang-format 98a20f937e common/fpsensor/fpsensor_state.c: Format with clang-format a2d255d8af common/fpsensor/fpsensor.c: Format with clang-format 84e53a65da board/nocturne_fp/board.h: Format with clang-format 73055eeb3f driver/fingerprint/fpc/bep/fpc_private.c: Format with clang-format 0f7b5cb509 common/fpsensor/fpsensor_private.h: Format with clang-format 1ceade6e65 driver/fingerprint/fpc/bep/fpc_private.h: Format with clang-format dca9d74321 Revert "trng: Rename rand to trng_rand" a6b0b3554f trng: Rename rand to trng_rand 28d0b75b70 third_party/boringssl: Remove unused header BRANCH=None BUG=b:244387210 b:242720240 b:215613183 b:242720910 b:236386294 BUG=b:234181908 b:244781166 b:234781655 b:234143158 b:234181908 BUG=b:237344361 b:236025198 b:234181908 b:180945056 chromium:1098010 BUG=b:246424843 b:234181908 b:131913998 TEST=`make -j buildall` TEST=./util/run_device_tests.py --board dartmonkey Test "aes": PASSED Test "cec": PASSED Test "cortexm_fpu": PASSED Test "crc": PASSED Test "flash_physical": PASSED Test "flash_write_protect": PASSED Test "fpsensor_hw": PASSED Test "fpsensor_spi_ro": PASSED Test "fpsensor_spi_rw": PASSED Test "fpsensor_uart_ro": PASSED Test "fpsensor_uart_rw": PASSED Test "mpu_ro": PASSED Test "mpu_rw": PASSED Test "mutex": PASSED Test "pingpong": PASSED Test "printf": PASSED Test "queue": PASSED Test "rollback_region0": PASSED Test "rollback_region1": PASSED Test "rollback_entropy": PASSED Test "rtc": PASSED Test "sha256": PASSED Test "sha256_unrolled": PASSED Test "static_if": PASSED Test "stdlib": PASSED Test "system_is_locked_wp_on": PASSED Test "system_is_locked_wp_off": PASSED Test "timer_dos": PASSED Test "utils": PASSED Test "utils_str": PASSED Test "panic_data_dartmonkey_v2.0.2887": PASSED Test "panic_data_nocturne_fp_v2.2.64": PASSED Test "panic_data_nami_fp_v2.2.144": PASSED Force-Relevant-Builds: all Signed-off-by: Tom Hughes <tomhughes@chromium.org> Change-Id: I2c312583a709fedae8fe11d92c22328c3b634bc7
Diffstat (limited to 'chip/stm32/clock-stm32f3.c')
-rw-r--r--[l---------]chip/stm32/clock-stm32f3.c502
1 files changed, 501 insertions, 1 deletions
diff --git a/chip/stm32/clock-stm32f3.c b/chip/stm32/clock-stm32f3.c
index be91154e52..7d2b3de7f2 120000..100644
--- a/chip/stm32/clock-stm32f3.c
+++ b/chip/stm32/clock-stm32f3.c
@@ -1 +1,501 @@
-clock-stm32f0.c \ No newline at end of file
+/* Copyright 2014 The ChromiumOS Authors
+ * 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 "chipset.h"
+#include "clock.h"
+#include "clock-f.h"
+#include "common.h"
+#include "console.h"
+#include "cpu.h"
+#include "hooks.h"
+#include "hwtimer.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)
+
+/* use 48Mhz USB-synchronized High-speed oscillator */
+#define HSI48_CLOCK 48000000
+
+/* use PLL at 38.4MHz as system clock. */
+#define PLL_CLOCK 38400000
+
+/* Low power idle statistics */
+#ifdef CONFIG_LOW_POWER_IDLE
+static int idle_sleep_cnt;
+static int idle_dsleep_cnt;
+static uint64_t idle_dsleep_time_us;
+static int dsleep_recovery_margin_us = 1000000;
+
+/*
+ * minimum delay to enter stop mode
+ *
+ * STOP_MODE_LATENCY: max time to wake up from STOP mode with regulator in low
+ * power mode is 5 us + PLL locking time is 200us.
+ *
+ * SET_RTC_MATCH_DELAY: max time to set RTC match alarm. If we set the alarm
+ * in the past, it will never wake up and cause a watchdog.
+ * For STM32F3, we are using HSE, which requires additional time to start up.
+ * Therefore, the latency for STM32F3 is set longer.
+ *
+ * RESTORE_HOST_ALARM_LATENCY: max latency between the deferred routine is
+ * called and the host alarm is actually restored. In practice, the max latency
+ * is measured as ~600us. 1000us should be conservative enough to guarantee
+ * we won't miss the host alarm.
+ */
+#ifdef CHIP_VARIANT_STM32F373
+#define STOP_MODE_LATENCY 500 /* us */
+#elif defined(CHIP_VARIANT_STM32F05X)
+#define STOP_MODE_LATENCY 300 /* us */
+#elif (CPU_CLOCK == PLL_CLOCK)
+#define STOP_MODE_LATENCY 300 /* us */
+#else
+#define STOP_MODE_LATENCY 50 /* us */
+#endif
+#define SET_RTC_MATCH_DELAY 200 /* us */
+
+#ifdef CONFIG_HOSTCMD_RTC
+#define RESTORE_HOST_ALARM_LATENCY 1000 /* us */
+#endif
+
+#endif /* CONFIG_LOW_POWER_IDLE */
+
+/*
+ * RTC clock frequency (By default connected to LSI clock)
+ *
+ * The LSI on any given chip can be between 30 kHz to 60 kHz.
+ * Without calibration, LSI frequency may be off by as much as 50%.
+ *
+ * Set synchronous clock freq to (RTC clock source / 2) to maximize
+ * subsecond resolution. Set asynchronous clock to 1 Hz.
+ */
+
+#define RTC_PREDIV_A 1
+#ifdef CONFIG_STM32_CLOCK_LSE
+#define RTC_FREQ (32768 / (RTC_PREDIV_A + 1)) /* Hz */
+/* GCD(RTC_FREQ, 1000000) */
+#define RTC_GCD 64
+#else /* LSI clock, 40kHz-ish */
+#define RTC_FREQ (40000 / (RTC_PREDIV_A + 1)) /* Hz */
+/* GCD(RTC_FREQ, 1000000) */
+#define RTC_GCD 20000
+#endif
+#define RTC_PREDIV_S (RTC_FREQ - 1)
+
+/*
+ * There are (1000000 / RTC_FREQ) us per RTC tick, take GCD of both terms
+ * for conversion calculations to fit in 32 bits.
+ */
+#define US_GCD (1000000 / RTC_GCD)
+#define RTC_FREQ_GCD (RTC_FREQ / RTC_GCD)
+
+int32_t rtcss_to_us(uint32_t rtcss)
+{
+ return ((RTC_PREDIV_S - (rtcss & 0x7fff)) * US_GCD) / RTC_FREQ_GCD;
+}
+
+uint32_t us_to_rtcss(int32_t us)
+{
+ return RTC_PREDIV_S - us * RTC_FREQ_GCD / US_GCD;
+}
+
+void config_hispeed_clock(void)
+{
+#ifdef CHIP_FAMILY_STM32F3
+ /* Ensure that HSE is ON */
+ wait_for_ready(&STM32_RCC_CR, BIT(16), BIT(17));
+
+ /*
+ * HSE = 24MHz, no prescalar, no MCO, with PLL *2 => 48MHz SYSCLK
+ * HCLK = SYSCLK, PCLK = HCLK / 2 = 24MHz
+ * ADCCLK = PCLK / 6 = 4MHz
+ * USB uses SYSCLK = 48MHz
+ */
+ STM32_RCC_CFGR = 0x0041a400;
+
+ /* Enable the PLL */
+ STM32_RCC_CR |= 0x01000000;
+
+ /* Wait until the PLL is ready */
+ while (!(STM32_RCC_CR & 0x02000000))
+ ;
+
+ /* Switch SYSCLK to PLL */
+ STM32_RCC_CFGR |= 0x2;
+
+ /* Wait until the PLL is the clock source */
+ while ((STM32_RCC_CFGR & 0xc) != 0x8)
+ ;
+/* F03X and F05X and F070 don't have HSI48 */
+#elif defined(CHIP_VARIANT_STM32F03X) || defined(CHIP_VARIANT_STM32F05X) || \
+ defined(CHIP_VARIANT_STM32F070)
+ /* If PLL is the clock source, PLL has already been set up. */
+ if ((STM32_RCC_CFGR & 0xc) == 0x8)
+ return;
+
+ /* Ensure that HSI is ON */
+ wait_for_ready(&STM32_RCC_CR, BIT(0), BIT(1));
+
+ /*
+ * HSI = 8MHz, HSI/2 with PLL *12 = ~48 MHz
+ * therefore PCLK = FCLK = SYSCLK = 48MHz
+ */
+ /* Switch the PLL source to HSI/2 */
+ STM32_RCC_CFGR &= ~(0x00018000);
+
+ /*
+ * Specify HSI/2 clock as input clock to PLL and set PLL (*12).
+ */
+ STM32_RCC_CFGR |= 0x00280000;
+
+ /* Enable the PLL. */
+ STM32_RCC_CR |= 0x01000000;
+
+ /* Wait until PLL is ready. */
+ while (!(STM32_RCC_CR & 0x02000000))
+ ;
+
+ /* Switch SYSCLK to PLL. */
+ STM32_RCC_CFGR |= 0x2;
+
+ /* wait until the PLL is the clock source */
+ while ((STM32_RCC_CFGR & 0xc) != 0x8)
+ ;
+#else
+ /* Ensure that HSI48 is ON */
+ wait_for_ready(&STM32_RCC_CR2, BIT(16), BIT(17));
+
+#if (CPU_CLOCK == HSI48_CLOCK)
+ /*
+ * HSI48 = 48MHz, no prescaler, no MCO, no PLL
+ * therefore PCLK = FCLK = SYSCLK = 48MHz
+ * USB uses HSI48 = 48MHz
+ */
+
+#ifdef CONFIG_USB
+ /*
+ * Configure and enable Clock Recovery System
+ *
+ * Since we are running from the internal RC HSI48 clock, the CSR
+ * is needed to guarantee an accurate 48MHz clock for USB.
+ *
+ * The default values configure the CRS to use the periodic USB SOF
+ * as the SYNC signal for calibrating the HSI48.
+ *
+ */
+
+ /* Enable Clock Recovery System */
+ STM32_RCC_APB1ENR |= STM32_RCC_PB1_CRS;
+
+ /* Enable automatic trimming */
+ STM32_CRS_CR |= STM32_CRS_CR_AUTOTRIMEN;
+
+ /* Enable oscillator clock for the frequency error counter */
+ STM32_CRS_CR |= STM32_CRS_CR_CEN;
+#endif
+
+ /* switch SYSCLK to HSI48 */
+ STM32_RCC_CFGR = 0x00000003;
+
+ /* wait until the HSI48 is the clock source */
+ while ((STM32_RCC_CFGR & 0xc) != 0xc)
+ ;
+
+#elif (CPU_CLOCK == PLL_CLOCK)
+ /*
+ * HSI48 = 48MHz, no prescalar, no MCO, with PLL *4/5 => 38.4MHz SYSCLK
+ * therefore PCLK = FCLK = SYSCLK = 38.4MHz
+ * USB uses HSI48 = 48MHz
+ */
+
+ /* If PLL is the clock source, PLL has already been set up. */
+ if ((STM32_RCC_CFGR & 0xc) == 0x8)
+ return;
+
+ /*
+ * Specify HSI48 clock as input clock to PLL and set PLL multiplier
+ * and divider.
+ */
+ STM32_RCC_CFGR = 0x00098000;
+ STM32_RCC_CFGR2 = 0x4;
+
+ /* Enable the PLL. */
+ STM32_RCC_CR |= 0x01000000;
+
+ /* Wait until PLL is ready. */
+ while (!(STM32_RCC_CR & 0x02000000))
+ ;
+
+ /* Switch SYSCLK to PLL. */
+ STM32_RCC_CFGR |= 0x2;
+
+ /* wait until the PLL is the clock source */
+ while ((STM32_RCC_CFGR & 0xc) != 0x8)
+ ;
+
+#else
+#error "CPU_CLOCK must be either 48MHz or 38.4MHz"
+#endif
+#endif
+}
+
+#ifdef CONFIG_HIBERNATE
+void __enter_hibernate(uint32_t seconds, uint32_t microseconds)
+{
+ struct rtc_time_reg rtc;
+
+ if (seconds || microseconds)
+ set_rtc_alarm(seconds, microseconds, &rtc, 0);
+
+ /* interrupts off now */
+ interrupt_disable();
+
+#ifdef CONFIG_HIBERNATE_WAKEUP_PINS
+ /* enable the wake up pins */
+ STM32_PWR_CSR |= CONFIG_HIBERNATE_WAKEUP_PINS;
+#endif
+ STM32_PWR_CR |= 0xe;
+ CPU_SCB_SYSCTRL |= 0x4;
+ /* go to Standby mode */
+ asm("wfi");
+
+ /* we should never reach that point */
+ while (1)
+ ;
+}
+#endif
+
+#ifdef CONFIG_HOSTCMD_RTC
+static void restore_host_wake_alarm_deferred(void)
+{
+ restore_host_wake_alarm();
+}
+DECLARE_DEFERRED(restore_host_wake_alarm_deferred);
+#endif
+
+#ifdef CONFIG_LOW_POWER_IDLE
+
+void clock_refresh_console_in_use(void)
+{
+}
+
+void __idle(void)
+{
+ timestamp_t t0;
+ uint32_t rtc_diff;
+ int next_delay, margin_us;
+ struct rtc_time_reg rtc0, rtc1;
+
+ while (1) {
+ interrupt_disable();
+
+ t0 = get_time();
+ next_delay = __hw_clock_event_get() - t0.le.lo;
+
+#ifdef CONFIG_LOW_POWER_IDLE_LIMITED
+ if (idle_is_disabled())
+ goto en_int;
+#endif
+
+ if (DEEP_SLEEP_ALLOWED &&
+#ifdef CONFIG_HOSTCMD_RTC
+ /*
+ * Don't go to deep sleep mode if we might miss the
+ * wake alarm that the host requested. Note that the
+ * host alarm always aligns to second. Considering the
+ * worst case, we have to ensure alarm won't go off
+ * within RESTORE_HOST_ALARM_LATENCY + 1 second after
+ * EC exits deep sleep mode.
+ */
+ !is_host_wake_alarm_expired(
+ (timestamp_t)(next_delay + t0.val + SECOND +
+ RESTORE_HOST_ALARM_LATENCY)) &&
+#endif
+ (next_delay > (STOP_MODE_LATENCY + SET_RTC_MATCH_DELAY))) {
+ /* Deep-sleep in STOP mode */
+ idle_dsleep_cnt++;
+
+ uart_enable_wakeup(1);
+
+ /* Set deep sleep bit */
+ CPU_SCB_SYSCTRL |= 0x4;
+
+ set_rtc_alarm(0, next_delay - STOP_MODE_LATENCY, &rtc0,
+ 0);
+ asm("wfi");
+
+ CPU_SCB_SYSCTRL &= ~0x4;
+
+ uart_enable_wakeup(0);
+
+ /*
+ * By default only HSI 8MHz is enabled here. Re-enable
+ * high-speed clock if in use.
+ */
+ config_hispeed_clock();
+
+ /* Fast forward timer according to RTC counter */
+ reset_rtc_alarm(&rtc1);
+ rtc_diff = get_rtc_diff(&rtc0, &rtc1);
+ t0.val = t0.val + rtc_diff;
+ force_time(t0);
+
+#ifdef CONFIG_HOSTCMD_RTC
+ hook_call_deferred(
+ &restore_host_wake_alarm_deferred_data, 0);
+#endif
+ /* Record time spent in deep sleep. */
+ idle_dsleep_time_us += rtc_diff;
+
+ /* Calculate how close we were to missing deadline */
+ margin_us = next_delay - rtc_diff;
+ if (margin_us < 0)
+ /* Use CPUTS to save stack space */
+ CPUTS("Idle overslept!\n");
+
+ /* Record the closest to missing a deadline. */
+ if (margin_us < dsleep_recovery_margin_us)
+ dsleep_recovery_margin_us = margin_us;
+ } else {
+ idle_sleep_cnt++;
+
+ /* Normal idle : only CPU clock stopped */
+ asm("wfi");
+ }
+#ifdef CONFIG_LOW_POWER_IDLE_LIMITED
+ en_int:
+#endif
+ interrupt_enable();
+ }
+}
+#endif /* CONFIG_LOW_POWER_IDLE */
+
+int clock_get_freq(void)
+{
+ return CPU_CLOCK;
+}
+
+void clock_wait_bus_cycles(enum bus_type bus, uint32_t cycles)
+{
+ volatile uint32_t unused __attribute__((unused));
+
+ if (bus == BUS_AHB) {
+ while (cycles--)
+ unused = STM32_DMA1_REGS->isr;
+ } else { /* APB */
+ while (cycles--)
+ unused = STM32_USART_BRR(STM32_USART1_BASE);
+ }
+}
+
+void clock_enable_module(enum module_id module, int enable)
+{
+ if (module == MODULE_ADC) {
+ if (enable)
+ STM32_RCC_APB2ENR |= STM32_RCC_APB2ENR_ADCEN;
+ else
+ STM32_RCC_APB2ENR &= ~STM32_RCC_APB2ENR_ADCEN;
+ return;
+ } else if (module == MODULE_USB) {
+ if (enable)
+ STM32_RCC_APB1ENR |= STM32_RCC_PB1_USB;
+ else
+ STM32_RCC_APB1ENR &= ~STM32_RCC_PB1_USB;
+ }
+}
+
+int clock_is_module_enabled(enum module_id module)
+{
+ if (module == MODULE_ADC)
+ return !!(STM32_RCC_APB2ENR & STM32_RCC_APB2ENR_ADCEN);
+ else if (module == MODULE_USB)
+ return !!(STM32_RCC_APB1ENR & STM32_RCC_PB1_USB);
+ return 0;
+}
+
+void rtc_init(void)
+{
+ rtc_unlock_regs();
+
+ /* Enter RTC initialize mode */
+ STM32_RTC_ISR |= STM32_RTC_ISR_INIT;
+ while (!(STM32_RTC_ISR & STM32_RTC_ISR_INITF))
+ ;
+
+ /* Set clock prescalars */
+ STM32_RTC_PRER = (RTC_PREDIV_A << 16) | RTC_PREDIV_S;
+
+ /* Start RTC timer */
+ STM32_RTC_ISR &= ~STM32_RTC_ISR_INIT;
+ while (STM32_RTC_ISR & STM32_RTC_ISR_INITF)
+ ;
+
+ /* Enable RTC alarm interrupt */
+ STM32_RTC_CR |= STM32_RTC_CR_ALRAIE | STM32_RTC_CR_BYPSHAD;
+ STM32_EXTI_RTSR |= EXTI_RTC_ALR_EVENT;
+ task_enable_irq(STM32_IRQ_RTC_ALARM);
+
+ rtc_lock_regs();
+}
+
+#if defined(CONFIG_CMD_RTC) || defined(CONFIG_HOSTCMD_RTC)
+void rtc_set(uint32_t sec)
+{
+ struct rtc_time_reg rtc;
+
+ sec_to_rtc(sec, &rtc);
+ rtc_unlock_regs();
+
+ /* Disable alarm */
+ STM32_RTC_CR &= ~STM32_RTC_CR_ALRAE;
+
+ /* Enter RTC initialize mode */
+ STM32_RTC_ISR |= STM32_RTC_ISR_INIT;
+ while (!(STM32_RTC_ISR & STM32_RTC_ISR_INITF))
+ ;
+
+ /* Set clock prescalars */
+ STM32_RTC_PRER = (RTC_PREDIV_A << 16) | RTC_PREDIV_S;
+
+ STM32_RTC_TR = rtc.rtc_tr;
+ STM32_RTC_DR = rtc.rtc_dr;
+ /* Start RTC timer */
+ STM32_RTC_ISR &= ~STM32_RTC_ISR_INIT;
+
+ rtc_lock_regs();
+}
+#endif
+
+#if defined(CONFIG_LOW_POWER_IDLE) && defined(CONFIG_COMMON_RUNTIME)
+#ifdef CONFIG_CMD_IDLE_STATS
+/**
+ * Print low power idle statistics
+ */
+static int command_idle_stats(int argc, const 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("Time spent in deep-sleep: %.6llds\n",
+ idle_dsleep_time_us);
+ ccprintf("Total time on: %.6llds\n", ts.val);
+ ccprintf("Deep-sleep closest to wake deadline: %dus\n",
+ dsleep_recovery_margin_us);
+
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(idlestats, command_idle_stats, "",
+ "Print last idle stats");
+#endif /* CONFIG_CMD_IDLE_STATS */
+#endif