1 /*
2 * Copyright (c) 2018 Foundries.io Ltd
3 * Copyright (c) 2019 STMicroelectronics
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <soc.h>
9 #include <stm32_ll_lptim.h>
10 #include <stm32_ll_bus.h>
11 #include <stm32_ll_rcc.h>
12 #include <stm32_ll_pwr.h>
13 #include <stm32_ll_system.h>
14 #include <drivers/clock_control.h>
15 #include <drivers/clock_control/stm32_clock_control.h>
16 #include <drivers/timer/system_timer.h>
17 #include <sys_clock.h>
18
19 #include <spinlock.h>
20
21 /*
22 * Assumptions and limitations:
23 *
24 * - system clock based on an LPTIM1 instance, clocked by LSI or LSE
25 * - prescaler is set to 1 (LL_LPTIM_PRESCALER_DIV1 in the related register)
26 * - using LPTIM1 AutoReload capability to trig the IRQ (timeout irq)
27 * - when timeout irq occurs the counter is already reset
28 * - the maximum timeout duration is reached with the LPTIM_TIMEBASE value
29 * - with prescaler of 1, the max timeout (LPTIM_TIMEBASE) is 2seconds
30 */
31
32 #define LPTIM_CLOCK CONFIG_STM32_LPTIM_CLOCK
33 #define LPTIM_TIMEBASE CONFIG_STM32_LPTIM_TIMEBASE
34
35 /* nb of LPTIM counter unit per kernel tick */
36 #define COUNT_PER_TICK (LPTIM_CLOCK / CONFIG_SYS_CLOCK_TICKS_PER_SEC)
37
38 /* minimum nb of clock cycles to have to set autoreload register correctly */
39 #define LPTIM_GUARD_VALUE 2
40
41 /* A 32bit value cannot exceed 0xFFFFFFFF/LPTIM_TIMEBASE counting cycles.
42 * This is for example about of 65000 x 2000ms when clocked by LSI
43 */
44 static uint32_t accumulated_lptim_cnt;
45
46 static struct k_spinlock lock;
47
lptim_irq_handler(const struct device * unused)48 static void lptim_irq_handler(const struct device *unused)
49 {
50
51 ARG_UNUSED(unused);
52
53 if ((LL_LPTIM_IsActiveFlag_ARRM(LPTIM1) != 0)
54 && LL_LPTIM_IsEnabledIT_ARRM(LPTIM1) != 0) {
55
56 k_spinlock_key_t key = k_spin_lock(&lock);
57
58 /* do not change ARR yet, sys_clock_announce will do */
59 LL_LPTIM_ClearFLAG_ARRM(LPTIM1);
60
61 /* increase the total nb of autoreload count
62 * used in the sys_clock_cycle_get_32() function.
63 * Reading the CNT register gives a reliable value
64 */
65 uint32_t autoreload = LL_LPTIM_GetAutoReload(LPTIM1) + 1;
66
67 accumulated_lptim_cnt += autoreload;
68
69 k_spin_unlock(&lock, key);
70
71 /* announce the elapsed time in ms (count register is 16bit) */
72 uint32_t dticks = (autoreload
73 * CONFIG_SYS_CLOCK_TICKS_PER_SEC)
74 / LPTIM_CLOCK;
75
76 sys_clock_announce(IS_ENABLED(CONFIG_TICKLESS_KERNEL)
77 ? dticks : (dticks > 0));
78 }
79 }
80
sys_clock_driver_init(const struct device * dev)81 int sys_clock_driver_init(const struct device *dev)
82 {
83 ARG_UNUSED(dev);
84
85 /* enable LPTIM clock source */
86 LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_LPTIM1);
87 LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_LPTIM1);
88
89 #if defined(CONFIG_STM32_LPTIM_CLOCK_LSI)
90 /* enable LSI clock */
91 #ifdef CONFIG_SOC_SERIES_STM32WBX
92 LL_RCC_LSI1_Enable();
93 while (!LL_RCC_LSI1_IsReady()) {
94 #else
95 LL_RCC_LSI_Enable();
96 while (!LL_RCC_LSI_IsReady()) {
97 #endif /* CONFIG_SOC_SERIES_STM32WBX */
98 /* Wait for LSI ready */
99 }
100
101 LL_RCC_SetLPTIMClockSource(LL_RCC_LPTIM1_CLKSOURCE_LSI);
102
103 #else /* CONFIG_STM32_LPTIM_CLOCK_LSI */
104 #if defined(LL_APB1_GRP1_PERIPH_PWR)
105 /* Enable the power interface clock */
106 LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR);
107 #endif /* LL_APB1_GRP1_PERIPH_PWR */
108
109 /* enable backup domain */
110 LL_PWR_EnableBkUpAccess();
111
112 /* enable LSE clock */
113 LL_RCC_LSE_DisableBypass();
114 LL_RCC_LSE_Enable();
115 while (!LL_RCC_LSE_IsReady()) {
116 /* Wait for LSE ready */
117 }
118 #ifdef RCC_BDCR_LSESYSEN
119 LL_RCC_LSE_EnablePropagation();
120 #endif /* RCC_BDCR_LSESYSEN */
121 LL_RCC_SetLPTIMClockSource(LL_RCC_LPTIM1_CLKSOURCE_LSE);
122
123 #endif /* CONFIG_STM32_LPTIM_CLOCK_LSI */
124
125 /* Clear the event flag and possible pending interrupt */
126 IRQ_CONNECT(DT_IRQN(DT_NODELABEL(lptim1)),
127 DT_IRQ(DT_NODELABEL(lptim1), priority),
128 lptim_irq_handler, 0, 0);
129 irq_enable(DT_IRQN(DT_NODELABEL(lptim1)));
130
131 #ifdef CONFIG_SOC_SERIES_STM32WLX
132 /* Enable the LPTIM1 wakeup EXTI line */
133 LL_EXTI_EnableIT_0_31(LL_EXTI_LINE_29);
134 #endif
135
136 /* configure the LPTIM1 counter */
137 LL_LPTIM_SetClockSource(LPTIM1, LL_LPTIM_CLK_SOURCE_INTERNAL);
138 /* configure the LPTIM1 prescaler with 1 */
139 LL_LPTIM_SetPrescaler(LPTIM1, LL_LPTIM_PRESCALER_DIV1);
140 LL_LPTIM_SetPolarity(LPTIM1, LL_LPTIM_OUTPUT_POLARITY_REGULAR);
141 LL_LPTIM_SetUpdateMode(LPTIM1, LL_LPTIM_UPDATE_MODE_IMMEDIATE);
142 LL_LPTIM_SetCounterMode(LPTIM1, LL_LPTIM_COUNTER_MODE_INTERNAL);
143 LL_LPTIM_DisableTimeout(LPTIM1);
144 /* counting start is initiated by software */
145 LL_LPTIM_TrigSw(LPTIM1);
146
147 /* LPTIM1 interrupt set-up before enabling */
148 /* no Compare match Interrupt */
149 LL_LPTIM_DisableIT_CMPM(LPTIM1);
150 LL_LPTIM_ClearFLAG_CMPM(LPTIM1);
151
152 /* Autoreload match Interrupt */
153 LL_LPTIM_EnableIT_ARRM(LPTIM1);
154 LL_LPTIM_ClearFLAG_ARRM(LPTIM1);
155 /* ARROK bit validates the write operation to ARR register */
156 LL_LPTIM_ClearFlag_ARROK(LPTIM1);
157
158 accumulated_lptim_cnt = 0;
159
160 /* Enable the LPTIM1 counter */
161 LL_LPTIM_Enable(LPTIM1);
162
163 /* Set the Autoreload value once the timer is enabled */
164 if (IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
165 /* LPTIM1 is triggered on a LPTIM_TIMEBASE period */
166 LL_LPTIM_SetAutoReload(LPTIM1, LPTIM_TIMEBASE);
167
168 } else {
169 /* LPTIM1 is triggered on a Tick period */
170 LL_LPTIM_SetAutoReload(LPTIM1, COUNT_PER_TICK - 1);
171 }
172
173 /* Start the LPTIM counter in continuous mode */
174 LL_LPTIM_StartCounter(LPTIM1, LL_LPTIM_OPERATING_MODE_CONTINUOUS);
175
176 #ifdef CONFIG_DEBUG
177 /* stop LPTIM1 during DEBUG */
178 LL_DBGMCU_APB1_GRP1_FreezePeriph(LL_DBGMCU_APB1_GRP1_LPTIM1_STOP);
179 #endif
180 return 0;
181 }
182
183 static inline uint32_t z_clock_lptim_getcounter(void)
184 {
185 uint32_t lp_time;
186 uint32_t lp_time_prev_read;
187
188 /* It should be noted that to read reliably the content
189 * of the LPTIM_CNT register, two successive read accesses
190 * must be performed and compared
191 */
192 lp_time = LL_LPTIM_GetCounter(LPTIM1);
193 do {
194 lp_time_prev_read = lp_time;
195 lp_time = LL_LPTIM_GetCounter(LPTIM1);
196 } while (lp_time != lp_time_prev_read);
197 return lp_time;
198 }
199
200 void sys_clock_set_timeout(int32_t ticks, bool idle)
201 {
202 /* new LPTIM1 AutoReload value to set (aligned on Kernel ticks) */
203 uint32_t next_arr = 0;
204
205 ARG_UNUSED(idle);
206
207 if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
208 return;
209 }
210
211 if (ticks == K_TICKS_FOREVER) {
212 /* disable LPTIM clock to avoid counting */
213 LL_APB1_GRP1_DisableClock(LL_APB1_GRP1_PERIPH_LPTIM1);
214 return;
215 }
216
217 /* if LPTIM clock was previously stopped, it must now be restored */
218 if (!LL_APB1_GRP1_IsEnabledClock(LL_APB1_GRP1_PERIPH_LPTIM1)) {
219 LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_LPTIM1);
220 }
221
222 /* passing ticks==1 means "announce the next tick",
223 * ticks value of zero (or even negative) is legal and
224 * treated identically: it simply indicates the kernel would like the
225 * next tick announcement as soon as possible.
226 */
227 ticks = CLAMP(ticks - 1, 1, (int32_t)LPTIM_TIMEBASE);
228
229 k_spinlock_key_t key = k_spin_lock(&lock);
230
231 /* read current counter value (cannot exceed 16bit) */
232
233 uint32_t lp_time = z_clock_lptim_getcounter();
234
235 uint32_t autoreload = LL_LPTIM_GetAutoReload(LPTIM1);
236
237 if (LL_LPTIM_IsActiveFlag_ARRM(LPTIM1)
238 || ((autoreload - lp_time) < LPTIM_GUARD_VALUE)) {
239 /* interrupt happens or happens soon.
240 * It's impossible to set autoreload value.
241 */
242 k_spin_unlock(&lock, key);
243 return;
244 }
245
246 /* calculate the next arr value (cannot exceed 16bit)
247 * adjust the next ARR match value to align on Ticks
248 * from the current counter value to first next Tick
249 */
250 next_arr = (((lp_time * CONFIG_SYS_CLOCK_TICKS_PER_SEC)
251 / LPTIM_CLOCK) + 1) * LPTIM_CLOCK
252 / (CONFIG_SYS_CLOCK_TICKS_PER_SEC);
253 /* add count unit from the expected nb of Ticks */
254 next_arr = next_arr + ((uint32_t)(ticks) * LPTIM_CLOCK)
255 / CONFIG_SYS_CLOCK_TICKS_PER_SEC - 1;
256
257 /* maximise to TIMEBASE */
258 if (next_arr > LPTIM_TIMEBASE) {
259 next_arr = LPTIM_TIMEBASE;
260 }
261 /* The new autoreload value must be LPTIM_GUARD_VALUE clock cycles
262 * after current lptim to make sure we don't miss
263 * an autoreload interrupt
264 */
265 else if (next_arr < (lp_time + LPTIM_GUARD_VALUE)) {
266 next_arr = lp_time + LPTIM_GUARD_VALUE;
267 }
268
269 /* ARROK bit validates previous write operation to ARR register */
270 while (LL_LPTIM_IsActiveFlag_ARROK(LPTIM1) == 0) {
271 }
272 LL_LPTIM_ClearFlag_ARROK(LPTIM1);
273
274 /* run timer and wait for the reload match */
275 LL_LPTIM_SetAutoReload(LPTIM1, next_arr);
276
277 k_spin_unlock(&lock, key);
278 }
279
280 uint32_t sys_clock_elapsed(void)
281 {
282 if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
283 return 0;
284 }
285
286 k_spinlock_key_t key = k_spin_lock(&lock);
287
288 uint32_t lp_time = z_clock_lptim_getcounter();
289
290 /* In case of counter roll-over, add this value,
291 * even if the irq has not yet been handled
292 */
293 if ((LL_LPTIM_IsActiveFlag_ARRM(LPTIM1) != 0)
294 && LL_LPTIM_IsEnabledIT_ARRM(LPTIM1) != 0) {
295 lp_time += LL_LPTIM_GetAutoReload(LPTIM1) + 1;
296 }
297
298 k_spin_unlock(&lock, key);
299
300 /* gives the value of LPTIM1 counter (ms)
301 * since the previous 'announce'
302 */
303 uint64_t ret = ((uint64_t)lp_time * CONFIG_SYS_CLOCK_TICKS_PER_SEC) / LPTIM_CLOCK;
304
305 return (uint32_t)(ret);
306 }
307
308 uint32_t sys_clock_cycle_get_32(void)
309 {
310 /* just gives the accumulated count in a number of hw cycles */
311
312 k_spinlock_key_t key = k_spin_lock(&lock);
313
314 uint32_t lp_time = z_clock_lptim_getcounter();
315
316 /* In case of counter roll-over, add this value,
317 * even if the irq has not yet been handled
318 */
319 if ((LL_LPTIM_IsActiveFlag_ARRM(LPTIM1) != 0)
320 && LL_LPTIM_IsEnabledIT_ARRM(LPTIM1) != 0) {
321 lp_time += LL_LPTIM_GetAutoReload(LPTIM1) + 1;
322 }
323
324 lp_time += accumulated_lptim_cnt;
325
326 /* convert lptim count in a nb of hw cycles with precision */
327 uint64_t ret = ((uint64_t)lp_time * sys_clock_hw_cycles_per_sec()) / LPTIM_CLOCK;
328
329 k_spin_unlock(&lock, key);
330
331 /* convert in hw cycles (keeping 32bit value) */
332 return (uint32_t)(ret);
333 }
334