1 /*
2  * Copyright 2024 NXP
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/device.h>
9 #include <zephyr/init.h>
10 #include <soc.h>
11 #include <fsl_common.h>
12 #include <fsl_clock.h>
13 #include <zephyr/arch/cpu.h>
14 
15 /*******************************************************************************
16  * Definitions
17  ******************************************************************************/
18 #define IRC48M_CLK_FREQ (48000000UL)
19 
20 #define MCG_NODE DT_NODELABEL(mcg)
21 #define OSC_NODE DT_NODELABEL(osc)
22 
23 #define SIM_MODULE_CLK_SEL_DISABLED     0U /*!< Module clock select: Disabled */
24 #define SIM_MODULE_CLK_SEL_IRC48M_CLK   1U /*!< Module clock select: IRC48M clock */
25 #define SIM_MODULE_CLK_SEL_OSCERCLK_CLK 2U /*!< Module clock select: OSCERCLK clock */
26 #define SIM_MODULE_CLK_SEL_MCGIRCLK_CLK 3U /*!< Module clock select: MCGIRCLK clock */
27 
28 #define CLOCK_NODEID(clk) DT_CHILD(DT_INST(0, nxp_kinetis_sim), clk)
29 
30 #define CLOCK_DIVIDER(clk) DT_PROP_OR(CLOCK_NODEID(clk), clock_div, 1) - 1
31 
32 #define LPUART_CLOCK_SEL(label) \
33 	(DT_PHA(DT_NODELABEL(label), clocks, name) == kCLOCK_McgIrc48MClk \
34 		 ? SIM_MODULE_CLK_SEL_IRC48M_CLK                                                   \
35 	 : DT_PHA(DT_NODELABEL(label), clocks, name) == kCLOCK_Osc0ErClk \
36 		 ? SIM_MODULE_CLK_SEL_OSCERCLK_CLK                                                 \
37 	 : DT_PHA(DT_NODELABEL(label), clocks, name) == kCLOCK_McgInternalRefClk \
38 		 ? SIM_MODULE_CLK_SEL_MCGIRCLK_CLK                                                 \
39 		 : SIM_MODULE_CLK_SEL_DISABLED)
40 
41 #define TPM_CLOCK_SEL(node_id)                                                                     \
42 	(DT_PHA(node_id, clocks, name) == kCLOCK_McgIrc48MClk ? SIM_MODULE_CLK_SEL_IRC48M_CLK      \
43 	 : DT_PHA(node_id, clocks, name) == kCLOCK_Osc0ErClk  ? SIM_MODULE_CLK_SEL_OSCERCLK_CLK    \
44 	 : DT_PHA(node_id, clocks, name) == kCLOCK_McgInternalRefClk                               \
45 		 ? SIM_MODULE_CLK_SEL_MCGIRCLK_CLK                                                 \
46 		 : SIM_MODULE_CLK_SEL_DISABLED)
47 
48 /*******************************************************************************
49  * Variables
50  ******************************************************************************/
51 
52 const mcglite_config_t mcgliteConfig_BOARD_BootClockRUN = {
53 	.outSrc = kMCGLITE_ClkSrcHirc, /* MCGOUTCLK source is HIRC */
54 	.irclkEnableMode = kMCGLITE_IrclkEnable, /* MCGIRCLK enabled */
55 	.ircs = kMCGLITE_Lirc8M, /* Slow internal reference (LIRC) 8 MHz clock */
56 	/* Low-frequency Reference Clock Divider */
57 	.fcrdiv = DT_PROP_OR(MCG_NODE, fcrdiv, 0),
58 	/* Second Low-frequency Reference Clock Divider */
59 	.lircDiv2 = DT_PROP_OR(MCG_NODE, lircdiv2, 0),
60 	.hircEnableInNotHircMode = true, /* HIRC source is enabled */
61 };
62 
63 const sim_clock_config_t simConfig_BOARD_BootClockRUN = {
64 	.er32kSrc = DT_PROP(DT_INST(0, nxp_kinetis_sim), er32k_select),
65 	.clkdiv1 = SIM_CLKDIV1_OUTDIV1(CLOCK_DIVIDER(core_clk)) |
66 		   SIM_CLKDIV1_OUTDIV4(CLOCK_DIVIDER(flash_clk)),
67 };
68 
69 const osc_config_t oscConfig_BOARD_BootClockRUN = {
70 	.freq = DT_PROP(OSC_NODE, clock_frequency),
71 	.capLoad = 0,
72 #if DT_ENUM_HAS_VALUE(OSC_NODE, mode, external)
73 	.workMode = kOSC_ModeExt,
74 #elif DT_ENUM_HAS_VALUE(OSC_NODE, mode, low_power)
75 	.workMode = kOSC_ModeOscLowPower,
76 #elif DT_ENUM_HAS_VALUE(OSC_NODE, mode, high_gain)
77 	.workMode = kOSC_ModeOscHighGain,
78 #else
79 	#error "An oscillator mode must be defined"
80 #endif
81 	.oscerConfig = {
82 		.enableMode = kOSC_ErClkEnable,
83 	}
84 };
85 
clock_init(void)86 static void clock_init(void)
87 {
88 	/* Set the system clock dividers in SIM to safe value. */
89 	CLOCK_SetSimSafeDivs();
90 	/* Initializes OSC0 according to board configuration. */
91 	CLOCK_InitOsc0(&oscConfig_BOARD_BootClockRUN);
92 	CLOCK_SetXtal0Freq(oscConfig_BOARD_BootClockRUN.freq);
93 	/* Set MCG to HIRC mode. */
94 	CLOCK_SetMcgliteConfig(&mcgliteConfig_BOARD_BootClockRUN);
95 	/* Set the clock configuration in SIM module. */
96 	CLOCK_SetSimConfig(&simConfig_BOARD_BootClockRUN);
97 	/* Set SystemCoreClock variable. */
98 	SystemCoreClock = DT_PROP(DT_NODELABEL(cpu0), clock_frequency);
99 	/* Set LPUART0 clock source. */
100 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpuart0))
101 	CLOCK_SetLpuart0Clock(LPUART_CLOCK_SEL(lpuart0));
102 #endif
103 #if DT_HAS_COMPAT_STATUS_OKAY(nxp_kinetis_tpm)
104 	/* All TPM instances share common clock source for counter clock.
105 	 * Select the clock source using an arbitrary enabled TPM node.
106 	 * All TPM nodes should use the same clock source in device tree.
107 	 */
108 	CLOCK_SetTpmClock(TPM_CLOCK_SEL(DT_COMPAT_GET_ANY_STATUS_OKAY(nxp_kinetis_tpm)));
109 #endif
110 #if CONFIG_USB_KINETIS || CONFIG_UDC_KINETIS
111 	CLOCK_EnableUsbfs0Clock(kCLOCK_UsbSrcIrc48M, IRC48M_CLK_FREQ);
112 #endif
113 }
114 
soc_early_init_hook(void)115 void soc_early_init_hook(void)
116 {
117 #ifdef CONFIG_TEMP_KINETIS
118 	/* enable bandgap buffer */
119 	PMC->REGSC |= PMC_REGSC_BGBE_MASK;
120 #endif /* CONFIG_TEMP_KINETIS */
121 
122 	clock_init();
123 }
124 
125 #ifdef CONFIG_SOC_RESET_HOOK
126 
soc_reset_hook(void)127 void soc_reset_hook(void)
128 {
129 	SystemInit();
130 }
131 
132 #endif /* CONFIG_SOC_RESET_HOOK */
133