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