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