|
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