diff options
author | Vincent Palatin <vpalatin@chromium.org> | 2017-11-09 13:43:58 +0100 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2018-01-08 05:41:23 -0800 |
commit | e24a3953c2c23df219fc0c735e0c188fd8edbded (patch) | |
tree | d1b36505f04da9767ba75513287364f86f9b5eeb /chip/stm32/clock-stm32h7.c | |
parent | 57bb4ddf4163dbe3da48ba56464adbabfa596344 (diff) | |
download | chrome-ec-e24a3953c2c23df219fc0c735e0c188fd8edbded.tar.gz |
stm32: Add STM32H7 family
Start adding support for the STM32H7 family of device and the first
available one the STM32H743.
Signed-off-by: Vincent Palatin <vpalatin@chromium.org>
BRANCH=none
BUG=b:67081508
TEST=manual, run on stm32h743i-eval and zerblebarn boards
get a stable serial console.
Change-Id: I9ae10f0d843e5318451713c21ed22d455a23758c
Reviewed-on: https://chromium-review.googlesource.com/806168
Commit-Ready: Vincent Palatin <vpalatin@chromium.org>
Tested-by: Vincent Palatin <vpalatin@chromium.org>
Reviewed-by: Shawn N <shawnn@chromium.org>
Diffstat (limited to 'chip/stm32/clock-stm32h7.c')
-rw-r--r-- | chip/stm32/clock-stm32h7.c | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/chip/stm32/clock-stm32h7.c b/chip/stm32/clock-stm32h7.c new file mode 100644 index 0000000000..291579ed16 --- /dev/null +++ b/chip/stm32/clock-stm32h7.c @@ -0,0 +1,213 @@ +/* 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 "chipset.h" +#include "clock.h" +#include "common.h" +#include "console.h" +#include "cpu.h" +#include "hooks.h" +#include "registers.h" +#include "util.h" + +/* High-speed oscillator default is 64 MHz */ +#define STM32_HSI_CLOCK 64000000 +/* + * PLL1 configuration: + * CPU freq = VCO / (DIVP + 1) = HSI / DIVM * DIVN / (DIVP + 1) + * = 64 * 4 * 50 / (4 + 1) + * = 160 Mhz + */ +#if !defined(PLL1_DIVM) && !defined(PLL1_DIVN) && !defined(PLL1_DIVP) +#define PLL1_DIVM 4 +#define PLL1_DIVN 50 +#define PLL1_DIVP 4 +#endif +#define PLL1_FREQ (STM32_HSI_CLOCK / PLL1_DIVM * PLL1_DIVN / (PLL1_DIVP+1)) + +enum clock_osc { + OSC_INIT = 0, /* Uninitialized */ + OSC_HSI, /* High-speed internal oscillator */ + OSC_CSI, /* Multi-speed internal oscillator: NOT IMPLEMENTED */ + OSC_HSE, /* High-speed external oscillator: NOT IMPLEMENTED */ + OSC_PLL, /* PLL */ +}; + +static int freq = STM32_HSI_CLOCK; +static int current_osc; + +int clock_get_freq(void) +{ + return freq; +} + +int clock_get_timer_freq(void) +{ + return clock_get_freq(); +} + +void clock_wait_bus_cycles(enum bus_type bus, uint32_t cycles) +{ + volatile uint32_t dummy __attribute__((unused)); + + if (bus == BUS_AHB) { + while (cycles--) + dummy = STM32_GPIO_IDR(GPIO_A); + } else { /* APB */ + while (cycles--) + dummy = STM32_USART_BRR(STM32_USART1_BASE); + } +} + +static void clock_enable_osc(enum clock_osc osc) +{ + uint32_t ready; + uint32_t on; + + switch (osc) { + case OSC_HSI: + ready = STM32_RCC_CR_HSIRDY; + on = STM32_RCC_CR_HSION; + break; + case OSC_PLL: + ready = STM32_RCC_CR_PLL1RDY; + on = STM32_RCC_CR_PLL1ON; + break; + default: + return; + } + + if (!(STM32_RCC_CR & ready)) { + STM32_RCC_CR |= on; + while (!(STM32_RCC_CR & 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; + sws = STM32_RCC_CFGR_SWS_HSI; + break; + case OSC_PLL: + sw = STM32_RCC_CFGR_SW_PLL1; + sws = STM32_RCC_CFGR_SWS_PLL1; + break; + default: + return; + } + + STM32_RCC_CFGR = sw; + while ((STM32_RCC_CFGR & STM32_RCC_CFGR_SWS_MASK) != sws) + ; +} + +static void clock_set_osc(enum clock_osc osc) +{ + uint32_t val; + + if (osc == current_osc) + return; + + if (current_osc != OSC_INIT) + hook_notify(HOOK_PRE_FREQ_CHANGE); + + switch (osc) { + case OSC_HSI: + /* Switch to HSI */ + clock_switch_osc(osc); + + freq = STM32_HSI_CLOCK; + break; + + case OSC_PLL: + /* Configure PLL1 using 64 Mhz HSI as input */ + STM32_RCC_PLLCKSELR = STM32_RCC_PLLCKSEL_PLLSRC_HSI | + STM32_RCC_PLLCKSEL_DIVM1(PLL1_DIVM); + /* in integer mode, wide range VCO with 16Mhz input, use divP */ + STM32_RCC_PLLCFGR = STM32_RCC_PLLCFG_PLL1VCOSEL_WIDE + | STM32_RCC_PLLCFG_PLL1RGE_8M_16M + | STM32_RCC_PLLCFG_DIVP1EN; + STM32_RCC_PLL1DIVR = STM32_RCC_PLLDIV_DIVP(PLL1_DIVP) + | STM32_RCC_PLLDIV_DIVN(PLL1_DIVN); + /* turn on PLL1 and wait that it's ready */ + clock_enable_osc(OSC_PLL); + freq = PLL1_FREQ; + + /* Adjust flash latency */ + val = STM32_FLASH_ACR_WRHIGHFREQ_185MHZ | + (2 << STM32_FLASH_ACR_LATENCY_SHIFT); + STM32_FLASH_ACR = val; + while (val != STM32_FLASH_ACR) + ; + + /* Switch to PLL */ + clock_switch_osc(OSC_PLL); + break; + default: + break; + } + + /* Notify modules of frequency change unless we're initializing */ + if (current_osc != OSC_INIT) { + current_osc = osc; + hook_notify(HOOK_FREQ_CHANGE); + } else { + current_osc = osc; + } +} + +void clock_enable_module(enum module_id module, int enable) +{ + static uint32_t clock_mask; + int new_mask; + + if (enable) + new_mask = clock_mask | (1 << module); + else + new_mask = clock_mask & ~(1 << module); + + /* Only change clock if needed */ + if ((!!new_mask) != (!!clock_mask)) { + + /* Flush UART before switching clock speed */ + cflush(); +#if 0 /* Power management policy: TODO(b/67081508) not implemented for now */ + clock_set_osc(new_mask ? OSC_PLL : OSC_CSI); +#endif + } + + clock_mask = new_mask; +} + +void clock_init(void) +{ +#if 0 /* Keep default for now: HSI at 64 Mhz */ + clock_set_osc(OSC_PLL); +#endif +} + +static int command_clock(int argc, char **argv) +{ + if (argc >= 2) { + if (!strcasecmp(argv[1], "hsi")) + clock_set_osc(OSC_HSI); + else if (!strcasecmp(argv[1], "pll")) + clock_set_osc(OSC_PLL); + else + return EC_ERROR_PARAM1; + } + ccprintf("Clock frequency is now %d Hz\n", freq); + return EC_SUCCESS; +} +DECLARE_CONSOLE_COMMAND(clock, command_clock, + "hsi | pll", "Set clock frequency"); |