|
7 | 7 | * either be read from the "time" and "timeh" CSRs, and can use the SBI to
|
8 | 8 | * setup events, or directly accessed using MMIO registers.
|
9 | 9 | */
|
| 10 | + |
| 11 | +#define pr_fmt(fmt) "riscv-timer: " fmt |
| 12 | + |
10 | 13 | #include <linux/clocksource.h>
|
11 | 14 | #include <linux/clockchips.h>
|
12 | 15 | #include <linux/cpu.h>
|
|
20 | 23 | #include <linux/of_irq.h>
|
21 | 24 | #include <clocksource/timer-riscv.h>
|
22 | 25 | #include <asm/smp.h>
|
| 26 | +#include <asm/hwcap.h> |
23 | 27 | #include <asm/sbi.h>
|
24 | 28 | #include <asm/timex.h>
|
25 | 29 |
|
| 30 | +static DEFINE_STATIC_KEY_FALSE(riscv_sstc_available); |
| 31 | + |
26 | 32 | static int riscv_clock_next_event(unsigned long delta,
|
27 | 33 | struct clock_event_device *ce)
|
28 | 34 | {
|
| 35 | + u64 next_tval = get_cycles64() + delta; |
| 36 | + |
29 | 37 | csr_set(CSR_IE, IE_TIE);
|
30 |
| - sbi_set_timer(get_cycles64() + delta); |
| 38 | + if (static_branch_likely(&riscv_sstc_available)) { |
| 39 | +#if defined(CONFIG_32BIT) |
| 40 | + csr_write(CSR_STIMECMP, next_tval & 0xFFFFFFFF); |
| 41 | + csr_write(CSR_STIMECMPH, next_tval >> 32); |
| 42 | +#else |
| 43 | + csr_write(CSR_STIMECMP, next_tval); |
| 44 | +#endif |
| 45 | + } else |
| 46 | + sbi_set_timer(next_tval); |
| 47 | + |
31 | 48 | return 0;
|
32 | 49 | }
|
33 | 50 |
|
@@ -165,6 +182,12 @@ static int __init riscv_timer_init_dt(struct device_node *n)
|
165 | 182 | if (error)
|
166 | 183 | pr_err("cpu hp setup state failed for RISCV timer [%d]\n",
|
167 | 184 | error);
|
| 185 | + |
| 186 | + if (riscv_isa_extension_available(NULL, SSTC)) { |
| 187 | + pr_info("Timer interrupt in S-mode is available via sstc extension\n"); |
| 188 | + static_branch_enable(&riscv_sstc_available); |
| 189 | + } |
| 190 | + |
168 | 191 | return error;
|
169 | 192 | }
|
170 | 193 |
|
|
0 commit comments