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