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