1 /*
2 * Copyright (c) 2018-2023 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <limits.h>
8
9 #include <zephyr/init.h>
10 #include <zephyr/devicetree.h>
11 #include <zephyr/drivers/timer/system_timer.h>
12 #include <zephyr/sys_clock.h>
13 #include <zephyr/spinlock.h>
14 #include <zephyr/irq.h>
15
16 /* andestech,machine-timer */
17 #if DT_HAS_COMPAT_STATUS_OKAY(andestech_machine_timer)
18 #define DT_DRV_COMPAT andestech_machine_timer
19
20 #define MTIME_REG DT_INST_REG_ADDR(0)
21 #define MTIMECMP_REG (DT_INST_REG_ADDR(0) + 8)
22 #define TIMER_IRQN DT_INST_IRQN(0)
23 /* neorv32-machine-timer */
24 #elif DT_HAS_COMPAT_STATUS_OKAY(neorv32_machine_timer)
25 #define DT_DRV_COMPAT neorv32_machine_timer
26
27 #define MTIME_REG DT_INST_REG_ADDR(0)
28 #define MTIMECMP_REG (DT_INST_REG_ADDR(0) + 8)
29 #define TIMER_IRQN DT_INST_IRQN(0)
30 /* nuclei,systimer */
31 #elif DT_HAS_COMPAT_STATUS_OKAY(nuclei_systimer)
32 #define DT_DRV_COMPAT nuclei_systimer
33
34 #define MTIME_REG DT_INST_REG_ADDR(0)
35 #define MTIMECMP_REG (DT_INST_REG_ADDR(0) + 8)
36 #define TIMER_IRQN DT_INST_IRQ_BY_IDX(0, 1, irq)
37 /* sifive,clint0 */
38 #elif DT_HAS_COMPAT_STATUS_OKAY(sifive_clint0)
39 #define DT_DRV_COMPAT sifive_clint0
40
41 #define MTIME_REG (DT_INST_REG_ADDR(0) + 0xbff8U)
42 #define MTIMECMP_REG (DT_INST_REG_ADDR(0) + 0x4000U)
43 #define TIMER_IRQN DT_INST_IRQ_BY_IDX(0, 1, irq)
44 /* telink,machine-timer */
45 #elif DT_HAS_COMPAT_STATUS_OKAY(telink_machine_timer)
46 #define DT_DRV_COMPAT telink_machine_timer
47
48 #define MTIME_REG DT_INST_REG_ADDR(0)
49 #define MTIMECMP_REG (DT_INST_REG_ADDR(0) + 8)
50 #define TIMER_IRQN DT_INST_IRQN(0)
51 /* lowrisc,machine-timer */
52 #elif DT_HAS_COMPAT_STATUS_OKAY(lowrisc_machine_timer)
53 #define DT_DRV_COMPAT lowrisc_machine_timer
54
55 #define MTIME_REG (DT_INST_REG_ADDR(0) + 0x110)
56 #define MTIMECMP_REG (DT_INST_REG_ADDR(0) + 0x118)
57 #define TIMER_IRQN DT_INST_IRQN(0)
58 /* niosv-machine-timer */
59 #elif DT_HAS_COMPAT_STATUS_OKAY(niosv_machine_timer)
60 #define DT_DRV_COMPAT niosv_machine_timer
61
62 #define MTIMECMP_REG DT_INST_REG_ADDR(0)
63 #define MTIME_REG (DT_INST_REG_ADDR(0) + 8)
64 #define TIMER_IRQN DT_INST_IRQN(0)
65 /* scr,machine-timer*/
66 #elif DT_HAS_COMPAT_STATUS_OKAY(scr_machine_timer)
67 #define DT_DRV_COMPAT scr_machine_timer
68 #define MTIMER_HAS_DIVIDER
69
70 #define MTIMEDIV_REG (DT_INST_REG_ADDR_U64(0) + 4)
71 #define MTIME_REG (DT_INST_REG_ADDR_U64(0) + 8)
72 #define MTIMECMP_REG (DT_INST_REG_ADDR_U64(0) + 16)
73 #define TIMER_IRQN DT_INST_IRQN(0)
74 #endif
75
76 #define CYC_PER_TICK (uint32_t)(sys_clock_hw_cycles_per_sec() \
77 / CONFIG_SYS_CLOCK_TICKS_PER_SEC)
78
79 /* the unsigned long cast limits divisions to native CPU register width */
80 #define cycle_diff_t unsigned long
81 #define CYCLE_DIFF_MAX (~(cycle_diff_t)0)
82
83 /*
84 * We have two constraints on the maximum number of cycles we can wait for.
85 *
86 * 1) sys_clock_announce() accepts at most INT32_MAX ticks.
87 *
88 * 2) The number of cycles between two reports must fit in a cycle_diff_t
89 * variable before converting it to ticks.
90 *
91 * Then:
92 *
93 * 3) Pick the smallest between (1) and (2).
94 *
95 * 4) Take into account some room for the unavoidable IRQ servicing latency.
96 * Let's use 3/4 of the max range.
97 *
98 * Finally let's add the LSB value to the result so to clear out a bunch of
99 * consecutive set bits coming from the original max values to produce a
100 * nicer literal for assembly generation.
101 */
102 #define CYCLES_MAX_1 ((uint64_t)INT32_MAX * (uint64_t)CYC_PER_TICK)
103 #define CYCLES_MAX_2 ((uint64_t)CYCLE_DIFF_MAX)
104 #define CYCLES_MAX_3 MIN(CYCLES_MAX_1, CYCLES_MAX_2)
105 #define CYCLES_MAX_4 (CYCLES_MAX_3 / 2 + CYCLES_MAX_3 / 4)
106 #define CYCLES_MAX (CYCLES_MAX_4 + LSB_GET(CYCLES_MAX_4))
107
108 static struct k_spinlock lock;
109 static uint64_t last_count;
110 static uint64_t last_ticks;
111 static uint32_t last_elapsed;
112
113 #if defined(CONFIG_TEST)
114 const int32_t z_sys_timer_irq_for_test = TIMER_IRQN;
115 #endif
116
get_hart_mtimecmp(void)117 static uintptr_t get_hart_mtimecmp(void)
118 {
119 return MTIMECMP_REG + (arch_proc_id() * 8);
120 }
121
set_mtimecmp(uint64_t time)122 static void set_mtimecmp(uint64_t time)
123 {
124 #ifdef CONFIG_64BIT
125 *(volatile uint64_t *)get_hart_mtimecmp() = time;
126 #else
127 volatile uint32_t *r = (uint32_t *)get_hart_mtimecmp();
128
129 /* Per spec, the RISC-V MTIME/MTIMECMP registers are 64 bit,
130 * but are NOT internally latched for multiword transfers. So
131 * we have to be careful about sequencing to avoid triggering
132 * spurious interrupts: always set the high word to a max
133 * value first.
134 */
135 r[1] = 0xffffffff;
136 r[0] = (uint32_t)time;
137 r[1] = (uint32_t)(time >> 32);
138 #endif
139 }
140
set_divider(void)141 static void set_divider(void)
142 {
143 #ifdef MTIMER_HAS_DIVIDER
144 *(volatile uint32_t *)MTIMEDIV_REG =
145 CONFIG_RISCV_MACHINE_TIMER_SYSTEM_CLOCK_DIVIDER;
146 #endif
147 }
148
mtime(void)149 static uint64_t mtime(void)
150 {
151 #ifdef CONFIG_64BIT
152 return *(volatile uint64_t *)MTIME_REG;
153 #else
154 volatile uint32_t *r = (uint32_t *)MTIME_REG;
155 uint32_t lo, hi;
156
157 /* Likewise, must guard against rollover when reading */
158 do {
159 hi = r[1];
160 lo = r[0];
161 } while (r[1] != hi);
162
163 return (((uint64_t)hi) << 32) | lo;
164 #endif
165 }
166
timer_isr(const void * arg)167 static void timer_isr(const void *arg)
168 {
169 ARG_UNUSED(arg);
170
171 k_spinlock_key_t key = k_spin_lock(&lock);
172
173 uint64_t now = mtime();
174 uint64_t dcycles = now - last_count;
175 uint32_t dticks = (cycle_diff_t)dcycles / CYC_PER_TICK;
176
177 last_count += (cycle_diff_t)dticks * CYC_PER_TICK;
178 last_ticks += dticks;
179 last_elapsed = 0;
180
181 if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
182 uint64_t next = last_count + CYC_PER_TICK;
183
184 set_mtimecmp(next);
185 }
186
187 k_spin_unlock(&lock, key);
188 sys_clock_announce(dticks);
189 }
190
sys_clock_set_timeout(int32_t ticks,bool idle)191 void sys_clock_set_timeout(int32_t ticks, bool idle)
192 {
193 ARG_UNUSED(idle);
194
195 if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
196 return;
197 }
198
199 k_spinlock_key_t key = k_spin_lock(&lock);
200 uint64_t cyc;
201
202 if (ticks == K_TICKS_FOREVER) {
203 cyc = last_count + CYCLES_MAX;
204 } else {
205 cyc = (last_ticks + last_elapsed + ticks) * CYC_PER_TICK;
206 if ((cyc - last_count) > CYCLES_MAX) {
207 cyc = last_count + CYCLES_MAX;
208 }
209 }
210 set_mtimecmp(cyc);
211
212 k_spin_unlock(&lock, key);
213 }
214
sys_clock_elapsed(void)215 uint32_t sys_clock_elapsed(void)
216 {
217 if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
218 return 0;
219 }
220
221 k_spinlock_key_t key = k_spin_lock(&lock);
222 uint64_t now = mtime();
223 uint64_t dcycles = now - last_count;
224 uint32_t dticks = (cycle_diff_t)dcycles / CYC_PER_TICK;
225
226 last_elapsed = dticks;
227 k_spin_unlock(&lock, key);
228 return dticks;
229 }
230
sys_clock_cycle_get_32(void)231 uint32_t sys_clock_cycle_get_32(void)
232 {
233 return ((uint32_t)mtime()) << CONFIG_RISCV_MACHINE_TIMER_SYSTEM_CLOCK_DIVIDER;
234 }
235
sys_clock_cycle_get_64(void)236 uint64_t sys_clock_cycle_get_64(void)
237 {
238 return mtime() << CONFIG_RISCV_MACHINE_TIMER_SYSTEM_CLOCK_DIVIDER;
239 }
240
sys_clock_driver_init(void)241 static int sys_clock_driver_init(void)
242 {
243
244 set_divider();
245
246 IRQ_CONNECT(TIMER_IRQN, 0, timer_isr, NULL, 0);
247 last_ticks = mtime() / CYC_PER_TICK;
248 last_count = last_ticks * CYC_PER_TICK;
249 set_mtimecmp(last_count + CYC_PER_TICK);
250 irq_enable(TIMER_IRQN);
251 return 0;
252 }
253
254 #ifdef CONFIG_SMP
smp_timer_init(void)255 void smp_timer_init(void)
256 {
257 set_mtimecmp(last_count + CYC_PER_TICK);
258 irq_enable(TIMER_IRQN);
259 }
260 #endif
261
262 SYS_INIT(sys_clock_driver_init, PRE_KERNEL_2,
263 CONFIG_SYSTEM_CLOCK_INIT_PRIORITY);
264