1 /*
2  * Copyright (c) 2021 Nuvoton Technology Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT nuvoton_npcx_itim_timer
8 
9 /**
10  * @file
11  * @brief Nuvoton NPCX kernel device driver for  "system clock driver" interface
12  *
13  * This file contains a kernel device driver implemented by the internal
14  * 64/32-bit timers in Nuvoton NPCX series. Via these two kinds of timers, the
15  * driver provides an standard "system clock driver" interface.
16  *
17  * It includes:
18  * - A system timer based on an ITIM64 (Internal 64-bit timer) instance, clocked
19  *   by APB2 which freq is the same as CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC.
20  * - Provide a 64-bit cycles reading and ticks computation based on it.
21  * - Its prescaler is set to 1 and provide the kernel cycles reading without
22  *   handling overflow mechanism.
23  * - After ec entered "sleep/deep sleep" power state which is used for better
24  *   power consumption, then its clock will stop.
25  *
26  * - A event timer based on an ITIM32 (Internal 32-bit timer) instance, clocked
27  *   by LFCLK which frequency is 32KHz and still activated when ec entered
28  *   "sleep/deep sleep" power state.
29  * - Provide a system clock timeout notification. In its ISR, the driver informs
30  *   the kernel that the specified number of ticks have elapsed.
31  * - Its prescaler is set to 1 and the formula between event timer's cycles and
32  *   ticks is 'cycles = (ticks * 32768) / CONFIG_SYS_CLOCK_TICKS_PER_SEC'
33  * - Compensate reading of ITIM64 which clock is gating after ec entered
34  *   "sleep/deep sleep" power state if CONFIG_PM is enabled.
35  */
36 
37 #include <zephyr/init.h>
38 #include <zephyr/drivers/clock_control.h>
39 #include <zephyr/drivers/timer/system_timer.h>
40 #include <zephyr/kernel.h>
41 #include <zephyr/sys_clock.h>
42 #include <zephyr/spinlock.h>
43 #include <soc.h>
44 
45 #include <zephyr/logging/log.h>
46 #include <zephyr/irq.h>
47 LOG_MODULE_REGISTER(itim, LOG_LEVEL_ERR);
48 
49 #define NPCX_ITIM32_MAX_CNT 0xffffffff
50 #define NPCX_ITIM64_MAX_HALF_CNT 0xffffffff
51 #define EVT_CYCLES_PER_SEC LFCLK /* 32768 Hz */
52 #define SYS_CYCLES_PER_TICK (sys_clock_hw_cycles_per_sec() \
53 					/ CONFIG_SYS_CLOCK_TICKS_PER_SEC)
54 #define SYS_CYCLES_PER_USEC (sys_clock_hw_cycles_per_sec() / 1000000)
55 #define EVT_CYCLES_FROM_TICKS(ticks) \
56 	DIV_ROUND_UP(ticks * EVT_CYCLES_PER_SEC, \
57 			 CONFIG_SYS_CLOCK_TICKS_PER_SEC)
58 #define NPCX_ITIM_CLK_SEL_DELAY 92 /* Delay for clock selection (Unit:us) */
59 /* Timeout for enabling ITIM module: 100us (Unit:cycles) */
60 #define NPCX_ITIM_EN_TIMEOUT_CYCLES (100 * SYS_CYCLES_PER_USEC)
61 #define SYS_CYC_PER_EVT_CYC         (sys_clock_hw_cycles_per_sec() / EVT_CYCLES_PER_SEC)
62 
63 /* Instance of system and event timers */
64 static struct itim64_reg *const sys_tmr = (struct itim64_reg *)
65 					DT_INST_REG_ADDR_BY_NAME(0, sys_itim);
66 static struct itim32_reg *const evt_tmr = (struct itim32_reg *)
67 					DT_INST_REG_ADDR_BY_NAME(0, evt_itim);
68 
69 static const struct npcx_clk_cfg itim_clk_cfg[] = NPCX_DT_CLK_CFG_ITEMS_LIST(0);
70 
71 static struct k_spinlock lock;
72 /* Announced cycles in system timer before executing sys_clock_announce() */
73 static uint64_t cyc_sys_announced;
74 static uint64_t last_ticks;
75 static uint32_t last_elapsed;
76 
77 /* Current target cycles of time-out signal in event timer */
78 static uint32_t cyc_evt_timeout;
79 /* Total cycles of system timer stopped in "sleep/deep sleep" mode */
80 __unused static uint64_t cyc_sys_compensated;
81 /* Current cycles in event timer when ec entered "sleep/deep sleep" mode */
82 __unused static uint32_t cyc_evt_enter_deep_idle;
83 
84 /* ITIM local inline functions */
npcx_itim_get_sys_cyc64(void)85 static inline uint64_t npcx_itim_get_sys_cyc64(void)
86 {
87 	uint32_t cnt64h, cnt64h_check, cnt64l;
88 
89 	/* Read 64-bit counter value from two 32-bit registers */
90 	do {
91 		cnt64h_check = sys_tmr->ITCNT64H;
92 		cnt64l = sys_tmr->ITCNT64L;
93 		cnt64h = sys_tmr->ITCNT64H;
94 	} while (cnt64h != cnt64h_check);
95 
96 	cnt64h = NPCX_ITIM64_MAX_HALF_CNT - cnt64h;
97 	cnt64l = NPCX_ITIM64_MAX_HALF_CNT - cnt64l + 1;
98 
99 	/* Return current value of 64-bit counter value of system timer */
100 	if (IS_ENABLED(CONFIG_PM)) {
101 		return ((((uint64_t)cnt64h) << 32) | cnt64l) +
102 							cyc_sys_compensated;
103 	} else {
104 		return (((uint64_t)cnt64h) << 32) | cnt64l;
105 	}
106 }
107 
npcx_itim_evt_enable(void)108 static inline int npcx_itim_evt_enable(void)
109 {
110 	uint64_t cyc_start;
111 
112 	/* Enable event timer and wait for it to take effect */
113 	evt_tmr->ITCTS32 |= BIT(NPCX_ITCTSXX_ITEN);
114 
115 	/*
116 	 * Usually, it need one clock (30.5 us) to take effect since
117 	 * asynchronization between core and itim32's source clock (LFCLK).
118 	 */
119 	cyc_start = npcx_itim_get_sys_cyc64();
120 	while (!IS_BIT_SET(evt_tmr->ITCTS32, NPCX_ITCTSXX_ITEN)) {
121 		if (npcx_itim_get_sys_cyc64() - cyc_start >
122 						NPCX_ITIM_EN_TIMEOUT_CYCLES) {
123 			/* ITEN bit is still unset? */
124 			if (!IS_BIT_SET(evt_tmr->ITCTS32, NPCX_ITCTSXX_ITEN)) {
125 				LOG_ERR("Timeout: enabling EVT timer!");
126 				return -ETIMEDOUT;
127 			}
128 		}
129 	}
130 
131 	return 0;
132 }
133 
npcx_itim_evt_disable(void)134 static inline void npcx_itim_evt_disable(void)
135 {
136 	/* Disable event timer and no need to wait for it to take effect */
137 	evt_tmr->ITCTS32 &= ~BIT(NPCX_ITCTSXX_ITEN);
138 }
139 
140 /* ITIM local functions */
npcx_itim_start_evt_tmr_by_tick(int32_t ticks)141 static int npcx_itim_start_evt_tmr_by_tick(int32_t ticks)
142 {
143 	/*
144 	 * Get desired cycles of event timer from the requested ticks which
145 	 * round up to next tick boundary.
146 	 */
147 
148 	if (ticks == K_TICKS_FOREVER) {
149 		cyc_evt_timeout = NPCX_ITIM32_MAX_CNT;
150 	} else {
151 		uint64_t next_cycs;
152 		uint64_t curr = npcx_itim_get_sys_cyc64();
153 		uint64_t dcycles;
154 
155 		if (ticks <= 0) {
156 			ticks = 1;
157 		}
158 
159 		next_cycs = (last_ticks + last_elapsed + ticks) * SYS_CYCLES_PER_TICK;
160 		if (unlikely(next_cycs <= curr)) {
161 			cyc_evt_timeout = 1;
162 		} else {
163 			uint32_t dticks;
164 
165 			dcycles = next_cycs - curr;
166 			dticks = DIV_ROUND_UP(dcycles * EVT_CYCLES_PER_SEC,
167 					      sys_clock_hw_cycles_per_sec());
168 			cyc_evt_timeout = CLAMP(dticks, 1, NPCX_ITIM32_MAX_CNT);
169 		}
170 	}
171 	LOG_DBG("ticks %x, cyc_evt_timeout %x", ticks, cyc_evt_timeout);
172 
173 	/* Disable event timer if needed before configuring counter */
174 	if (IS_BIT_SET(evt_tmr->ITCTS32, NPCX_ITCTSXX_ITEN)) {
175 		npcx_itim_evt_disable();
176 	}
177 
178 	/* Upload counter of event timer */
179 	evt_tmr->ITCNT32 = MAX(cyc_evt_timeout - 1, 1);
180 
181 	/* Enable event timer and start ticking */
182 	return npcx_itim_evt_enable();
183 }
184 
npcx_itim_evt_isr(const struct device * dev)185 static void npcx_itim_evt_isr(const struct device *dev)
186 {
187 	ARG_UNUSED(dev);
188 
189 	/* Disable ITIM event module first */
190 	npcx_itim_evt_disable();
191 	/* Clear timeout status for event */
192 	evt_tmr->ITCTS32 |= BIT(NPCX_ITCTSXX_TO_STS);
193 
194 	if (IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
195 		k_spinlock_key_t key = k_spin_lock(&lock);
196 		uint64_t curr = npcx_itim_get_sys_cyc64();
197 		uint32_t delta_ticks = (uint32_t)((curr - cyc_sys_announced) / SYS_CYCLES_PER_TICK);
198 
199 		cyc_sys_announced += delta_ticks * SYS_CYCLES_PER_TICK;
200 		last_ticks += delta_ticks;
201 		last_elapsed = 0;
202 		k_spin_unlock(&lock, key);
203 
204 		/* Informs kernel that specified number of ticks have elapsed */
205 		sys_clock_announce(delta_ticks);
206 	} else {
207 		/* Enable event timer for ticking and wait to it take effect */
208 		npcx_itim_evt_enable();
209 
210 		/* Informs kernel that one tick has elapsed */
211 		sys_clock_announce(1);
212 	}
213 }
214 
215 #if defined(CONFIG_PM)
npcx_itim_get_evt_cyc32(void)216 static inline uint32_t npcx_itim_get_evt_cyc32(void)
217 {
218 	uint32_t cnt1, cnt2;
219 
220 	__asm__ volatile(
221 		"ldr    %[c2], [%[tmr], %[itcnt32_off]]\n\t"
222 		".read_itim_cnt_loop_%=:\n\t"
223 		"mov    %[c1], %[c2]\n\t"
224 		"ldr    %[c2], [%[tmr], %[itcnt32_off]]\n\t"
225 		"nop\n\t"
226 		"nop\n\t"
227 		"cmp    %[c1], %[c2]\n\t"
228 		"bne    .read_itim_cnt_loop_%=\n\t"
229 		: [c1] "=&r"(cnt1), [c2] "=&r"(cnt2)
230 		: [tmr] "r"(evt_tmr), [itcnt32_off] "i"(offsetof(struct itim32_reg, ITCNT32))
231 		: "memory");
232 	/* Return current value of 32-bit counter of event timer  */
233 	return cnt2;
234 }
235 
npcx_itim_evt_elapsed_cyc32(void)236 static uint32_t npcx_itim_evt_elapsed_cyc32(void)
237 {
238 	uint32_t cnt1 = npcx_itim_get_evt_cyc32();
239 	uint8_t  sys_cts = evt_tmr->ITCTS32;
240 	uint32_t cnt2 = npcx_itim_get_evt_cyc32();
241 
242 	/* Event has been triggered but timer ISR doesn't handle it */
243 	if (IS_BIT_SET(sys_cts, NPCX_ITCTSXX_TO_STS) || (cnt2 > cnt1)) {
244 		cnt2 = cyc_evt_timeout;
245 	} else {
246 		cnt2 = cyc_evt_timeout - cnt2 - 1;
247 	}
248 
249 	/* Return elapsed cycles of 32-bit counter of event timer  */
250 	return cnt2;
251 }
252 #endif /* CONFIG_PM */
253 
254 /* System timer api functions */
sys_clock_set_timeout(int32_t ticks,bool idle)255 void sys_clock_set_timeout(int32_t ticks, bool idle)
256 {
257 	ARG_UNUSED(idle);
258 
259 	if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
260 		/* Only for tickless kernel system */
261 		return;
262 	}
263 
264 	LOG_DBG("timeout is %d", ticks);
265 	/* Start a event timer in ticks */
266 
267 	k_spinlock_key_t key = k_spin_lock(&lock);
268 	npcx_itim_start_evt_tmr_by_tick(ticks);
269 	k_spin_unlock(&lock, key);
270 }
271 
sys_clock_elapsed(void)272 uint32_t sys_clock_elapsed(void)
273 {
274 	if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
275 		/* Always return 0 for tickful kernel system */
276 		return 0;
277 	}
278 
279 	k_spinlock_key_t key = k_spin_lock(&lock);
280 	uint64_t delta_cycle = npcx_itim_get_sys_cyc64() - cyc_sys_announced;
281 	uint32_t delta_ticks = (uint32_t)(delta_cycle / SYS_CYCLES_PER_TICK);
282 
283 	last_elapsed = delta_ticks;
284 	k_spin_unlock(&lock, key);
285 
286 	/* Return how many ticks elapsed since last sys_clock_announce() call */
287 	return delta_ticks;
288 }
289 
sys_clock_cycle_get_32(void)290 uint32_t sys_clock_cycle_get_32(void)
291 {
292 	k_spinlock_key_t key = k_spin_lock(&lock);
293 	uint64_t current = npcx_itim_get_sys_cyc64();
294 
295 	k_spin_unlock(&lock, key);
296 
297 	/* Return how many cycles since system kernel timer start counting */
298 	return (uint32_t)(current);
299 }
300 
sys_clock_cycle_get_64(void)301 uint64_t sys_clock_cycle_get_64(void)
302 {
303 	k_spinlock_key_t key = k_spin_lock(&lock);
304 	uint64_t current = npcx_itim_get_sys_cyc64();
305 
306 	k_spin_unlock(&lock, key);
307 
308 	/* Return how many cycles since system kernel timer start counting */
309 	return current;
310 }
311 
312 /* Platform specific system timer functions */
313 #if defined(CONFIG_PM)
npcx_clock_capture_low_freq_timer(void)314 void npcx_clock_capture_low_freq_timer(void)
315 {
316 	cyc_evt_enter_deep_idle = npcx_itim_evt_elapsed_cyc32();
317 }
318 
npcx_clock_compensate_system_timer(void)319 void npcx_clock_compensate_system_timer(void)
320 {
321 	uint32_t cyc_evt_elapsed_in_deep = npcx_itim_evt_elapsed_cyc32() -
322 							cyc_evt_enter_deep_idle;
323 
324 	cyc_sys_compensated += ((uint64_t)cyc_evt_elapsed_in_deep *
325 			sys_clock_hw_cycles_per_sec()) / EVT_CYCLES_PER_SEC;
326 }
327 
npcx_clock_get_sleep_ticks(void)328 uint64_t npcx_clock_get_sleep_ticks(void)
329 {
330 	return  cyc_sys_compensated / SYS_CYCLES_PER_TICK;
331 }
332 #endif /* CONFIG_PM */
333 
sys_clock_driver_init(void)334 static int sys_clock_driver_init(void)
335 {
336 	int ret;
337 	uint32_t sys_tmr_rate;
338 	const struct device *const clk_dev = DEVICE_DT_GET(NPCX_CLK_CTRL_NODE);
339 
340 	if (!device_is_ready(clk_dev)) {
341 		LOG_ERR("clock control device not ready");
342 		return -ENODEV;
343 	}
344 
345 	/* Turn on all itim module clocks used for counting */
346 	for (int i = 0; i < ARRAY_SIZE(itim_clk_cfg); i++) {
347 		ret = clock_control_on(clk_dev, (clock_control_subsys_t)
348 				&itim_clk_cfg[i]);
349 		if (ret < 0) {
350 			LOG_ERR("Turn on timer %d clock failed.", i);
351 			return ret;
352 		}
353 	}
354 
355 	/*
356 	 * In npcx series, we use ITIM64 as system kernel timer. Its source
357 	 * clock frequency must equal to CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC.
358 	 */
359 	ret = clock_control_get_rate(clk_dev, (clock_control_subsys_t)
360 			&itim_clk_cfg[1], &sys_tmr_rate);
361 	if (ret < 0) {
362 		LOG_ERR("Get ITIM64 clock rate failed %d", ret);
363 		return ret;
364 	}
365 
366 	if (sys_tmr_rate != CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC) {
367 		LOG_ERR("CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC doesn't match "
368 			"ITIM64 clock frequency %d", sys_tmr_rate);
369 		return -EINVAL;
370 	}
371 
372 	/*
373 	 * Step 1. Use a ITIM64 timer as system kernel timer for counting.
374 	 * Configure 64-bit timer counter and its prescaler to 1 first.
375 	 */
376 	sys_tmr->ITPRE64 = 0;
377 	sys_tmr->ITCNT64L = NPCX_ITIM64_MAX_HALF_CNT;
378 	sys_tmr->ITCNT64H = NPCX_ITIM64_MAX_HALF_CNT;
379 	/*
380 	 * Select APB2 clock which freq is CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC,
381 	 * and clear timeout status bit before enabling the whole module.
382 	 */
383 	sys_tmr->ITCTS64 = BIT(NPCX_ITCTSXX_TO_STS);
384 	/* Enable 64-bit timer and start ticking */
385 	sys_tmr->ITCTS64 |= BIT(NPCX_ITCTSXX_ITEN);
386 
387 	/*
388 	 * Step 2. Use a ITIM32 timer for event handling (ex. timeout event).
389 	 * Configure 32-bit timer's prescaler to 1 first.
390 	 */
391 	evt_tmr->ITPRE32 = 0;
392 	/*
393 	 * Select low frequency clock source (The freq is 32kHz), enable its
394 	 * interrupt/wake-up sources, and clear timeout status bit before
395 	 * enabling it.
396 	 */
397 	evt_tmr->ITCTS32 = BIT(NPCX_ITCTSXX_CKSEL) | BIT(NPCX_ITCTSXX_TO_WUE)
398 			 | BIT(NPCX_ITCTSXX_TO_IE) | BIT(NPCX_ITCTSXX_TO_STS);
399 
400 	/* A delay for ITIM source clock selection */
401 	k_busy_wait(NPCX_ITIM_CLK_SEL_DELAY);
402 
403 	/* Configure event timer's ISR */
404 	IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority),
405 					npcx_itim_evt_isr, NULL, 0);
406 	/* Enable event timer interrupt */
407 	irq_enable(DT_INST_IRQN(0));
408 
409 	if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
410 		/* Start a event timer in one tick */
411 		ret = npcx_itim_start_evt_tmr_by_tick(1);
412 		if (ret < 0) {
413 			return ret;
414 		}
415 	}
416 
417 	return 0;
418 }
419 SYS_INIT(sys_clock_driver_init, PRE_KERNEL_2,
420 	 CONFIG_SYSTEM_CLOCK_INIT_PRIORITY);
421