Commit | Line | Data |
---|---|---|
62b01943 PD |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Copyright (C) 2012 Regents of the University of California | |
4 | * Copyright (C) 2017 SiFive | |
5 | */ | |
6 | #include <linux/clocksource.h> | |
7 | #include <linux/clockchips.h> | |
8 | #include <linux/cpu.h> | |
9 | #include <linux/delay.h> | |
10 | #include <linux/irq.h> | |
f99fb607 | 11 | #include <asm/smp.h> |
62b01943 PD |
12 | #include <asm/sbi.h> |
13 | ||
14 | /* | |
15 | * All RISC-V systems have a timer attached to every hart. These timers can be | |
16 | * read by the 'rdcycle' pseudo instruction, and can use the SBI to setup | |
17 | * events. In order to abstract the architecture-specific timer reading and | |
18 | * setting functions away from the clock event insertion code, we provide | |
19 | * function pointers to the clockevent subsystem that perform two basic | |
20 | * operations: rdtime() reads the timer on the current CPU, and | |
21 | * next_event(delta) sets the next timer event to 'delta' cycles in the future. | |
22 | * As the timers are inherently a per-cpu resource, these callbacks perform | |
23 | * operations on the current hart. There is guaranteed to be exactly one timer | |
24 | * per hart on all RISC-V systems. | |
25 | */ | |
26 | ||
27 | static int riscv_clock_next_event(unsigned long delta, | |
28 | struct clock_event_device *ce) | |
29 | { | |
30 | csr_set(sie, SIE_STIE); | |
31 | sbi_set_timer(get_cycles64() + delta); | |
32 | return 0; | |
33 | } | |
34 | ||
35 | static DEFINE_PER_CPU(struct clock_event_device, riscv_clock_event) = { | |
36 | .name = "riscv_timer_clockevent", | |
37 | .features = CLOCK_EVT_FEAT_ONESHOT, | |
38 | .rating = 100, | |
39 | .set_next_event = riscv_clock_next_event, | |
40 | }; | |
41 | ||
42 | /* | |
43 | * It is guaranteed that all the timers across all the harts are synchronized | |
44 | * within one tick of each other, so while this could technically go | |
45 | * backwards when hopping between CPUs, practically it won't happen. | |
46 | */ | |
47 | static unsigned long long riscv_clocksource_rdtime(struct clocksource *cs) | |
48 | { | |
49 | return get_cycles64(); | |
50 | } | |
51 | ||
52 | static DEFINE_PER_CPU(struct clocksource, riscv_clocksource) = { | |
53 | .name = "riscv_clocksource", | |
54 | .rating = 300, | |
55 | .mask = CLOCKSOURCE_MASK(BITS_PER_LONG), | |
56 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | |
57 | .read = riscv_clocksource_rdtime, | |
58 | }; | |
59 | ||
60 | static int riscv_timer_starting_cpu(unsigned int cpu) | |
61 | { | |
62 | struct clock_event_device *ce = per_cpu_ptr(&riscv_clock_event, cpu); | |
63 | ||
64 | ce->cpumask = cpumask_of(cpu); | |
65 | clockevents_config_and_register(ce, riscv_timebase, 100, 0x7fffffff); | |
66 | ||
67 | csr_set(sie, SIE_STIE); | |
68 | return 0; | |
69 | } | |
70 | ||
71 | static int riscv_timer_dying_cpu(unsigned int cpu) | |
72 | { | |
73 | csr_clear(sie, SIE_STIE); | |
74 | return 0; | |
75 | } | |
76 | ||
77 | /* called directly from the low-level interrupt handler */ | |
78 | void riscv_timer_interrupt(void) | |
79 | { | |
80 | struct clock_event_device *evdev = this_cpu_ptr(&riscv_clock_event); | |
81 | ||
82 | csr_clear(sie, SIE_STIE); | |
83 | evdev->event_handler(evdev); | |
84 | } | |
85 | ||
86 | static int __init riscv_timer_init_dt(struct device_node *n) | |
87 | { | |
f99fb607 | 88 | int cpuid, hartid, error; |
62b01943 PD |
89 | struct clocksource *cs; |
90 | ||
f99fb607 AP |
91 | hartid = riscv_of_processor_hartid(n); |
92 | cpuid = riscv_hartid_to_cpuid(hartid); | |
93 | ||
94 | if (cpuid != smp_processor_id()) | |
62b01943 PD |
95 | return 0; |
96 | ||
f99fb607 | 97 | cs = per_cpu_ptr(&riscv_clocksource, cpuid); |
62b01943 PD |
98 | clocksource_register_hz(cs, riscv_timebase); |
99 | ||
100 | error = cpuhp_setup_state(CPUHP_AP_RISCV_TIMER_STARTING, | |
101 | "clockevents/riscv/timer:starting", | |
102 | riscv_timer_starting_cpu, riscv_timer_dying_cpu); | |
103 | if (error) | |
104 | pr_err("RISCV timer register failed [%d] for cpu = [%d]\n", | |
f99fb607 | 105 | error, cpuid); |
62b01943 PD |
106 | return error; |
107 | } | |
108 | ||
109 | TIMER_OF_DECLARE(riscv_timer, "riscv", riscv_timer_init_dt); |