1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/cpu/stm32/stmclk/stmclk_mp1.c
Gilles DOFFE 8279e54272 cpu/stm32: add clock configuration for stm32mp1
Configure stm32mp1 Cortex-M4 MCU core clock according to board
configuration.

Signed-off-by: Gilles DOFFE <gilles.doffe@savoirfairelinux.com>
2020-11-13 10:43:08 +01:00

221 lines
7.3 KiB
C

/*
* Copyright (C) 2020 Savoir-faire Linux
*
* This file is subject to the terms and conditions of the GNU Lesser General
* Public License v2.1. See the file LICENSE in the top level directory for more
* details.
*/
/**
* @ingroup cpu_stm32
* @{
*
* @file
* @brief Implementation of STM32 clock configuration for STM32MP1
*
* @author Gilles DOFFE <gilles.doffe@savoirfairelinux.com>
*
* @}
*/
#include "cpu.h"
#include "stmclk.h"
#include "periph_conf.h"
/* PLL configuration */
#if IS_ACTIVE(CONFIG_BOARD_HAS_HSE)
#define PLL_SRC RCC_RCK3SELR_PLL3SRC_1
#else
#define PLL_SRC RCC_RCK3SELR_PLL3SRC_0
#endif
/* Compute the bitfields for the PLL configuration */
#define PLL_P (((CONFIG_CLOCK_PLL_P / 2)) \
<< RCC_PLL3CFGR2_DIVP_Pos)
#define PLL_M ((CONFIG_CLOCK_PLL_M) \
<< RCC_PLL3CFGR1_DIVM3_Pos)
#define PLL_N ((CONFIG_CLOCK_PLL_N) \
<< RCC_PLL3CFGR1_DIVN_Pos)
#define PLL_Q ((CONFIG_CLOCK_PLL_Q) \
<< RCC_PLL3CFGR2_DIVQ_Pos)
#if defined(RCC_PLL3CFGR2_DIVR) && defined(CONFIG_CLOCK_PLL_R)
#define PLL_R ((CONFIG_CLOCK_PLL_R) \
<< RCC_PLL3CFGR2_DIVR_Pos)
#else
#define PLL_R (0)
#endif
/* Configure HLCK and PCLK prescalers */
#if CONFIG_CLOCK_MCU_DIV == 1
#define CLOCK_MCU_DIV (RCC_MCUDIVR_MCUDIV_0)
#elif CONFIG_CLOCK_MCU_DIV == 2
#define CLOCK_MCU_DIV (RCC_MCUDIVR_MCUDIV_1)
#elif CONFIG_CLOCK_MCU_DIV == 4
#define CLOCK_MCU_DIV (RCC_MCUDIVR_MCUDIV_2)
#elif CONFIG_CLOCK_MCU_DIV == 8
#define CLOCK_MCU_DIV (RCC_MCUDIVR_MCUDIV_3)
#elif CONFIG_CLOCK_MCU_DIV == 16
#define CLOCK_MCU_DIV (RCC_MCUDIVR_MCUDIV_4)
#elif CONFIG_CLOCK_MCU_DIV == 32
#define CLOCK_MCU_DIV (RCC_MCUDIVR_MCUDIV_5)
#elif CONFIG_CLOCK_MCU_DIV == 64
#define CLOCK_MCU_DIV (RCC_MCUDIVR_MCUDIV_6)
#elif CONFIG_CLOCK_MCU_DIV == 128
#define CLOCK_MCU_DIV (RCC_MCUDIVR_MCUDIV_7)
#elif CONFIG_CLOCK_MCU_DIV == 256
#define CLOCK_MCU_DIV (RCC_MCUDIVR_MCUDIV_8)
#elif CONFIG_CLOCK_MCU_DIV == 512
#define CLOCK_MCU_DIV (RCC_MCUDIVR_MCUDIV_9)
#else
#error "Invalid MCU prescaler value (only 1, 2, 4, 8, 16, 32, 64, 128, 256 \
and 512 allowed)"
#endif
#if CONFIG_CLOCK_APB1_DIV == 1
#define CLOCK_APB1_DIV (RCC_APB1DIVR_APB1DIV_0)
#elif CONFIG_CLOCK_APB1_DIV == 2
#define CLOCK_APB1_DIV (RCC_APB1DIVR_APB1DIV_1)
#elif CONFIG_CLOCK_APB1_DIV == 4
#define CLOCK_APB1_DIV (RCC_APB1DIVR_APB1DIV_2)
#elif CONFIG_CLOCK_APB1_DIV == 8
#define CLOCK_APB1_DIV (RCC_APB1DIVR_APB1DIV_3)
#elif CONFIG_CLOCK_APB1_DIV == 16
#define CLOCK_APB1_DIV (RCC_APB1DIVR_APB1DIV_4)
#else
#error "Invalid APB1 prescaler value (only 1, 2, 4, 8 and 16 allowed)"
#endif
#if CONFIG_CLOCK_APB2_DIV == 1
#define CLOCK_APB2_DIV (RCC_APB2DIVR_APB2DIV_0)
#elif CONFIG_CLOCK_APB2_DIV == 2
#define CLOCK_APB2_DIV (RCC_APB2DIVR_APB2DIV_1)
#elif CONFIG_CLOCK_APB2_DIV == 4
#define CLOCK_APB2_DIV (RCC_APB2DIVR_APB2DIV_2)
#elif CONFIG_CLOCK_APB2_DIV == 8
#define CLOCK_APB2_DIV (RCC_APB2DIVR_APB2DIV_3)
#elif CONFIG_CLOCK_APB2_DIV == 16
#define CLOCK_APB2_DIV (RCC_APB2DIVR_APB2DIV_4)
#else
#error "Invalid APB2 prescaler value (only 1, 2, 4, 8 and 16 allowed)"
#endif
#if CONFIG_CLOCK_APB3_DIV == 1
#define CLOCK_APB3_DIV (RCC_APB3DIVR_APB3DIV_0)
#elif CONFIG_CLOCK_APB3_DIV == 2
#define CLOCK_APB3_DIV (RCC_APB3DIVR_APB3DIV_1)
#elif CONFIG_CLOCK_APB3_DIV == 4
#define CLOCK_APB3_DIV (RCC_APB3DIVR_APB3DIV_2)
#elif CONFIG_CLOCK_APB3_DIV == 8
#define CLOCK_APB3_DIV (RCC_APB3DIVR_APB3DIV_3)
#elif CONFIG_CLOCK_APB3_DIV == 16
#define CLOCK_APB3_DIV (RCC_APB3DIVR_APB3DIV_4)
#else
#error "Invalid APB3 prescaler value (only 1, 2, 4, 8 and 16 allowed)"
#endif
/* Check whether PLL must be enabled:
- When PLL is used as SYSCLK
- When PLLQ is required
*/
#if IS_ACTIVE(CONFIG_USE_CLOCK_PLL) || IS_ACTIVE(CONFIG_CLOCK_ENABLE_PLLQ)
#define CONFIG_CLOCK_USE_PLL 1
#else
#define CONFIG_CLOCK_USE_PLL 0
#endif
/* Check whether HSE must be enabled:
- When HSE is used as SYSCLK
- When PLL is used as SYSCLK and the board provides HSE (since HSE will be
used as PLL input clock)
*/
#if IS_ACTIVE(CONFIG_USE_CLOCK_HSE) || \
(IS_ACTIVE(CONFIG_BOARD_HAS_HSE) && IS_ACTIVE(CONFIG_CLOCK_USE_PLL))
#define CONFIG_CLOCK_USE_HSE 1
#else
#define CONFIG_CLOCK_USE_HSE 0
#endif
void stmclk_enable_hsi(void)
{
RCC->OCENSETR |= RCC_OCENSETR_HSION;
while (!(RCC->OCRDYR & RCC_OCRDYR_HSIRDY)) {}
}
static void stmclk_enable_hse(void)
{
RCC->OCENSETR |= RCC_OCENSETR_HSEON;
while (!(RCC->OCRDYR & RCC_OCRDYR_HSERDY)) {}
}
void stmclk_init_sysclk(void)
{
/* disable any interrupts. Global interrupts could be enabled if this is
* called from some kind of bootloader... */
unsigned is = irq_disable();
RCC->MC_CIFR = 0;
/* enable HSI clock for the duration of initialization */
stmclk_enable_hsi();
/* use HSI as system clock while we do any further configuration and
* configure the AHB and APB clock dividers as configured by the board */
/* MCUDIV */
RCC->MCUDIVR = CLOCK_MCU_DIV;
while ((RCC->MCUDIVR & RCC_MCUDIVR_MCUDIVRDY)
!= RCC_MCUDIVR_MCUDIVRDY) {}
/* APB1DIV */
RCC->APB1DIVR = CLOCK_APB1_DIV;
while ((RCC->APB1DIVR & RCC_APB1DIVR_APB1DIVRDY)
!= RCC_APB1DIVR_APB1DIVRDY) {}
/* APB2DIV */
RCC->APB2DIVR = CLOCK_APB2_DIV;
while ((RCC->APB2DIVR & RCC_APB2DIVR_APB2DIVRDY)
!= RCC_APB2DIVR_APB2DIVRDY) {}
/* APB3DIV */
RCC->APB3DIVR = CLOCK_APB3_DIV;
while ((RCC->APB3DIVR & RCC_APB3DIVR_APB3DIVRDY)
!= RCC_APB3DIVR_APB3DIVRDY) {}
/* MCU clock source */
RCC->MSSCKSELR = RCC_MSSCKSELR_MCUSSRC_0; /* HSI */
while ((RCC->MSSCKSELR & RCC_MSSCKSELR_MCUSSRCRDY)
!= RCC_MSSCKSELR_MCUSSRCRDY) {}
/* disable all active clocks except HSI -> resets the clk configuration */
RCC->OCENCLRR = ~(RCC_OCENSETR_HSION);
/* if configured, we need to enable the HSE clock now */
if (IS_ACTIVE(CONFIG_CLOCK_USE_HSE)) {
stmclk_enable_hse();
}
if (IS_ACTIVE(CONFIG_CLOCK_USE_PLL)) {
/* now we can safely configure the PLL */
RCC->PLL3CFGR1 = (PLL_M | PLL_N);
RCC->PLL3CFGR2 = (PLL_P | PLL_Q | PLL_R);
RCC->RCK3SELR |= PLL_SRC;
while (!(RCC->RCK3SELR & RCC_RCK3SELR_PLL3SRCRDY)) {}
/* and start the PLL */
RCC->PLL3CR |= (RCC_PLL3CR_DIVPEN | RCC_PLL3CR_DIVQEN
| RCC_PLL3CR_DIVREN | RCC_PLL3CR_PLLON);
while (!(RCC->PLL3CR & RCC_PLL3CR_PLL3RDY)) {}
}
/* Configure SYSCLK */
if (IS_ACTIVE(CONFIG_CLOCK_USE_PLL)) {
RCC->MSSCKSELR = RCC_MSSCKSELR_MCUSSRC_3; /* PLL3 */
}
else if (IS_ACTIVE(CONFIG_CLOCK_USE_HSE)) {
RCC->MSSCKSELR = RCC_MSSCKSELR_MCUSSRC_1; /* HSE */
}
else {
RCC->MSSCKSELR = RCC_MSSCKSELR_MCUSSRC_0; /* HSI by default */
}
/* Wait SYSCLK to be ready */
while (!(RCC->MSSCKSELR & RCC_MSSCKSELR_MCUSSRCRDY)) {}
irq_restore(is);
}