예제 #1
0
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
    }
}
예제 #2
0
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);
}