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