blob: 15073fbc2486f1c972ba82d53a9f6b84fe0c502c [file] [log] [blame]
/****************************************************************************
* arch/arm/src/imxrt/imxrt_clockconfig_ver1.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include "arm_internal.h"
#include <arch/board/board.h>
#include "hardware/imxrt_ccm.h"
#include "hardware/imxrt_dcdc.h"
#include "imxrt_clockconfig_ver1.h"
#include "imxrt_lcd.h"
#include "hardware/imxrt_memorymap.h"
#include "hardware/imxrt_iomuxc.h"
#include <stdlib.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define VIDEO_PLL_MIN_FREQ 650000000
#define OSC24_FREQ 24000000
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: imxrt_lcd_clockconfig
****************************************************************************/
#ifdef CONFIG_IMXRT_LCD
static void imxrt_lcd_clockconfig(void)
{
uint32_t reg;
uint32_t reg2;
int post;
int pre;
uint32_t numerator;
uint32_t denominator;
uint32_t post_divider;
uint32_t pre_divider;
uint32_t loop_divider;
uint32_t target_freq;
uint32_t freq_error;
target_freq = (CONFIG_IMXRT_LCD_HWIDTH +
CONFIG_IMXRT_LCD_HPULSE +
CONFIG_IMXRT_LCD_HFRONTPORCH +
CONFIG_IMXRT_LCD_HBACKPORCH) *
(CONFIG_IMXRT_LCD_VHEIGHT +
CONFIG_IMXRT_LCD_VPULSE +
CONFIG_IMXRT_LCD_VFRONTPORCH +
CONFIG_IMXRT_LCD_VBACKPORCH) *
CONFIG_IMXRT_LCD_REFRESH_FREQ;
for (post_divider = 1; post_divider < 16; post_divider <<= 1)
{
if (IMXRT_LCD_VIDEO_PLL_FREQ * post_divider >= VIDEO_PLL_MIN_FREQ)
{
break;
}
}
loop_divider = (IMXRT_LCD_VIDEO_PLL_FREQ * post_divider) / OSC24_FREQ;
numerator = (IMXRT_LCD_VIDEO_PLL_FREQ * post_divider) -
(loop_divider * OSC24_FREQ);
denominator = OSC24_FREQ;
/* Bypass PLL first */
modifyreg32(IMXRT_CCM_ANALOG_PLL_VIDEO,
CCM_ANALOG_PLL_VIDEO_BYPASS_CLK_SRC_MASK,
CCM_ANALOG_PLL_VIDEO_BYPASS |
CCM_ANALOG_PLL_VIDEO_BYPASS_CLK_SRC_REF_24M);
putreg32(CCM_ANALOG_PLL_VIDEO_NUM_A(numerator),
IMXRT_CCM_ANALOG_PLL_VIDEO_NUM);
putreg32(CCM_ANALOG_PLL_VIDEO_DENOM_B(denominator),
IMXRT_CCM_ANALOG_PLL_VIDEO_DENOM);
/* Set post divider:
*
* ------------------------------------------------------------------------
* | config->postDivider | PLL_VIDEO[POST_DIV_SELECT] | MISC2[VIDEO_DIV] |
* ------------------------------------------------------------------------
* | 1 | 2 | 0 |
* ------------------------------------------------------------------------
* | 2 | 1 | 0 |
* ------------------------------------------------------------------------
* | 4 | 2 | 3 |
* ------------------------------------------------------------------------
* | 8 | 1 | 3 |
* ------------------------------------------------------------------------
* | 16 | 0 | 3 |
* ------------------------------------------------------------------------
*/
reg = getreg32(IMXRT_CCM_ANALOG_PLL_VIDEO);
reg &= ~(CCM_ANALOG_PLL_VIDEO_DIV_SELECT_MASK |
CCM_ANALOG_PLL_VIDEO_POWERDOWN);
reg |= CCM_ANALOG_PLL_VIDEO_ENABLE |
CCM_ANALOG_PLL_VIDEO_DIV_SELECT(loop_divider);
reg2 = getreg32(IMXRT_CCM_ANALOG_MISC2);
reg2 &= ~CCM_ANALOG_MISC2_VIDEO_DIV_MASK;
switch (post_divider)
{
case 16:
reg |= CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT_DIV4;
reg2 |= CCM_ANALOG_MISC2_VIDEO_DIV(3);
break;
case 8:
reg |= CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT_DIV2;
reg2 |= CCM_ANALOG_MISC2_VIDEO_DIV(3);
break;
case 4:
reg |= CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT_DIV1;
reg2 |= CCM_ANALOG_MISC2_VIDEO_DIV(3);
break;
case 2:
reg |= CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT_DIV2;
reg2 |= 0;
break;
default:
reg |= CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT_DIV1;
reg2 |= 0;
break;
}
putreg32(reg, IMXRT_CCM_ANALOG_PLL_VIDEO);
putreg32(reg2, IMXRT_CCM_ANALOG_MISC2);
while ((getreg32(IMXRT_CCM_ANALOG_PLL_VIDEO) &
CCM_ANALOG_PLL_VIDEO_LOCK) == 0)
{
}
/* Disable Bypass */
modifyreg32(IMXRT_CCM_ANALOG_PLL_VIDEO,
CCM_ANALOG_PLL_VIDEO_BYPASS,
0);
freq_error = IMXRT_LCD_VIDEO_PLL_FREQ;
pre_divider = 0;
post_divider = 0;
for (post = 0; post < 8; post++)
{
for (pre = 0; pre < 8; pre++)
{
int32_t temp_error;
temp_error = labs((post + 1) * (pre + 1) * target_freq -
IMXRT_LCD_VIDEO_PLL_FREQ);
if (temp_error < freq_error)
{
pre_divider = pre;
post_divider = post;
freq_error = temp_error;
}
}
}
/* Select PLL5 as LCD Clock and set Pre divider. */
modifyreg32(IMXRT_CCM_CSCDR2,
CCM_CSCDR2_LCDIF_PRE_CLK_SEL_MASK |
CCM_CSCDR2_LCDIF_PRED_MASK,
CCM_CSCDR2_LCDIF_PRE_CLK_SEL_PLL5 |
CCM_CSCDR2_LCDIF_PRED(pre_divider));
/* Set Post divider. */
modifyreg32(IMXRT_CCM_CBCMR, CCM_CBCMR_LCDIF_PODF_MASK,
CCM_CBCMR_LCDIF_PODF(post_divider));
}
#endif
/****************************************************************************
* Name: imxrt_pllsetup
****************************************************************************/
static void imxrt_pllsetup(void)
{
#ifdef CONFIG_ARCH_FAMILY_IMXRT102x
uint32_t pll2reg;
#endif
uint32_t pll3reg;
uint32_t reg;
#if (defined(CONFIG_ARCH_FAMILY_IMXRT105x) || \
defined(CONFIG_ARCH_FAMILY_IMXRT106x))
/* Init Arm PLL1 */
reg = CCM_ANALOG_PLL_ARM_DIV_SELECT(IMXRT_ARM_PLL_DIV_SELECT) |
CCM_ANALOG_PLL_ARM_ENABLE;
putreg32(reg, IMXRT_CCM_ANALOG_PLL_ARM);
while ((getreg32(IMXRT_CCM_ANALOG_PLL_ARM) & CCM_ANALOG_PLL_ARM_LOCK) == 0)
{
}
/* Init Sys PLL2 */
reg = CCM_ANALOG_PLL_SYS_DIV_SELECT(IMXRT_SYS_PLL_SELECT) |
CCM_ANALOG_PLL_SYS_ENABLE;
putreg32(reg, IMXRT_CCM_ANALOG_PLL_SYS);
while ((getreg32(IMXRT_CCM_ANALOG_PLL_SYS) & CCM_ANALOG_PLL_SYS_LOCK) == 0)
{
}
/* Init USB PLL3 */
/* capture it's original value */
pll3reg = getreg32(IMXRT_CCM_ANALOG_PFD_480);
putreg32(pll3reg |
CCM_ANALOG_PFD_480_PFD0_CLKGATE |
CCM_ANALOG_PFD_480_PFD1_CLKGATE |
CCM_ANALOG_PFD_480_PFD2_CLKGATE |
CCM_ANALOG_PFD_480_PFD3_CLKGATE,
IMXRT_CCM_ANALOG_PFD_480);
reg = IMXRT_USB1_PLL_DIV_SELECT |
CCM_ANALOG_PLL_USB1_ENABLE |
CCM_ANALOG_PLL_USB1_EN_USB_CLKS |
CCM_ANALOG_PLL_USB1_POWER;
putreg32(reg, IMXRT_CCM_ANALOG_PLL_USB1);
while ((getreg32(IMXRT_CCM_ANALOG_PLL_USB1) &
CCM_ANALOG_PLL_USB1_LOCK) == 0)
{
}
putreg32(pll3reg, IMXRT_CCM_ANALOG_PFD_480);
#ifdef CONFIG_IMXRT_LCD
/* Init Video PLL5 */
imxrt_lcd_clockconfig();
#endif
#if defined(CONFIG_IMXRT_ENET)
/* Init ENET PLL6 */
# if defined(CONFIG_IMXRT_ENET1)
reg = CCM_ANALOG_PLL_ENET_ENET1_DIV_SELECT_50MHZ |
CCM_ANALOG_PLL_ENET_ENABLE |
# if defined(IMXRT_MAC_PROVIDES_TXC)
CCM_ANALOG_PLL_ENET_ENET1_25M_REF_EN;
# else
0;
# endif
# endif
# if defined(CONFIG_IMXRT_ENET2)
reg = CCM_ANALOG_PLL_ENET_ENET2_DIV_SELECT_50MHZ |
CCM_ANALOG_PLL_ENET_ENABLE |
# if defined(IMXRT_MAC_PROVIDES_TXC)
CCM_ANALOG_PLL_ENET_ENET2_25M_REF_EN;
# else
0;
# endif
# endif
putreg32(reg, IMXRT_CCM_ANALOG_PLL_ENET);
while ((getreg32(IMXRT_CCM_ANALOG_PLL_ENET) &
CCM_ANALOG_PLL_ENET_LOCK) == 0)
{
}
#endif
#elif defined(CONFIG_ARCH_FAMILY_IMXRT102x)
/* Init Sys PLL2 */
/* First reset its fractional dividers */
pll2reg = getreg32(IMXRT_CCM_ANALOG_PFD_528);
putreg32(pll2reg |
CCM_ANALOG_PFD_528_PFD0_CLKGATE |
CCM_ANALOG_PFD_528_PFD1_CLKGATE |
CCM_ANALOG_PFD_528_PFD2_CLKGATE |
CCM_ANALOG_PFD_528_PFD3_CLKGATE,
IMXRT_CCM_ANALOG_PFD_528);
reg = CCM_ANALOG_PLL_SYS_DIV_SELECT(IMXRT_SYS_PLL_DIV_SELECT) |
CCM_ANALOG_PLL_SYS_ENABLE;
putreg32(reg, IMXRT_CCM_ANALOG_PLL_SYS);
while ((getreg32(IMXRT_CCM_ANALOG_PLL_SYS) &
CCM_ANALOG_PLL_SYS_LOCK) == 0)
{
}
putreg32(pll2reg, IMXRT_CCM_ANALOG_PFD_528);
/* Init USB PLL3 */
/* capture it's original value */
pll3reg = getreg32(IMXRT_CCM_ANALOG_PFD_480);
putreg32(pll3reg |
CCM_ANALOG_PFD_480_PFD0_CLKGATE |
CCM_ANALOG_PFD_480_PFD1_CLKGATE |
CCM_ANALOG_PFD_480_PFD2_CLKGATE |
CCM_ANALOG_PFD_480_PFD3_CLKGATE,
IMXRT_CCM_ANALOG_PFD_480);
reg = CCM_ANALOG_PLL_USB1_DIV_SELECT(IMXRT_USB1_PLL_DIV_SELECT) |
CCM_ANALOG_PLL_USB1_ENABLE | CCM_ANALOG_PLL_USB1_EN_USB_CLKS |
CCM_ANALOG_PLL_USB1_POWER;
putreg32(reg, IMXRT_CCM_ANALOG_PLL_USB1);
while ((getreg32(IMXRT_CCM_ANALOG_PLL_USB1) &
CCM_ANALOG_PLL_USB1_LOCK) == 0)
{
}
putreg32(pll3reg, IMXRT_CCM_ANALOG_PFD_480);
/* Init Audio PLL4 */
reg = CCM_ANALOG_PLL_AUDIO_DIV_SELECT(IMXRT_AUDIO_PLL_DIV_SELECT) |
CCM_ANALOG_PLL_AUDIO_ENABLE;
putreg32(reg, IMXRT_CCM_ANALOG_PLL_AUDIO);
while ((getreg32(IMXRT_CCM_ANALOG_PLL_AUDIO) &
CCM_ANALOG_PLL_AUDIO_LOCK) == 0)
{
}
/* Init ENET PLL6 */
reg = CCM_ANALOG_PLL_ENET_ENET1_DIV_SELECT_50MHZ |
CCM_ANALOG_PLL_ENET_ENABLE |
CCM_ANALOG_PLL_ENET_ENET_25M_REF_EN |
CCM_ANALOG_PLL_ENET_ENET_500M_REF_EN;
putreg32(reg, IMXRT_CCM_ANALOG_PLL_ENET);
while ((getreg32(IMXRT_CCM_ANALOG_PLL_ENET) &
CCM_ANALOG_PLL_ENET_LOCK) == 0)
{
}
#else
# error Unrecognised IMXRT family member for clock config
#endif
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: imxrt_clockconfig
*
* Description:
* Called to initialize the i.MXRT. This does whatever setup is needed to
* put the SoC in a usable state. This includes the initialization of
* clocking using the settings in board.h.
*
****************************************************************************/
void imxrt_clockconfig(void)
{
/* Don't change the current basic clock configuration if we are running
* from SDRAM. In this case, some bootloader logic has already configured
* clocking and SDRAM. We are pretty much committed to using things the
* way that the bootloader has left them.
*
* Note that although this is safe at boot while nothing is using
* the clocks additional caution is required if at some later date
* we want to manipulate the PODFs while the system is running
* (for power minimisation) because changing those is not glitch free.
*/
#ifndef CONFIG_IMXRT_BOOT_SDRAM
uint32_t reg;
/* Set clock mux and dividers */
/* Set PERIPH_CLK2 MUX to OSC */
reg = getreg32(IMXRT_CCM_CBCMR);
reg &= ~CCM_CBCMR_PERIPH_CLK2_SEL_MASK;
reg |= CCM_CBCMR_PERIPH_CLK2_SEL_OSC_CLK;
putreg32(reg, IMXRT_CCM_CBCMR);
while ((getreg32(IMXRT_CCM_CDHIPR) & CCM_CDHIPR_PERIPH2_CLK_SEL_BUSY) != 0)
{
}
/* Set PERIPH_CLK MUX to PERIPH_CLK2 */
reg = getreg32(IMXRT_CCM_CBCDR);
reg &= ~CCM_CBCDR_PERIPH_CLK_SEL_MASK;
reg |= CCM_CBCDR_PERIPH_CLK_SEL(CCM_CBCDR_PERIPH_CLK_SEL_PERIPH_CLK2);
putreg32(reg, IMXRT_CCM_CBCDR);
while ((getreg32(IMXRT_CCM_CDHIPR) & CCM_CDHIPR_PERIPH_CLK_SEL_BUSY) != 0)
{
}
/* Set Soc VDD and wait for it to stablise */
reg = getreg32(IMXRT_DCDC_REG3);
reg &= ~(DCDC_REG3_TRG_MASK);
reg |= DCDC_REG3_TRG(IMXRT_VDD_SOC);
putreg32(reg, IMXRT_DCDC_REG3);
while ((getreg32(IMXRT_DCDC_REG0) & DCDC_REG0_STS_DC_OK) == 0)
{
}
/* OK, now nothing is depending on us, configure the PLLs */
imxrt_pllsetup();
/* Set Dividers */
reg = getreg32(IMXRT_CCM_CACRR);
reg &= ~CCM_CACRR_ARM_PODF_MASK;
reg |= CCM_CACRR_ARM_PODF(CCM_PODF_FROM_DIVISOR(IMXRT_ARM_PODF_DIVIDER));
putreg32(reg, IMXRT_CCM_CACRR);
while ((getreg32(IMXRT_CCM_CDHIPR) & CCM_CDHIPR_ARM_PODF_BUSY) != 0)
{
}
reg = getreg32(IMXRT_CCM_CBCDR);
reg &= ~CCM_CBCDR_AHB_PODF_MASK;
reg |= CCM_CBCDR_AHB_PODF(CCM_PODF_FROM_DIVISOR(IMXRT_AHB_PODF_DIVIDER));
putreg32(reg, IMXRT_CCM_CBCDR);
while ((getreg32(IMXRT_CCM_CDHIPR) & CCM_CDHIPR_AHB_PODF_BUSY) != 0)
{
}
/* Adjust IPG and PERCLK PODFs. Consumers of these clocks will need to
* be gated if there are any (there aren't at boot).
*/
reg = getreg32(IMXRT_CCM_CBCDR);
reg &= ~CCM_CBCDR_IPG_PODF_MASK;
reg |= CCM_CBCDR_IPG_PODF(CCM_PODF_FROM_DIVISOR(IMXRT_IPG_PODF_DIVIDER));
putreg32(reg, IMXRT_CCM_CBCDR);
reg = getreg32(IMXRT_CCM_CSCMR1);
reg &= ~CCM_CSCMR1_PERCLK_PODF_MASK;
reg |= CCM_CSCMR1_PERCLK_PODF(
CCM_PODF_FROM_DIVISOR(IMXRT_PERCLK_PODF_DIVIDER));
putreg32(reg, IMXRT_CCM_CSCMR1);
#ifndef CONFIG_IMXRT_SEMC_INIT_DONE
/* Configure SEMC Clock only if not already done by DCD SDR */
reg = getreg32(IMXRT_CCM_CBCDR);
reg &= ~CCM_CBCDR_SEMC_PODF_MASK;
reg |= CCM_CBCDR_SEMC_PODF(CCM_PODF_FROM_DIVISOR(IMXRT_SEMC_PODF_DIVIDER));
putreg32(reg, IMXRT_CCM_CBCDR);
while ((getreg32(IMXRT_CCM_CDHIPR) & CCM_CDHIPR_SEMC_PODF_BUSY) != 0)
{
}
#endif
/* Set PRE_PERIPH_CLK to Board Selection */
reg = getreg32(IMXRT_CCM_CBCMR);
reg &= ~CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK;
reg |= CCM_CBCMR_PRE_PERIPH_CLK_SEL(IMXRT_PRE_PERIPH_CLK_SEL);
putreg32(reg, IMXRT_CCM_CBCMR);
/* Set PERIPH_CLK MUX to Board Selection */
reg = getreg32(IMXRT_CCM_CBCDR);
reg &= ~CCM_CBCDR_PERIPH_CLK_SEL_MASK;
reg |= CCM_CBCDR_PERIPH_CLK_SEL(IMXRT_PERIPH_CLK_SEL);
putreg32(reg, IMXRT_CCM_CBCDR);
/* Wait handshake */
while ((getreg32(IMXRT_CCM_CDHIPR) & CCM_CDHIPR_PERIPH_CLK_SEL_BUSY) != 0)
{
}
/* Set PERCLK_CLK_SEL to Board Selection */
reg = getreg32(IMXRT_CCM_CSCMR1);
reg &= ~CCM_CSCMR1_PERCLK_CLK_SEL_MASK;
reg |= CCM_CSCMR1_PERCLK_CLK_SEL(IMXRT_PERCLK_CLK_SEL);
putreg32(reg, IMXRT_CCM_CSCMR1);
while ((getreg32(IMXRT_CCM_CDHIPR) & CCM_CDHIPR_PERIPH_CLK_SEL_BUSY) != 0)
{
}
/* Setup perhiperals. At this point these are not activated so don't
* need to worry too much about switching off the clock feeds.
*/
/* Set UART source to PLL3 80M */
reg = getreg32(IMXRT_CCM_CSCDR1);
reg &= ~CCM_CSCDR1_UART_CLK_SEL;
reg |= CCM_CSCDR1_UART_CLK_SEL_PLL3_80;
putreg32(reg, IMXRT_CCM_CSCDR1);
/* Set UART divider to 1 */
reg = getreg32(IMXRT_CCM_CSCDR1);
reg &= ~CCM_CSCDR1_UART_CLK_PODF_MASK;
reg |= CCM_CSCDR1_UART_CLK_PODF(CCM_PODF_FROM_DIVISOR(1));
putreg32(reg, IMXRT_CCM_CSCDR1);
#ifdef CONFIG_IMXRT_FLEXIO1
#ifdef CONFIG_ARCH_FAMILY_IMXRT102x
/* Set FlEXIO1 source */
reg = getreg32(IMXRT_CCM_CSCMR2);
reg &= ~CCM_CSCMR2_FLEXIO1_CLK_SEL_MASK;
reg |= CCM_CSCMR2_FLEXIO1_CLK_SEL(CONFIG_FLEXIO1_CLK);
putreg32(reg, IMXRT_CCM_CSCMR2);
/* Set FlEXIO1 divider */
reg = getreg32(IMXRT_CCM_CS1CDR);
reg &= ~(CCM_CS1CDR_FLEXIO1_CLK_PODF_MASK | \
CCM_CS1CDR_FLEXIO1_CLK_PRED_MASK);
reg |= CCM_CS1CDR_FLEXIO1_CLK_PODF
(CCM_PODF_FROM_DIVISOR(CONFIG_FLEXIO1_PODF_DIVIDER));
reg |= CCM_CS1CDR_FLEXIO1_CLK_PRED
(CCM_PRED_FROM_DIVISOR(CONFIG_FLEXIO1_PRED_DIVIDER));
putreg32(reg, IMXRT_CCM_CS1CDR);
#elif (defined(CONFIG_ARCH_FAMILY_IMXRT105x) || \
defined(CONFIG_ARCH_FAMILY_IMXRT106x))
/* Set FlEXIO1 source & divider */
reg = getreg32(IMXRT_CCM_CDCDR);
reg &= ~(CCM_CDCDR_FLEXIO1_CLK_SEL_MASK |
CCM_CDCDR_FLEXIO1_CLK_PODF_MASK |
CCM_CDCDR_FLEXIO1_CLK_PRED_MASK);
reg |= CCM_CDCDR_FLEXIO1_CLK_SEL(CONFIG_FLEXIO1_CLK);
reg |= CCM_CDCDR_FLEXIO1_CLK_PODF
(CCM_PODF_FROM_DIVISOR(CONFIG_FLEXIO1_PODF_DIVIDER));
reg |= CCM_CDCDR_FLEXIO1_CLK_PRED
(CCM_PRED_FROM_DIVISOR(CONFIG_FLEXIO1_PRED_DIVIDER));
putreg32(reg, IMXRT_CCM_CDCDR);
#endif /* CONFIG_ARCH_FAMILY_IMXRT102x */
#endif /* CONFIG_IMXRT_FLEXIO1 */
#if (defined(CONFIG_IMXRT_FLEXIO2) || defined(CONFIG_IMXRT_FLEXIO3))
/* Set FlEXIO2 source */
reg = getreg32(IMXRT_CCM_CSCMR2);
reg &= ~CCM_CSCMR2_FLEXIO2_CLK_SEL_MASK;
reg |= CCM_CSCMR2_FLEXIO2_CLK_SEL(CONFIG_FLEXIO2_CLK);
putreg32(reg, IMXRT_CCM_CSCMR2);
/* Set FlEXIO2 divider */
reg = getreg32(IMXRT_CCM_CS1CDR);
reg &= ~(CCM_CS1CDR_FLEXIO2_CLK_PODF_MASK | \
CCM_CS1CDR_FLEXIO2_CLK_PRED_MASK);
reg |= CCM_CS1CDR_FLEXIO2_CLK_PODF
(CCM_PODF_FROM_DIVISOR(CONFIG_FLEXIO2_PODF_DIVIDER));
reg |= CCM_CS1CDR_FLEXIO2_CLK_PRED
(CCM_PRED_FROM_DIVISOR(CONFIG_FLEXIO2_PRED_DIVIDER));
putreg32(reg, IMXRT_CCM_CS1CDR);
#endif /* CONFIG_IMXRT_FLEXIO2 */
#ifdef CONFIG_IMXRT_LPI2C
/* Set LPI2C source to PLL3 60M */
reg = getreg32(IMXRT_CCM_CSCDR2);
reg &= ~CCM_CSCDR2_LPI2C_CLK_SEL;
reg |= IMXRT_LPI2C_CLK_SELECT;
putreg32(reg, IMXRT_CCM_CSCDR2);
/* Set LPI2C divider to 5 for 12 MHz */
reg = getreg32(IMXRT_CCM_CSCDR2);
reg &= ~CCM_CSCDR2_LPI2C_CLK_PODF_MASK;
reg |= CCM_CSCDR2_LPI2C_CLK_PODF(
CCM_PODF_FROM_DIVISOR(IMXRT_LSI2C_PODF_DIVIDER)
);
putreg32(reg, IMXRT_CCM_CSCDR2);
#endif
#ifdef CONFIG_IMXRT_FLEXCAN
/* Set FlexCAN clock source to PLL3 80M */
reg = getreg32(IMXRT_CCM_CSCMR2);
reg &= ~CCM_CSCMR2_CAN_CLK_SEL_MASK;
reg |= IMXRT_CAN_CLK_SELECT;
putreg32(reg, IMXRT_CCM_CSCMR2);
/* Set FlexCAN dividet to 1 for 80 MHz */
reg = getreg32(IMXRT_CCM_CSCMR2);
reg &= ~CCM_CSCMR2_CAN_CLK_PODF_MASK;
reg |= CCM_CSCMR2_CAN_CLK_PODF(
CCM_PODF_FROM_DIVISOR(IMXRT_CAN_PODF_DIVIDER)
);
putreg32(reg, IMXRT_CCM_CSCMR2);
#endif
#ifdef CONFIG_IMXRT_LPSPI
/* Set LPSPI clock source to PLL3 PFD0 */
reg = getreg32(IMXRT_CCM_CBCMR);
reg &= ~CCM_CBCMR_LPSPI_CLK_SEL_MASK;
reg |= IMXRT_LPSPI_CLK_SELECT;
putreg32(reg, IMXRT_CCM_CBCMR);
/* Set LPSPI divider to IMXRT_LSPI_PODF_DIVIDER */
reg = getreg32(IMXRT_CCM_CBCMR);
reg &= ~CCM_CBCMR_LPSPI_PODF_MASK;
reg |= CCM_CBCMR_LPSPI_PODF(
CCM_PODF_FROM_DIVISOR(IMXRT_LSPI_PODF_DIVIDER)
);
putreg32(reg, IMXRT_CCM_CBCMR);
#endif
#ifdef IMXRT_TRACE_PODF_DIVIDER
/* Set TRACE clock source and speed */
reg = getreg32(IMXRT_CCM_CBCMR);
reg &= ~CCM_CBCMR_TRACE_CLK_SEL_MASK;
reg |= IMXRT_TRACE_CLK_SELECT;
putreg32(reg, IMXRT_CCM_CBCMR);
reg = getreg32(IMXRT_CCM_CSCDR1);
reg &= ~CCM_CSCDR1_TRACE_PODF_MASK;
reg |= CCM_CSCDR1_TRACE_PODF(
CCM_PODF_FROM_DIVISOR(IMXRT_TRACE_PODF_DIVIDER));
putreg32(reg, IMXRT_CCM_CSCDR1);
#endif
#ifdef CONFIG_IMXRT_USDHC
/* Optionally set USDHC1 & 2 to generate clocks
* from IMXRT_USDHC1_CLK_SELECT
*/
reg = getreg32(IMXRT_CCM_CSCMR1);
reg &= ~(CCM_CSCMR1_USDHC1_CLK_SEL | CCM_CSCMR1_USDHC2_CLK_SEL);
#if defined(IMXRT_USDHC1_CLK_SELECT)
reg |= IMXRT_USDHC1_CLK_SELECT;
#endif
#if defined(IMXRT_USDHC2_CLK_SELECT)
reg |= IMXRT_USDHC2_CLK_SELECT;
#endif
putreg32(reg, IMXRT_CCM_CSCMR1);
/* Now divide down clocks by IMXRT_USDHC[1|2]_PODF_DIVIDER */
reg = getreg32(IMXRT_CCM_CSCDR1);
reg &= ~(CCM_CSCDR1_USDHC1_PODF_MASK | CCM_CSCDR1_USDHC2_PODF_MASK);
#if defined(IMXRT_USDHC1_PODF_DIVIDER)
reg |= CCM_CSCDR1_USDHC1_PODF(
CCM_PODF_FROM_DIVISOR(IMXRT_USDHC1_PODF_DIVIDER));
#endif
#if defined(IMXRT_USDHC2_PODF_DIVIDER)
reg |= CCM_CSCDR1_USDHC2_PODF(
CCM_PODF_FROM_DIVISOR(IMXRT_USDHC2_PODF_DIVIDER));
#endif
putreg32(reg, IMXRT_CCM_CSCDR1);
#endif
/* Ensure platform memory clocks remain enabled in WFI */
reg = getreg32(IMXRT_CCM_CGPR);
reg |= CCM_CGPR_INT_MEM_CLK_LPM;
putreg32(reg, IMXRT_CCM_CGPR);
/* Remain in run mode */
modifyreg32(IMXRT_CCM_CLPCR,
CCM_CLPCR_LPM_MASK,
CCM_CLPCR_LPM_RUN);
#endif
}