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