1 /* USER CODE BEGIN Header */
2 /**
3   ******************************************************************************
4   * @file    scm.c
5   * @author  MCD Application Team
6   * @brief   Functions for the System Clock Manager.
7   ******************************************************************************
8   * @attention
9   *
10   * Copyright (c) 2024 STMicroelectronics.
11   * All rights reserved.
12   *
13   * This software is licensed under terms that can be found in the LICENSE file
14   * in the root directory of this software component.
15   * If no LICENSE file comes with this software, it is provided AS-IS.
16   *
17   ******************************************************************************
18   */
19 /* USER CODE END Header */
20 
21 /* Includes ------------------------------------------------------------------*/
22 #include "scm.h"
23 #include "RTDebug.h"
24 #include "utilities_common.h"
25 
26 #if (CFG_SCM_SUPPORTED == 1)
27 
SCM_HSI_CLK_ON(void)28 __weak void SCM_HSI_CLK_ON(void)
29 {
30   LL_RCC_HSI_Enable();
31   while(LL_RCC_HSI_IsReady() == 0);
32 }
33 
SCM_HSI_CLK_OFF(void)34 __weak void SCM_HSI_CLK_OFF(void)
35 {
36 
37 }
38 
39 /* SCM HSE BEGIN */
SCM_HSI_SwithSystemClock_Entry(void)40 __weak void SCM_HSI_SwithSystemClock_Entry(void)
41 {
42 
43 }
44 
SCM_HSI_SwithSystemClock_Exit(void)45 __weak void SCM_HSI_SwithSystemClock_Exit(void)
46 {
47 
48 }
49 /* SCM HSE END */
50 /* Private typedef -----------------------------------------------------------*/
51 #define PLL_INPUTRANGE0_FREQMAX         8000000u  /* 8 MHz is maximum frequency for VCO input range 0 */
52 
53 /* Private define ------------------------------------------------------------*/
54 
55 /* Private macro -------------------------------------------------------------*/
56 /* Private variables ---------------------------------------------------------*/
57 RAMCFG_HandleTypeDef sram1_ns =
58 {
59   RAMCFG_SRAM1,           /* Instance */
60   HAL_RAMCFG_STATE_READY, /* RAMCFG State */
61   0U,                     /* RAMCFG Error Code */
62 };
63 
64 RAMCFG_HandleTypeDef sram2_ns =
65 {
66   RAMCFG_SRAM2,           /* Instance */
67   HAL_RAMCFG_STATE_READY, /* RAMCFG State */
68   0U,                     /* RAMCFG Error Code */
69 };
70 
71 static scm_system_clock_t scm_system_clock_config;
72 static scm_clockconfig_t scm_system_clock_requests[(scm_user_id_t)TOTAL_CLIENT_NUM] = {NO_CLOCK_CONFIG};
73 static scm_radio_state_t RadioState;
74 
75 /* Private function prototypes -----------------------------------------------*/
76 static scm_clockconfig_t scm_getmaxfreq(void);
77 static void scm_systemclockconfig(void);
78 static void ConfigStartPll(void);
79 static void ConfigHwPll(scm_pll_config_t *p_hw_config);
80 static void SwitchHsePre(scm_hse_hsepre_t hse_pre);
81 static void SwitchHse16toHse32(void);
82 static void SwitchHse32toHse16(void);
83 static void SwitchPlltoHse32(void);
84 
85 /* Private functions ---------------------------------------------------------*/
scm_getmaxfreq(void)86 OPTIMIZED static scm_clockconfig_t scm_getmaxfreq(void)
87 {
88   uint8_t idx = 0;
89   scm_clockconfig_t max = NO_CLOCK_CONFIG;
90 
91   for(idx = 0; idx < sizeof(scm_system_clock_requests) ; idx++)
92   {
93     if(scm_system_clock_requests[idx] > max)
94     {
95       max = scm_system_clock_requests[idx];
96     }
97   }
98 
99   return max;
100 }
101 
scm_systemclockconfig(void)102 OPTIMIZED static void scm_systemclockconfig(void)
103 {
104   SYSTEM_DEBUG_SIGNAL_SET(SCM_SYSTEM_CLOCK_CONFIG);
105 
106   switch (scm_system_clock_config.targeted_clock_freq)
107   {
108     case HSE_16MHZ:
109 
110       if(LL_RCC_GetSysClkSource() == LL_RCC_SYS_CLKSOURCE_STATUS_PLL1R)
111       {
112         /* currently running on PLL */
113         SwitchPlltoHse32();
114       }
115 
116       SwitchHse32toHse16();
117 
118       /* Ensure time base clock coherency */
119       SystemCoreClockUpdate();
120 
121       break;
122 
123     case HSE_32MHZ:
124 
125       if (LL_RCC_HSE_IsEnabledPrescaler())
126       {
127         /* currently running on HSE16 */
128         SwitchHse16toHse32();
129 
130         /* Ensure time base clock coherency */
131         SystemCoreClockUpdate();
132       }
133       else if(LL_RCC_GetSysClkSource() == LL_RCC_SYS_CLKSOURCE_STATUS_PLL1R)
134       {
135         /* currently running on PLL */
136         SwitchPlltoHse32();
137 
138         /* Ensure time base clock coherency */
139         SystemCoreClockUpdate();
140       }
141       else
142       {
143         /**
144           * The system is already running on HSE32
145           * The only case is when the PLL has been requested and
146           * aborted before the system switched to PLL
147           */
148 
149         /* Disable PLL */
150         LL_RCC_PLL1_Disable();
151 
152         /**
153           * Disable PLL1RDY interrupt
154           * No need to worry the case when the PLL interrupt
155           * may already be pending at this time
156           */
157         __HAL_RCC_DISABLE_IT(RCC_IT_PLL1RDY);
158       }
159 
160       break;
161 
162     case SYS_PLL:
163 
164       if (LL_RCC_HSE_IsEnabledPrescaler())
165       {
166         /* currently running on HSE16 */
167         SwitchHse16toHse32();
168 
169         /* Ensure time base clock coherency */
170         SystemCoreClockUpdate();
171       }
172 
173       ConfigStartPll();
174 
175       break;
176 
177     default:
178       break;
179   }
180 
181   SYSTEM_DEBUG_SIGNAL_RESET(SCM_SYSTEM_CLOCK_CONFIG);
182 }
183 
SwitchHsePre(scm_hse_hsepre_t hse_pre)184 OPTIMIZED static void SwitchHsePre(scm_hse_hsepre_t hse_pre)
185 {
186   /* Start HSI */
187   SCM_HSI_CLK_ON();
188 
189   /* SCM HSE BEGIN */
190   /* Entry hook for HSI switch */
191   SCM_HSI_SwithSystemClock_Entry();
192   /* SCM HSE END */
193 
194   /* Set HSI as SYSCLK */
195   LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSI);
196   while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSI);
197 
198   /* Enable HSEON */
199   /* SCM HSE BEGIN */
200   LL_RCC_HSE_Enable();
201   while(LL_RCC_HSE_IsReady() == 0);
202 
203   /* Exit hook for HSI switch */
204   SCM_HSI_SwithSystemClock_Exit();
205   /* SCM HSE END */
206 
207   /* Set/Clear HSEPRE */
208   if(hse_pre == HSEPRE_DISABLE)
209   {
210     LL_RCC_HSE_DisablePrescaler();
211   }
212   else
213   {
214     LL_RCC_HSE_EnablePrescaler();
215   }
216 
217   /* Set HSE as SYSCLK */
218   LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSE);
219   while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSE);
220 
221   /* Disable HSI */
222   SCM_HSI_CLK_OFF();
223 
224 #if defined(STM32WBAXX_SI_CUT1_0)
225   /* STM32WBA5 Cut1.0 only: if the radio is not active is set to OFF by the hardware. */
226   if(isRadioActive() == SCM_RADIO_NOT_ACTIVE)
227   {
228     /* SCM HSE BEGIN */
229     SCM_HSE_Clear_SW_HSERDY();
230 	/* SCM HSE END */
231   }
232 #endif /* STM32WBAXX_SI_CUT1_0 */
233 }
234 
SwitchHse16toHse32(void)235 OPTIMIZED static void SwitchHse16toHse32(void)
236 {
237   /**
238     * Switch from HSE_16MHz to HSE_32MHz
239     * 1. Voltage Range1
240     * 2. Disable prescaler ==> HSE16 to HSE32
241     * 3. Change RAM/FLASH waitstates (no limitation in Rang1)
242     * 4. AHB5 Div 1
243     */
244 
245   /* first switch to VOS1 */
246   LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);
247   while (LL_PWR_IsActiveFlag_VOS() == 0);
248 
249   /* Switch to 32Mhz */
250   SwitchHsePre(HSEPRE_DISABLE);
251 
252   /* Configure flash and SRAMs */
253   scm_setwaitstates(HSE32);
254 
255   /* Need to set HDIV5 */
256   LL_RCC_SetAHB5Divider(LL_RCC_AHB5_DIVIDER_1); /* divided by 1 */
257 }
258 
SwitchHse32toHse16(void)259 OPTIMIZED static void SwitchHse32toHse16(void)
260 {
261   /**
262     * Switch from HSE_16MHz to HSE_32MHz
263     * 1. AHB5 Div 2
264     * 2. Change RAM/FLASH waitstates
265     * 3. Disable prescaler ==> HSE16 to HSE32
266     * 4. Voltage Range2
267     */
268 
269   /* Divide HDIV5 by 2 */
270   LL_RCC_SetAHB5Divider(LL_RCC_AHB5_DIVIDER_2);
271 
272   /* Configure flash and SRAMs before switching to VOS2 */
273   scm_setwaitstates(HSE16);
274 
275   /* Switch to HSE 16 */
276   SwitchHsePre(HSEPRE_ENABLE);
277 
278   LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE2);
279 }
280 
SwitchPlltoHse32(void)281 OPTIMIZED static void SwitchPlltoHse32(void)
282 {
283   /**
284     * Switch from PLL to HSE_32MHz
285     * 1. Switch system clock source to HSE
286     * 2. Turn OFF PLL
287     * 3. Change RAM/FLASH waitstates (no limitation in Rang1)
288     */
289 
290   /* Switch to HSE */
291   LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSE);
292   while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSE);
293 
294   /* Disable PLL */
295   LL_RCC_PLL1_Disable();
296 
297   /* Configure flash and SRAMs */
298   scm_setwaitstates(HSE32);
299 }
300 
ConfigStartPll(void)301 OPTIMIZED static void ConfigStartPll(void)
302 {
303   /* Enable PLL1 output for SYSCLK (PLL1R) */
304   LL_RCC_PLL1_EnableDomain_PLL1R();
305 
306   /* Configure and start the PLL */
307   LL_RCC_PLL1_SetMainSource(LL_RCC_PLL1SOURCE_HSE);
308 
309   /* Enable PLL1 */
310   __HAL_RCC_PLL1_ENABLE();
311 
312   /* PLL1RDY interrupt raised when PLL is enabled */
313   __HAL_RCC_ENABLE_IT(RCC_IT_PLL1RDY);
314 }
315 
ConfigHwPll(scm_pll_config_t * p_hw_config)316 static void ConfigHwPll(scm_pll_config_t *p_hw_config)
317 {
318   uint32_t freq_vco_in = 0;
319 
320   /* Apply user PLL mode */
321   if(p_hw_config->pll_mode == PLL_FRACTIONAL_MODE)
322   {
323     scm_pll_fractional_update(p_hw_config->PLLFractional);
324   }
325   else
326   {
327     /* Integer configuration will be used for PLL mode */
328     LL_RCC_PLL1FRACN_Disable();
329   }
330 
331   /* Apply correct frequency range for VCO_IN */
332   /* Note as PLL clock source is always HSE 32MHz, only PLL1M value impact VCO_IN */
333 
334   freq_vco_in = 32000000UL/p_hw_config->PLLM;
335   if (freq_vco_in > PLL_INPUTRANGE0_FREQMAX)
336   {
337     freq_vco_in = RCC_PLL_VCOINPUT_RANGE1;
338   }
339   else
340   {
341     freq_vco_in = RCC_PLL_VCOINPUT_RANGE0;
342   }
343   __HAL_RCC_PLL1_VCOINPUTRANGE_CONFIG(freq_vco_in);
344 
345   __HAL_RCC_PLL1_CONFIG(RCC_PLLSOURCE_HSE, /* PLL clock source is always HSE 32MHz */
346                         p_hw_config->PLLM,
347                         p_hw_config->PLLN,
348                         p_hw_config->PLLP,
349                         p_hw_config->PLLQ,
350                         p_hw_config->PLLR
351                         );
352 
353   LL_RCC_SetAHB5Prescaler(p_hw_config->AHB5_PLL1_CLKDivider);
354 
355   /* PLL is now initialized */
356   scm_system_clock_config.pll.are_pll_params_initialized = 1;
357 }
358 
359 /* Public functions ----------------------------------------------------------*/
360 
361 /**
362   * @brief  System Clock Manager init code
363   * @param  None
364   * @retval None
365   */
scm_init()366 OPTIMIZED void scm_init()
367 {
368   /* init scm_system_clock_config with LP config
369    * scm_system_clock_config SHALL BE UPDATED BY READING HW CONFIG FROM HAL APIs
370    * SHALL BE CALLED AFTER SystemClock_Config()
371    **/
372 
373   /* Default PLL configuration => no configuration */
374   memset(&(scm_system_clock_config.pll), 0, sizeof(scm_pll_config_t));
375 
376   /* Reading FLASH and SRAMs waitstates from registers */
377   scm_system_clock_config.flash_ws_cfg = __HAL_FLASH_GET_LATENCY();
378   scm_system_clock_config.sram_ws_cfg = HAL_RAMCFG_GetWaitState(&sram1_ns);
379 
380   /* Link Layer is not active at this stage */
381   RadioState = SCM_RADIO_NOT_ACTIVE;
382 
383   /* Enable RAMCFG clock */
384   __HAL_RCC_RAMCFG_CLK_ENABLE();
385 
386   /* Reading system core clock configuration from registers */
387   switch(LL_RCC_GetSysClkSource())
388   {
389     case LL_RCC_SYS_CLKSOURCE_STATUS_HSI:
390       /* HSI system clock configuration is not supported on SCM module as radio activity is not possible.
391        * Switch to HSE_16MHz required.
392        */
393 
394       /* Target system clock frequency is now HSE_16MHZ */
395       scm_system_clock_config.targeted_clock_freq = HSE_16MHZ;
396 
397       /* Enable prescaler */
398        LL_RCC_HSE_EnablePrescaler();
399 
400       /* Set HDIV 5 */
401       LL_RCC_SetAHB5Divider(LL_RCC_AHB5_DIVIDER_2); /* divided by 2 */
402 
403       scm_setup();
404 
405       /* Set VOS to range 2 */
406       LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE2);
407 
408       break;
409 
410     case LL_RCC_SYS_CLKSOURCE_STATUS_HSE:
411 
412       /* Get AHB5 divider for HSE frequency */
413       if (LL_RCC_HSE_IsEnabledPrescaler())
414       {
415         /* System core clock is HSE_16MHz */
416         scm_system_clock_config.targeted_clock_freq = HSE_16MHZ;
417       }
418       else
419       {
420         /* System core clock is HSE_32MHz */
421         scm_system_clock_config.targeted_clock_freq = HSE_32MHZ;
422       }
423 
424       break;
425 
426     case LL_RCC_SYS_CLKSOURCE_STATUS_PLL1R:
427         scm_system_clock_config.targeted_clock_freq = SYS_PLL;
428 
429         /* Initial PLL configuration */
430         scm_system_clock_config.pll.PLLM = LL_RCC_PLL1_GetDivider();
431         scm_system_clock_config.pll.PLLN = LL_RCC_PLL1_GetN();
432         scm_system_clock_config.pll.PLLP = LL_RCC_PLL1_GetP();
433         scm_system_clock_config.pll.PLLQ = LL_RCC_PLL1_GetQ();
434         scm_system_clock_config.pll.PLLR = LL_RCC_PLL1_GetR();
435         scm_system_clock_config.pll.PLLFractional = LL_RCC_PLL1_GetFRACN();
436         scm_system_clock_config.pll.AHB5_PLL1_CLKDivider = LL_RCC_GetAHB5Prescaler();
437         if(scm_system_clock_config.pll.PLLFractional == PLL_FRACTIONAL_MODE)
438         {
439           scm_system_clock_config.pll.pll_mode = PLL_FRACTIONAL_MODE;
440         }
441         else
442         {
443           scm_system_clock_config.pll.pll_mode = PLL_INTEGER_MODE;
444         }
445 
446       break;
447   }
448 
449   scm_system_clock_requests[SCM_USER_APP]= scm_system_clock_config.targeted_clock_freq;
450 }
451 
452 /**
453   * @brief  Setup the system clock source in usable configuration for Connectivity use cases.
454   *         Called at startup or out of low power modes.
455   * @param  None
456   * @retval None
457   */
scm_setup(void)458 OPTIMIZED void scm_setup(void)
459 {
460   SYSTEM_DEBUG_SIGNAL_SET(SCM_SETUP);
461 
462   /* System clock is now on HSI 16Mhz, as it exits from stop mode */
463 
464   /* Start HSE */
465   LL_RCC_HSE_Enable();
466 
467   if ((LL_RCC_HSE_IsReady() != 0) && (RadioState == SCM_RADIO_ACTIVE))
468   {
469     /**
470       * The current system configuration is:
471       * Range1, HDIV5 cleared, HSEPRE cleared
472       */
473 
474     /* Switch System Clock on HSE32 */
475     LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSE);
476 
477     while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSE);
478 
479     scm_setwaitstates(HSE32); /* There is no limitation when in Range1 */
480 
481     /* As system switched to HSE, disable HSI */
482     SCM_HSI_CLK_OFF();
483 
484     /* Check if the clock system used PLL before low power mode entry */
485     if(scm_system_clock_config.targeted_clock_freq == SYS_PLL)
486     {
487       /* Configure system clock to use PLL */
488       ConfigStartPll();
489     }
490 
491     /* Ensure time base clock coherency */
492     SystemCoreClockUpdate();
493   }
494   else
495   {
496     scm_setwaitstates(HSE16);
497 
498     /* Check if the system need to increase VOS range (clock frequency higher than HSE 16Mhz)*/
499     if(scm_system_clock_config.targeted_clock_freq != HSE_16MHZ)
500     {
501       /* Set VOS to range 1 */
502       LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);
503     }
504 
505     if (LL_RCC_HSE_IsReady() != 0)
506     {
507       scm_hserdy_isr();
508     }
509     else
510     {
511       /* Enable HSERDY interrupt */
512       __HAL_RCC_ENABLE_IT(RCC_IT_HSERDY);
513     }
514   }
515   SYSTEM_DEBUG_SIGNAL_RESET(SCM_SETUP);
516 }
517 
518 /**
519   * @brief  Configure the PLL mode and parameters before PLL selection as system clock.
520   * @param  p_pll_config PLL coniguration to apply
521   * @retval None
522   * @note   scm_pll_setconfig to be called before PLL activation (PLL set as system core clock)
523   */
scm_pll_setconfig(const scm_pll_config_t * p_pll_config)524 OPTIMIZED void scm_pll_setconfig(const scm_pll_config_t *p_pll_config)
525 {
526   /* Initial PLL configuration */
527   scm_system_clock_config.pll.PLLM = p_pll_config->PLLM;
528   scm_system_clock_config.pll.PLLN = p_pll_config->PLLN;
529   scm_system_clock_config.pll.PLLP = p_pll_config->PLLP;
530   scm_system_clock_config.pll.PLLQ = p_pll_config->PLLQ;
531   scm_system_clock_config.pll.PLLR = p_pll_config->PLLR;
532   scm_system_clock_config.pll.PLLFractional = p_pll_config->PLLFractional;
533   scm_system_clock_config.pll.pll_mode = p_pll_config->pll_mode;
534   scm_system_clock_config.pll.AHB5_PLL1_CLKDivider = p_pll_config->AHB5_PLL1_CLKDivider;
535 
536   ConfigHwPll(&scm_system_clock_config.pll);
537 }
538 
539 /**
540   * @brief  Configure the PLL for switching fractional parameters on the fly.
541   * @param  pll_frac Up to date fractional configuration.
542   * @retval None
543   * @note   A PLL update is requested only when the system clock is
544   *         running on the PLL with a different configuration that the
545   *         one required
546   */
scm_pll_fractional_update(uint32_t pll_frac)547 OPTIMIZED void scm_pll_fractional_update(uint32_t pll_frac)
548 {
549   /* PLL1FRACEN set to 0 */
550   LL_RCC_PLL1FRACN_Disable();
551 
552   /* Update PLL1FRACR register */
553   LL_RCC_PLL1_SetFRACN(pll_frac);
554 
555   /* PLL1FRACEN set to 1 */
556   LL_RCC_PLL1FRACN_Enable();
557 
558   /* Ensure time base clock coherency */
559   SystemCoreClockUpdate();
560 }
561 
562 /**
563   * @brief  Set the system clock to the requested frequency.
564   * @param  user_id This parameter can be one of the following:
565   *         @arg SCM_USER_APP
566   *         @arg SCM_USER_LL_FW
567   * @param  sysclockconfig This parameter can be one of the following:
568   *         @arg HSE_16MHZ
569   *         @arg HSE_32MHZ
570   *         @arg SYS_PLL
571   * @retval None
572   */
scm_setsystemclock(scm_user_id_t user_id,scm_clockconfig_t sysclockconfig)573 OPTIMIZED void scm_setsystemclock(scm_user_id_t user_id, scm_clockconfig_t sysclockconfig)
574 {
575   scm_clockconfig_t max_freq_requested;
576 
577   UTILS_ENTER_LIMITED_CRITICAL_SECTION(RCC_INTR_PRIO<<4);
578 
579   /* Register the request by updating the requested frequency for this user */
580   scm_system_clock_requests[user_id] = sysclockconfig;
581 
582   /* Get the higher frequency required by the clients */
583   max_freq_requested = scm_getmaxfreq();
584 
585   /* Check if we need to apply another clock frequency */
586   if(scm_system_clock_config.targeted_clock_freq != max_freq_requested)
587   {
588     scm_system_clock_config.targeted_clock_freq = max_freq_requested;
589 
590     /* Check the current system clock source (HSI or HSE) */
591     if(LL_RCC_GetSysClkSource() == LL_RCC_SYS_CLKSOURCE_STATUS_HSI)
592     {
593       /* HSI is still the system clock */
594 
595       if(scm_system_clock_config.targeted_clock_freq == HSE_16MHZ)
596       {
597         /* The system clock target is HSE 16Mhz */
598 
599         /* Clear VOS (Range 2) */
600         LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE2);
601       }
602       else
603       {
604         /* The system clock target is higher than HSE 16Mhz */
605 
606         /* Set VOS (Range 1) */
607         LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);
608 
609         if(RadioState != SCM_RADIO_NOT_ACTIVE)
610         {
611             /* Disable HSERDY interrupt */
612             __HAL_RCC_DISABLE_IT(RCC_IT_HSERDY);
613 
614             /* Wait until VOS has changed */
615             while (LL_PWR_IsActiveFlag_VOS() == 0);
616 
617             /* Wait until HSE is ready */
618             while (LL_RCC_HSE_IsReady() == 0);
619 
620             LL_RCC_HSE_DisablePrescaler();
621 
622             /* Switch to HSE */
623             LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSE);
624             while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSE);
625 
626             scm_setwaitstates(HSE32); /* There is no limitation when in Range1 */
627 
628             LL_RCC_SetAHB5Divider(LL_RCC_AHB5_DIVIDER_1);
629 
630             SCM_HSI_CLK_OFF();
631 
632             /* Check if PLL is requested */
633             if(scm_system_clock_config.targeted_clock_freq == SYS_PLL)
634             {
635                 /* Configure system clock to use PLL */
636                 ConfigStartPll();
637             }
638 
639             /* Ensure time base clock coherency */
640             SystemCoreClockUpdate();
641         }
642       }
643 
644       /* System clock is going to be configured in RCC HSERDY interrupt */
645     }
646     else
647     {
648       /* HSE is already the system clock source */
649       /* Configure the system clock */
650       scm_systemclockconfig();
651     }
652   }
653   else if(scm_system_clock_config.targeted_clock_freq == SYS_PLL)
654   {
655     /* PLL has requested but system clock is already on PLL */
656     scm_pllready();
657   }
658 
659   UTILS_EXIT_LIMITED_CRITICAL_SECTION();
660 }
661 
662 /**
663   * @brief  Called each time the PLL is ready
664   * @param  None
665   * @retval None
666   * @note   This function is defined as weak in SCM module.
667   *         Can be overridden by user.
668   */
scm_pllready(void)669 __WEAK void scm_pllready(void)
670 {
671   /* To be override by user */
672 }
673 
674 /**
675   * @brief  Configure the Flash and SRAMs wait cycle (when required for system clock source change)
676   * @param  ws_lp_config: This parameter can be one of the following:
677   *         @arg LP
678   *         @arg RUN
679   *         @arg HSE16
680   *         @arg HSE32
681   *         @arg PLL
682   * @retval None
683   */
scm_setwaitstates(const scm_ws_lp_t ws_lp_config)684 OPTIMIZED void scm_setwaitstates(const scm_ws_lp_t ws_lp_config)
685 {
686   /* Configure flash and SRAMs */
687   switch (ws_lp_config) {
688   case LP:
689     __HAL_FLASH_SET_LATENCY(FLASH_LATENCY_3);
690     while(__HAL_FLASH_GET_LATENCY() != FLASH_LATENCY_3);
691     HAL_RAMCFG_ConfigWaitState(&sram1_ns, RAMCFG_WAITSTATE_1);
692     HAL_RAMCFG_ConfigWaitState(&sram2_ns, RAMCFG_WAITSTATE_1);
693     break;
694 
695   case RUN:
696     __HAL_FLASH_SET_LATENCY(scm_system_clock_config.flash_ws_cfg);
697     while(__HAL_FLASH_GET_LATENCY() != scm_system_clock_config.flash_ws_cfg);
698     HAL_RAMCFG_ConfigWaitState(&sram1_ns, scm_system_clock_config.sram_ws_cfg);
699     HAL_RAMCFG_ConfigWaitState(&sram2_ns, scm_system_clock_config.sram_ws_cfg);
700     break;
701 
702   case HSE16:
703     __HAL_FLASH_SET_LATENCY(FLASH_LATENCY_1);
704     while(__HAL_FLASH_GET_LATENCY() != FLASH_LATENCY_1);
705     HAL_RAMCFG_ConfigWaitState(&sram1_ns, RAMCFG_WAITSTATE_1);
706     HAL_RAMCFG_ConfigWaitState(&sram2_ns, RAMCFG_WAITSTATE_1);
707 
708     scm_system_clock_config.flash_ws_cfg = FLASH_LATENCY_1;
709     scm_system_clock_config.sram_ws_cfg = RAMCFG_WAITSTATE_1;
710 
711     break;
712 
713   case HSE32:
714     __HAL_FLASH_SET_LATENCY(FLASH_LATENCY_0);
715     while(__HAL_FLASH_GET_LATENCY() != FLASH_LATENCY_0);
716     HAL_RAMCFG_ConfigWaitState(&sram1_ns, RAMCFG_WAITSTATE_0);
717     HAL_RAMCFG_ConfigWaitState(&sram2_ns, RAMCFG_WAITSTATE_0);
718 
719     scm_system_clock_config.flash_ws_cfg = FLASH_LATENCY_0;
720     scm_system_clock_config.sram_ws_cfg = RAMCFG_WAITSTATE_0;
721 
722     break;
723 
724   case PLL:
725     /* RAM latencies are alreadey set to 0WS */
726     /* Set Flash LATENCY according to PLL configuration */
727     /* BELOW CONFIGURATION IS WORST CASE, SHALL BE OPTIMIZED */
728     __HAL_FLASH_SET_LATENCY(FLASH_LATENCY_3);
729     while(__HAL_FLASH_GET_LATENCY() != FLASH_LATENCY_3);
730     scm_system_clock_config.flash_ws_cfg = FLASH_LATENCY_3;
731     break;
732 
733   default:
734     break;
735   }
736 }
737 
738 /**
739   * @brief  SCM HSERDY interrupt handler.
740   *         Switch system clock on HSE.
741   * @param  None
742   * @retval None
743   */
scm_hserdy_isr(void)744 OPTIMIZED void scm_hserdy_isr(void)
745 {
746   SYSTEM_DEBUG_SIGNAL_SET(SCM_HSERDY_ISR);
747 
748   if(LL_RCC_GetSysClkSource() == LL_RCC_SYS_CLKSOURCE_STATUS_HSI)
749   {
750     /* Wait until VOS has changed */
751     while (LL_PWR_IsActiveFlag_VOS() == 0);
752 
753     if(scm_system_clock_config.targeted_clock_freq == HSE_16MHZ)
754     {
755       /**
756         * The current system configuration is:
757         * Range2, HDIV5 set, Wait States compliant to HSE16
758         */
759       LL_RCC_HSE_EnablePrescaler();
760       /* Switch to HSE */
761       LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSE);
762       while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSE);
763     }
764     else
765     {
766       /**
767         * The current system configuration is:
768         * Range1
769         */
770 
771       LL_RCC_HSE_DisablePrescaler();
772 
773       /* Switch to HSE */
774       LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSE);
775       while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSE);
776 
777       scm_setwaitstates(HSE32); /* There is no limitation when in Range1 */
778 
779       if(scm_system_clock_config.targeted_clock_freq == SYS_PLL)
780       {
781         /* The system clock target is based on PLL */
782 
783         /* Configure and start PLL */
784         ConfigStartPll();
785       }
786 
787       /* Set HDIV 5 */
788       LL_RCC_SetAHB5Divider(LL_RCC_AHB5_DIVIDER_1); /* divided by 1 */
789     }
790 
791     /* As system switched to HSE, disable HSI */
792     SCM_HSI_CLK_OFF();
793 
794     /* Disable HSERDY interrupt */
795     __HAL_RCC_DISABLE_IT(RCC_IT_HSERDY);
796 
797     /* Ensure time base clock coherency */
798     SystemCoreClockUpdate();
799   }
800 
801   SYSTEM_DEBUG_SIGNAL_RESET(SCM_HSERDY_ISR);
802 }
803 
804 /**
805   * @brief  SCM PLLRDY interrupt handler.
806   *         Switch system clock on PLL.
807   * @param  None
808   * @retval None
809   */
scm_pllrdy_isr(void)810 OPTIMIZED void scm_pllrdy_isr(void)
811 {
812   if(scm_system_clock_config.targeted_clock_freq == SYS_PLL)
813   {
814     /* Set PLL compatible waitstates */
815     scm_setwaitstates(PLL);
816 
817     /* Switch to PLL */
818     LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL1R);
819     while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL1R);
820 
821     /* Ensure time base clock coherency */
822     SystemCoreClockUpdate();
823 
824     scm_pllready();
825   }
826   else
827   {
828     /**
829       * The PLL was enabled but is not used anymore as system clock
830       * The only case is when a request has been made and cancelled before
831       * the system had time to switch the system clock on PLL
832       */
833     /* Disable PLL */
834     LL_RCC_PLL1_Disable();
835 
836     /* Disable PLL1RDY interrupt */
837     __HAL_RCC_DISABLE_IT(RCC_IT_PLL1RDY);
838   }
839 }
840 
841 /**
842   * @brief  Notify the state of the Radio
843   * @param  radio_state: This parameter can be one of the following:
844   *         @arg SCM_RADIO_ACTIVE
845   *         @arg SCM_RADIO_NOT_ACTIVE
846   * @retval None
847   */
scm_notifyradiostate(const scm_radio_state_t radio_state)848 OPTIMIZED void scm_notifyradiostate(const scm_radio_state_t radio_state)
849 {
850   if(radio_state != SCM_RADIO_NOT_ACTIVE)
851   {
852     RadioState = SCM_RADIO_ACTIVE; /* shall be set before calling scm_setsystemclock() */
853     scm_setsystemclock(SCM_USER_LL_FW, HSE_32MHZ); /* shall be set before calling scm_setsystemclock() */
854   }
855   else
856   {
857     RadioState = SCM_RADIO_NOT_ACTIVE;
858     scm_setsystemclock(SCM_USER_LL_FW, HSE_16MHZ);
859   }
860 }
861 
862 /**
863   * @brief  Restore system clock configuration when moving out of standby.
864   * @param  None
865   * @retval None
866   */
scm_standbyexit(void)867 OPTIMIZED void scm_standbyexit(void)
868 {
869   if(scm_system_clock_config.pll.are_pll_params_initialized == 1)
870   {
871     /* Restore PLL even if not yet used in case it has been setup upfron at initialization */
872     ConfigHwPll(&scm_system_clock_config.pll);
873   }
874 
875   scm_setup();
876 }
877 
878 #else /* CFG_SCM_SUPPORTED */
scm_pllrdy_isr(void)879 __weak void scm_pllrdy_isr(void){/* Intentionally enpty */}
scm_hserdy_isr(void)880 __weak void scm_hserdy_isr(void){/* Intentionally enpty */}
881 #endif /* CFG_SCM_SUPPORTED */
882