blob: e17d6a91d16ed15d31b4145431162642d31b994b [file] [log] [blame]
/*
* Copyright 2023 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/arch/cpu.h>
#include <zephyr/device.h>
#include <zephyr/init.h>
#include <zephyr/kernel.h>
#include <zephyr/linker/sections.h>
#include <soc.h>
#include <fsl_ccm32k.h>
#include <fsl_common.h>
#include <fsl_clock.h>
extern uint32_t SystemCoreClock;
static ALWAYS_INLINE void clock_init(void)
{
/* Unlock Reference Clock Status Registers to allow writes */
CLOCK_UnlockFircControlStatusReg();
CLOCK_UnlockSircControlStatusReg();
CLOCK_UnlockRoscControlStatusReg();
CLOCK_UnlockSysOscControlStatusReg();
/*
* Configuration for the 32 kHz Oscillator module
* Internal capatitor bank is required in order to use the more stable OSC32K source
*/
ccm32k_osc_config_t ccm32k_osc_config = {
.coarseAdjustment = kCCM32K_OscCoarseAdjustmentRange0, /* ESR_Range0 */
.enableInternalCapBank = true, /* Internal capacitance bank is enabled */
.xtalCap = kCCM32K_OscXtal8pFCap, /* 8 pF */
.extalCap = kCCM32K_OscExtal8pFCap, /* 8 pF */
};
/* Enable OSC32K */
CCM32K_Set32kOscConfig(CCM32K, kCCM32K_Enable32kHzCrystalOsc, &ccm32k_osc_config);
/* Disable ROSC Monitor, because switching the source would generate an expected error */
CLOCK_SetRoscMonitorMode(kSCG_RoscMonitorDisable);
/* Select the Real Time Clock (RTC) source as OSC32K */
CCM32K_SelectClockSource(CCM32K, kCCM32K_ClockSourceSelectOsc32k);
/* Wait for RTC Oscillator to be Valid */
while (!CLOCK_IsRoscValid())
;
/* Re-enable monitor */
CLOCK_SetRoscMonitorMode(kSCG_RoscMonitorInt);
/* Disable the FRO32K to save power */
CCM32K_Enable32kFro(CCM32K, false);
/* Configuration to set FIRC to maximum frequency */
scg_firc_config_t scg_firc_config = {
.enableMode = kSCG_FircEnable, /* Fast IRC is enabled */
.range = kSCG_FircRange96M, /* 96 Mhz FIRC clock selected */
.trimConfig = NULL,
};
scg_sys_clk_config_t sys_clk_safe_config_source = {
.divSlow = (uint32_t)kSCG_SysClkDivBy4,
.divCore = (uint32_t)kSCG_SysClkDivBy1,
.src = (uint32_t)kSCG_SysClkSrcSirc,
};
CLOCK_SetRunModeSysClkConfig(&sys_clk_safe_config_source);
scg_sys_clk_config_t cur_config;
do {
CLOCK_GetCurSysClkConfig(&cur_config);
} while (cur_config.src != sys_clk_safe_config_source.src);
(void)CLOCK_InitFirc(&scg_firc_config);
scg_sys_clk_config_t sys_clk_config = {
.divSlow = (uint32_t)kSCG_SysClkDivBy4, /* Slow Clock Divider: divided by 4 */
.divBus = (uint32_t)kSCG_SysClkDivBy1, /* Bus Clock Divider: divided by 1 */
.divCore = (uint32_t)kSCG_SysClkDivBy1, /* Core Clock Divider: divided by 1 */
.src = (uint32_t)kSCG_SysClkSrcFirc, /* Select Fast IRC as System Clock */
};
CLOCK_SetRunModeSysClkConfig(&sys_clk_config);
/* Wait for clock source switch to finish */
do {
CLOCK_GetCurSysClkConfig(&cur_config);
} while (cur_config.src != sys_clk_config.src);
SystemCoreClock = 96000000U;
/* OSC-RF / System Oscillator Configuration */
scg_sosc_config_t sosc_config = {
.freq = 32000U,
.monitorMode = kSCG_SysOscMonitorDisable,
.enableMode = kSCG_SoscEnable,
};
/* Init OSC-RF / SOSC */
(void)CLOCK_InitSysOsc(&sosc_config);
CLOCK_SetXtal0Freq(sosc_config.freq);
/* Slow internal reference clock (SIRC) configuration */
scg_sirc_config_t sirc_config = {
.enableMode = kSCG_SircDisableInSleep,
};
/* Init SIRC */
(void)CLOCK_InitSirc(&sirc_config);
/* Attach Clocks */
CLOCK_SetIpSrc(kCLOCK_Lpuart0, kCLOCK_IpSrcFro192M);
CLOCK_SetIpSrc(kCLOCK_Lpuart1, kCLOCK_IpSrcFro192M);
CLOCK_SetIpSrc(kCLOCK_Lpspi0, kCLOCK_IpSrcFro192M);
CLOCK_SetIpSrc(kCLOCK_Lpspi1, kCLOCK_IpSrcFro192M);
CLOCK_SetIpSrc(kCLOCK_Can0, kCLOCK_IpSrcFro192M);
CLOCK_SetIpSrc(kCLOCK_Tpm0, kCLOCK_IpSrcFro192M);
CLOCK_SetIpSrc(kCLOCK_Tpm1, kCLOCK_IpSrcFro192M);
CLOCK_SetIpSrc(kCLOCK_Lpi2c0, kCLOCK_IpSrcFro192M);
CLOCK_SetIpSrcDiv(kCLOCK_Lpi2c0, kSCG_SysClkDivBy16);
CLOCK_SetIpSrc(kCLOCK_Lpi2c1, kCLOCK_IpSrcFro192M);
CLOCK_SetIpSrcDiv(kCLOCK_Lpi2c1, kSCG_SysClkDivBy16);
CLOCK_SetIpSrc(kCLOCK_Lpspi0, kCLOCK_IpSrcFro192M);
CLOCK_SetIpSrc(kCLOCK_Lpspi1, kCLOCK_IpSrcFro192M);
CLOCK_SetIpSrc(kCLOCK_Lpadc0, kCLOCK_IpSrcFro192M);
CLOCK_SetIpSrcDiv(kCLOCK_Lpadc0, kSCG_SysClkDivBy10);
/* Ungate clocks if the peripheral is enabled in devicetree */
if (DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(lpuart0), nxp_lpc_lpuart, okay)) {
CLOCK_EnableClock(kCLOCK_Lpuart0);
}
if (DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(lpuart1), nxp_lpc_lpuart, okay)) {
CLOCK_EnableClock(kCLOCK_Lpuart1);
}
if (DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(tpm0), nxp_kinetis_tpm, okay)) {
CLOCK_EnableClock(kCLOCK_Tpm0);
}
if (DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(tpm1), nxp_kinetis_tpm, okay)) {
CLOCK_EnableClock(kCLOCK_Tpm1);
}
if (DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(lpi2c0), nxp_imx_lpi2c, okay)) {
CLOCK_EnableClock(kCLOCK_Lpi2c0);
}
if (DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(lpi2c1), nxp_imx_lpi2c, okay)) {
CLOCK_EnableClock(kCLOCK_Lpi2c1);
}
if (DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(lpspi0), nxp_imx_lpspi, okay)) {
CLOCK_EnableClock(kCLOCK_Lpspi0);
}
if (DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(lpspi1), nxp_imx_lpspi, okay)) {
CLOCK_EnableClock(kCLOCK_Lpspi1);
}
if (IS_ENABLED(CONFIG_CAN_MCUX_FLEXCAN)) {
CLOCK_EnableClock(kCLOCK_Can0);
}
if (DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(vref), nxp_vref, okay)) {
CLOCK_EnableClock(kCLOCK_Vref0);
}
if (DT_NODE_HAS_COMPAT_STATUS(adc0, nxp_lpadc, okay)) {
CLOCK_EnableClock(kCLOCK_Lpadc0);
}
}
static void vbat_init(void)
{
VBAT_Type *base = (VBAT_Type *)DT_REG_ADDR(DT_NODELABEL(vbat));
/* Write 1 to Clear POR detect status bit.
*
* Clearing this bit is acknowledement
* that software has recognized a power on reset.
*
* This avoids also niche issues with NVIC read/write
* when searching for available interrupt lines.
*/
base->STATUSA |= VBAT_STATUSA_POR_DET_MASK;
};
void soc_early_init_hook(void)
{
unsigned int oldLevel; /* old interrupt lock level */
/* disable interrupts */
oldLevel = irq_lock();
/* Initialize system clock to 96 MHz */
clock_init();
/* Smart power switch initialization */
vbat_init();
/* restore interrupt state */
irq_unlock(oldLevel);
}