static void stm32l4_stdclockconfig(void) { uint32_t regval; volatile int32_t timeout; #ifdef STM32L4_BOARD_USEHSI /* Enable Internal High-Speed Clock (HSI) */ regval = getreg32(STM32L4_RCC_CR); regval |= RCC_CR_HSION; /* Enable HSI */ putreg32(regval, STM32L4_RCC_CR); /* Wait until the HSI is ready (or until a timeout elapsed) */ for (timeout = HSIRDY_TIMEOUT; timeout > 0; timeout--) { /* Check if the HSIRDY flag is the set in the CR */ if ((getreg32(STM32L4_RCC_CR) & RCC_CR_HSIRDY) != 0) { /* If so, then break-out with timeout > 0 */ break; } } #elif defined(STM32L4_BOARD_USEMSI) /* Enable Internal Multi-Speed Clock (MSI) */ # error STM32L4_BOARD_USEMSI not yet implemented in arch/arm/src/stm32l4/stm32l4x6xx_rcc.c /* setting MSIRANGE */ /* setting MSIPLLEN */ regval = getreg32(STM32L4_RCC_CR); regval |= RCC_CR_MSION; /* Enable MSI */ putreg32(regval, STM32L4_RCC_CR); #elif defined(STM32L4_BOARD_USEHSE) /* Enable External High-Speed Clock (HSE) */ regval = getreg32(STM32L4_RCC_CR); regval |= RCC_CR_HSEON; /* Enable HSE */ putreg32(regval, STM32L4_RCC_CR); /* Wait until the HSE is ready (or until a timeout elapsed) */ for (timeout = HSERDY_TIMEOUT; timeout > 0; timeout--) { /* Check if the HSERDY flag is the set in the CR */ if ((getreg32(STM32L4_RCC_CR) & RCC_CR_HSERDY) != 0) { /* If so, then break-out with timeout > 0 */ break; } } #else # error stm32l4_stdclockconfig(), must have one of STM32L4_BOARD_USEHSI, STM32L4_BOARD_USEMSI, STM32L4_BOARD_USEHSE defined #endif /* Check for a timeout. If this timeout occurs, then we are hosed. We * have no real back-up plan, although the following logic makes it look * as though we do. */ if (timeout > 0) { #warning todo: regulator voltage according to clock freq #if 0 /* Ensure Power control is enabled before modifying it. */ regval = getreg32(STM32L4_RCC_APB1ENR); regval |= RCC_APB1ENR_PWREN; putreg32(regval, STM32L4_RCC_APB1ENR); /* Select regulator voltage output Scale 1 mode to support system * frequencies up to 168 MHz. */ regval = getreg32(STM32L4_PWR_CR); regval &= ~PWR_CR_VOS_MASK; regval |= PWR_CR_VOS_SCALE_1; putreg32(regval, STM32L4_PWR_CR); #endif /* Set the HCLK source/divider */ regval = getreg32(STM32L4_RCC_CFGR); regval &= ~RCC_CFGR_HPRE_MASK; regval |= STM32L4_RCC_CFGR_HPRE; putreg32(regval, STM32L4_RCC_CFGR); /* Set the PCLK2 divider */ regval = getreg32(STM32L4_RCC_CFGR); regval &= ~RCC_CFGR_PPRE2_MASK; regval |= STM32L4_RCC_CFGR_PPRE2; putreg32(regval, STM32L4_RCC_CFGR); /* Set the PCLK1 divider */ regval = getreg32(STM32L4_RCC_CFGR); regval &= ~RCC_CFGR_PPRE1_MASK; regval |= STM32L4_RCC_CFGR_PPRE1; putreg32(regval, STM32L4_RCC_CFGR); #ifdef CONFIG_RTC_HSECLOCK /* Set the RTC clock divisor */ regval = getreg32(STM32L4_RCC_CFGR); regval &= ~RCC_CFGR_RTCPRE_MASK; regval |= RCC_CFGR_RTCPRE(HSE_DIVISOR); putreg32(regval, STM32L4_RCC_CFGR); #endif /* Set the PLL source and main divider */ regval = getreg32(STM32L4_RCC_PLLCFG); /* Configure Main PLL */ /* Set the PLL dividers and multipliers to configure the main PLL */ regval = (STM32L4_PLLCFG_PLLM | STM32L4_PLLCFG_PLLN | STM32L4_PLLCFG_PLLP | STM32L4_PLLCFG_PLLQ | STM32L4_PLLCFG_PLLR); #ifdef STM32L4_PLLCFG_PLLP_ENABLED regval |= RCC_PLLCFG_PLLPEN; #endif #ifdef STM32L4_PLLCFG_PLLQ_ENABLED regval |= RCC_PLLCFG_PLLQEN; #endif #ifdef STM32L4_PLLCFG_PLLR_ENABLED regval |= RCC_PLLCFG_PLLREN; #endif /* XXX The choice of clock source to PLL (all three) is independent * of the sys clock source choice, review the STM32L4_BOARD_USEHSI * name; probably split it into two, one for PLL source and one * for sys clock source. */ #ifdef STM32L4_BOARD_USEHSI regval |= RCC_PLLCFG_PLLSRC_HSI; #else /* if STM32L4_BOARD_USEHSE */ regval |= RCC_PLLCFG_PLLSRC_HSE; #endif putreg32(regval, STM32L4_RCC_PLLCFG); /* Enable the main PLL */ regval = getreg32(STM32L4_RCC_CR); regval |= RCC_CR_PLLON; putreg32(regval, STM32L4_RCC_CR); /* Wait until the PLL is ready */ while ((getreg32(STM32L4_RCC_CR) & RCC_CR_PLLRDY) == 0) { } #ifdef CONFIG_STM32L4_SAI1PLL /* Configure SAI1 PLL */ regval = getreg32(STM32L4_RCC_PLLSAI1CFG); /* Set the PLL dividers and multipliers to configure the SAI1 PLL */ regval = (STM32L4_PLLSAI1CFG_PLLN | STM32L4_PLLSAI1CFG_PLLP | STM32L4_PLLSAI1CFG_PLLQ | STM32L4_PLLSAI1CFG_PLLR); #ifdef STM32L4_PLLSAI1CFG_PLLP_ENABLED regval |= RCC_PLLSAI1CFG_PLLPEN; #endif #ifdef STM32L4_PLLSAI1CFG_PLLQ_ENABLED regval |= RCC_PLLSAI1CFG_PLLQEN; #endif #ifdef STM32L4_PLLSAI1CFG_PLLR_ENABLED regval |= RCC_PLLSAI1CFG_PLLREN; #endif putreg32(regval, STM32L4_RCC_PLLSAI1CFG); /* Enable the SAI1 PLL */ regval = getreg32(STM32L4_RCC_CR); regval |= RCC_CR_PLLSAI1ON; putreg32(regval, STM32L4_RCC_CR); /* Wait until the PLL is ready */ while ((getreg32(STM32L4_RCC_CR) & RCC_CR_PLLSAI1RDY) == 0) { } #endif #ifdef CONFIG_STM32L4_SAI2PLL /* Configure SAI2 PLL */ regval = getreg32(STM32L4_RCC_PLLSAI2CFG); /* Enable the SAI2 PLL */ /* Set the PLL dividers and multipliers to configure the SAI2 PLL */ regval = (STM32L4_PLLSAI2CFG_PLLN | STM32L4_PLLSAI2CFG_PLLP | STM32L4_PLLSAI2CFG_PLLR); #ifdef STM32L4_PLLSAI2CFG_PLLP_ENABLED regval |= RCC_PLLSAI2CFG_PLLPEN; #endif #ifdef STM32L4_PLLSAI2CFG_PLLR_ENABLED regval |= RCC_PLLSAI2CFG_PLLREN; #endif putreg32(regval, STM32L4_RCC_PLLSAI2CFG); /* Enable the SAI1 PLL */ regval = getreg32(STM32L4_RCC_CR); regval |= RCC_CR_PLLSAI2ON; putreg32(regval, STM32L4_RCC_CR); /* Wait until the PLL is ready */ while ((getreg32(STM32L4_RCC_CR) & RCC_CR_PLLSAI2RDY) == 0) { } #endif /* Enable FLASH prefetch, instruction cache, data cache, and 5 wait states */ #ifdef CONFIG_STM32L4_FLASH_PREFETCH regval = (FLASH_ACR_LATENCY_4 | FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_PRFTEN); #else regval = (FLASH_ACR_LATENCY_4 | FLASH_ACR_ICEN | FLASH_ACR_DCEN); #endif putreg32(regval, STM32L4_FLASH_ACR); /* Select the main PLL as system clock source */ regval = getreg32(STM32L4_RCC_CFGR); regval &= ~RCC_CFGR_SW_MASK; regval |= RCC_CFGR_SW_PLL; putreg32(regval, STM32L4_RCC_CFGR); /* Wait until the PLL source is used as the system clock source */ while ((getreg32(STM32L4_RCC_CFGR) & RCC_CFGR_SWS_MASK) != RCC_CFGR_SWS_PLL) { } #if defined(CONFIG_STM32L4_IWDG) || defined(CONFIG_RTC_LSICLOCK) /* Low speed internal clock source LSI */ stm32l4_rcc_enablelsi(); #endif #if defined(STM32L4_USE_LSE) /* Low speed external clock source LSE * * TODO: There is another case where the LSE needs to * be enabled: if the MCO1 pin selects LSE as source. * XXX and other cases, like automatic trimming of MSI for USB use */ /* ensure Power control is enabled since it is indirectly required * to alter the LSE parameters. */ stm32l4_pwr_enableclk(true); /* XXX other LSE settings must be made before turning on the oscillator * and we need to ensure it is first off before doing so. */ /* turn on the LSE oscillator * XXX this will almost surely get moved since we also want to use * this for automatically trimming MSI, etc. */ stm32l4_rcc_enablelse(); #endif #if defined(STM32L4_USE_CLK48) /* XXX sanity if sdmmc1 or usb or rng, then we need to set the clk48 source * and then we can also do away with STM32L4_USE_CLK48, and give better * warning messages * * XXX sanity if our STM32L4_CLK48_SEL is YYY then we need to have already * enabled ZZZ */ regval = getreg32(STM32L4_RCC_CCIPR); regval &= RCC_CCIPR_CLK48SEL_MASK; regval |= STM32L4_CLK48_SEL; putreg32(regval, STM32L4_RCC_CCIPR); #endif } }
void stm32l4_board_clockconfig(void) { uint32_t regval; /* Enable Internal High-Speed Clock (HSI) */ regval = getreg32(STM32L4_RCC_CR); regval |= RCC_CR_HSION; /* Enable HSI */ putreg32(regval, STM32L4_RCC_CR); /* Wait until the HSI is ready */ while ((getreg32(STM32L4_RCC_CR) & RCC_CR_HSIRDY) == 0) { } /* Set the HCLK source/divider */ regval = getreg32(STM32L4_RCC_CFGR); regval &= ~RCC_CFGR_HPRE_MASK; regval |= STM32L4_RCC_CFGR_HPRE; putreg32(regval, STM32L4_RCC_CFGR); /* Set the PCLK2 divider */ regval = getreg32(STM32L4_RCC_CFGR); regval &= ~RCC_CFGR_PPRE2_MASK; regval |= STM32L4_RCC_CFGR_PPRE2; putreg32(regval, STM32L4_RCC_CFGR); /* Set the PCLK1 divider */ regval = getreg32(STM32L4_RCC_CFGR); regval &= ~RCC_CFGR_PPRE1_MASK; regval |= STM32L4_RCC_CFGR_PPRE1; putreg32(regval, STM32L4_RCC_CFGR); /* Set the PLL source and main divider */ regval = getreg32(STM32L4_RCC_PLLCFG); /* Configure Main PLL */ /* Set the PLL dividers and multipliers to configure the main PLL */ regval = (STM32L4_PLLCFG_PLLM | STM32L4_PLLCFG_PLLN | STM32L4_PLLCFG_PLLP | STM32L4_PLLCFG_PLLQ | STM32L4_PLLCFG_PLLR); regval |= RCC_PLLCFG_PLLQEN; regval |= RCC_PLLCFG_PLLREN; /* XXX The choice of clock source to PLL (all three) is independent * of the sys clock source choice, review the STM32L4_BOARD_USEHSI * name; probably split it into two, one for PLL source and one * for sys clock source. */ regval |= RCC_PLLCFG_PLLSRC_HSI; putreg32(regval, STM32L4_RCC_PLLCFG); /* Enable the main PLL */ regval = getreg32(STM32L4_RCC_CR); regval |= RCC_CR_PLLON; putreg32(regval, STM32L4_RCC_CR); /* Wait until the PLL is ready */ while ((getreg32(STM32L4_RCC_CR) & RCC_CR_PLLRDY) == 0) { } /* Configure SAI1 PLL */ regval = getreg32(STM32L4_RCC_PLLSAI1CFG); /* Set the PLL dividers and multipliers to configure the SAI1 PLL */ regval = (STM32L4_PLLSAI1CFG_PLLN | STM32L4_PLLSAI1CFG_PLLP | STM32L4_PLLSAI1CFG_PLLQ | STM32L4_PLLSAI1CFG_PLLR); regval |= RCC_PLLSAI1CFG_PLLQEN; putreg32(regval, STM32L4_RCC_PLLSAI1CFG); /* Enable the SAI1 PLL */ regval = getreg32(STM32L4_RCC_CR); regval |= RCC_CR_PLLSAI1ON; putreg32(regval, STM32L4_RCC_CR); /* Wait until the PLL is ready */ while ((getreg32(STM32L4_RCC_CR) & RCC_CR_PLLSAI1RDY) == 0) { } /* Configure SAI2 PLL */ regval = getreg32(STM32L4_RCC_PLLSAI2CFG); /* Enable the SAI2 PLL */ /* Set the PLL dividers and multipliers to configure the SAI2 PLL */ regval = (STM32L4_PLLSAI2CFG_PLLN | STM32L4_PLLSAI2CFG_PLLP | STM32L4_PLLSAI2CFG_PLLR); putreg32(regval, STM32L4_RCC_PLLSAI2CFG); /* Enable the SAI1 PLL */ regval = getreg32(STM32L4_RCC_CR); regval |= RCC_CR_PLLSAI2ON; putreg32(regval, STM32L4_RCC_CR); /* Wait until the PLL is ready */ while ((getreg32(STM32L4_RCC_CR) & RCC_CR_PLLSAI2RDY) == 0) { } /* Enable FLASH prefetch, instruction cache, data cache, and 5 wait states */ #ifdef CONFIG_STM32L4_FLASH_PREFETCH regval = (FLASH_ACR_LATENCY_4 | FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_PRFTEN); #else regval = (FLASH_ACR_LATENCY_4 | FLASH_ACR_ICEN | FLASH_ACR_DCEN); #endif putreg32(regval, STM32L4_FLASH_ACR); /* Select the main PLL as system clock source */ regval = getreg32(STM32L4_RCC_CFGR); regval &= ~RCC_CFGR_SW_MASK; regval |= RCC_CFGR_SW_PLL; putreg32(regval, STM32L4_RCC_CFGR); /* Wait until the PLL source is used as the system clock source */ while ((getreg32(STM32L4_RCC_CFGR) & RCC_CFGR_SWS_MASK) != RCC_CFGR_SWS_PLL) { } #if defined(CONFIG_STM32L4_IWDG) || defined(CONFIG_RTC_LSICLOCK) /* Low speed internal clock source LSI */ stm32l4_rcc_enablelsi(); #endif #if defined(STM32L4_USE_LSE) /* Low speed external clock source LSE * * TODO: There is another case where the LSE needs to * be enabled: if the MCO1 pin selects LSE as source. */ stm32l4_pwr_enableclk(true); stm32l4_rcc_enablelse(); #endif /* XXX sanity if sdmmc1 or usb or rng, then we need to set the clk48 source * and then we can also do away with STM32L4_USE_CLK48, and give better * warning messages * * XXX sanity if our STM32L4_CLK48_SEL is YYY then we need to have already * enabled ZZZ */ regval = getreg32(STM32L4_RCC_CCIPR); regval &= RCC_CCIPR_CLK48SEL_MASK; regval |= STM32L4_CLK48_SEL; putreg32(regval, STM32L4_RCC_CCIPR); }