1 /***************************************************************************//**
2  * @file
3  * @brief CMSIS Cortex-M33 system support for EFR32MG24 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    (39000000UL)
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)
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 // #else
186   // #error "The startup code requires access to the CMSE toolchain extension to set proper SAU settings."
187 #endif /* __ARM_FEATURE_CMSE */
188 
189 /* Clear and Enable the SMU PPUSEC and BMPUSEC interrupt. */
190   NVIC_ClearPendingIRQ(SMU_SECURE_IRQn);
191   SMU->IF_CLR = SMU_IF_PPUSEC | SMU_IF_BMPUSEC;
192   NVIC_EnableIRQ(SMU_SECURE_IRQn);
193   SMU->IEN = SMU_IEN_PPUSEC | SMU_IEN_BMPUSEC;
194 #endif /*SL_TRUSTZONE_SECURE */
195 }
196 
197 /**************************************************************************//**
198  * @brief
199  *   Get current HFRCODPLL frequency.
200  *
201  * @note
202  *   This is a EFR32MG24 specific function, not part of the
203  *   CMSIS definition.
204  *
205  * @return
206  *   HFRCODPLL frequency in Hz.
207  *****************************************************************************/
SystemHFRCODPLLClockGet(void)208 uint32_t SystemHFRCODPLLClockGet(void)
209 {
210 #if !defined(SYSTEM_NO_STATIC_MEMORY)
211   return SystemHFRCODPLLClock;
212 #else
213   uint32_t ret = 0UL;
214 
215   /* Get oscillator frequency band */
216   switch ((HFRCO0->CAL & _HFRCO_CAL_FREQRANGE_MASK)
217           >> _HFRCO_CAL_FREQRANGE_SHIFT) {
218     case 0:
219       switch (HFRCO0->CAL & _HFRCO_CAL_CLKDIV_MASK) {
220         case HFRCO_CAL_CLKDIV_DIV1:
221           ret = 4000000UL;
222           break;
223 
224         case HFRCO_CAL_CLKDIV_DIV2:
225           ret = 2000000UL;
226           break;
227 
228         case HFRCO_CAL_CLKDIV_DIV4:
229           ret = 1000000UL;
230           break;
231 
232         default:
233           ret = 0UL;
234           break;
235       }
236       break;
237 
238     case 3:
239       ret = 7000000UL;
240       break;
241 
242     case 6:
243       ret = 13000000UL;
244       break;
245 
246     case 7:
247       ret = 16000000UL;
248       break;
249 
250     case 8:
251       ret = 19000000UL;
252       break;
253 
254     case 10:
255       ret = 26000000UL;
256       break;
257 
258     case 11:
259       ret = 32000000UL;
260       break;
261 
262     case 12:
263       ret = 38000000UL;
264       break;
265 
266     case 13:
267       ret = 48000000UL;
268       break;
269 
270     case 14:
271       ret = 56000000UL;
272       break;
273 
274     case 15:
275       ret = 64000000UL;
276       break;
277 
278     case 16:
279       ret = 80000000UL;
280       break;
281 
282     default:
283       break;
284   }
285   return ret;
286 #endif
287 }
288 
289 /**************************************************************************//**
290  * @brief
291  *   Set HFRCODPLL frequency value.
292  *
293  * @note
294  *   This is a EFR32MG24 specific function, not part of the
295  *   CMSIS definition.
296  *
297  * @param[in] freq
298  *   HFRCODPLL frequency in Hz.
299  *****************************************************************************/
SystemHFRCODPLLClockSet(uint32_t freq)300 void SystemHFRCODPLLClockSet(uint32_t freq)
301 {
302 #if !defined(SYSTEM_NO_STATIC_MEMORY)
303   SystemHFRCODPLLClock = freq;
304 #else
305   (void) freq; /* Unused parameter */
306 #endif
307 }
308 
309 /***************************************************************************//**
310  * @brief
311  *   Get the current system clock frequency (SYSCLK).
312  *
313  * @details
314  *   Calculate and get the current core clock frequency based on the current
315  *   hardware configuration.
316  *
317  * @note
318  *   This is an EFR32MG24 specific function, not part of the
319  *   CMSIS definition.
320  *
321  * @return
322  *   Current system clock (SYSCLK) frequency in Hz.
323  ******************************************************************************/
SystemSYSCLKGet(void)324 uint32_t SystemSYSCLKGet(void)
325 {
326   uint32_t ret = 0U;
327 
328   /* Find clock source */
329   switch (CMU->SYSCLKCTRL & _CMU_SYSCLKCTRL_CLKSEL_MASK) {
330     case _CMU_SYSCLKCTRL_CLKSEL_HFRCODPLL:
331       ret = SystemHFRCODPLLClockGet();
332       break;
333 
334 #if (HFXO_FREQ > 0U)
335     case _CMU_SYSCLKCTRL_CLKSEL_HFXO:
336 #if defined(SYSTEM_NO_STATIC_MEMORY)
337       ret = HFXO_FREQ;
338 #else
339       ret = SystemHFXOClock;
340 #endif
341       break;
342 #endif
343 
344 #if (CLKIN0_FREQ > 0U)
345     case _CMU_SYSCLKCTRL_CLKSEL_CLKIN0:
346       ret = CLKIN0_FREQ;
347       break;
348 #endif
349 
350     case _CMU_SYSCLKCTRL_CLKSEL_FSRCO:
351       ret = FSRCO_FREQ;
352       break;
353 
354     default:
355       /* Unknown clock source. */
356       while (1) {
357       }
358   }
359   return ret;
360 }
361 
362 /***************************************************************************//**
363  * @brief
364  *   Get the current system core clock frequency (HCLK).
365  *
366  * @details
367  *   Calculate and get the current core clock frequency based on the current
368  *   configuration. Assuming that the SystemCoreClock global variable is
369  *   maintained, the core clock frequency is stored in that variable as well.
370  *   This function will however calculate the core clock based on actual HW
371  *   configuration. It will also update the SystemCoreClock global variable.
372  *
373  * @note
374  *   This is a EFR32MG24 specific function, not part of the
375  *   CMSIS definition.
376  *
377  * @return
378  *   The current core clock (HCLK) frequency in Hz.
379  ******************************************************************************/
SystemHCLKGet(void)380 uint32_t SystemHCLKGet(void)
381 {
382   uint32_t presc, ret;
383 
384   ret = SystemSYSCLKGet();
385 
386   presc = (CMU->SYSCLKCTRL & _CMU_SYSCLKCTRL_HCLKPRESC_MASK)
387           >> _CMU_SYSCLKCTRL_HCLKPRESC_SHIFT;
388 
389   ret /= presc + 1U;
390 
391 #if !defined(SYSTEM_NO_STATIC_MEMORY)
392   /* Keep CMSIS system clock variable up-to-date */
393   SystemCoreClock = ret;
394 #endif
395 
396   return ret;
397 }
398 
399 /***************************************************************************//**
400  * @brief
401  *   Get the maximum core clock frequency.
402  *
403  * @note
404  *   This is a EFR32MG24 specific function, not part of the
405  *   CMSIS definition.
406  *
407  * @return
408  *   The maximum core clock frequency in Hz.
409  ******************************************************************************/
SystemMaxCoreClockGet(void)410 uint32_t SystemMaxCoreClockGet(void)
411 {
412   return(HFRCODPLL_MAX_FREQ > HFXO_FREQ \
413          ? HFRCODPLL_MAX_FREQ : HFXO_FREQ);
414 }
415 
416 /**************************************************************************//**
417  * @brief
418  *   Get high frequency crystal oscillator clock frequency for target system.
419  *
420  * @note
421  *   This is a EFR32MG24 specific function, not part of the
422  *   CMSIS definition.
423  *
424  * @return
425  *   HFXO frequency in Hz. 0 if the external crystal oscillator is not present.
426  *****************************************************************************/
SystemHFXOClockGet(void)427 uint32_t SystemHFXOClockGet(void)
428 {
429   /* The external crystal oscillator is not present if HFXO_FREQ==0 */
430 #if (HFXO_FREQ > 0U)
431 #if defined(SYSTEM_NO_STATIC_MEMORY)
432   return HFXO_FREQ;
433 #else
434   return SystemHFXOClock;
435 #endif
436 #else
437   return 0U;
438 #endif
439 }
440 
441 /**************************************************************************//**
442  * @brief
443  *   Set high frequency crystal oscillator clock frequency for target system.
444  *
445  * @note
446  *   This function is mainly provided for being able to handle target systems
447  *   with different HF crystal oscillator frequencies run-time. If used, it
448  *   should probably only be used once during system startup.
449  *
450  * @note
451  *   This is a EFR32MG24 specific function, not part of the
452  *   CMSIS definition.
453  *
454  * @param[in] freq
455  *   HFXO frequency in Hz used for target.
456  *****************************************************************************/
SystemHFXOClockSet(uint32_t freq)457 void SystemHFXOClockSet(uint32_t freq)
458 {
459   /* External crystal oscillator present? */
460 #if (HFXO_FREQ > 0) && !defined(SYSTEM_NO_STATIC_MEMORY)
461   SystemHFXOClock = freq;
462 
463   /* Update core clock frequency if HFXO is used to clock core */
464   if ((CMU->SYSCLKCTRL & _CMU_SYSCLKCTRL_CLKSEL_MASK)
465       == _CMU_SYSCLKCTRL_CLKSEL_HFXO) {
466     /* This function will update the global variable */
467     SystemHCLKGet();
468   }
469 #else
470   (void) freq; /* Unused parameter */
471 #endif
472 }
473 
474 /**************************************************************************//**
475  * @brief
476  *   Get current CLKIN0 frequency.
477  *
478  * @note
479  *   This is a EFR32MG24 specific function, not part of the
480  *   CMSIS definition.
481  *
482  * @return
483  *   CLKIN0 frequency in Hz.
484  *****************************************************************************/
SystemCLKIN0Get(void)485 uint32_t SystemCLKIN0Get(void)
486 {
487   return CLKIN0_FREQ;
488 }
489 
490 /**************************************************************************//**
491  * @brief
492  *   Get FSRCO frequency.
493  *
494  * @note
495  *   This is a EFR32MG24 specific function, not part of the
496  *   CMSIS definition.
497  *
498  * @return
499  *   FSRCO frequency in Hz.
500  *****************************************************************************/
SystemFSRCOClockGet(void)501 uint32_t SystemFSRCOClockGet(void)
502 {
503   return FSRCO_FREQ;
504 }
505 
506 /**************************************************************************//**
507  * @brief
508  *   Get current HFRCOEM23 frequency.
509  *
510  * @note
511  *   This is a EFR32MG24 specific function, not part of the
512  *   CMSIS definition.
513  *
514  * @return
515  *   HFRCOEM23 frequency in Hz.
516  *****************************************************************************/
SystemHFRCOEM23ClockGet(void)517 uint32_t SystemHFRCOEM23ClockGet(void)
518 {
519   uint32_t ret = 0UL;
520 
521   /* Get oscillator frequency band */
522   switch ((HFRCOEM23->CAL & _HFRCO_CAL_FREQRANGE_MASK)
523           >> _HFRCO_CAL_FREQRANGE_SHIFT) {
524     case 0:
525       switch (HFRCOEM23->CAL & _HFRCO_CAL_CLKDIV_MASK) {
526         case HFRCO_CAL_CLKDIV_DIV1:
527           ret = 4000000UL;
528           break;
529 
530         case HFRCO_CAL_CLKDIV_DIV2:
531           ret = 2000000UL;
532           break;
533 
534         case HFRCO_CAL_CLKDIV_DIV4:
535           ret = 1000000UL;
536           break;
537 
538         default:
539           ret = 0UL;
540           break;
541       }
542       break;
543 
544     case 6:
545       ret = 13000000UL;
546       break;
547 
548     case 7:
549       ret = 16000000UL;
550       break;
551 
552     case 8:
553       ret = 19000000UL;
554       break;
555 
556     case 10:
557       ret = 26000000UL;
558       break;
559 
560     case 11:
561       ret = 32000000UL;
562       break;
563 
564     case 12:
565       ret = 40000000UL;
566       break;
567 
568     default:
569       break;
570   }
571   return ret;
572 }
573 
574 /**************************************************************************//**
575  * @brief
576  *   Get low frequency RC oscillator clock frequency for target system.
577  *
578  * @note
579  *   This is a EFR32MG24 specific function, not part of the
580  *   CMSIS definition.
581  *
582  * @return
583  *   LFRCO frequency in Hz.
584  *****************************************************************************/
SystemLFRCOClockGet(void)585 uint32_t SystemLFRCOClockGet(void)
586 {
587   return LFRCO_FREQ;
588 }
589 
590 /**************************************************************************//**
591  * @brief
592  *   Get ultra low frequency RC oscillator clock frequency for target system.
593  *
594  * @note
595  *   This is a EFR32MG24 specific function, not part of the
596  *   CMSIS definition.
597  *
598  * @return
599  *   ULFRCO frequency in Hz.
600  *****************************************************************************/
SystemULFRCOClockGet(void)601 uint32_t SystemULFRCOClockGet(void)
602 {
603   /* The ULFRCO frequency is not tuned, and can be very inaccurate */
604   return ULFRCO_FREQ;
605 }
606 
607 /**************************************************************************//**
608  * @brief
609  *   Get low frequency crystal oscillator clock frequency for target system.
610  *
611  * @note
612  *   This is a EFR32MG24 specific function, not part of the
613  *   CMSIS definition.
614  *
615  * @return
616  *   LFXO frequency in Hz.
617  *****************************************************************************/
SystemLFXOClockGet(void)618 uint32_t SystemLFXOClockGet(void)
619 {
620   /* External crystal present? */
621 #if (LFXO_FREQ > 0U)
622 #if defined(SYSTEM_NO_STATIC_MEMORY)
623   return LFXO_FREQ;
624 #else
625   return SystemLFXOClock;
626 #endif
627 #else
628   return 0U;
629 #endif
630 }
631 
632 /**************************************************************************//**
633  * @brief
634  *   Set low frequency crystal oscillator clock frequency for target system.
635  *
636  * @note
637  *   This function is mainly provided for being able to handle target systems
638  *   with different HF crystal oscillator frequencies run-time. If used, it
639  *   should probably only be used once during system startup.
640  *
641  * @note
642  *   This is a EFR32MG24 specific function, not part of the
643  *   CMSIS definition.
644  *
645  * @param[in] freq
646  *   LFXO frequency in Hz used for target.
647  *****************************************************************************/
SystemLFXOClockSet(uint32_t freq)648 void SystemLFXOClockSet(uint32_t freq)
649 {
650   /* External crystal oscillator present? */
651 #if (LFXO_FREQ > 0U) && !defined(SYSTEM_NO_STATIC_MEMORY)
652   SystemLFXOClock = freq;
653 #else
654   (void) freq; /* Unused parameter */
655 #endif
656 }
657