1 /**
2 ******************************************************************************
3 * @file system_stm32n6xx_fsbl.c
4 * @author MCD Application Team
5 * @brief CMSIS Cortex-M55 Device Peripheral Access Layer System Source File
6 * to be used after the boot ROM execution in an applicative code called
7 * "FSBL" for First Stage Boot Loader.
8 *
9 * This file provides two functions and one global variable to be called from
10 * user application:
11 * - SystemInit(): This function is called at secure startup just after the
12 * boot ROM execution and before branch to secure main program.
13 * This call is made inside the "startup_stm32n6xx_fsbl.s" file.
14 * This function does not manage security isolation (IDAU/SAU,
15 * interrupts, ...) unless USER_TZ_SAU_SETUP is defined at
16 * project level.
17 *
18 * - SystemCoreClock variable: Contains the CPU core clock, it can be used
19 * by the user application to setup the SysTick
20 * timer or configure other parameters.
21 *
22 * - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must
23 * be called whenever the core clock is changed
24 * during program execution.
25 *
26 * After each device reset the HSI (64 MHz) is used as system clock source.
27 * Then SystemInit() function is called, in "startup_stm32n6xx_fsbl.s" file, to
28 * configure the system before to branch to main program.
29 *
30 ******************************************************************************
31 * @attention
32 *
33 * Copyright (c) 2023 STMicroelectronics.
34 * All rights reserved.
35 *
36 * This software is licensed under terms that can be found in the LICENSE file
37 * in the root directory of this software component.
38 * If no LICENSE file comes with this software, it is provided AS-IS.
39 *
40 ******************************************************************************
41 */
42
43 /** @addtogroup CMSIS
44 * @{
45 */
46
47 /** @addtogroup STM32N6xx_System
48 * @{
49 */
50
51 /** @addtogroup STM32N6xx_System_Private_Includes
52 * @{
53 */
54
55 #include "stm32n6xx.h"
56 #if defined(USER_TZ_SAU_SETUP)
57 #include "partition_stm32n6xx.h" /* Trustzone-M core secure attributes */
58 #endif /* USER_TZ_SAU_SETUP */
59 #include <math.h>
60
61 /**
62 * @}
63 */
64
65 /** @addtogroup STM32N6xx_System_Private_TypesDefinitions
66 * @{
67 */
68
69 #if defined ( __ICCARM__ )
70 # define CMSE_NS_ENTRY __cmse_nonsecure_entry
71 #else
72 # define CMSE_NS_ENTRY __attribute((cmse_nonsecure_entry))
73 #endif
74
75 /**
76 * @}
77 */
78
79 /** @addtogroup STM32N6xx_System_Private_Defines
80 * @{
81 */
82 #if !defined (HSE_VALUE)
83 #if defined(USE_FPGA)
84 #define HSE_VALUE 30000000UL /*!< Value of the High-Speed External oscillator in Hz */
85 #else
86 #define HSE_VALUE 48000000UL /*!< Value of the High-Speed External oscillator in Hz */
87 #endif /* USE_FPGA */
88 #endif /* HSE_VALUE */
89
90 #if !defined (HSI_VALUE)
91 #if defined(USE_FPGA)
92 #define HSI_VALUE 48000000UL /*!< Value of the High-Speed Internal oscillator in Hz */
93 #else
94 #define HSI_VALUE 64000000UL /*!< Value of the High-Speed Internal oscillator in Hz */
95 #endif /* USE_FPGA */
96 #endif /* HSI_VALUE */
97
98 #if !defined (MSI_VALUE)
99 #define MSI_VALUE 4000000UL /*!< Minimum value of the Low-power Internal oscillator in Hz */
100 #endif /* MSI_VALUE */
101
102 #if !defined (EXTERNAL_I2S_CLOCK_VALUE)
103 #define EXTERNAL_I2S_CLOCK_VALUE 12288000UL /*!< Value of the External clock for I2S_CKIN in Hz */
104 #endif /* EXTERNAL_I2S_CLOCK_VALUE */
105
106
107 /* Note: Following vector table addresses must be defined in line with linker
108 configuration. */
109 /*!< Uncomment the following line if you need to relocate the vector table
110 anywhere in memory, else the vector table is kept at the automatic
111 selected boot address */
112 /* #define USER_VECT_TAB_ADDRESS */
113
114 #if defined(USER_VECT_TAB_ADDRESS)
115 #if !defined(VECT_TAB_BASE_ADDRESS)
116 #define VECT_TAB_BASE_ADDRESS SRAM1_AXI_BASE_S /*!< Vector Table base address field.
117 This value must be a multiple of 0x400. */
118 #endif
119
120 #if !defined(VECT_TAB_OFFSET)
121 #define VECT_TAB_OFFSET 0x00000000U /*!< Vector Table base offset field.
122 This value must be a multiple of 0x400. */
123 #endif
124 #endif /* USER_VECT_TAB_ADDRESS */
125
126 /******************************************************************************/
127 /**
128 * @}
129 */
130
131 /** @addtogroup STM32N6xx_System_Private_Macros
132 * @{
133 */
134
135 /**
136 * @}
137 */
138
139 /** @addtogroup STM32N6xx_System_Private_Variables
140 * @{
141 */
142 /* The SystemCoreClock variable is updated in three ways:
143 1) by calling CMSIS function SystemCoreClockUpdate()
144 2) by calling HAL API function HAL_RCC_GetHCLKFreq()
145 3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency
146 Note: If you use this function to configure the system clock; then there
147 is no need to call the 2 first functions listed above, since SystemCoreClock
148 variable is updated automatically.
149 */
150 uint32_t SystemCoreClock = HSI_VALUE;
151 /**
152 * @}
153 */
154
155 /** @addtogroup STM32N6xx_System_Private_FunctionPrototypes
156 * @{
157 */
158
159 /**
160 * @}
161 */
162
163 /** @addtogroup STM32N6xx_System_Private_Functions
164 * @{
165 */
166
167 #if defined(__ICCARM__)
168 extern uint32_t __vector_table;
169 #define INTVECT_START ((uint32_t)&__vector_table)
170 #elif defined(__ARMCC_VERSION)
171 extern void *__Vectors;
172 #define INTVECT_START ((uint32_t)&__Vectors)
173 #elif defined(__GNUC__)
174 extern void *g_pfnVectors;
175 #define INTVECT_START ((uint32_t)&g_pfnVectors)
176 #endif
177
178 /**
179 * @brief Setup the microcontroller system.
180 * @retval None
181 */
182
SystemInit(void)183 void SystemInit(void)
184 {
185
186 /* Configure the Vector Table location -------------------------------------*/
187 #if defined(USER_VECT_TAB_ADDRESS)
188 SCB->VTOR = VECT_TAB_BASE_ADDRESS | VECT_TAB_OFFSET;
189 #else
190 SCB->VTOR = INTVECT_START;
191 #endif /* USER_VECT_TAB_ADDRESS */
192
193 /* RNG reset */
194 RCC->AHB3RSTSR = RCC_AHB3RSTSR_RNGRSTS;
195 RCC->AHB3RSTCR = RCC_AHB3RSTCR_RNGRSTC;
196 /* Deactivate RNG clock */
197 RCC->AHB3ENCR = RCC_AHB3ENCR_RNGENC;
198
199 /* Clear SAU regions */
200 SAU->RNR = 0;
201 SAU->RBAR = 0;
202 SAU->RLAR = 0;
203 SAU->RNR = 1;
204 SAU->RBAR = 0;
205 SAU->RLAR = 0;
206 SAU->RNR = 2;
207 SAU->RBAR = 0;
208 SAU->RLAR = 0;
209 SAU->RNR = 3;
210 SAU->RBAR = 0;
211 SAU->RLAR = 0;
212 SAU->RNR = 4;
213 SAU->RBAR = 0;
214 SAU->RLAR = 0;
215 SAU->RNR = 5;
216 SAU->RBAR = 0;
217 SAU->RLAR = 0;
218 SAU->RNR = 6;
219 SAU->RBAR = 0;
220 SAU->RLAR = 0;
221 SAU->RNR = 7;
222 SAU->RBAR = 0;
223 SAU->RLAR = 0;
224
225 /* System configuration setup */
226 RCC->APB4ENSR2 = RCC_APB4ENSR2_SYSCFGENS;
227 /* Delay after an RCC peripheral clock enabling */
228 (void)RCC->APB4ENR2;
229
230 /* Set default Vector Table location after system reset or return from Standby */
231 SYSCFG->INITSVTORCR = SCB->VTOR;
232
233 /* Enable VDDADC CLAMP */
234 PWR->SVMCR3 |= PWR_SVMCR3_ASV;
235 PWR->SVMCR3 |= PWR_SVMCR3_AVMEN;
236 /* read back the register to make sure that the transaction has taken place */
237 (void) PWR->SVMCR3;
238 /* enable VREF */
239 RCC->APB4ENR1 |= RCC_APB4ENR1_VREFBUFEN;
240
241 /* RCC Fix to lower power consumption */
242 RCC->APB4ENR2 |= 0x00000010UL;
243 (void) RCC->APB4ENR2;
244 RCC->APB4ENR2 &= ~(0x00000010UL);
245
246 /* XSPI2 & XSPIM reset */
247 RCC->AHB5RSTSR = RCC_AHB5RSTSR_XSPIMRSTS | RCC_AHB5RSTSR_XSPI2RSTS;
248 RCC->AHB5RSTCR = RCC_AHB5RSTCR_XSPIMRSTC | RCC_AHB5RSTCR_XSPI2RSTC;
249
250 /* TIM2 reset */
251 RCC->APB1RSTSR1 = RCC_APB1RSTSR1_TIM2RSTS;
252 RCC->APB1RSTCR1 = RCC_APB1RSTCR1_TIM2RSTC;
253 /* Deactivate TIM2 clock */
254 RCC->APB1ENCR1 = RCC_APB1ENCR1_TIM2ENC;
255
256 /* Deactivate GPIOG clock */
257 RCC->AHB4ENCR = RCC_AHB4ENCR_GPIOGENC;
258
259 /* Read back the value to make sure it is written before deactivating SYSCFG */
260 (void) SYSCFG->INITSVTORCR;
261 /* Deactivate SYSCFG clock */
262 RCC->APB4ENCR2 = RCC_APB4ENCR2_SYSCFGENC;
263
264 #if defined(USER_TZ_SAU_SETUP)
265 /* SAU/IDAU, FPU and Interrupts secure/non-secure allocation settings */
266 TZ_SAU_Setup();
267 #endif /* USER_TZ_SAU_SETUP */
268
269 /* FPU settings ------------------------------------------------------------*/
270 #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
271 SCB->CPACR |= ((3UL << 20U)|(3UL << 22U)); /* set CP10 and CP11 Full Access */
272
273 SCB_NS->CPACR |= ((3UL << 20U)|(3UL << 22U)); /* set CP10 and CP11 Full Access */
274 #endif /* __FPU_PRESENT && __FPU_USED */
275
276 }
277
278 /**
279 * @brief Update SystemCoreClock variable according to Clock Register Values.
280 * The SystemCoreClock variable contains the core clock (HCLK), it can
281 * be used by the user application to setup the SysTick timer or configure
282 * other parameters.
283 *
284 * @note Each time the CPU core clock changes, this function must be called
285 * to update SystemCoreClock variable value. Otherwise, any configuration
286 * based on this variable will be incorrect.
287 *
288 * @note - The system frequency computed by this function is not the real
289 * frequency in the chip. It is calculated based on the predefined
290 * constant and the selected clock source:
291 *
292 * - If CPUCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*)
293 *
294 * - If CPUCLK source is MSI, SystemCoreClock will contain the MSI_VALUE(**)
295 *
296 * - If CPUCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(***)
297 *
298 * - If CPUCLK source is IC1, SystemCoreClock will contain the HSI_VALUE(*)
299 * or MSI_VALUE(**) or HSE_VALUE(***) or EXTERNAL_I2S_CLOCK_VALUE (****)
300 * multiplied/divided by the PLL factors.
301 *
302 * (*) HSI_VALUE default value is 64 MHz.
303 * With the HAL, HSI_VALUE is a constant defined in stm32n6xx_hal_conf.h file
304 * but the real value may vary depending on the variations in voltage and temperature.
305 *
306 * (**) MSI_VALUE default value is 4 MHz.
307 * With the HAL, MSI_VALUE is a constant defined in stm32n6xx_hal_conf.h file
308 * but the real value may vary depending on the variations in voltage and temperature.
309 *
310 * (***) HSE_VALUE default value is 30 MHz.
311 * With the HAL, HSE_VALUE is a constant defined in stm32n6xx_hal_conf.h file.
312 * User has to ensure that HSE_VALUE is same as the real frequency of the crystal used.
313 * Otherwise, this function may have wrong result.
314 *
315 * (****) EXTERNAL_I2S_CLOCK_VALUE default value is 12.288 MHz.
316 * With the HAL, EXTERNAL_I2S_CLOCK_VALUE is a constant defined in stm32n6xx_hal_conf.h file.
317 * User has to ensure that EXTERNAL_I2S_CLOCK_VALUE is same as the real I2S_CKIN
318 * pin frequency. Otherwise, this function may have wrong result.
319 *
320 * - The result of this function could be not correct when using fractional
321 * value for HSE crystal.
322 *
323 * @retval None
324 */
SystemCoreClockUpdate(void)325 void SystemCoreClockUpdate(void)
326 {
327 uint32_t sysclk = 0;
328 uint32_t pllm = 0;
329 uint32_t plln = 0;
330 uint32_t pllfracn = 0;
331 uint32_t pllp1 = 0;
332 uint32_t pllp2 = 0;
333 uint32_t pllcfgr, pllsource, pllbypass, ic_divider;
334 float_t pllvco;
335
336 /* Get CPUCLK source -------------------------------------------------------*/
337 switch (RCC->CFGR1 & RCC_CFGR1_CPUSWS)
338 {
339 case 0: /* HSI used as system clock source (default after reset) */
340 sysclk = HSI_VALUE >> ((RCC->HSICFGR & RCC_HSICFGR_HSIDIV) >> RCC_HSICFGR_HSIDIV_Pos);
341 break;
342
343 case RCC_CFGR1_CPUSWS_0: /* MSI used as system clock source */
344 if (READ_BIT(RCC->MSICFGR, RCC_MSICFGR_MSIFREQSEL) == 0UL)
345 {
346 sysclk = MSI_VALUE;
347 }
348 else
349 {
350 sysclk = 16000000UL;
351 }
352 break;
353
354 case RCC_CFGR1_CPUSWS_1: /* HSE used as system clock source */
355 sysclk = HSE_VALUE;
356 break;
357
358 case (RCC_CFGR1_CPUSWS_1 | RCC_CFGR1_CPUSWS_0): /* IC1 used as system clock source */
359 /* Get IC1 clock source parameters */
360 switch (READ_BIT(RCC->IC1CFGR, RCC_IC1CFGR_IC1SEL))
361 {
362 case 0: /* PLL1 selected at IC1 clock source */
363 pllcfgr = READ_REG(RCC->PLL1CFGR1);
364 pllsource = pllcfgr & RCC_PLL1CFGR1_PLL1SEL;
365 pllbypass = pllcfgr & RCC_PLL1CFGR1_PLL1BYP;
366 if (pllbypass == 0U)
367 {
368 pllm = (pllcfgr & RCC_PLL1CFGR1_PLL1DIVM) >> RCC_PLL1CFGR1_PLL1DIVM_Pos;
369 plln = (pllcfgr & RCC_PLL1CFGR1_PLL1DIVN) >> RCC_PLL1CFGR1_PLL1DIVN_Pos;
370 pllfracn = READ_BIT(RCC->PLL1CFGR2, RCC_PLL1CFGR2_PLL1DIVNFRAC) >> RCC_PLL1CFGR2_PLL1DIVNFRAC_Pos;
371 pllcfgr = READ_REG(RCC->PLL1CFGR3);
372 pllp1 = (pllcfgr & RCC_PLL1CFGR3_PLL1PDIV1) >> RCC_PLL1CFGR3_PLL1PDIV1_Pos;
373 pllp2 = (pllcfgr & RCC_PLL1CFGR3_PLL1PDIV2) >> RCC_PLL1CFGR3_PLL1PDIV2_Pos;
374 }
375 break;
376 case RCC_IC1CFGR_IC1SEL_0: /* PLL2 selected at IC1 clock source */
377 pllcfgr = READ_REG(RCC->PLL2CFGR1);
378 pllsource = pllcfgr & RCC_PLL2CFGR1_PLL2SEL;
379 pllbypass = pllcfgr & RCC_PLL2CFGR1_PLL2BYP;
380 if (pllbypass == 0U)
381 {
382 pllm = (pllcfgr & RCC_PLL2CFGR1_PLL2DIVM) >> RCC_PLL2CFGR1_PLL2DIVM_Pos;
383 plln = (pllcfgr & RCC_PLL2CFGR1_PLL2DIVN) >> RCC_PLL2CFGR1_PLL2DIVN_Pos;
384 pllfracn = READ_BIT(RCC->PLL2CFGR2, RCC_PLL2CFGR2_PLL2DIVNFRAC) >> RCC_PLL2CFGR2_PLL2DIVNFRAC_Pos;
385 pllcfgr = READ_REG(RCC->PLL2CFGR3);
386 pllp1 = (pllcfgr & RCC_PLL2CFGR3_PLL2PDIV1) >> RCC_PLL2CFGR3_PLL2PDIV1_Pos;
387 pllp2 = (pllcfgr & RCC_PLL2CFGR3_PLL2PDIV2) >> RCC_PLL2CFGR3_PLL2PDIV2_Pos;
388 }
389 break;
390
391 case RCC_IC1CFGR_IC1SEL_1: /* PLL3 selected at IC1 clock source */
392 pllcfgr = READ_REG(RCC->PLL3CFGR1);
393 pllsource = pllcfgr & RCC_PLL3CFGR1_PLL3SEL;
394 pllbypass = pllcfgr & RCC_PLL3CFGR1_PLL3BYP;
395 if (pllbypass == 0U)
396 {
397 pllm = (pllcfgr & RCC_PLL3CFGR1_PLL3DIVM) >> RCC_PLL3CFGR1_PLL3DIVM_Pos;
398 plln = (pllcfgr & RCC_PLL3CFGR1_PLL3DIVN) >> RCC_PLL3CFGR1_PLL3DIVN_Pos;
399 pllfracn = READ_BIT(RCC->PLL3CFGR2, RCC_PLL3CFGR2_PLL3DIVNFRAC) >> RCC_PLL3CFGR2_PLL3DIVNFRAC_Pos;
400 pllcfgr = READ_REG(RCC->PLL3CFGR3);
401 pllp1 = (pllcfgr & RCC_PLL3CFGR3_PLL3PDIV1) >> RCC_PLL3CFGR3_PLL3PDIV1_Pos;
402 pllp2 = (pllcfgr & RCC_PLL3CFGR3_PLL3PDIV2) >> RCC_PLL3CFGR3_PLL3PDIV2_Pos;
403 }
404 break;
405
406 default: /* RCC_IC1CFGR_IC1SEL_1 | RCC_IC1CFGR_IC1SEL_0 */ /* PLL4 selected at IC1 clock source */
407 pllcfgr = READ_REG(RCC->PLL4CFGR1);
408 pllsource = pllcfgr & RCC_PLL4CFGR1_PLL4SEL;
409 pllbypass = pllcfgr & RCC_PLL4CFGR1_PLL4BYP;
410 if (pllbypass == 0U)
411 {
412 pllm = (pllcfgr & RCC_PLL4CFGR1_PLL4DIVM) >> RCC_PLL4CFGR1_PLL4DIVM_Pos;
413 plln = (pllcfgr & RCC_PLL4CFGR1_PLL4DIVN) >> RCC_PLL4CFGR1_PLL4DIVN_Pos;
414 pllfracn = READ_BIT(RCC->PLL4CFGR2, RCC_PLL4CFGR2_PLL4DIVNFRAC) >> RCC_PLL4CFGR2_PLL4DIVNFRAC_Pos;
415 pllcfgr = READ_REG(RCC->PLL4CFGR3);
416 pllp1 = (pllcfgr & RCC_PLL4CFGR3_PLL4PDIV1) >> RCC_PLL4CFGR3_PLL4PDIV1_Pos;
417 pllp2 = (pllcfgr & RCC_PLL4CFGR3_PLL4PDIV2) >> RCC_PLL4CFGR3_PLL4PDIV2_Pos;
418 }
419 break;
420 }
421
422 #if defined(USE_FPGA)
423 /********** FPGA SPECIFIC *************/
424 /* FPGA PLL implementation use 32MHz as fixed PLL input frequency */
425 (void)pllsource;
426 sysclk = 32000000UL;
427 pllbypass = 0U;
428 #else
429 /* Get oscillator frequency used as PLL clock source */
430 switch (pllsource)
431 {
432 case 0: /* HSI selected as PLL clock source */
433 sysclk = HSI_VALUE >> ((RCC->HSICFGR & RCC_HSICFGR_HSIDIV) >> RCC_HSICFGR_HSIDIV_Pos);
434 break;
435 case RCC_PLL1CFGR1_PLL1SEL_0: /* MSI selected as PLL clock source */
436 if (READ_BIT(RCC->MSICFGR, RCC_MSICFGR_MSIFREQSEL) == 0UL)
437 {
438 sysclk = MSI_VALUE;
439 }
440 else
441 {
442 sysclk = 16000000UL;
443 }
444 break;
445 case RCC_PLL1CFGR1_PLL1SEL_1: /* HSE selected as PLL clock source */
446 sysclk = HSE_VALUE;
447 break;
448 case (RCC_PLL1CFGR1_PLL1SEL_1 | RCC_PLL1CFGR1_PLL1SEL_0): /* I2S_CKIN selected as PLL clock source */
449 sysclk = EXTERNAL_I2S_CLOCK_VALUE;
450 break;
451 default:
452 /* Nothing to do, should not occur */
453 break;
454 }
455 #endif /* USE_FPGA */
456 /* Check whether PLL is in bypass mode or not */
457 if (pllbypass == 0U)
458 {
459 /* Compte PLL output frequency (Integer and fractional modes) */
460 /* PLLVCO = (Freq * (DIVN + (FRACN / 0x1000000) / DIVM) / (DIVP1 * DIVP2)) */
461 pllvco = ((float_t)sysclk * ((float_t)plln + ((float_t)pllfracn/(float_t)0x1000000UL))) / (float_t)pllm;
462 sysclk = (uint32_t)((float_t)(pllvco/(((float_t)pllp1) * ((float_t)pllp2))));
463 }
464 /* Apply IC1 divider */
465 ic_divider = (READ_BIT(RCC->IC1CFGR, RCC_IC1CFGR_IC1INT) >> RCC_IC1CFGR_IC1INT_Pos) + 1UL;
466 sysclk = sysclk / ic_divider;
467 break;
468 default:
469 /* Nothing to do, should not occur */
470 break;
471 }
472
473 /* Return system clock frequency (CPU frequency) */
474 SystemCoreClock = sysclk;
475 }
476
477 /**
478 * @brief Secure Non-Secure-Callable function to return the current
479 * SystemCoreClock value after SystemCoreClock update.
480 * The SystemCoreClock variable contains the CPU core clock, it can
481 * be used by the user application to setup the SysTick timer or configure
482 * other parameters.
483 * @retval SystemCoreClock value
484 */
SECURE_SystemCoreClockUpdate(void)485 uint32_t SECURE_SystemCoreClockUpdate(void)
486 {
487 SystemCoreClockUpdate();
488
489 return SystemCoreClock;
490 }
491
492 /**
493 * @}
494 */
495
496 /**
497 * @}
498 */
499
500 /**
501 * @}
502 */
503