soc: mimxrt1064: Enable low power clocking for mimxrt1064
Enables low power clocks for mimxrt1064. This allows the soc to transition into very low power states during idle, as most PLLs can be disabled. Power states need to be enabled and selected at the board level. Signed-off-by: Daniel DeGrasse <daniel.degrasse@nxp.com>
This commit is contained in:
parent
6696d834cf
commit
cbb52e8c50
3 changed files with 496 additions and 0 deletions
|
@ -100,6 +100,25 @@
|
|||
};
|
||||
};
|
||||
};
|
||||
|
||||
power-states {
|
||||
idle: idle {
|
||||
compatible = "zephyr,power-state";
|
||||
power-state-name = "runtime-idle";
|
||||
exit-latency-us = <4000>;
|
||||
min-residency-us = <5000>;
|
||||
};
|
||||
suspend: suspend {
|
||||
compatible = "zephyr,power-state";
|
||||
power-state-name = "suspend-to-idle";
|
||||
exit-latency-us = <5000>;
|
||||
min-residency-us = <10000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&cpu0 {
|
||||
cpu-power-states = <&idle &suspend>;
|
||||
};
|
||||
|
||||
arduino_i2c: &lpi2c1 {};
|
||||
|
|
|
@ -28,8 +28,16 @@ endif()
|
|||
if (CONFIG_PM AND CONFIG_SOC_SERIES_IMX_RT10XX)
|
||||
zephyr_sources(power_rt10xx.c)
|
||||
zephyr_code_relocate(power_rt10xx.c ITCM_TEXT)
|
||||
if (CONFIG_SOC_MIMXRT1064)
|
||||
zephyr_sources(lpm_rt1064.c)
|
||||
zephyr_code_relocate(lpm_rt1064.c ITCM_TEXT)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
zephyr_compile_definitions(
|
||||
XIP_EXTERNAL_FLASH
|
||||
)
|
||||
|
||||
zephyr_linker_section_configure(
|
||||
SECTION .rom_start
|
||||
INPUT ".boot_hdr.ivt"
|
||||
|
|
469
soc/arm/nxp_imx/rt/lpm_rt1064.c
Normal file
469
soc/arm/nxp_imx/rt/lpm_rt1064.c
Normal file
|
@ -0,0 +1,469 @@
|
|||
/*
|
||||
* Copyright (c) 2021, NXP
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Note: this file is linked to RAM. Any functions called while changing clocks
|
||||
* to the flexspi modules must be linked to RAM, or within this file
|
||||
*/
|
||||
|
||||
#include <init.h>
|
||||
#include <power_rt10xx.h>
|
||||
#include <zephyr.h>
|
||||
#include "clock_config.h"
|
||||
|
||||
|
||||
/*
|
||||
* Clock configuration structures populated at boot time. These structures are
|
||||
* used to reinitialize the PLLs after exiting low power mode.
|
||||
*/
|
||||
#ifdef CONFIG_INIT_ARM_PLL
|
||||
static clock_arm_pll_config_t arm_pll_config;
|
||||
#endif
|
||||
#ifdef CONFIG_INIT_VIDEO_PLL
|
||||
static clock_video_pll_config_t video_pll_config;
|
||||
#endif
|
||||
#ifdef CONFIG_INIT_ENET_PLL
|
||||
static clock_enet_pll_config_t enet_pll_config;
|
||||
#endif
|
||||
static clock_sys_pll_config_t sys_pll_config;
|
||||
static clock_usb_pll_config_t usb1_pll_config;
|
||||
|
||||
#define IMX_RT_SYS_PFD_FRAC(reg, pfd_num) \
|
||||
(((reg) >> (8U * pfd_num)) &\
|
||||
CCM_ANALOG_PFD_528_PFD0_FRAC_MASK)
|
||||
#define IMX_RT_USB1_PFD_FRAC(reg, pfd_num) \
|
||||
(((reg) >> (8U * pfd_num)) &\
|
||||
CCM_ANALOG_PFD_480_PFD0_FRAC_MASK)
|
||||
|
||||
uint8_t sys_pll_pfd0_frac;
|
||||
uint8_t sys_pll_pfd1_frac;
|
||||
uint8_t sys_pll_pfd2_frac;
|
||||
uint8_t sys_pll_pfd3_frac;
|
||||
|
||||
uint8_t usb1_pll_pfd1_frac;
|
||||
uint8_t usb1_pll_pfd2_frac;
|
||||
uint8_t usb1_pll_pfd3_frac;
|
||||
|
||||
uint32_t flexspi_div;
|
||||
|
||||
/*
|
||||
* Duplicate implementation of CLOCK_SetMux() provided by SDK. This function
|
||||
* must be linked to ITCM, as it will be used to change the clocks of the
|
||||
* FLEXSPI and SEMC peripherals.
|
||||
* Any function called from this function must also reside in ITCM
|
||||
*/
|
||||
static void clock_set_mux(clock_mux_t mux, uint32_t value)
|
||||
{
|
||||
uint32_t busy_shift;
|
||||
|
||||
busy_shift = (uint32_t)CCM_TUPLE_BUSY_SHIFT(mux);
|
||||
CCM_TUPLE_REG(CCM, mux) = (CCM_TUPLE_REG(CCM, mux) & (~CCM_TUPLE_MASK(mux))) |
|
||||
(((uint32_t)((value) << CCM_TUPLE_SHIFT(mux))) & CCM_TUPLE_MASK(mux));
|
||||
|
||||
/* Clock switch need Handshake? */
|
||||
if (busy_shift != CCM_NO_BUSY_WAIT) {
|
||||
/* Wait until CCM internal handshake finish. */
|
||||
while ((CCM->CDHIPR & ((1UL << busy_shift))) != 0UL) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Duplicate implementation of CLOCK_SetDiv() provided by SDK. This function
|
||||
* must be linked to ITCM, as it will be used to change the clocks of the
|
||||
* FLEXSPI and SEMC peripherals.
|
||||
* Any function called from this function must also reside in ITCM
|
||||
*/
|
||||
static void clock_set_div(clock_div_t divider, uint32_t value)
|
||||
{
|
||||
uint32_t busy_shift;
|
||||
|
||||
busy_shift = CCM_TUPLE_BUSY_SHIFT(divider);
|
||||
CCM_TUPLE_REG(CCM, divider) = (CCM_TUPLE_REG(CCM, divider) & (~CCM_TUPLE_MASK(divider))) |
|
||||
(((uint32_t)((value) << CCM_TUPLE_SHIFT(divider))) & CCM_TUPLE_MASK(divider));
|
||||
|
||||
/* Clock switch need Handshake? */
|
||||
if (busy_shift != CCM_NO_BUSY_WAIT) {
|
||||
/* Wait until CCM internal handshake finish. */
|
||||
while ((CCM->CDHIPR & ((uint32_t)(1UL << busy_shift))) != 0UL) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Duplicate implementation of CLOCK_InitUsb1Pll() provided by SDK. This function
|
||||
* must be linked to ITCM, as it will be used to change the clocks of the
|
||||
* FLEXSPI and SEMC peripherals.
|
||||
* Any function called from this function must also reside in ITCM
|
||||
*/
|
||||
static void clock_init_usb1_pll(const clock_usb_pll_config_t *config)
|
||||
{
|
||||
/* Bypass PLL first */
|
||||
CCM_ANALOG->PLL_USB1 = (CCM_ANALOG->PLL_USB1 & (~CCM_ANALOG_PLL_USB1_BYPASS_CLK_SRC_MASK)) |
|
||||
CCM_ANALOG_PLL_USB1_BYPASS_MASK | CCM_ANALOG_PLL_USB1_BYPASS_CLK_SRC(config->src);
|
||||
|
||||
CCM_ANALOG->PLL_USB1 = (CCM_ANALOG->PLL_USB1 & (~CCM_ANALOG_PLL_USB1_DIV_SELECT_MASK)) |
|
||||
CCM_ANALOG_PLL_USB1_ENABLE_MASK | CCM_ANALOG_PLL_USB1_POWER_MASK |
|
||||
CCM_ANALOG_PLL_USB1_EN_USB_CLKS_MASK |
|
||||
CCM_ANALOG_PLL_USB1_DIV_SELECT(config->loopDivider);
|
||||
|
||||
while ((CCM_ANALOG->PLL_USB1 & CCM_ANALOG_PLL_USB1_LOCK_MASK) == 0UL) {
|
||||
;
|
||||
}
|
||||
|
||||
/* Disable Bypass */
|
||||
CCM_ANALOG->PLL_USB1 &= ~CCM_ANALOG_PLL_USB1_BYPASS_MASK;
|
||||
}
|
||||
|
||||
static void flexspi_enter_critical(void)
|
||||
{
|
||||
#if CONFIG_CODE_FLEXSPI2
|
||||
/* Wait for flexspi to be inactive, and gate the clock */
|
||||
while (!((FLEXSPI2->STS0 & FLEXSPI_STS0_ARBIDLE_MASK) &&
|
||||
(FLEXSPI2->STS0 & FLEXSPI_STS0_SEQIDLE_MASK))) {
|
||||
}
|
||||
FLEXSPI2->MCR0 |= FLEXSPI_MCR0_MDIS_MASK;
|
||||
|
||||
/* Disable clock gate of flexspi2. */
|
||||
CCM->CCGR7 &= (~CCM_CCGR7_CG1_MASK);
|
||||
#elif CONFIG_CODE_FLEXSPI
|
||||
/* Wait for flexspi to be inactive, and gate the clock */
|
||||
while (!((FLEXSPI->STS0 & FLEXSPI_STS0_ARBIDLE_MASK) &&
|
||||
(FLEXSPI->STS0 & FLEXSPI_STS0_SEQIDLE_MASK))) {
|
||||
}
|
||||
FLEXSPI->MCR0 |= FLEXSPI_MCR0_MDIS_MASK;
|
||||
|
||||
/* Disable clock of flexspi. */
|
||||
CCM->CCGR6 &= (~CCM_CCGR6_CG5_MASK);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void flexspi_exit_critical(void)
|
||||
{
|
||||
#if CONFIG_CODE_FLEXSPI2
|
||||
/* Enable clock gate of flexspi2. */
|
||||
CCM->CCGR7 |= (CCM_CCGR7_CG1_MASK);
|
||||
|
||||
FLEXSPI2->MCR0 &= ~FLEXSPI_MCR0_MDIS_MASK;
|
||||
FLEXSPI2->MCR0 |= FLEXSPI_MCR0_SWRESET_MASK;
|
||||
while (FLEXSPI2->MCR0 & FLEXSPI_MCR0_SWRESET_MASK) {
|
||||
}
|
||||
while (!((FLEXSPI2->STS0 & FLEXSPI_STS0_ARBIDLE_MASK) &&
|
||||
(FLEXSPI2->STS0 & FLEXSPI_STS0_SEQIDLE_MASK))) {
|
||||
}
|
||||
#elif CONFIG_CODE_FLEXSPI
|
||||
/* Enable clock of flexspi. */
|
||||
CCM->CCGR6 |= CCM_CCGR6_CG5_MASK;
|
||||
|
||||
FLEXSPI->MCR0 &= ~FLEXSPI_MCR0_MDIS_MASK;
|
||||
FLEXSPI->MCR0 |= FLEXSPI_MCR0_SWRESET_MASK;
|
||||
while (FLEXSPI->MCR0 & FLEXSPI_MCR0_SWRESET_MASK) {
|
||||
}
|
||||
while (!((FLEXSPI->STS0 & FLEXSPI_STS0_ARBIDLE_MASK) &&
|
||||
(FLEXSPI->STS0 & FLEXSPI_STS0_SEQIDLE_MASK))) {
|
||||
}
|
||||
#endif
|
||||
/* Invalidate I-cache after flexspi clock changed. */
|
||||
if (SCB_CCR_IC_Msk == (SCB_CCR_IC_Msk & SCB->CCR)) {
|
||||
SCB_InvalidateICache();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void clock_full_power(void)
|
||||
{
|
||||
/* Power up PLLS */
|
||||
/* Set arm PLL div to divide by 2*/
|
||||
clock_set_div(kCLOCK_ArmDiv, 1);
|
||||
#ifdef CONFIG_INIT_ARM_PLL
|
||||
/* Reinit arm pll based on saved configuration */
|
||||
CLOCK_InitArmPll(&arm_pll_config);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_INIT_VIDEO_PLL
|
||||
/* Reinit video pll */
|
||||
CLOCK_InitVideoPll(&video_pll_config);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_INIT_ENET_PLL
|
||||
/* Reinit enet pll */
|
||||
CLOCK_InitEnetPll(&enet_pll_config);
|
||||
#endif
|
||||
/* Init SYS PLL */
|
||||
CLOCK_InitSysPll(&sys_pll_config);
|
||||
|
||||
/* Enable USB PLL PFD 1 2 3 */
|
||||
CLOCK_InitUsb1Pfd(kCLOCK_Pfd1, usb1_pll_pfd1_frac);
|
||||
CLOCK_InitUsb1Pfd(kCLOCK_Pfd2, usb1_pll_pfd2_frac);
|
||||
CLOCK_InitUsb1Pfd(kCLOCK_Pfd3, usb1_pll_pfd3_frac);
|
||||
|
||||
/* Enable SYS PLL PFD0 1 2 3 */
|
||||
CLOCK_InitSysPfd(kCLOCK_Pfd0, sys_pll_pfd0_frac);
|
||||
CLOCK_InitSysPfd(kCLOCK_Pfd1, sys_pll_pfd1_frac);
|
||||
CLOCK_InitSysPfd(kCLOCK_Pfd2, sys_pll_pfd2_frac);
|
||||
CLOCK_InitSysPfd(kCLOCK_Pfd3, sys_pll_pfd3_frac);
|
||||
|
||||
/* Switch to full speed clocks */
|
||||
#if (defined(XIP_EXTERNAL_FLASH) && (XIP_EXTERNAL_FLASH == 1))
|
||||
flexspi_enter_critical();
|
||||
#endif
|
||||
|
||||
/* Set Flexspi divider before increasing frequency of PLL3 PDF0. */
|
||||
#if CONFIG_CODE_FLEXSPI
|
||||
clock_set_div(kCLOCK_FlexspiDiv, flexspi_div);
|
||||
clock_set_mux(kCLOCK_FlexspiMux, 3);
|
||||
#elif CONFIG_CODE_FLEXSPI2
|
||||
clock_set_div(kCLOCK_Flexspi2Div, flexspi_div);
|
||||
clock_set_mux(kCLOCK_Flexspi2Mux, 1);
|
||||
#endif
|
||||
/* Init USB1 PLL. This will disable the PLL3 bypass. */
|
||||
clock_init_usb1_pll(&usb1_pll_config);
|
||||
|
||||
/* Switch SEMC clock to PLL2_PFD2 clock */
|
||||
clock_set_mux(kCLOCK_SemcMux, 1);
|
||||
|
||||
/* CORE CLK to 600MHz, AHB, IPG to 150MHz, PERCLK to 75MHz */
|
||||
clock_set_div(kCLOCK_PerclkDiv, 1);
|
||||
clock_set_div(kCLOCK_IpgDiv, 3);
|
||||
clock_set_div(kCLOCK_AhbDiv, 0);
|
||||
/* PERCLK mux to IPG CLK */
|
||||
clock_set_mux(kCLOCK_PerclkMux, 0);
|
||||
/* MUX to ENET_500M (RT1010-1024) / ARM_PODF (RT1050-1064) */
|
||||
clock_set_mux(kCLOCK_PrePeriphMux, 3);
|
||||
/* PERIPH mux to periph clock 2 output */
|
||||
clock_set_mux(kCLOCK_PeriphMux, 0);
|
||||
|
||||
#if (defined(XIP_EXTERNAL_FLASH) && (XIP_EXTERNAL_FLASH == 1))
|
||||
flexspi_exit_critical();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void clock_low_power(void)
|
||||
{
|
||||
#if (defined(XIP_EXTERNAL_FLASH) && (XIP_EXTERNAL_FLASH == 1))
|
||||
flexspi_enter_critical();
|
||||
#endif
|
||||
/* Switch to 24MHz core clock, so ARM PLL can power down */
|
||||
clock_set_div(kCLOCK_PeriphClk2Div, 0);
|
||||
/* Switch to OSC clock */
|
||||
clock_set_mux(kCLOCK_PeriphClk2Mux, 1);
|
||||
/* Switch peripheral mux to 24MHz source */
|
||||
clock_set_mux(kCLOCK_PeriphMux, 1);
|
||||
/* Set PLL3 to bypass mode, output 24M clock */
|
||||
CCM_ANALOG->PLL_USB1_SET = CCM_ANALOG_PLL_USB1_BYPASS_MASK;
|
||||
CCM_ANALOG->PLL_USB1_SET = CCM_ANALOG_PLL_USB1_ENABLE_MASK;
|
||||
CCM_ANALOG->PFD_480_CLR = CCM_ANALOG_PFD_480_PFD0_CLKGATE_MASK;
|
||||
/* Change flexspi to use PLL3 PFD0 with no divisor (24M flexspi clock) */
|
||||
#if CONFIG_CODE_FLEXSPI
|
||||
clock_set_div(kCLOCK_FlexspiDiv, 0);
|
||||
/* FLEXSPI1 mux to PLL3 PFD0 BYPASS */
|
||||
clock_set_mux(kCLOCK_FlexspiMux, 3);
|
||||
#elif CONFIG_CODE_FLEXSPI2
|
||||
clock_set_div(kCLOCK_Flexspi2Div, 0);
|
||||
/* FLEXSPI2 mux to PLL3 PFD0 BYPASS */
|
||||
clock_set_mux(kCLOCK_Flexspi2Mux, 1);
|
||||
#endif
|
||||
/* CORE CLK to 24MHz and AHB, IPG, PERCLK to 12MHz */
|
||||
clock_set_div(kCLOCK_PerclkDiv, 0);
|
||||
clock_set_div(kCLOCK_IpgDiv, 1);
|
||||
clock_set_div(kCLOCK_AhbDiv, 0);
|
||||
/* PERCLK mux to IPG CLK */
|
||||
clock_set_mux(kCLOCK_PerclkMux, 0);
|
||||
/* Switch SEMC clock to peripheral clock */
|
||||
clock_set_mux(kCLOCK_SemcMux, 0);
|
||||
#if (defined(XIP_EXTERNAL_FLASH) && (XIP_EXTERNAL_FLASH == 1))
|
||||
flexspi_exit_critical();
|
||||
#endif
|
||||
/* After switching clocks, it is safe to power down the PLLs */
|
||||
#ifdef CONFIG_INIT_ARM_PLL
|
||||
/* Deinit ARM PLL */
|
||||
CLOCK_DeinitArmPll();
|
||||
#endif
|
||||
/* Deinit SYS PLL */
|
||||
CLOCK_DeinitSysPll();
|
||||
|
||||
/* Deinit SYS PLL PFD 0 1 2 3 */
|
||||
CLOCK_DeinitSysPfd(kCLOCK_Pfd0);
|
||||
CLOCK_DeinitSysPfd(kCLOCK_Pfd1);
|
||||
CLOCK_DeinitSysPfd(kCLOCK_Pfd2);
|
||||
CLOCK_DeinitSysPfd(kCLOCK_Pfd3);
|
||||
|
||||
|
||||
/* Deinit USB1 PLL PFD 1 2 3 */
|
||||
CLOCK_DeinitUsb1Pfd(kCLOCK_Pfd1);
|
||||
CLOCK_DeinitUsb1Pfd(kCLOCK_Pfd2);
|
||||
CLOCK_DeinitUsb1Pfd(kCLOCK_Pfd3);
|
||||
|
||||
/* Deinit VIDEO PLL */
|
||||
CLOCK_DeinitVideoPll();
|
||||
|
||||
/* Deinit ENET PLL */
|
||||
CLOCK_DeinitEnetPll();
|
||||
}
|
||||
|
||||
void clock_lpm_init(void)
|
||||
{
|
||||
uint32_t tmp_reg = 0;
|
||||
|
||||
CLOCK_SetMode(kCLOCK_ModeRun);
|
||||
/* Enable RC OSC. It needs at least 4ms to be stable, so self tuning need to be enabled. */
|
||||
XTALOSC24M->LOWPWR_CTRL |= XTALOSC24M_LOWPWR_CTRL_RC_OSC_EN_MASK;
|
||||
/* Configure RC OSC */
|
||||
XTALOSC24M->OSC_CONFIG0 = XTALOSC24M_OSC_CONFIG0_RC_OSC_PROG_CUR(0x4) |
|
||||
XTALOSC24M_OSC_CONFIG0_SET_HYST_MINUS(0x2) |
|
||||
XTALOSC24M_OSC_CONFIG0_RC_OSC_PROG(0xA7) |
|
||||
XTALOSC24M_OSC_CONFIG0_START_MASK |
|
||||
XTALOSC24M_OSC_CONFIG0_ENABLE_MASK;
|
||||
XTALOSC24M->OSC_CONFIG1 = XTALOSC24M_OSC_CONFIG1_COUNT_RC_CUR(0x40) |
|
||||
XTALOSC24M_OSC_CONFIG1_COUNT_RC_TRG(0x2DC);
|
||||
/* Take some delay */
|
||||
SDK_DelayAtLeastUs(4000, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
|
||||
/* Add some hysteresis */
|
||||
tmp_reg = XTALOSC24M->OSC_CONFIG0;
|
||||
tmp_reg &= ~(XTALOSC24M_OSC_CONFIG0_HYST_PLUS_MASK |
|
||||
XTALOSC24M_OSC_CONFIG0_HYST_MINUS_MASK);
|
||||
tmp_reg |= XTALOSC24M_OSC_CONFIG0_HYST_PLUS(3) | XTALOSC24M_OSC_CONFIG0_HYST_MINUS(3);
|
||||
XTALOSC24M->OSC_CONFIG0 = tmp_reg;
|
||||
/* Set COUNT_1M_TRG */
|
||||
tmp_reg = XTALOSC24M->OSC_CONFIG2;
|
||||
tmp_reg &= ~XTALOSC24M_OSC_CONFIG2_COUNT_1M_TRG_MASK;
|
||||
tmp_reg |= XTALOSC24M_OSC_CONFIG2_COUNT_1M_TRG(0x2d7);
|
||||
XTALOSC24M->OSC_CONFIG2 = tmp_reg;
|
||||
/* Hardware requires to read OSC_CONFIG0 or OSC_CONFIG1 to make OSC_CONFIG2 write work */
|
||||
tmp_reg = XTALOSC24M->OSC_CONFIG1;
|
||||
XTALOSC24M->OSC_CONFIG1 = tmp_reg;
|
||||
}
|
||||
|
||||
static int imxrt_lpm_init(const struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
struct clock_callbacks callbacks;
|
||||
uint32_t usb1_pll_pfd0_frac;
|
||||
|
||||
callbacks.clock_set_run = clock_full_power;
|
||||
callbacks.clock_set_low_power = clock_low_power;
|
||||
callbacks.clock_lpm_init = clock_lpm_init;
|
||||
|
||||
/*
|
||||
* Read the boot time configuration of all PLLs.
|
||||
* This is required because not all PLLs preserve register state
|
||||
* when powered down. Additionally, populating these configuration
|
||||
* structures enables the rest of the code to use the fsl_clock HAL api.
|
||||
*/
|
||||
#ifdef CONFIG_INIT_ARM_PLL
|
||||
/* Read configuration values for arm pll */
|
||||
arm_pll_config.src = ((CCM_ANALOG->PLL_ARM &
|
||||
CCM_ANALOG_PLL_ARM_BYPASS_CLK_SRC_MASK) >>
|
||||
CCM_ANALOG_PLL_ARM_BYPASS_CLK_SRC_SHIFT);
|
||||
arm_pll_config.loopDivider = ((CCM_ANALOG->PLL_ARM &
|
||||
CCM_ANALOG_PLL_ARM_DIV_SELECT_MASK) >>
|
||||
CCM_ANALOG_PLL_ARM_DIV_SELECT_SHIFT);
|
||||
#endif
|
||||
/* Read configuration values for sys pll */
|
||||
sys_pll_config.src = ((CCM_ANALOG->PLL_SYS &
|
||||
CCM_ANALOG_PLL_SYS_BYPASS_CLK_SRC_MASK) >>
|
||||
CCM_ANALOG_PLL_SYS_BYPASS_CLK_SRC_SHIFT);
|
||||
sys_pll_config.loopDivider = ((CCM_ANALOG->PLL_SYS &
|
||||
CCM_ANALOG_PLL_SYS_DIV_SELECT_MASK) >>
|
||||
CCM_ANALOG_PLL_SYS_DIV_SELECT_SHIFT);
|
||||
sys_pll_config.numerator = CCM_ANALOG->PLL_SYS_NUM;
|
||||
sys_pll_config.denominator = CCM_ANALOG->PLL_SYS_DENOM;
|
||||
sys_pll_config.ss_step = ((CCM_ANALOG->PLL_SYS_SS &
|
||||
CCM_ANALOG_PLL_SYS_SS_STEP_MASK) >>
|
||||
CCM_ANALOG_PLL_SYS_SS_STEP_SHIFT);
|
||||
sys_pll_config.ss_enable = ((CCM_ANALOG->PLL_SYS_SS &
|
||||
CCM_ANALOG_PLL_SYS_SS_ENABLE_MASK) >>
|
||||
CCM_ANALOG_PLL_SYS_SS_ENABLE_SHIFT);
|
||||
sys_pll_config.ss_stop = ((CCM_ANALOG->PLL_SYS_SS &
|
||||
CCM_ANALOG_PLL_SYS_SS_STOP_MASK) >>
|
||||
CCM_ANALOG_PLL_SYS_SS_STOP_SHIFT);
|
||||
|
||||
/* Read configuration values for usb1 pll */
|
||||
usb1_pll_config.src = ((CCM_ANALOG->PLL_USB1 &
|
||||
CCM_ANALOG_PLL_USB1_BYPASS_CLK_SRC_MASK) >>
|
||||
CCM_ANALOG_PLL_USB1_BYPASS_CLK_SRC_SHIFT);
|
||||
usb1_pll_config.loopDivider = ((CCM_ANALOG->PLL_USB1 &
|
||||
CCM_ANALOG_PLL_USB1_DIV_SELECT_MASK) >>
|
||||
CCM_ANALOG_PLL_USB1_DIV_SELECT_SHIFT);
|
||||
#ifdef CONFIG_INIT_VIDEO_PLL
|
||||
/* Read configuration values for video pll */
|
||||
video_pll_config.src = ((CCM_ANALOG->PLL_VIDEO &
|
||||
CCM_ANALOG_PLL_VIDEO_BYPASS_CLK_SRC_MASK) >>
|
||||
CCM_ANALOG_PLL_VIDEO_BYPASS_CLK_SRC_SHIFT);
|
||||
video_pll_config.loopDivider = ((CCM_ANALOG->PLL_VIDEO &
|
||||
CCM_ANALOG_PLL_VIDEO_DIV_SELECT_MASK) >>
|
||||
CCM_ANALOG_PLL_VIDEO_DIV_SELECT_SHIFT);
|
||||
video_pll_config.numerator = CCM_ANALOG->PLL_VIDEO_NUM
|
||||
video_pll_config.denominator = CCM_ANALOG->PLL_VIDEO_DENOM;
|
||||
switch ((CCM_ANALOG->PLL_VIDEO &
|
||||
CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT_MASK) >>
|
||||
CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT_SHIFT) {
|
||||
case 0:
|
||||
video_pll_config.postDivider = 16;
|
||||
break;
|
||||
case 1:
|
||||
if (CCM_ANALOG->MISC2 & CCM_ANALOG_MISC2_VIDEO_DIV(3)) {
|
||||
video_pll_config.postDivider = 8;
|
||||
} else {
|
||||
video_pll_config.postDivider = 2;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (CCM_ANALOG->MISC2 & CCM_ANALOG_MISC2_VIDEO_DIV(3)) {
|
||||
video_pll_config.postDivider = 4
|
||||
} else {
|
||||
video_pll_config.postDivider = 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
video_pll_config.postDivider = 1;
|
||||
}
|
||||
#endif
|
||||
#if CONFIG_INIT_ENET_PLL
|
||||
enet_pll_config.src = ((CCM_ANALOG->PLL_ENET &
|
||||
CCM_ANALOG_PLL_ENET_BYPASS_CLK_SRC_MASK) >>
|
||||
CCM_ANALOG_PLL_ENET_BYPASS_CLK_SRC_SHIFT);
|
||||
enet_pll_config.loopDivider = ((CCM_ANALOG->PLL_ENET &
|
||||
CCM_ANALOG_PLL_ENET_DIV_SELECT_MASK) >>
|
||||
CCM_ANALOG_PLL_ENET_DIV_SELECT_SHIFT);
|
||||
enet_pll_config.loopDivider1 = ((CCM_ANALOG->PLL_ENET &
|
||||
CCM_ANALOG_PLL_ENET_ENET2_DIV_SELECT_MASK) >>
|
||||
CCM_ANALOG_PLL_ENET_ENET2_DIV_SELECT_SHIFT);
|
||||
enet_pll_config.enableClkOutput = (CCM_ANALOG->PLL_ENET &
|
||||
CCM_ANALOG_PLL_ENET_ENABLE_MASK);
|
||||
enet_pll_config.enableClkOutput1 = (CCM_ANALOG->PLL_ENET &
|
||||
CCM_ANALOG_PLL_ENET_ENET2_REF_EN_MASK);
|
||||
enet_pll_config.enableClkOutput25M = (CCM_ANALOG->PLL_ENET &
|
||||
CCM_ANALOG_PLL_ENET_ENET_25M_REF_EN_MASK);
|
||||
#endif
|
||||
|
||||
/* Record all pll PFD values that we intend to disable in low power mode */
|
||||
sys_pll_pfd0_frac = IMX_RT_SYS_PFD_FRAC(CCM_ANALOG->PFD_528, kCLOCK_Pfd0);
|
||||
sys_pll_pfd1_frac = IMX_RT_SYS_PFD_FRAC(CCM_ANALOG->PFD_528, kCLOCK_Pfd1);
|
||||
sys_pll_pfd2_frac = IMX_RT_SYS_PFD_FRAC(CCM_ANALOG->PFD_528, kCLOCK_Pfd2);
|
||||
sys_pll_pfd3_frac = IMX_RT_SYS_PFD_FRAC(CCM_ANALOG->PFD_528, kCLOCK_Pfd3);
|
||||
|
||||
usb1_pll_pfd0_frac = IMX_RT_USB1_PFD_FRAC(CCM_ANALOG->PFD_480, kCLOCK_Pfd0);
|
||||
/* The target full power frequency for the flexspi clock is ~100MHz.
|
||||
* Use the PFD0 value currently set to calculate the div we should use for
|
||||
* the full power flexspi div
|
||||
* PFD output frequency formula = (480 * 18) / pfd0_frac
|
||||
* flexspi div formula = FLOOR((480*18) / (pfd0_frac * target_full_power_freq))
|
||||
*/
|
||||
flexspi_div = (480 * 18) / (usb1_pll_pfd0_frac * 100);
|
||||
|
||||
|
||||
usb1_pll_pfd1_frac = IMX_RT_USB1_PFD_FRAC(CCM_ANALOG->PFD_480, kCLOCK_Pfd1);
|
||||
usb1_pll_pfd2_frac = IMX_RT_USB1_PFD_FRAC(CCM_ANALOG->PFD_480, kCLOCK_Pfd2);
|
||||
usb1_pll_pfd3_frac = IMX_RT_USB1_PFD_FRAC(CCM_ANALOG->PFD_480, kCLOCK_Pfd3);
|
||||
|
||||
/* Install LPM callbacks */
|
||||
imxrt_clock_pm_callbacks_register(&callbacks);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
SYS_INIT(imxrt_lpm_init, PRE_KERNEL_1, 0);
|
Loading…
Add table
Add a link
Reference in a new issue