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