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