diff options
author | Tom Hughes <tomhughes@chromium.org> | 2022-09-21 14:08:36 -0700 |
---|---|---|
committer | Tom Hughes <tomhughes@chromium.org> | 2022-09-22 12:59:38 -0700 |
commit | c453fd704268ef72de871b0c5ac7a989de662334 (patch) | |
tree | fcf6ce5810f9ff9e3c8cce434812dd75492269ed /chip/stm32/clock-stm32f3.c | |
parent | 6c1587ca70f558b4f96b3f0b18ad8b027d3ba99d (diff) | |
parent | 28712dae9d7ed1e694f7622cc083afa71090d4d5 (diff) | |
download | chrome-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.c | 502 |
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 |