1 /***************************************************************************//**
2 * @file
3 * @brief CMSIS Cortex-M33 system support for EFR32ZG23 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 (39000000UL)
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)
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 EFR32ZG23 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 EFR32ZG23 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 EFR32ZG23 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 EFR32ZG23 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 EFR32ZG23 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 EFR32ZG23 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 EFR32ZG23 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 EFR32ZG23 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 EFR32ZG23 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 current HFRCOEM23 frequency.
519 *
520 * @note
521 * This is a EFR32ZG23 specific function, not part of the
522 * CMSIS definition.
523 *
524 * @return
525 * HFRCOEM23 frequency in Hz.
526 *****************************************************************************/
SystemHFRCOEM23ClockGet(void)527 uint32_t SystemHFRCOEM23ClockGet(void)
528 {
529 uint32_t ret = 0UL;
530 CMU->CLKEN0_SET = CMU_CLKEN0_HFRCOEM23;
531
532 // Get oscillator frequency band
533 switch ((HFRCOEM23->CAL & _HFRCO_CAL_FREQRANGE_MASK)
534 >> _HFRCO_CAL_FREQRANGE_SHIFT) {
535 case 0:
536 switch (HFRCOEM23->CAL & _HFRCO_CAL_CLKDIV_MASK) {
537 case HFRCO_CAL_CLKDIV_DIV1:
538 ret = 4000000UL;
539 break;
540
541 case HFRCO_CAL_CLKDIV_DIV2:
542 ret = 2000000UL;
543 break;
544
545 case HFRCO_CAL_CLKDIV_DIV4:
546 ret = 1000000UL;
547 break;
548
549 default:
550 ret = 0UL;
551 break;
552 }
553 break;
554
555 case 6:
556 ret = 13000000UL;
557 break;
558
559 case 7:
560 ret = 16000000UL;
561 break;
562
563 case 8:
564 ret = 19000000UL;
565 break;
566
567 case 10:
568 ret = 26000000UL;
569 break;
570
571 case 11:
572 ret = 32000000UL;
573 break;
574
575 case 12:
576 ret = 40000000UL;
577 break;
578
579 default:
580 break;
581 }
582 return ret;
583 }
584
585 /**************************************************************************//**
586 * @brief
587 * Get low frequency RC oscillator clock frequency for target system.
588 *
589 * @note
590 * This is a EFR32ZG23 specific function, not part of the
591 * CMSIS definition.
592 *
593 * @return
594 * LFRCO frequency in Hz.
595 *****************************************************************************/
SystemLFRCOClockGet(void)596 uint32_t SystemLFRCOClockGet(void)
597 {
598 return LFRCO_FREQ;
599 }
600
601 /**************************************************************************//**
602 * @brief
603 * Get ultra low frequency RC oscillator clock frequency for target system.
604 *
605 * @note
606 * This is a EFR32ZG23 specific function, not part of the
607 * CMSIS definition.
608 *
609 * @return
610 * ULFRCO frequency in Hz.
611 *****************************************************************************/
SystemULFRCOClockGet(void)612 uint32_t SystemULFRCOClockGet(void)
613 {
614 // The ULFRCO frequency is not tuned, and can be very inaccurate
615 return ULFRCO_FREQ;
616 }
617
618 /**************************************************************************//**
619 * @brief
620 * Get low frequency crystal oscillator clock frequency for target system.
621 *
622 * @note
623 * This is a EFR32ZG23 specific function, not part of the
624 * CMSIS definition.
625 *
626 * @return
627 * LFXO frequency in Hz.
628 *****************************************************************************/
SystemLFXOClockGet(void)629 uint32_t SystemLFXOClockGet(void)
630 {
631 // External crystal present?
632 #if (LFXO_FREQ > 0U)
633 #if defined(SYSTEM_NO_STATIC_MEMORY)
634 return LFXO_FREQ;
635 #else
636 return SystemLFXOClock;
637 #endif
638 #else
639 return 0U;
640 #endif
641 }
642
643 /**************************************************************************//**
644 * @brief
645 * Set low frequency crystal oscillator clock frequency for target system.
646 *
647 * @note
648 * This function is mainly provided for being able to handle target systems
649 * with different HF crystal oscillator frequencies run-time. If used, it
650 * should probably only be used once during system startup.
651 *
652 * @note
653 * This is a EFR32ZG23 specific function, not part of the
654 * CMSIS definition.
655 *
656 * @param[in] freq
657 * LFXO frequency in Hz used for target.
658 *****************************************************************************/
SystemLFXOClockSet(uint32_t freq)659 void SystemLFXOClockSet(uint32_t freq)
660 {
661 // External crystal oscillator present?
662 #if (LFXO_FREQ > 0U) && !defined(SYSTEM_NO_STATIC_MEMORY)
663 SystemLFXOClock = freq;
664 #else
665 (void) freq; // Unused parameter
666 #endif
667 }
668