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