summaryrefslogtreecommitdiff
path: root/chip/stm32/clock-stm32f4.c
diff options
context:
space:
mode:
Diffstat (limited to 'chip/stm32/clock-stm32f4.c')
-rw-r--r--chip/stm32/clock-stm32f4.c553
1 files changed, 0 insertions, 553 deletions
diff --git a/chip/stm32/clock-stm32f4.c b/chip/stm32/clock-stm32f4.c
deleted file mode 100644
index a50f5f51dd..0000000000
--- a/chip/stm32/clock-stm32f4.c
+++ /dev/null
@@ -1,553 +0,0 @@
-/* Copyright 2016 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 "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 "util.h"
-
-/* Console output macros */
-#define CPUTS(outstr) cputs(CC_CLOCK, outstr)
-#define CPRINTS(format, args...) cprints(CC_CLOCK, format, ## args)
-
-enum clock_osc {
- OSC_HSI = 0, /* High-speed internal oscillator */
- OSC_HSE, /* High-speed external oscillator */
- OSC_PLL, /* PLL */
-};
-
-/*
- * NOTE: Sweetberry requires MCO2 <- HSE @ 24MHz
- * MCO outputs are selected here but are not changeable later.
- * A CONFIG may be needed if other boards have different MCO
- * requirements.
- */
-#define RCC_CFGR_MCO_CONFIG ((2 << 30) | /* MCO2 <- HSE */ \
- (0 << 27) | /* MCO2 div / 4 */ \
- (6 << 24) | /* MCO1 div / 4 */ \
- (3 << 21)) /* MCO1 <- PLL */
-
-#ifdef CONFIG_STM32_CLOCK_HSE_HZ
-/* RTC clock must 1 Mhz when derived from HSE */
-#define RTC_DIV DIV_ROUND_NEAREST(CONFIG_STM32_CLOCK_HSE_HZ, STM32F4_RTC_REQ)
-#else /* !CONFIG_STM32_CLOCK_HSE_HZ */
-/* RTC clock not derived from HSE, turn it off */
-#define RTC_DIV 0
-#endif /* CONFIG_STM32_CLOCK_HSE_HZ */
-
-
-/* Bus clocks dividers depending on the configuration */
-/*
- * max speed configuration with the PLL ON
- * as defined in the registers file.
- * For STM32F446: max 45 MHz
- * For STM32F412: max AHB 100 MHz / APB2 100 Mhz / APB1 50 Mhz
- */
-#define RCC_CFGR_DIVIDERS_WITH_PLL (RCC_CFGR_MCO_CONFIG | \
- CFGR_RTCPRE(RTC_DIV) | \
- CFGR_PPRE2(STM32F4_APB2_PRE) | \
- CFGR_PPRE1(STM32F4_APB1_PRE) | \
- CFGR_HPRE(STM32F4_AHB_PRE))
-/*
- * lower power configuration without the PLL
- * the frequency will be low (8-24Mhz), we don't want dividers to the
- * peripheral clocks, put /1 everywhere.
- */
-#define RCC_CFGR_DIVIDERS_NO_PLL (RCC_CFGR_MCO_CONFIG | CFGR_RTCPRE(0) | \
- CFGR_PPRE2(0) | CFGR_PPRE1(0) | CFGR_HPRE(0))
-
-/* PLL output frequency */
-#define STM32F4_PLL_CLOCK (STM32F4_VCO_CLOCK / STM32F4_PLLP_DIV)
-
-/* current clock settings (PLL is initialized at startup) */
-static int current_osc = OSC_PLL;
-static int current_io_freq = STM32F4_IO_CLOCK;
-static int current_timer_freq = STM32F4_TIMER_CLOCK;
-
-/* the EC code expects to get the USART/I2C clock frequency here (APB clock) */
-int clock_get_freq(void)
-{
- return current_io_freq;
-}
-
-int clock_get_timer_freq(void)
-{
- return current_timer_freq;
-}
-
-static void clock_enable_osc(enum clock_osc osc, bool enabled)
-{
- uint32_t ready;
- uint32_t on;
-
- switch (osc) {
- case OSC_HSI:
- ready = STM32_RCC_CR_HSIRDY;
- on = STM32_RCC_CR_HSION;
- break;
- case OSC_HSE:
- ready = STM32_RCC_CR_HSERDY;
- on = STM32_RCC_CR_HSEON;
- break;
- case OSC_PLL:
- ready = STM32_RCC_CR_PLLRDY;
- on = STM32_RCC_CR_PLLON;
- break;
- default:
- ASSERT(0);
- return;
- }
-
- /* Turn off the oscillator, but don't wait for shutdown */
- if (!enabled) {
- STM32_RCC_CR &= ~on;
- return;
- }
-
- /* Turn on the oscillator if not already on */
- wait_for_ready(&STM32_RCC_CR, on, ready);
-}
-
-static void clock_switch_osc(enum clock_osc osc)
-{
- uint32_t sw;
- uint32_t sws;
-
- switch (osc) {
- case OSC_HSI:
- sw = STM32_RCC_CFGR_SW_HSI | RCC_CFGR_DIVIDERS_NO_PLL;
- sws = STM32_RCC_CFGR_SWS_HSI;
- break;
- case OSC_HSE:
- sw = STM32_RCC_CFGR_SW_HSE | RCC_CFGR_DIVIDERS_NO_PLL;
- sws = STM32_RCC_CFGR_SWS_HSE;
- break;
- case OSC_PLL:
- sw = STM32_RCC_CFGR_SW_PLL | RCC_CFGR_DIVIDERS_WITH_PLL;
- sws = STM32_RCC_CFGR_SWS_PLL;
- break;
- default:
- return;
- }
-
- STM32_RCC_CFGR = sw;
- while ((STM32_RCC_CFGR & STM32_RCC_CFGR_SWS_MASK) != sws)
- ;
-}
-
-void clock_set_osc(enum clock_osc osc)
-{
- volatile uint32_t unused __attribute__((unused));
-
- if (osc == current_osc)
- return;
-
- hook_notify(HOOK_PRE_FREQ_CHANGE);
-
- switch (osc) {
- default:
- case OSC_HSI:
- /* new clock settings: no dividers */
- current_io_freq = STM32F4_HSI_CLOCK;
- current_timer_freq = STM32F4_HSI_CLOCK;
- /* Switch to HSI */
- clock_switch_osc(OSC_HSI);
- /* optimized flash latency settings for <30Mhz clock (0-WS) */
- STM32_FLASH_ACR = (STM32_FLASH_ACR & ~STM32_FLASH_ACR_LAT_MASK)
- | STM32_FLASH_ACR_LATENCY_SLOW;
- /* read-back the latency as advised by the Reference Manual */
- unused = STM32_FLASH_ACR;
- /* Turn off the PLL1 to save power */
- clock_enable_osc(OSC_PLL, false);
- break;
-
-#ifdef CONFIG_STM32_CLOCK_HSE_HZ
- case OSC_HSE:
- /* new clock settings: no dividers */
- current_io_freq = CONFIG_STM32_CLOCK_HSE_HZ;
- current_timer_freq = CONFIG_STM32_CLOCK_HSE_HZ;
- /* Switch to HSE */
- clock_switch_osc(OSC_HSE);
- /* optimized flash latency settings for <30Mhz clock (0-WS) */
- STM32_FLASH_ACR = (STM32_FLASH_ACR & ~STM32_FLASH_ACR_LAT_MASK)
- | STM32_FLASH_ACR_LATENCY_SLOW;
- /* read-back the latency as advised by the Reference Manual */
- unused = STM32_FLASH_ACR;
- /* Turn off the PLL1 to save power */
- clock_enable_osc(OSC_PLL, false);
- break;
-#endif /* CONFIG_STM32_CLOCK_HSE_HZ */
-
- case OSC_PLL:
- /* new clock settings */
- current_io_freq = STM32F4_IO_CLOCK;
- current_timer_freq = STM32F4_TIMER_CLOCK;
- /* turn on PLL and wait until it's ready */
- clock_enable_osc(OSC_PLL, true);
- /*
- * Increase flash latency before transition the clock
- * Use the minimum Wait States value optimized for the platform.
- */
- STM32_FLASH_ACR = (STM32_FLASH_ACR & ~STM32_FLASH_ACR_LAT_MASK)
- | STM32_FLASH_ACR_LATENCY;
- /* read-back the latency as advised by the Reference Manual */
- unused = STM32_FLASH_ACR;
- /* Switch to PLL */
- clock_switch_osc(OSC_PLL);
-
- break;
- }
-
- current_osc = osc;
- hook_notify(HOOK_FREQ_CHANGE);
-}
-
-static void clock_pll_configure(void)
-{
-#ifdef CONFIG_STM32_CLOCK_HSE_HZ
- int srcclock = CONFIG_STM32_CLOCK_HSE_HZ;
-#else
- int srcclock = STM32F4_HSI_CLOCK;
-#endif
- int plldiv, pllinputclock;
- int pllmult, vcoclock;
- int systemclock;
- int usbdiv;
- int i2sdiv;
-
- /* PLL input must be between 1-2MHz, near 2 */
- /* Valid values 2-63 */
- plldiv = (srcclock + STM32F4_PLL_REQ - 1) / STM32F4_PLL_REQ;
- pllinputclock = srcclock / plldiv;
-
- /* PLL output clock: Must be 100-432MHz */
- pllmult = (STM32F4_VCO_CLOCK + (pllinputclock / 2)) / pllinputclock;
- vcoclock = pllinputclock * pllmult;
-
- /* CPU/System clock */
- systemclock = vcoclock / STM32F4_PLLP_DIV;
- /* USB clock = 48MHz exactly */
- usbdiv = (vcoclock + (STM32F4_USB_REQ / 2)) / STM32F4_USB_REQ;
- assert(vcoclock / usbdiv == STM32F4_USB_REQ);
-
- /* SYSTEM/I2S: same system clock */
- i2sdiv = (vcoclock + (systemclock / 2)) / systemclock;
-
- /* Set up PLL */
- STM32_RCC_PLLCFGR =
- PLLCFGR_PLLM(plldiv) |
- PLLCFGR_PLLN(pllmult) |
- PLLCFGR_PLLP(STM32F4_PLLP_DIV / 2 - 1) |
-#if defined(CONFIG_STM32_CLOCK_HSE_HZ)
- PLLCFGR_PLLSRC_HSE |
-#else
- PLLCFGR_PLLSRC_HSI |
-#endif
- PLLCFGR_PLLQ(usbdiv) |
- PLLCFGR_PLLR(i2sdiv);
-}
-
-void low_power_init(void);
-
-void config_hispeed_clock(void)
-{
-#ifdef CONFIG_STM32_CLOCK_HSE_HZ
- /* Ensure that HSE is ON */
- clock_enable_osc(OSC_HSE, true);
-#endif
-
- /* Put the PLL settings, they are never changing */
- clock_pll_configure();
- clock_enable_osc(OSC_PLL, true);
-
- /* Switch SYSCLK to PLL, setup bus prescalers. */
- clock_switch_osc(OSC_PLL);
-
-#ifdef CONFIG_LOW_POWER_IDLE
- low_power_init();
-#endif
-}
-
-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_DMA_GET_ISR(0);
- } else { /* APB */
- while (cycles--)
- unused = STM32_USART_BRR(STM32_USART1_BASE);
- }
-}
-
-void clock_enable_module(enum module_id module, int enable)
-{
- if (module == MODULE_USB) {
- if (enable) {
- STM32_RCC_AHB2ENR |= STM32_RCC_AHB2ENR_OTGFSEN;
- STM32_RCC_AHB1ENR |= STM32_RCC_AHB1ENR_OTGHSEN |
- STM32_RCC_AHB1ENR_OTGHSULPIEN;
- } else {
- STM32_RCC_AHB2ENR &= ~STM32_RCC_AHB2ENR_OTGFSEN;
- STM32_RCC_AHB1ENR &= ~STM32_RCC_AHB1ENR_OTGHSEN &
- ~STM32_RCC_AHB1ENR_OTGHSULPIEN;
- }
- return;
- } else if (module == MODULE_I2C) {
- if (enable) {
- /* Enable clocks to I2C modules if necessary */
- STM32_RCC_APB1ENR |=
- STM32_RCC_I2C1EN | STM32_RCC_I2C2EN
- | STM32_RCC_I2C3EN | STM32_RCC_FMPI2C4EN;
- STM32_RCC_DCKCFGR2 =
- (STM32_RCC_DCKCFGR2 & ~DCKCFGR2_FMPI2C1SEL_MASK)
- | DCKCFGR2_FMPI2C1SEL(FMPI2C1SEL_APB);
- } else {
- STM32_RCC_APB1ENR &=
- ~(STM32_RCC_I2C1EN | STM32_RCC_I2C2EN |
- STM32_RCC_I2C3EN | STM32_RCC_FMPI2C4EN);
- }
- return;
- } else if (module == MODULE_ADC) {
- if (enable)
- STM32_RCC_APB2ENR |= STM32_RCC_APB2ENR_ADC1EN;
- else
- STM32_RCC_APB2ENR &= ~STM32_RCC_APB2ENR_ADC1EN;
- return;
- }
-}
-
-/* Real Time Clock (RTC) */
-
-#ifdef CONFIG_STM32_CLOCK_HSE_HZ
-#define RTC_PREDIV_A 39
-#define RTC_FREQ ((STM32F4_RTC_REQ) / (RTC_PREDIV_A + 1)) /* Hz */
-#else /* from LSI clock */
-#define RTC_PREDIV_A 1
-#define RTC_FREQ (STM32F4_LSI_CLOCK / (RTC_PREDIV_A + 1)) /* Hz */
-#endif
-#define RTC_PREDIV_S (RTC_FREQ - 1)
-/*
- * Scaling factor to ensure that the intermediate values computed from/to the
- * RTC frequency are fitting in a 32-bit integer.
- */
-#define SCALING 1000
-
-int32_t rtcss_to_us(uint32_t rtcss)
-{
- return ((RTC_PREDIV_S - rtcss) * (SECOND/SCALING) / (RTC_FREQ/SCALING));
-}
-
-uint32_t us_to_rtcss(int32_t us)
-{
- return (RTC_PREDIV_S - (us * (RTC_FREQ/SCALING) / (SECOND/SCALING)));
-}
-
-void rtc_init(void)
-{
- /* Setup RTC Clock input */
-#ifdef CONFIG_STM32_CLOCK_HSE_HZ
- /* RTC clocked from the HSE */
- STM32_RCC_BDCR = STM32_RCC_BDCR_RTCEN | BDCR_RTCSEL(BDCR_SRC_HSE);
-#else
- /* RTC clocked from the LSI, ensure first it is ON */
- wait_for_ready(&(STM32_RCC_CSR),
- STM32_RCC_CSR_LSION, STM32_RCC_CSR_LSIRDY);
-
- STM32_RCC_BDCR = STM32_RCC_BDCR_RTCEN | BDCR_RTCSEL(BDCR_SRC_LSI);
-#endif
-
- 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: Needs two separate writes. */
- STM32_RTC_PRER =
- (STM32_RTC_PRER & ~STM32_RTC_PRER_S_MASK) | RTC_PREDIV_S;
- STM32_RTC_PRER =
- (STM32_RTC_PRER & ~STM32_RTC_PRER_A_MASK)
- | (RTC_PREDIV_A << 16);
-
- /* 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
-
-#ifdef CONFIG_LOW_POWER_IDLE
-/* Low power idle statistics */
-static int idle_sleep_cnt;
-static int idle_dsleep_cnt;
-static uint64_t idle_dsleep_time_us;
-static int dsleep_recovery_margin_us = 1000000;
-
-/* STOP_MODE_LATENCY: delay to wake up from STOP mode with main regulator off */
-#define STOP_MODE_LATENCY 50 /* us */
-/* PLL_LOCK_LATENCY: delay to switch from HSI to PLL */
-#define PLL_LOCK_LATENCY 150 /* us */
-/*
- * 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.
- */
-#define SET_RTC_MATCH_DELAY 120 /* us */
-
-
-void low_power_init(void)
-{
- /* Turn off the main regulator during stop mode */
- STM32_PWR_CR |= STM32_PWR_CR_LPSDSR /* aka LPDS */;
-}
-
-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) {
- asm volatile("cpsid i");
-
- t0 = get_time();
- next_delay = __hw_clock_event_get() - t0.le.lo;
-
- if (DEEP_SLEEP_ALLOWED &&
- (next_delay > (STOP_MODE_LATENCY + PLL_LOCK_LATENCY +
- SET_RTC_MATCH_DELAY))) {
- /* Deep-sleep in STOP mode */
- idle_dsleep_cnt++;
-
- /*
- * TODO(b/174337385) no support for wake-up on USART
- * uart_enable_wakeup(1);
- */
-
- /* Set deep sleep bit */
- CPU_SCB_SYSCTRL |= 0x4;
-
- set_rtc_alarm(0, next_delay - STOP_MODE_LATENCY
- - PLL_LOCK_LATENCY,
- &rtc0, 0);
-
- /* Switch to HSI */
- clock_switch_osc(OSC_HSI);
- /* Turn off the PLL1 to save power */
- clock_enable_osc(OSC_PLL, false);
-
- /* ensure outstanding memory transactions complete */
- asm volatile("dsb");
-
- asm("wfi");
-
- CPU_SCB_SYSCTRL &= ~0x4;
-
- /* turn on PLL and wait until it's ready */
- clock_enable_osc(OSC_PLL, true);
- /* Switch to PLL */
- clock_switch_osc(OSC_PLL);
-
- /*uart_enable_wakeup(0);*/
-
- /* 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);
-
- /* 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");
- }
- asm volatile("cpsie i");
- }
-}
-
-/* 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("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_LOW_POWER_IDLE */