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