drivers: clock: stm32: fix Flash latency & clock settings for MSI & HSE

According to RM, when increasing the CPU frequency, the new number of
wait states to the Flash latency bits must be written and verified
before modifying the CPU clock source and/or the CPU clock prescaler,
to prevent NMI to occur; when decreasing the CPU frequency, after.
Tested with STM32L462 SOC and MSI with several frequencies, both
increasing and decreasing. HSE built, not tested.

Signed-off-by: Giancarlo Stasi <giancarlo.stasi@nexxiot.com>
This commit is contained in:
Giancarlo Stasi 2020-06-12 23:44:29 +02:00 committed by Carles Cufí
commit 82a08a7678
2 changed files with 55 additions and 14 deletions

View file

@ -9,6 +9,7 @@
#include <soc.h> #include <soc.h>
#include <drivers/clock_control.h> #include <drivers/clock_control.h>
#include <sys/util.h> #include <sys/util.h>
#include <sys/__assert.h>
#include <drivers/clock_control/stm32_clock_control.h> #include <drivers/clock_control/stm32_clock_control.h>
#include "clock_stm32_ll_common.h" #include "clock_stm32_ll_common.h"
@ -286,6 +287,11 @@ static int stm32_clock_control_init(struct device *dev)
{ {
LL_UTILS_ClkInitTypeDef s_ClkInitStruct; LL_UTILS_ClkInitTypeDef s_ClkInitStruct;
uint32_t hclk_prescaler; uint32_t hclk_prescaler;
#if defined(CONFIG_CLOCK_STM32_SYSCLK_SRC_HSE) || \
defined(CONFIG_CLOCK_STM32_SYSCLK_SRC_MSI)
uint32_t old_hclk_freq;
uint32_t new_hclk_freq;
#endif
ARG_UNUSED(dev); ARG_UNUSED(dev);
@ -381,6 +387,22 @@ static int stm32_clock_control_init(struct device *dev)
#elif CONFIG_CLOCK_STM32_SYSCLK_SRC_HSE #elif CONFIG_CLOCK_STM32_SYSCLK_SRC_HSE
old_hclk_freq = HAL_RCC_GetHCLKFreq();
/* Calculate new SystemCoreClock variable based on HSE freq */
new_hclk_freq = __LL_RCC_CALC_HCLK_FREQ(CONFIG_CLOCK_STM32_HSE_CLOCK,
hclk_prescaler);
#if defined(CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC)
__ASSERT(new_hclk_freq == CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC,
"Config mismatch HCLK frequency %u %u",
CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC, new_hclk_freq);
#endif
/* If freq increases, set flash latency before any clock setting */
if (new_hclk_freq > old_hclk_freq) {
LL_SetFlashLatency(new_hclk_freq);
}
/* Enable HSE if not enabled */ /* Enable HSE if not enabled */
if (LL_RCC_HSE_IsReady() != 1) { if (LL_RCC_HSE_IsReady() != 1) {
/* Check if need to enable HSE bypass feature or not */ /* Check if need to enable HSE bypass feature or not */
@ -404,9 +426,7 @@ static int stm32_clock_control_init(struct device *dev)
} }
/* Update SystemCoreClock variable */ /* Update SystemCoreClock variable */
LL_SetSystemCoreClock(__LL_RCC_CALC_HCLK_FREQ( LL_SetSystemCoreClock(new_hclk_freq);
CONFIG_CLOCK_STM32_HSE_CLOCK,
hclk_prescaler));
/* Set APB1 & APB2 prescaler*/ /* Set APB1 & APB2 prescaler*/
LL_RCC_SetAPB1Prescaler(s_ClkInitStruct.APB1CLKDivider); LL_RCC_SetAPB1Prescaler(s_ClkInitStruct.APB1CLKDivider);
@ -414,9 +434,10 @@ static int stm32_clock_control_init(struct device *dev)
LL_RCC_SetAPB2Prescaler(s_ClkInitStruct.APB2CLKDivider); LL_RCC_SetAPB2Prescaler(s_ClkInitStruct.APB2CLKDivider);
#endif /* CONFIG_SOC_SERIES_STM32F0X && CONFIG_SOC_SERIES_STM32G0X */ #endif /* CONFIG_SOC_SERIES_STM32F0X && CONFIG_SOC_SERIES_STM32G0X */
/* Set flash latency */ /* If freq not increased, set flash latency after all clock setting */
/* HSI used as SYSCLK, set latency to 0 */ if (new_hclk_freq <= old_hclk_freq) {
LL_FLASH_SetLatency(LL_FLASH_LATENCY_0); LL_SetFlashLatency(new_hclk_freq);
}
/* Disable other clocks */ /* Disable other clocks */
LL_RCC_HSI_Disable(); LL_RCC_HSI_Disable();
@ -425,6 +446,27 @@ static int stm32_clock_control_init(struct device *dev)
#elif CONFIG_CLOCK_STM32_SYSCLK_SRC_MSI #elif CONFIG_CLOCK_STM32_SYSCLK_SRC_MSI
old_hclk_freq = HAL_RCC_GetHCLKFreq();
/* Calculate new SystemCoreClock variable with MSI freq */
/* MSI freq is defined from RUN range selection */
new_hclk_freq =
__LL_RCC_CALC_HCLK_FREQ(
__LL_RCC_CALC_MSI_FREQ(LL_RCC_MSIRANGESEL_RUN,
CONFIG_CLOCK_STM32_MSI_RANGE << RCC_CR_MSIRANGE_Pos),
hclk_prescaler);
#if defined(CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC)
__ASSERT(new_hclk_freq == CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC,
"Config mismatch HCLK frequency %u %u",
CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC, new_hclk_freq);
#endif
/* If freq increases, set flash latency before any clock setting */
if (new_hclk_freq > old_hclk_freq) {
LL_SetFlashLatency(new_hclk_freq);
}
/* Set MSI Range */ /* Set MSI Range */
LL_RCC_MSI_EnableRangeSelection(); LL_RCC_MSI_EnableRangeSelection();
LL_RCC_MSI_SetRange(CONFIG_CLOCK_STM32_MSI_RANGE << RCC_CR_MSIRANGE_Pos); LL_RCC_MSI_SetRange(CONFIG_CLOCK_STM32_MSI_RANGE << RCC_CR_MSIRANGE_Pos);
@ -448,10 +490,8 @@ static int stm32_clock_control_init(struct device *dev)
while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_MSI) { while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_MSI) {
} }
/* Update SystemCoreClock variable with MSI freq */ /* Update SystemCoreClock variable */
/* MSI freq is defined from RUN range selection */ LL_SetSystemCoreClock(new_hclk_freq);
LL_SetSystemCoreClock(__LL_RCC_CALC_MSI_FREQ(LL_RCC_MSIRANGESEL_RUN,
LL_RCC_MSI_GetRange()));
/* Set APB1 & APB2 prescaler*/ /* Set APB1 & APB2 prescaler*/
LL_RCC_SetAPB1Prescaler(s_ClkInitStruct.APB1CLKDivider); LL_RCC_SetAPB1Prescaler(s_ClkInitStruct.APB1CLKDivider);
@ -462,9 +502,10 @@ static int stm32_clock_control_init(struct device *dev)
LL_RCC_SetAHB4Prescaler(s_ClkInitStruct->AHB4CLKDivider); LL_RCC_SetAHB4Prescaler(s_ClkInitStruct->AHB4CLKDivider);
#endif /* CONFIG_SOC_SERIES_STM32WBX */ #endif /* CONFIG_SOC_SERIES_STM32WBX */
/* Set flash latency */ /* If freq not increased, set flash latency after all clock setting */
/* MSI used as SYSCLK (16MHz), set latency to 0 */ if (new_hclk_freq <= old_hclk_freq) {
LL_FLASH_SetLatency(LL_FLASH_LATENCY_0); LL_SetFlashLatency(new_hclk_freq);
}
/* Disable other clocks */ /* Disable other clocks */
LL_RCC_HSE_Disable(); LL_RCC_HSE_Disable();

View file

@ -71,7 +71,7 @@ manifest:
revision: 5b3ec3e182d4310e8943cc34c6c70ae57d9711da revision: 5b3ec3e182d4310e8943cc34c6c70ae57d9711da
path: modules/hal/st path: modules/hal/st
- name: hal_stm32 - name: hal_stm32
revision: 6812113dc58d134b74acdeebbffb4f80b8eeab75 revision: pull/54/head
path: modules/hal/stm32 path: modules/hal/stm32
- name: hal_ti - name: hal_ti
revision: aabc6a04a8e871cbb01e02c22bb409f68001dc64 revision: aabc6a04a8e871cbb01e02c22bb409f68001dc64