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