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