1 /*
2  * Copyright (c) 2018 omSquare s.r.o.
3  * Copyright (c) 2024 Gerson Fernando Budke <nandojve@gmail.com>
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #define DT_DRV_COMPAT atmel_sam0_rtc
9 
10 /**
11  * @file
12  * @brief Atmel SAM0 series RTC-based system timer
13  *
14  * This system timer implementation supports both tickless and ticking modes.
15  * In tickless mode, RTC counts continually in 32-bit mode and timeouts are
16  * scheduled using the RTC comparator. In ticking mode, RTC is configured to
17  * generate an interrupt every tick.
18  */
19 
20 #include <zephyr/init.h>
21 #include <soc.h>
22 #include <zephyr/drivers/clock_control.h>
23 #include <zephyr/drivers/timer/system_timer.h>
24 #include <zephyr/drivers/pinctrl.h>
25 #include <zephyr/sys_clock.h>
26 #include <zephyr/irq.h>
27 #include <zephyr/sys/util.h>
28 
29 /* clang-format off */
30 
31 /* RTC registers. */
32 #define RTC0 ((RtcMode0 *) DT_INST_REG_ADDR(0))
33 
34 #ifdef MCLK
35 #define RTC_CLOCK_HW_CYCLES_PER_SEC SOC_ATMEL_SAM0_OSC32K_FREQ_HZ
36 #else
37 #define RTC_CLOCK_HW_CYCLES_PER_SEC SOC_ATMEL_SAM0_GCLK0_FREQ_HZ
38 #endif
39 
40 /* Number of sys timer cycles per on tick. */
41 #define CYCLES_PER_TICK (RTC_CLOCK_HW_CYCLES_PER_SEC \
42 			 / CONFIG_SYS_CLOCK_TICKS_PER_SEC)
43 
44 /* Maximum number of ticks. */
45 #define MAX_TICKS (UINT32_MAX / CYCLES_PER_TICK - 2)
46 
47 #ifdef CONFIG_TICKLESS_KERNEL
48 
49 /*
50  * Due to the nature of clock synchronization, reading from or writing to some
51  * RTC registers takes approximately six RTC_GCLK cycles. This constant defines
52  * a safe threshold for the comparator.
53  */
54 #define TICK_THRESHOLD 7
55 
56 BUILD_ASSERT(CYCLES_PER_TICK > TICK_THRESHOLD,
57 	     "CYCLES_PER_TICK must be greater than TICK_THRESHOLD for "
58 	     "tickless mode");
59 
60 #else /* !CONFIG_TICKLESS_KERNEL */
61 
62 /*
63  * For some reason, RTC does not generate interrupts when COMP == 0,
64  * MATCHCLR == 1 and PRESCALER == 0. So we need to check that CYCLES_PER_TICK
65  * is more than one.
66  */
67 BUILD_ASSERT(CYCLES_PER_TICK > 1,
68 	     "CYCLES_PER_TICK must be greater than 1 for ticking mode");
69 
70 #endif /* CONFIG_TICKLESS_KERNEL */
71 
72 /* Tick/cycle count of the last announce call. */
73 static volatile uint32_t rtc_last;
74 
75 #ifndef CONFIG_TICKLESS_KERNEL
76 
77 /* Current tick count. */
78 static volatile uint32_t rtc_counter;
79 
80 /* Tick value of the next timeout. */
81 static volatile uint32_t rtc_timeout;
82 
83 PINCTRL_DT_INST_DEFINE(0);
84 static const struct pinctrl_dev_config *pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0);
85 
86 #endif /* CONFIG_TICKLESS_KERNEL */
87 
88 /*
89  * Waits for RTC bus synchronization.
90  */
rtc_sync(void)91 static inline void rtc_sync(void)
92 {
93 	/* Wait for bus synchronization... */
94 #ifdef RTC_STATUS_SYNCBUSY
95 	while (RTC0->STATUS.reg & RTC_STATUS_SYNCBUSY) {
96 	}
97 #else
98 	while (RTC0->SYNCBUSY.reg) {
99 	}
100 #endif
101 }
102 
103 /*
104  * Reads RTC COUNT register. First a read request must be written to READREQ,
105  * then - when bus synchronization completes - the COUNT register is read and
106  * returned.
107  */
rtc_count(void)108 static uint32_t rtc_count(void)
109 {
110 #ifdef RTC_READREQ_RREQ
111 	RTC0->READREQ.reg = RTC_READREQ_RREQ;
112 #endif
113 	rtc_sync();
114 	return RTC0->COUNT.reg;
115 }
116 
rtc_reset(void)117 static void rtc_reset(void)
118 {
119 	rtc_sync();
120 
121 	/* Disable interrupt. */
122 	RTC0->INTENCLR.reg = RTC_MODE0_INTENCLR_MASK;
123 	/* Clear interrupt flag. */
124 	RTC0->INTFLAG.reg = RTC_MODE0_INTFLAG_MASK;
125 
126 	/* Disable RTC module. */
127 #ifdef RTC_MODE0_CTRL_ENABLE
128 	RTC0->CTRL.reg &= ~RTC_MODE0_CTRL_ENABLE;
129 #else
130 	RTC0->CTRLA.reg &= ~RTC_MODE0_CTRLA_ENABLE;
131 #endif
132 
133 	rtc_sync();
134 
135 	/* Initiate software reset. */
136 #ifdef RTC_MODE0_CTRL_SWRST
137 	RTC0->CTRL.bit.SWRST = 1;
138 	while (RTC0->CTRL.bit.SWRST) {
139 	}
140 #else
141 	RTC0->CTRLA.bit.SWRST = 1;
142 	while (RTC0->CTRLA.bit.SWRST) {
143 	}
144 #endif
145 }
146 
rtc_isr(const void * arg)147 static void rtc_isr(const void *arg)
148 {
149 	ARG_UNUSED(arg);
150 
151 	/* Read and clear the interrupt flag register. */
152 	uint16_t status = RTC0->INTFLAG.reg;
153 
154 	RTC0->INTFLAG.reg = status;
155 
156 #ifdef CONFIG_TICKLESS_KERNEL
157 
158 	/* Read the current counter and announce the elapsed time in ticks. */
159 	uint32_t count = rtc_count();
160 
161 	if (count != rtc_last) {
162 		uint32_t ticks = (count - rtc_last) / CYCLES_PER_TICK;
163 
164 		sys_clock_announce(ticks);
165 		rtc_last += ticks * CYCLES_PER_TICK;
166 	}
167 
168 #else /* !CONFIG_TICKLESS_KERNEL */
169 
170 	if (status) {
171 		/* RTC just ticked one more tick... */
172 		if (++rtc_counter == rtc_timeout) {
173 			sys_clock_announce(rtc_counter - rtc_last);
174 			rtc_last = rtc_counter;
175 		}
176 	} else {
177 		/* ISR was invoked directly from sys_clock_set_timeout. */
178 		sys_clock_announce(0);
179 	}
180 
181 #endif /* CONFIG_TICKLESS_KERNEL */
182 }
183 
sys_clock_set_timeout(int32_t ticks,bool idle)184 void sys_clock_set_timeout(int32_t ticks, bool idle)
185 {
186 	ARG_UNUSED(idle);
187 
188 #ifdef CONFIG_TICKLESS_KERNEL
189 
190 	ticks = (ticks == K_TICKS_FOREVER) ? MAX_TICKS : ticks;
191 	ticks = CLAMP(ticks - 1, 0, (int32_t) MAX_TICKS);
192 
193 	/* Compute number of RTC cycles until the next timeout. */
194 	uint32_t count = rtc_count();
195 	uint32_t timeout = ticks * CYCLES_PER_TICK + count % CYCLES_PER_TICK;
196 
197 	/* Round to the nearest tick boundary. */
198 	timeout = DIV_ROUND_UP(timeout, CYCLES_PER_TICK) * CYCLES_PER_TICK;
199 
200 	if (timeout < TICK_THRESHOLD) {
201 		timeout += CYCLES_PER_TICK;
202 	}
203 
204 	rtc_sync();
205 	RTC0->COMP[0].reg = count + timeout;
206 
207 #else /* !CONFIG_TICKLESS_KERNEL */
208 
209 	if (ticks == K_TICKS_FOREVER) {
210 		/* Disable comparator for K_TICKS_FOREVER and other negative
211 		 * values.
212 		 */
213 		rtc_timeout = rtc_counter;
214 		return;
215 	}
216 
217 	if (ticks < 1) {
218 		ticks = 1;
219 	}
220 
221 	/* Avoid race condition between reading counter and ISR incrementing
222 	 * it.
223 	 */
224 	unsigned int key = irq_lock();
225 
226 	rtc_timeout = rtc_counter + ticks;
227 	irq_unlock(key);
228 
229 #endif /* CONFIG_TICKLESS_KERNEL */
230 }
231 
sys_clock_elapsed(void)232 uint32_t sys_clock_elapsed(void)
233 {
234 #ifdef CONFIG_TICKLESS_KERNEL
235 	return (rtc_count() - rtc_last) / CYCLES_PER_TICK;
236 #else
237 	return rtc_counter - rtc_last;
238 #endif
239 }
240 
sys_clock_cycle_get_32(void)241 uint32_t sys_clock_cycle_get_32(void)
242 {
243 	/* Just return the absolute value of RTC cycle counter. */
244 	return rtc_count();
245 }
246 
247 #define ASSIGNED_CLOCKS_CELL_BY_NAME						\
248 	ATMEL_SAM0_DT_INST_ASSIGNED_CLOCKS_CELL_BY_NAME
249 
sys_clock_driver_init(void)250 static int sys_clock_driver_init(void)
251 {
252 	volatile uint32_t *mclk = ATMEL_SAM0_DT_INST_MCLK_PM_REG_ADDR_OFFSET(0);
253 	uint32_t mclk_mask = ATMEL_SAM0_DT_INST_MCLK_PM_PERIPH_MASK(0, bit);
254 
255 	*mclk |= mclk_mask;
256 
257 #ifdef MCLK
258 	OSC32KCTRL->RTCCTRL.reg = OSC32KCTRL_RTCCTRL_RTCSEL_ULP32K;
259 #else
260 	GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN
261 			  | GCLK_CLKCTRL_GEN(ASSIGNED_CLOCKS_CELL_BY_NAME(0, gclk, gen))
262 			  | GCLK_CLKCTRL_ID(DT_INST_CLOCKS_CELL_BY_NAME(0, gclk, id));
263 
264 	/* Synchronize GCLK. */
265 	while (GCLK->STATUS.bit.SYNCBUSY) {
266 	}
267 #endif
268 
269 #ifndef CONFIG_TICKLESS_KERNEL
270 	int retval = pinctrl_apply_state(pcfg, PINCTRL_STATE_DEFAULT);
271 
272 	if (retval < 0 && retval != -ENOENT) {
273 		return retval;
274 	}
275 #endif
276 
277 	/* Reset module to hardware defaults. */
278 	rtc_reset();
279 
280 	rtc_last = 0U;
281 
282 	/* Configure RTC with 32-bit mode, configured prescaler and MATCHCLR. */
283 #ifdef RTC_MODE0_CTRL_MODE
284 	uint16_t ctrl = RTC_MODE0_CTRL_MODE(0) | RTC_MODE0_CTRL_PRESCALER(0);
285 #else
286 	uint16_t ctrl = RTC_MODE0_CTRLA_MODE(0) | RTC_MODE0_CTRLA_PRESCALER(0);
287 #endif
288 
289 #ifdef RTC_MODE0_CTRLA_COUNTSYNC
290 	ctrl |= RTC_MODE0_CTRLA_COUNTSYNC;
291 #endif
292 
293 #ifndef CONFIG_TICKLESS_KERNEL
294 #ifdef RTC_MODE0_CTRL_MATCHCLR
295 	ctrl |= RTC_MODE0_CTRL_MATCHCLR;
296 #else
297 	ctrl |= RTC_MODE0_CTRLA_MATCHCLR;
298 #endif
299 #endif
300 	rtc_sync();
301 #ifdef RTC_MODE0_CTRL_MODE
302 	RTC0->CTRL.reg = ctrl;
303 #else
304 	RTC0->CTRLA.reg = ctrl;
305 #endif
306 
307 #ifdef CONFIG_TICKLESS_KERNEL
308 	/* Tickless kernel lets RTC count continually and ignores overflows. */
309 	RTC0->INTENSET.reg = RTC_MODE0_INTENSET_CMP0;
310 #else
311 	/* Non-tickless mode uses comparator together with MATCHCLR. */
312 	rtc_sync();
313 	RTC0->COMP[0].reg = CYCLES_PER_TICK;
314 	RTC0->INTENSET.reg = RTC_MODE0_INTENSET_OVF;
315 	rtc_counter = 0U;
316 	rtc_timeout = 0U;
317 #endif
318 
319 	/* Enable RTC module. */
320 	rtc_sync();
321 #ifdef RTC_MODE0_CTRL_ENABLE
322 	RTC0->CTRL.reg |= RTC_MODE0_CTRL_ENABLE;
323 #else
324 	RTC0->CTRLA.reg |= RTC_MODE0_CTRLA_ENABLE;
325 #endif
326 
327 	/* Enable RTC interrupt. */
328 	NVIC_ClearPendingIRQ(DT_INST_IRQN(0));
329 	IRQ_CONNECT(DT_INST_IRQN(0),
330 		    DT_INST_IRQ(0, priority), rtc_isr, 0, 0);
331 	irq_enable(DT_INST_IRQN(0));
332 
333 	return 0;
334 }
335 
336 SYS_INIT(sys_clock_driver_init, PRE_KERNEL_2,
337 	 CONFIG_SYSTEM_CLOCK_INIT_PRIORITY);
338 
339 /* clang-format on */
340