1 /*
2  *
3  * Copyright (c) 2017 Linaro Limited.
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 
9 #include <soc.h>
10 #include <stm32_ll_bus.h>
11 #include <stm32_ll_rcc.h>
12 #include <stm32_ll_utils.h>
13 #include <zephyr/drivers/clock_control.h>
14 #include <zephyr/sys/util.h>
15 #include <zephyr/drivers/clock_control/stm32_clock_control.h>
16 #include "clock_stm32_ll_common.h"
17 
18 #if defined(RCC_CFGR_USBPRE)
19 #define STM32_USB_PRE_ENABLED	RCC_CFGR_USBPRE
20 #elif defined(RCC_CFGR_OTGFSPRE)
21 #define STM32_USB_PRE_ENABLED	RCC_CFGR_OTGFSPRE
22 #endif
23 
24 #if defined(STM32_PLL_ENABLED)
25 
get_pllout_frequency(void)26 uint32_t get_pllout_frequency(void)
27 {
28 	/* Stub implementation for compatibility with clock_stm32_ll_common.
29 	 * The PLL domain clock is only used for MCO configuration, but the
30 	 * MCO driver never queries the PLL output clock frequency.
31 	 */
32 	return 0;
33 }
34 
35 /*
36  * Select PLL source for STM32F1 Connectivity line devices (STM32F105xx and
37  * STM32F107xx).
38  * Both flags are defined in STM32Cube LL API. Keep only the selected one.
39  */
40 
41 /**
42  * @brief Set up pll configuration
43  */
44 __unused
config_pll_sysclock(void)45 void config_pll_sysclock(void)
46 {
47 	uint32_t pll_source, pll_mul, pll_div;
48 
49 	/*
50 	 * PLLMUL on SOC_STM32F10X_DENSITY_DEVICE
51 	 * 2  -> LL_RCC_PLL_MUL_2  -> 0x00000000
52 	 * 3  -> LL_RCC_PLL_MUL_3  -> 0x00040000
53 	 * 4  -> LL_RCC_PLL_MUL_4  -> 0x00080000
54 	 * ...
55 	 * 16 -> LL_RCC_PLL_MUL_16 -> 0x00380000
56 	 *
57 	 * PLLMUL on SOC_STM32F10X_CONNECTIVITY_LINE_DEVICE
58 	 * 4  -> LL_RCC_PLL_MUL_4   -> 0x00080000
59 	 * ...
60 	 * 9  -> LL_RCC_PLL_MUL_9   -> 0x001C0000
61 	 * 13 -> LL_RCC_PLL_MUL_6_5 -> 0x00340000
62 	 */
63 	pll_mul = ((STM32_PLL_MULTIPLIER - 2) << RCC_CFGR_PLLMULL_Pos);
64 
65 	if (!IS_ENABLED(STM32_PLL_SRC_HSI)) {
66 		/* In case PLL source is not HSI, set prediv case by case */
67 #ifdef CONFIG_SOC_STM32F10X_DENSITY_DEVICE
68 		/* PLL prediv */
69 		if (IS_ENABLED(STM32_PLL_XTPRE)) {
70 			/*
71 			 * SOC_STM32F10X_DENSITY_DEVICE:
72 			 * PLLXPTRE (depends on PLL source HSE)
73 			 * HSE/2 used as PLL source
74 			 */
75 			pll_div = LL_RCC_PREDIV_DIV_2;
76 		} else {
77 			/*
78 			 * SOC_STM32F10X_DENSITY_DEVICE:
79 			 * PLLXPTRE (depends on PLL source HSE)
80 			 * HSE used as direct PLL source
81 			 */
82 			pll_div = LL_RCC_PREDIV_DIV_1;
83 		}
84 #else
85 		/*
86 		 * SOC_STM32F10X_CONNECTIVITY_LINE_DEVICE
87 		 * 1  -> LL_RCC_PREDIV_DIV_1  -> 0x00000000
88 		 * 2  -> LL_RCC_PREDIV_DIV_2  -> 0x00000001
89 		 * 3  -> LL_RCC_PREDIV_DIV_3  -> 0x00000002
90 		 * ...
91 		 * 16 -> LL_RCC_PREDIV_DIV_16 -> 0x0000000F
92 		 */
93 		pll_div = STM32_PLL_PREDIV - 1;
94 #endif /* CONFIG_SOC_STM32F10X_DENSITY_DEVICE */
95 	}
96 
97 	/* Configure PLL source */
98 	if (IS_ENABLED(STM32_PLL_SRC_HSI)) {
99 		pll_source = LL_RCC_PLLSOURCE_HSI_DIV_2;
100 	} else if (IS_ENABLED(STM32_PLL_SRC_HSE)) {
101 		pll_source = LL_RCC_PLLSOURCE_HSE | pll_div;
102 #if defined(RCC_CFGR2_PREDIV1SRC)
103 	} else if (IS_ENABLED(STM32_PLL_SRC_PLL2)) {
104 		pll_source = LL_RCC_PLLSOURCE_PLL2 | pll_div;
105 #endif
106 	} else {
107 		__ASSERT(0, "Invalid source");
108 	}
109 
110 	LL_RCC_PLL_ConfigDomain_SYS(pll_source, pll_mul);
111 
112 #ifdef STM32_USB_PRE_ENABLED
113 	/* Prescaler is enabled: PLL clock is not divided */
114 	LL_RCC_SetUSBClockSource(IS_ENABLED(STM32_PLL_USBPRE) ?
115 				 STM32_USB_PRE_ENABLED : 0);
116 #endif
117 }
118 
119 #endif /* defined(STM32_PLL_ENABLED) */
120 
121 #if defined(STM32_PLL2_ENABLED)
122 
123 /**
124  * @brief Set up pll2 configuration
125  */
126 __unused
config_pll2(void)127 void config_pll2(void)
128 {
129 	uint32_t pll_mul, pll_div;
130 
131 	/*
132 	 * PLL2MUL on SOC_STM32F10X_CONNECTIVITY_LINE_DEVICE
133 	 * 8  -> LL_RCC_PLL2_MUL_8  -> 0x00000600
134 	 * 9  -> LL_RCC_PLL2_MUL_9  -> 0x00000700
135 	 * ...
136 	 * 14 -> LL_RCC_PLL2_MUL_14 -> 0x00000C00
137 	 * 16 -> LL_RCC_PLL2_MUL_16 -> 0x00000E00
138 	 * 20 -> LL_RCC_PLL2_MUL_20 -> 0x00000F00
139 	 */
140 	if (STM32_PLL2_MULTIPLIER == 20) {
141 		pll_mul = RCC_CFGR2_PLL2MUL20;
142 	} else {
143 		pll_mul = ((STM32_PLL2_MULTIPLIER - 2) << RCC_CFGR2_PLL2MUL_Pos);
144 	}
145 
146 	/*
147 	 * SOC_STM32F10X_CONNECTIVITY_LINE_DEVICE
148 	 * 1  -> LL_RCC_HSE_PREDIV2_DIV_1  -> 0x00000000
149 	 * 2  -> LL_RCC_HSE_PREDIV2_DIV_2  -> 0x00000010
150 	 * ...
151 	 * 16 -> LL_RCC_HSE_PREDIV2_DIV_16 -> 0x000000F0
152 	 */
153 	pll_div = ((STM32_PLL2_PREDIV - 1) << RCC_CFGR2_PREDIV2_Pos);
154 
155 	/* Check PLL2 source */
156 	if (!IS_ENABLED(STM32_PLL2_SRC_HSE)) {
157 		__ASSERT(0, "Invalid source");
158 	}
159 
160 	LL_RCC_PLL_ConfigDomain_PLL2(pll_div, pll_mul);
161 }
162 
163 #endif /* defined(STM32_PLL2_ENABLED) */
164 
165 /**
166  * @brief Activate default clocks
167  */
config_enable_default_clocks(void)168 void config_enable_default_clocks(void)
169 {
170 	if (IS_ENABLED(STM32_LSE_ENABLED)) {
171 		/* Set the PWREN and BKPEN bits in the RCC_APB1ENR register */
172 		LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR);
173 		LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_BKP);
174 	}
175 }
176