1 /*
2 * Copyright (c) 2018, Christian Taedcke
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /**
8 * @file
9 * @brief Common SoC initialization for the Silabs products
10 */
11
12 #include <zephyr/init.h>
13 #include <zephyr/kernel.h>
14 #include <zephyr/logging/log.h>
15
16 #include <em_chip.h>
17 #include <em_cmu.h>
18 #include <em_emu.h>
19 #include <soc.h>
20 #include <cmsis_core.h>
21
22 LOG_MODULE_REGISTER(soc, CONFIG_SOC_LOG_LEVEL);
23
24 #ifdef CONFIG_CMU_HFCLK_HFXO
25 /**
26 * @brief Initialization parameters for the external high frequency oscillator
27 */
28 static CMU_HFXOInit_TypeDef hfxoInit = CMU_HFXOINIT_DEFAULT;
29 #endif
30
31 #ifdef CONFIG_CMU_NEED_LFXO
32 /**
33 * @brief Initialization parameters for the external low frequency oscillator
34 */
35 static CMU_LFXOInit_TypeDef lfxoInit = CMU_LFXOINIT_DEFAULT;
36
init_lfxo(void)37 static void init_lfxo(void)
38 {
39 /*
40 * Configuring LFXO disables it, so we can do that only if it's not
41 * used as a SYSCLK/HFCLK source.
42 */
43 #if defined(_SILICON_LABS_32B_SERIES_2)
44 if (CMU_ClockSelectGet(cmuClock_SYSCLK) != cmuSelect_LFXO) {
45 /*
46 * Check if device has LFXO configuration info in DEVINFO
47 * See AN0016.2
48 */
49 if ((DEVINFO->MODULEINFO & DEVINFO_MODULEINFO_LFXOCALVAL) ==
50 DEVINFO_MODULEINFO_LFXOCALVAL_VALID) {
51 lfxoInit.capTune =
52 (DEVINFO->MODXOCAL & _DEVINFO_MODXOCAL_LFXOCAPTUNE_MASK) >>
53 _DEVINFO_MODXOCAL_LFXOCAPTUNE_SHIFT;
54 }
55 CMU_LFXOInit(&lfxoInit);
56 }
57 #else
58 if (CMU_ClockSelectGet(cmuClock_HF) != cmuSelect_LFXO) {
59 CMU_LFXOInit(&lfxoInit);
60 CMU_OscillatorEnable(cmuOsc_LFXO, true, true);
61 }
62 #endif /* _SILICON_LABS_32B_SERIES_2 */
63 SystemLFXOClockSet(CONFIG_CMU_LFXO_FREQ);
64 }
65
66 #endif /* CONFIG_CMU_NEED_LFXO */
67
68 /**
69 * @brief Initialize the system clock
70 */
clock_init(void)71 static ALWAYS_INLINE void clock_init(void)
72 {
73 #ifdef CONFIG_CMU_HFCLK_HFXO
74 #if defined(_SILICON_LABS_32B_SERIES_2)
75 if (CMU_ClockSelectGet(cmuClock_SYSCLK) != cmuSelect_HFXO) {
76 /*
77 * Check if device has HFXO configuration info in DEVINFO
78 * See AN0016.2
79 */
80 if ((DEVINFO->MODULEINFO & DEVINFO_MODULEINFO_HFXOCALVAL) ==
81 DEVINFO_MODULEINFO_HFXOCALVAL_VALID) {
82 hfxoInit.ctuneXoAna =
83 (DEVINFO->MODXOCAL & _DEVINFO_MODXOCAL_HFXOCTUNEXOANA_MASK) >>
84 _DEVINFO_MODXOCAL_HFXOCTUNEXOANA_SHIFT;
85 hfxoInit.ctuneXiAna =
86 (DEVINFO->MODXOCAL & _DEVINFO_MODXOCAL_HFXOCTUNEXIANA_MASK) >>
87 _DEVINFO_MODXOCAL_HFXOCTUNEXIANA_SHIFT;
88 }
89
90 CMU_HFXOInit(&hfxoInit);
91 CMU_ClockSelectSet(cmuClock_SYSCLK, cmuSelect_HFXO);
92 }
93
94 SystemHFXOClockSet(CONFIG_CMU_HFXO_FREQ);
95 #else
96 if (CMU_ClockSelectGet(cmuClock_HF) != cmuSelect_HFXO) {
97 CMU_HFXOInit(&hfxoInit);
98 CMU_OscillatorEnable(cmuOsc_HFXO, true, true);
99 CMU_ClockSelectSet(cmuClock_HF, cmuSelect_HFXO);
100 }
101 SystemHFXOClockSet(CONFIG_CMU_HFXO_FREQ);
102 CMU_OscillatorEnable(cmuOsc_HFRCO, false, false);
103 #endif /* _SILICON_LABS_32B_SERIES_2 */
104 #elif (defined CONFIG_CMU_HFCLK_LFXO)
105 /* LFXO should've been already brought up by init_lfxo() */
106 #if defined(_SILICON_LABS_32B_SERIES_2)
107 CMU_ClockSelectSet(cmuClock_SYSCLK, cmuSelect_LFXO);
108 #else
109 CMU_ClockSelectSet(cmuClock_HF, cmuSelect_LFXO);
110 CMU_OscillatorEnable(cmuOsc_HFRCO, false, false);
111 #endif /* _SILICON_LABS_32B_SERIES_2 */
112 #elif (defined CONFIG_CMU_HFCLK_HFRCO)
113 /*
114 * This is the default clock, the controller starts with
115 */
116
117 #ifdef CONFIG_SOC_GECKO_HAS_HFRCO_FREQRANGE
118 if (CONFIG_CMU_HFRCO_FREQ) {
119 /* Setting system HFRCO frequency */
120 CMU_HFRCOBandSet(CONFIG_CMU_HFRCO_FREQ);
121
122 /* Using HFRCO as high frequency clock, HFCLK */
123 CMU_ClockSelectSet(cmuClock_HF, cmuSelect_HFRCO);
124 }
125 #endif
126 #else
127 #error "Unsupported clock source for HFCLK selected"
128 #endif
129
130 #if defined(_SILICON_LABS_32B_SERIES_2)
131 /* Enable the High Frequency Peripheral Clock */
132 CMU_ClockEnable(cmuClock_PCLK, true);
133 #else
134 /* Enable the High Frequency Peripheral Clock */
135 CMU_ClockEnable(cmuClock_HFPER, true);
136 #endif /* _SILICON_LABS_32B_SERIES_2 */
137
138 #if defined(CONFIG_GPIO_GECKO) || defined(CONFIG_LOG_BACKEND_SWO)
139 CMU_ClockEnable(cmuClock_GPIO, true);
140 #endif
141 }
142
143 #ifdef CONFIG_SOC_GECKO_EMU_DCDC
dcdc_init(void)144 static ALWAYS_INLINE void dcdc_init(void)
145 {
146 #if defined(CONFIG_SOC_GECKO_EMU_DCDC_MODE_UNCONFIGURED)
147 /* Nothing to do, leave DC/DC converter in unconfigured, safe state. */
148 #elif defined(CONFIG_SOC_GECKO_EMU_DCDC_MODE_ON) || defined(CONFIG_SOC_GECKO_EMU_DCDC_MODE_BYPASS)
149 EMU_DCDCInit_TypeDef init_cfg = EMU_DCDCINIT_DEFAULT;
150 #if defined(CONFIG_SOC_GECKO_EMU_DCDC_MODE_BYPASS)
151 init_cfg.dcdcMode = emuDcdcMode_Bypass;
152 #endif
153 EMU_DCDCInit(&init_cfg);
154 #elif defined(CONFIG_SOC_GECKO_EMU_DCDC_MODE_OFF)
155 EMU_DCDCPowerOff();
156 #else
157 #error "Unsupported power configuration mode of the on chip DC/DC converter."
158 #endif
159 }
160 #endif
161
162 #ifdef CONFIG_LOG_BACKEND_SWO
swo_init(void)163 static void swo_init(void)
164 {
165 struct soc_gpio_pin pin_swo = PIN_SWO;
166
167 #if defined(_SILICON_LABS_32B_SERIES_2)
168 GPIO->TRACEROUTEPEN = GPIO_TRACEROUTEPEN_SWVPEN;
169 #else
170 /* Select HFCLK as the debug trace clock */
171 CMU->DBGCLKSEL = CMU_DBGCLKSEL_DBG_HFCLK;
172
173 #if defined(_GPIO_ROUTEPEN_MASK)
174 /* Enable Serial wire output pin */
175 GPIO->ROUTEPEN |= GPIO_ROUTEPEN_SWVPEN;
176 /* Set SWO location */
177 GPIO->ROUTELOC0 = SWO_LOCATION << _GPIO_ROUTELOC0_SWVLOC_SHIFT;
178 #else
179 GPIO->ROUTE = GPIO_ROUTE_SWOPEN | (SWO_LOCATION << 8);
180 #endif
181 #endif /* _SILICON_LABS_32B_SERIES_2 */
182
183 GPIO_PinModeSet(pin_swo.port, pin_swo.pin, pin_swo.mode, pin_swo.out);
184 }
185 #endif /* CONFIG_LOG_BACKEND_SWO */
186
187 /**
188 * @brief Perform basic hardware initialization
189 *
190 * Initialize the interrupt controller device drivers.
191 * Also initialize the timer device driver, if required.
192 *
193 * @return 0
194 */
soc_early_init_hook(void)195 void soc_early_init_hook(void)
196 {
197 /* handle chip errata */
198 CHIP_Init();
199
200 #ifdef CONFIG_CMU_NEED_LFXO
201 init_lfxo();
202 #endif
203
204 #ifdef CONFIG_SOC_GECKO_EMU_DCDC
205 dcdc_init();
206 #endif
207
208 /* Initialize system clock according to CONFIG_CMU settings */
209 clock_init();
210
211 #ifdef CONFIG_LOG_BACKEND_SWO
212 /* Configure SWO debug output */
213 swo_init();
214 #endif
215 }
216