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 k_spinlock_key_t key = k_spin_lock(&lock);
144
145 /*
146 * Get desired cycles of event timer from the requested ticks which
147 * round up to next tick boundary.
148 */
149
150 if (ticks == K_TICKS_FOREVER) {
151 cyc_evt_timeout = NPCX_ITIM32_MAX_CNT;
152 } else {
153 uint64_t next_cycs;
154 uint64_t curr = npcx_itim_get_sys_cyc64();
155 uint32_t dcycles;
156
157 if (ticks <= 0) {
158 ticks = 1;
159 }
160
161 next_cycs = (last_ticks + last_elapsed + ticks) * SYS_CYCLES_PER_TICK;
162 if (unlikely(next_cycs <= curr)) {
163 cyc_evt_timeout = 1;
164 } else {
165 dcycles = next_cycs - curr;
166 cyc_evt_timeout =
167 CLAMP((dcycles / SYS_CYC_PER_EVT_CYC), 1, NPCX_ITIM32_MAX_CNT);
168 }
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 k_spin_unlock(&lock, key);
182 /* Enable event timer and start ticking */
183 return npcx_itim_evt_enable();
184 }
185
npcx_itim_evt_isr(const struct device * dev)186 static void npcx_itim_evt_isr(const struct device *dev)
187 {
188 ARG_UNUSED(dev);
189
190 /* Disable ITIM event module first */
191 npcx_itim_evt_disable();
192 /* Clear timeout status for event */
193 evt_tmr->ITCTS32 |= BIT(NPCX_ITCTSXX_TO_STS);
194
195 if (IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
196 k_spinlock_key_t key = k_spin_lock(&lock);
197 uint64_t curr = npcx_itim_get_sys_cyc64();
198 uint32_t delta_ticks = (uint32_t)((curr - cyc_sys_announced) / SYS_CYCLES_PER_TICK);
199
200 cyc_sys_announced += delta_ticks * SYS_CYCLES_PER_TICK;
201 last_ticks += delta_ticks;
202 last_elapsed = 0;
203 k_spin_unlock(&lock, key);
204
205 /* Informs kernel that specified number of ticks have elapsed */
206 sys_clock_announce(delta_ticks);
207 } else {
208 /* Enable event timer for ticking and wait to it take effect */
209 npcx_itim_evt_enable();
210
211 /* Informs kernel that one tick has elapsed */
212 sys_clock_announce(1);
213 }
214 }
215
216 #if defined(CONFIG_PM)
npcx_itim_get_evt_cyc32(void)217 static inline uint32_t npcx_itim_get_evt_cyc32(void)
218 {
219 uint32_t cnt1, cnt2;
220
221 cnt1 = evt_tmr->ITCNT32;
222 /*
223 * Wait for two consecutive equal values are read since the source clock
224 * of event timer is 32KHz.
225 */
226 while ((cnt2 = evt_tmr->ITCNT32) != cnt1)
227 cnt1 = cnt2;
228
229 /* Return current value of 32-bit counter of event timer */
230 return cnt2;
231 }
232
npcx_itim_evt_elapsed_cyc32(void)233 static uint32_t npcx_itim_evt_elapsed_cyc32(void)
234 {
235 uint32_t cnt1 = npcx_itim_get_evt_cyc32();
236 uint8_t sys_cts = evt_tmr->ITCTS32;
237 uint16_t cnt2 = npcx_itim_get_evt_cyc32();
238
239 /* Event has been triggered but timer ISR doesn't handle it */
240 if (IS_BIT_SET(sys_cts, NPCX_ITCTSXX_TO_STS) || (cnt2 > cnt1)) {
241 cnt2 = cyc_evt_timeout;
242 } else {
243 cnt2 = cyc_evt_timeout - cnt2;
244 }
245
246 /* Return elapsed cycles of 32-bit counter of event timer */
247 return cnt2;
248 }
249 #endif /* CONFIG_PM */
250
251 /* System timer api functions */
sys_clock_set_timeout(int32_t ticks,bool idle)252 void sys_clock_set_timeout(int32_t ticks, bool idle)
253 {
254 ARG_UNUSED(idle);
255
256 if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
257 /* Only for tickless kernel system */
258 return;
259 }
260
261 LOG_DBG("timeout is %d", ticks);
262 /* Start a event timer in ticks */
263 npcx_itim_start_evt_tmr_by_tick(ticks);
264 }
265
sys_clock_elapsed(void)266 uint32_t sys_clock_elapsed(void)
267 {
268 if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
269 /* Always return 0 for tickful kernel system */
270 return 0;
271 }
272
273 k_spinlock_key_t key = k_spin_lock(&lock);
274 uint64_t delta_cycle = npcx_itim_get_sys_cyc64() - cyc_sys_announced;
275 uint32_t delta_ticks = (uint32_t)delta_cycle / SYS_CYCLES_PER_TICK;
276
277 last_elapsed = delta_ticks;
278 k_spin_unlock(&lock, key);
279
280 /* Return how many ticks elapsed since last sys_clock_announce() call */
281 return delta_ticks;
282 }
283
sys_clock_cycle_get_32(void)284 uint32_t sys_clock_cycle_get_32(void)
285 {
286 k_spinlock_key_t key = k_spin_lock(&lock);
287 uint64_t current = npcx_itim_get_sys_cyc64();
288
289 k_spin_unlock(&lock, key);
290
291 /* Return how many cycles since system kernel timer start counting */
292 return (uint32_t)(current);
293 }
294
sys_clock_cycle_get_64(void)295 uint64_t sys_clock_cycle_get_64(void)
296 {
297 k_spinlock_key_t key = k_spin_lock(&lock);
298 uint64_t current = npcx_itim_get_sys_cyc64();
299
300 k_spin_unlock(&lock, key);
301
302 /* Return how many cycles since system kernel timer start counting */
303 return current;
304 }
305
306 /* Platform specific system timer functions */
307 #if defined(CONFIG_PM)
npcx_clock_capture_low_freq_timer(void)308 void npcx_clock_capture_low_freq_timer(void)
309 {
310 cyc_evt_enter_deep_idle = npcx_itim_evt_elapsed_cyc32();
311 }
312
npcx_clock_compensate_system_timer(void)313 void npcx_clock_compensate_system_timer(void)
314 {
315 uint32_t cyc_evt_elapsed_in_deep = npcx_itim_evt_elapsed_cyc32() -
316 cyc_evt_enter_deep_idle;
317
318 cyc_sys_compensated += ((uint64_t)cyc_evt_elapsed_in_deep *
319 sys_clock_hw_cycles_per_sec()) / EVT_CYCLES_PER_SEC;
320 }
321
npcx_clock_get_sleep_ticks(void)322 uint64_t npcx_clock_get_sleep_ticks(void)
323 {
324 return cyc_sys_compensated / SYS_CYCLES_PER_TICK;
325 }
326 #endif /* CONFIG_PM */
327
sys_clock_driver_init(void)328 static int sys_clock_driver_init(void)
329 {
330 int ret;
331 uint32_t sys_tmr_rate;
332 const struct device *const clk_dev = DEVICE_DT_GET(NPCX_CLK_CTRL_NODE);
333
334 if (!device_is_ready(clk_dev)) {
335 LOG_ERR("clock control device not ready");
336 return -ENODEV;
337 }
338
339 /* Turn on all itim module clocks used for counting */
340 for (int i = 0; i < ARRAY_SIZE(itim_clk_cfg); i++) {
341 ret = clock_control_on(clk_dev, (clock_control_subsys_t)
342 &itim_clk_cfg[i]);
343 if (ret < 0) {
344 LOG_ERR("Turn on timer %d clock failed.", i);
345 return ret;
346 }
347 }
348
349 /*
350 * In npcx series, we use ITIM64 as system kernel timer. Its source
351 * clock frequency must equal to CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC.
352 */
353 ret = clock_control_get_rate(clk_dev, (clock_control_subsys_t)
354 &itim_clk_cfg[1], &sys_tmr_rate);
355 if (ret < 0) {
356 LOG_ERR("Get ITIM64 clock rate failed %d", ret);
357 return ret;
358 }
359
360 if (sys_tmr_rate != CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC) {
361 LOG_ERR("CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC doesn't match "
362 "ITIM64 clock frequency %d", sys_tmr_rate);
363 return -EINVAL;
364 }
365
366 /*
367 * Step 1. Use a ITIM64 timer as system kernel timer for counting.
368 * Configure 64-bit timer counter and its prescaler to 1 first.
369 */
370 sys_tmr->ITPRE64 = 0;
371 sys_tmr->ITCNT64L = NPCX_ITIM64_MAX_HALF_CNT;
372 sys_tmr->ITCNT64H = NPCX_ITIM64_MAX_HALF_CNT;
373 /*
374 * Select APB2 clock which freq is CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC,
375 * and clear timeout status bit before enabling the whole module.
376 */
377 sys_tmr->ITCTS64 = BIT(NPCX_ITCTSXX_TO_STS);
378 /* Enable 64-bit timer and start ticking */
379 sys_tmr->ITCTS64 |= BIT(NPCX_ITCTSXX_ITEN);
380
381 /*
382 * Step 2. Use a ITIM32 timer for event handling (ex. timeout event).
383 * Configure 32-bit timer's prescaler to 1 first.
384 */
385 evt_tmr->ITPRE32 = 0;
386 /*
387 * Select low frequency clock source (The freq is 32kHz), enable its
388 * interrupt/wake-up sources, and clear timeout status bit before
389 * enabling it.
390 */
391 evt_tmr->ITCTS32 = BIT(NPCX_ITCTSXX_CKSEL) | BIT(NPCX_ITCTSXX_TO_WUE)
392 | BIT(NPCX_ITCTSXX_TO_IE) | BIT(NPCX_ITCTSXX_TO_STS);
393
394 /* A delay for ITIM source clock selection */
395 k_busy_wait(NPCX_ITIM_CLK_SEL_DELAY);
396
397 /* Configure event timer's ISR */
398 IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority),
399 npcx_itim_evt_isr, NULL, 0);
400 /* Enable event timer interrupt */
401 irq_enable(DT_INST_IRQN(0));
402
403 if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
404 /* Start a event timer in one tick */
405 ret = npcx_itim_start_evt_tmr_by_tick(1);
406 if (ret < 0) {
407 return ret;
408 }
409 }
410
411 return 0;
412 }
413 SYS_INIT(sys_clock_driver_init, PRE_KERNEL_2,
414 CONFIG_SYSTEM_CLOCK_INIT_PRIORITY);
415