1 /***************************************************************************//**
2 * @file
3 * @brief CMSIS Cortex-M33 system support for EFR32MG21 devices.
4 ******************************************************************************
5 * # License
6 * <b>Copyright 2024 Silicon Laboratories, Inc. www.silabs.com</b>
7 ******************************************************************************
8 *
9 * SPDX-License-Identifier: Zlib
10 *
11 * The licensor of this software is Silicon Laboratories Inc.
12 *
13 * This software is provided 'as-is', without any express or implied
14 * warranty. In no event will the authors be held liable for any damages
15 * arising from the use of this software.
16 *
17 * Permission is granted to anyone to use this software for any purpose,
18 * including commercial applications, and to alter it and redistribute it
19 * freely, subject to the following restrictions:
20 *
21 * 1. The origin of this software must not be misrepresented; you must not
22 * claim that you wrote the original software. If you use this software
23 * in a product, an acknowledgment in the product documentation would be
24 * appreciated but is not required.
25 * 2. Altered source versions must be plainly marked as such, and must not be
26 * misrepresented as being the original software.
27 * 3. This notice may not be removed or altered from any source distribution.
28 *
29 *****************************************************************************/
30
31 #include <stdint.h>
32 #include "em_device.h"
33
34 #if defined(SL_COMPONENT_CATALOG_PRESENT)
35 #include "sl_component_catalog.h"
36
37 #endif
38 #if defined(SL_CATALOG_CLOCK_MANAGER_PRESENT)
39 #include "sl_clock_manager_oscillator_config.h"
40
41 #endif
42
43 /*******************************************************************************
44 ****************************** DEFINES ************************************
45 ******************************************************************************/
46
47 // System oscillator frequencies. These frequencies are normally constant
48 // for a target, but they are made configurable in order to allow run-time
49 // handling of different boards. The crystal oscillator clocks can be set
50 // compile time to a non-default value by defining respective nFXO_FREQ
51 // values according to board design. By defining the nFXO_FREQ to 0,
52 // one indicates that the oscillator is not present, in order to save some
53 // SW footprint.
54
55 #if !defined(FSRCO_FREQ)
56 // FSRCO frequency
57 #define FSRCO_FREQ (20000000UL)
58 #endif
59
60 #if !defined(HFXO_FREQ)
61 // HFXO frequency
62 #define HFXO_FREQ (38400000UL)
63 #endif
64
65 #if !defined(HFRCODPLL_STARTUP_FREQ)
66 // HFRCODPLL startup frequency
67 #define HFRCODPLL_STARTUP_FREQ (19000000UL)
68 #endif
69
70 #if !defined(HFRCODPLL_MAX_FREQ)
71 // Maximum HFRCODPLL frequency
72 #define HFRCODPLL_MAX_FREQ (80000000UL)
73 #endif
74
75 // CLKIN0 input
76 #if defined(SL_CLOCK_MANAGER_CLKIN0_FREQ)
77 // Clock Manager takes control of this define when present.
78 #define CLKIN0_FREQ (SL_CLOCK_MANAGER_CLKIN0_FREQ)
79 #elif !defined(CLKIN0_FREQ)
80 #define CLKIN0_FREQ (0UL)
81 #endif
82
83 #if !defined(LFRCO_MAX_FREQ)
84 // LFRCO frequency, tuned to below frequency during manufacturing.
85 #define LFRCO_FREQ (32768UL)
86 #endif
87
88 #if !defined(ULFRCO_FREQ)
89 // ULFRCO frequency
90 #define ULFRCO_FREQ (1000UL)
91 #endif
92
93 #if !defined(LFXO_FREQ)
94 // LFXO frequency
95 #define LFXO_FREQ (LFRCO_FREQ)
96 #endif
97
98 /*******************************************************************************
99 ************************** LOCAL VARIABLES ********************************
100 ******************************************************************************/
101
102 #if (HFXO_FREQ > 0) && !defined(SYSTEM_NO_STATIC_MEMORY)
103 // NOTE: Gecko bootloaders can't have static variable allocation.
104 // System HFXO clock frequency
105 static uint32_t SystemHFXOClock = HFXO_FREQ;
106 #endif
107
108 #if (LFXO_FREQ > 0) && !defined(SYSTEM_NO_STATIC_MEMORY)
109 // System LFXO clock frequency
110 static uint32_t SystemLFXOClock = LFXO_FREQ;
111 #endif
112
113 #if !defined(SYSTEM_NO_STATIC_MEMORY)
114 // System HFRCODPLL clock frequency
115 static uint32_t SystemHFRCODPLLClock = HFRCODPLL_STARTUP_FREQ;
116 #endif
117
118 /*******************************************************************************
119 ************************** GLOBAL VARIABLES *******************************
120 ******************************************************************************/
121
122 #if !defined(SYSTEM_NO_STATIC_MEMORY)
123
124 /**
125 * @brief
126 * System System Clock Frequency (Core Clock).
127 *
128 * @details
129 * Required CMSIS global variable that must be kept up-to-date.
130 */
131 uint32_t SystemCoreClock = HFRCODPLL_STARTUP_FREQ;
132
133 #endif
134
135 /*---------------------------------------------------------------------------
136 * Exception / Interrupt Vector table
137 *---------------------------------------------------------------------------*/
138 extern const tVectorEntry __VECTOR_TABLE[16 + EXT_IRQ_COUNT];
139
140 /*******************************************************************************
141 ************************** GLOBAL FUNCTIONS *******************************
142 ******************************************************************************/
143
144 /**************************************************************************//**
145 * @brief
146 * Initialize the system.
147 *
148 * @details
149 * Do required generic HW system init.
150 *
151 * @note
152 * This function is invoked during system init, before the main() routine
153 * and any data has been initialized. For this reason, it cannot do any
154 * initialization of variables etc.
155 *****************************************************************************/
SystemInit(void)156 void SystemInit(void)
157 {
158 #if defined (__VTOR_PRESENT) && (__VTOR_PRESENT == 1U)
159 SCB->VTOR = (uint32_t) (&__VECTOR_TABLE[0]);
160 #endif
161
162 #if defined(UNALIGNED_SUPPORT_DISABLE)
163 SCB->CCR |= SCB_CCR_UNALIGN_TRP_Msk;
164 #endif
165
166 #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
167 SCB->CPACR |= ((3U << 10U * 2U) /* set CP10 Full Access */
168 | (3U << 11U * 2U)); /* set CP11 Full Access */
169 #endif
170
171 /* Secure app takes care of moving between the security states.
172 * SL_TRUSTZONE_SECURE MACRO is for secure access.
173 * SL_TRUSTZONE_NONSECURE MACRO is for non-secure access.
174 * When both the MACROS are not defined, during start-up below code makes sure
175 * that all the peripherals are accessed from non-secure address except SMU,
176 * as SMU is used to configure the trustzone state of the system. */
177 #if !defined(SL_TRUSTZONE_SECURE) && !defined(SL_TRUSTZONE_NONSECURE) \
178 && defined(__TZ_PRESENT)
179
180 // config SMU to Secure and other peripherals to Non-Secure.
181 SMU->PPUSATD0_CLR = _SMU_PPUSATD0_MASK;
182 #if defined (SEMAILBOX_PRESENT)
183 SMU->PPUSATD1_CLR = (_SMU_PPUSATD1_MASK & (~SMU_PPUSATD1_SMU & ~SMU_PPUSATD1_SEMAILBOX));
184 #else
185 SMU->PPUSATD1_CLR = (_SMU_PPUSATD1_MASK & ~SMU_PPUSATD1_SMU);
186 #endif
187
188 // SAU treats all accesses as non-secure
189 #if defined(__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)
190 SAU->CTRL = SAU_CTRL_ALLNS_Msk;
191 __DSB();
192 __ISB();
193 #else
194 #error "The startup code requires access to the CMSE toolchain extension to set proper SAU settings."
195 #endif // __ARM_FEATURE_CMSE
196
197 // Clear and Enable the SMU PPUSEC and BMPUSEC interrupt.
198 NVIC_ClearPendingIRQ(SMU_SECURE_IRQn);
199 SMU->IF_CLR = SMU_IF_PPUSEC | SMU_IF_BMPUSEC;
200 NVIC_EnableIRQ(SMU_SECURE_IRQn);
201 SMU->IEN = SMU_IEN_PPUSEC | SMU_IEN_BMPUSEC;
202 #endif //SL_TRUSTZONE_SECURE
203 }
204
205 /**************************************************************************//**
206 * @brief
207 * Get current HFRCODPLL frequency.
208 *
209 * @note
210 * This is a EFR32MG21 specific function, not part of the
211 * CMSIS definition.
212 *
213 * @return
214 * HFRCODPLL frequency in Hz.
215 *****************************************************************************/
SystemHFRCODPLLClockGet(void)216 uint32_t SystemHFRCODPLLClockGet(void)
217 {
218 #if !defined(SYSTEM_NO_STATIC_MEMORY)
219 return SystemHFRCODPLLClock;
220 #else
221 uint32_t ret = 0UL;
222 // Get oscillator frequency band
223 switch ((HFRCO0->CAL & _HFRCO_CAL_FREQRANGE_MASK)
224 >> _HFRCO_CAL_FREQRANGE_SHIFT) {
225 case 0:
226 switch (HFRCO0->CAL & _HFRCO_CAL_CLKDIV_MASK) {
227 case HFRCO_CAL_CLKDIV_DIV1:
228 ret = 4000000UL;
229 break;
230
231 case HFRCO_CAL_CLKDIV_DIV2:
232 ret = 2000000UL;
233 break;
234
235 case HFRCO_CAL_CLKDIV_DIV4:
236 ret = 1000000UL;
237 break;
238
239 default:
240 ret = 0UL;
241 break;
242 }
243 break;
244
245 case 3:
246 ret = 7000000UL;
247 break;
248
249 case 6:
250 ret = 13000000UL;
251 break;
252
253 case 7:
254 ret = 16000000UL;
255 break;
256
257 case 8:
258 ret = 19000000UL;
259 break;
260
261 case 10:
262 ret = 26000000UL;
263 break;
264
265 case 11:
266 ret = 32000000UL;
267 break;
268
269 case 12:
270 ret = 38000000UL;
271 break;
272
273 case 13:
274 ret = 48000000UL;
275 break;
276
277 case 14:
278 ret = 56000000UL;
279 break;
280
281 case 15:
282 ret = 64000000UL;
283 break;
284
285 case 16:
286 ret = 80000000UL;
287 break;
288
289 default:
290 break;
291 }
292 return ret;
293 #endif
294 }
295
296 /**************************************************************************//**
297 * @brief
298 * Set HFRCODPLL frequency value.
299 *
300 * @note
301 * This is a EFR32MG21 specific function, not part of the
302 * CMSIS definition.
303 *
304 * @param[in] freq
305 * HFRCODPLL frequency in Hz.
306 *****************************************************************************/
SystemHFRCODPLLClockSet(uint32_t freq)307 void SystemHFRCODPLLClockSet(uint32_t freq)
308 {
309 #if !defined(SYSTEM_NO_STATIC_MEMORY)
310 SystemHFRCODPLLClock = freq;
311 #else
312 (void) freq; // Unused parameter
313 #endif
314 }
315
316 /***************************************************************************//**
317 * @brief
318 * Get the current system clock frequency (SYSCLK).
319 *
320 * @details
321 * Calculate and get the current core clock frequency based on the current
322 * hardware configuration.
323 *
324 * @note
325 * This is an EFR32MG21 specific function, not part of the
326 * CMSIS definition.
327 *
328 * @return
329 * Current system clock (SYSCLK) frequency in Hz.
330 ******************************************************************************/
SystemSYSCLKGet(void)331 uint32_t SystemSYSCLKGet(void)
332 {
333 uint32_t ret = 0U;
334
335 // Find clock source
336 switch (CMU->SYSCLKCTRL & _CMU_SYSCLKCTRL_CLKSEL_MASK) {
337 case _CMU_SYSCLKCTRL_CLKSEL_HFRCODPLL:
338 ret = SystemHFRCODPLLClockGet();
339 break;
340
341 #if (HFXO_FREQ > 0U)
342 case _CMU_SYSCLKCTRL_CLKSEL_HFXO:
343 #if defined(SYSTEM_NO_STATIC_MEMORY)
344 ret = HFXO_FREQ;
345 #else
346 ret = SystemHFXOClock;
347 #endif
348 break;
349 #endif
350
351 #if (CLKIN0_FREQ > 0U)
352 case _CMU_SYSCLKCTRL_CLKSEL_CLKIN0:
353 ret = CLKIN0_FREQ;
354 break;
355 #endif
356
357 case _CMU_SYSCLKCTRL_CLKSEL_FSRCO:
358 ret = FSRCO_FREQ;
359 break;
360
361 default:
362 // Unknown clock source.
363 while (1) {
364 }
365 }
366 return ret;
367 }
368
369 /***************************************************************************//**
370 * @brief
371 * Get the current system core clock frequency (HCLK).
372 *
373 * @details
374 * Calculate and get the current core clock frequency based on the current
375 * configuration. Assuming that the SystemCoreClock global variable is
376 * maintained, the core clock frequency is stored in that variable as well.
377 * This function will however calculate the core clock based on actual HW
378 * configuration. It will also update the SystemCoreClock global variable.
379 *
380 * @note
381 * This is a EFR32MG21 specific function, not part of the
382 * CMSIS definition.
383 *
384 * @return
385 * The current core clock (HCLK) frequency in Hz.
386 ******************************************************************************/
SystemHCLKGet(void)387 uint32_t SystemHCLKGet(void)
388 {
389 uint32_t presc, ret;
390
391 ret = SystemSYSCLKGet();
392
393 presc = (CMU->SYSCLKCTRL & _CMU_SYSCLKCTRL_HCLKPRESC_MASK)
394 >> _CMU_SYSCLKCTRL_HCLKPRESC_SHIFT;
395
396 ret /= presc + 1U;
397
398 #if !defined(SYSTEM_NO_STATIC_MEMORY)
399 // Keep CMSIS system clock variable up-to-date
400 SystemCoreClock = ret;
401 #endif
402
403 return ret;
404 }
405
406 /***************************************************************************//**
407 * @brief
408 * Get the maximum core clock frequency.
409 *
410 * @note
411 * This is a EFR32MG21 specific function, not part of the
412 * CMSIS definition.
413 *
414 * @return
415 * The maximum core clock frequency in Hz.
416 ******************************************************************************/
SystemMaxCoreClockGet(void)417 uint32_t SystemMaxCoreClockGet(void)
418 {
419 return(HFRCODPLL_MAX_FREQ > HFXO_FREQ \
420 ? HFRCODPLL_MAX_FREQ : HFXO_FREQ);
421 }
422
423 /**************************************************************************//**
424 * @brief
425 * Get high frequency crystal oscillator clock frequency for target system.
426 *
427 * @note
428 * This is a EFR32MG21 specific function, not part of the
429 * CMSIS definition.
430 *
431 * @return
432 * HFXO frequency in Hz. 0 if the external crystal oscillator is not present.
433 *****************************************************************************/
SystemHFXOClockGet(void)434 uint32_t SystemHFXOClockGet(void)
435 {
436 // The external crystal oscillator is not present if HFXO_FREQ==0
437 #if (HFXO_FREQ > 0U)
438 #if defined(SYSTEM_NO_STATIC_MEMORY)
439 return HFXO_FREQ;
440 #else
441 return SystemHFXOClock;
442 #endif
443 #else
444 return 0U;
445 #endif
446 }
447
448 /**************************************************************************//**
449 * @brief
450 * Set high frequency crystal oscillator clock frequency for target system.
451 *
452 * @note
453 * This function is mainly provided for being able to handle target systems
454 * with different HF crystal oscillator frequencies run-time. If used, it
455 * should probably only be used once during system startup.
456 *
457 * @note
458 * This is a EFR32MG21 specific function, not part of the
459 * CMSIS definition.
460 *
461 * @param[in] freq
462 * HFXO frequency in Hz used for target.
463 *****************************************************************************/
SystemHFXOClockSet(uint32_t freq)464 void SystemHFXOClockSet(uint32_t freq)
465 {
466 // External crystal oscillator present?
467 #if (HFXO_FREQ > 0) && !defined(SYSTEM_NO_STATIC_MEMORY)
468 SystemHFXOClock = freq;
469
470 // Update core clock frequency if HFXO is used to clock core
471 if ((CMU->SYSCLKCTRL & _CMU_SYSCLKCTRL_CLKSEL_MASK)
472 == _CMU_SYSCLKCTRL_CLKSEL_HFXO) {
473 // This function will update the global variable
474 SystemHCLKGet();
475 }
476 #else
477 (void) freq; // Unused parameter
478 #endif
479 }
480
481 /**************************************************************************//**
482 * @brief
483 * Get current CLKIN0 frequency.
484 *
485 * @note
486 * This is a EFR32MG21 specific function, not part of the
487 * CMSIS definition.
488 *
489 * @return
490 * CLKIN0 frequency in Hz.
491 *****************************************************************************/
SystemCLKIN0Get(void)492 uint32_t SystemCLKIN0Get(void)
493 {
494 return CLKIN0_FREQ;
495 }
496
497 /**************************************************************************//**
498 * @brief
499 * Get FSRCO frequency.
500 *
501 * @note
502 * This is a EFR32MG21 specific function, not part of the
503 * CMSIS definition.
504 *
505 * @return
506 * FSRCO frequency in Hz.
507 *****************************************************************************/
SystemFSRCOClockGet(void)508 uint32_t SystemFSRCOClockGet(void)
509 {
510 return FSRCO_FREQ;
511 }
512
513 /**************************************************************************//**
514 * @brief
515 * Get current HFRCOEM23 frequency.
516 *
517 * @note
518 * This is a EFR32MG21 specific function, not part of the
519 * CMSIS definition.
520 *
521 * @return
522 * HFRCOEM23 frequency in Hz.
523 *****************************************************************************/
SystemHFRCOEM23ClockGet(void)524 uint32_t SystemHFRCOEM23ClockGet(void)
525 {
526 uint32_t ret = 0UL;
527 // Get oscillator frequency band
528 switch ((HFRCOEM23->CAL & _HFRCO_CAL_FREQRANGE_MASK)
529 >> _HFRCO_CAL_FREQRANGE_SHIFT) {
530 case 0:
531 switch (HFRCOEM23->CAL & _HFRCO_CAL_CLKDIV_MASK) {
532 case HFRCO_CAL_CLKDIV_DIV1:
533 ret = 4000000UL;
534 break;
535
536 case HFRCO_CAL_CLKDIV_DIV2:
537 ret = 2000000UL;
538 break;
539
540 case HFRCO_CAL_CLKDIV_DIV4:
541 ret = 1000000UL;
542 break;
543
544 default:
545 ret = 0UL;
546 break;
547 }
548 break;
549
550 case 6:
551 ret = 13000000UL;
552 break;
553
554 case 7:
555 ret = 16000000UL;
556 break;
557
558 case 8:
559 ret = 19000000UL;
560 break;
561
562 case 10:
563 ret = 26000000UL;
564 break;
565
566 case 11:
567 ret = 32000000UL;
568 break;
569
570 case 12:
571 ret = 40000000UL;
572 break;
573
574 default:
575 break;
576 }
577 return ret;
578 }
579
580 /**************************************************************************//**
581 * @brief
582 * Get low frequency RC oscillator clock frequency for target system.
583 *
584 * @note
585 * This is a EFR32MG21 specific function, not part of the
586 * CMSIS definition.
587 *
588 * @return
589 * LFRCO frequency in Hz.
590 *****************************************************************************/
SystemLFRCOClockGet(void)591 uint32_t SystemLFRCOClockGet(void)
592 {
593 return LFRCO_FREQ;
594 }
595
596 /**************************************************************************//**
597 * @brief
598 * Get ultra low frequency RC oscillator clock frequency for target system.
599 *
600 * @note
601 * This is a EFR32MG21 specific function, not part of the
602 * CMSIS definition.
603 *
604 * @return
605 * ULFRCO frequency in Hz.
606 *****************************************************************************/
SystemULFRCOClockGet(void)607 uint32_t SystemULFRCOClockGet(void)
608 {
609 // The ULFRCO frequency is not tuned, and can be very inaccurate
610 return ULFRCO_FREQ;
611 }
612
613 /**************************************************************************//**
614 * @brief
615 * Get low frequency crystal oscillator clock frequency for target system.
616 *
617 * @note
618 * This is a EFR32MG21 specific function, not part of the
619 * CMSIS definition.
620 *
621 * @return
622 * LFXO frequency in Hz.
623 *****************************************************************************/
SystemLFXOClockGet(void)624 uint32_t SystemLFXOClockGet(void)
625 {
626 // External crystal present?
627 #if (LFXO_FREQ > 0U)
628 #if defined(SYSTEM_NO_STATIC_MEMORY)
629 return LFXO_FREQ;
630 #else
631 return SystemLFXOClock;
632 #endif
633 #else
634 return 0U;
635 #endif
636 }
637
638 /**************************************************************************//**
639 * @brief
640 * Set low frequency crystal oscillator clock frequency for target system.
641 *
642 * @note
643 * This function is mainly provided for being able to handle target systems
644 * with different HF crystal oscillator frequencies run-time. If used, it
645 * should probably only be used once during system startup.
646 *
647 * @note
648 * This is a EFR32MG21 specific function, not part of the
649 * CMSIS definition.
650 *
651 * @param[in] freq
652 * LFXO frequency in Hz used for target.
653 *****************************************************************************/
SystemLFXOClockSet(uint32_t freq)654 void SystemLFXOClockSet(uint32_t freq)
655 {
656 // External crystal oscillator present?
657 #if (LFXO_FREQ > 0U) && !defined(SYSTEM_NO_STATIC_MEMORY)
658 SystemLFXOClock = freq;
659 #else
660 (void) freq; // Unused parameter
661 #endif
662 }
663