mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
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>
This commit is contained in:
parent
d78e13e906
commit
8279e54272
220
cpu/stm32/stmclk/stmclk_mp1.c
Normal file
220
cpu/stm32/stmclk/stmclk_mp1.c
Normal file
@ -0,0 +1,220 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user