Commit | Line | Data |
---|---|---|
caab277b | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
1aee5d7a MR |
2 | /* |
3 | * arch/arm64/include/asm/arch_timer.h | |
4 | * | |
5 | * Copyright (C) 2012 ARM Ltd. | |
6 | * Author: Marc Zyngier <marc.zyngier@arm.com> | |
1aee5d7a MR |
7 | */ |
8 | #ifndef __ASM_ARCH_TIMER_H | |
9 | #define __ASM_ARCH_TIMER_H | |
10 | ||
11 | #include <asm/barrier.h> | |
5a354412 | 12 | #include <asm/hwcap.h> |
cd5f22d7 | 13 | #include <asm/sysreg.h> |
1aee5d7a | 14 | |
082471a8 | 15 | #include <linux/bug.h> |
1aee5d7a | 16 | #include <linux/init.h> |
f6dc1576 | 17 | #include <linux/jump_label.h> |
6acc71cc | 18 | #include <linux/smp.h> |
1aee5d7a MR |
19 | #include <linux/types.h> |
20 | ||
21 | #include <clocksource/arm_arch_timer.h> | |
22 | ||
16d10ef2 | 23 | #if IS_ENABLED(CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND) |
5ef19a16 MZ |
24 | #define has_erratum_handler(h) \ |
25 | ({ \ | |
26 | const struct arch_timer_erratum_workaround *__wa; \ | |
27 | __wa = __this_cpu_read(timer_unstable_counter_workaround); \ | |
28 | (__wa && __wa->h); \ | |
29 | }) | |
30 | ||
31 | #define erratum_handler(h) \ | |
32 | ({ \ | |
33 | const struct arch_timer_erratum_workaround *__wa; \ | |
34 | __wa = __this_cpu_read(timer_unstable_counter_workaround); \ | |
35 | (__wa && __wa->h) ? __wa->h : arch_timer_##h; \ | |
36 | }) | |
37 | ||
f6dc1576 | 38 | #else |
5ef19a16 MZ |
39 | #define has_erratum_handler(h) false |
40 | #define erratum_handler(h) (arch_timer_##h) | |
f6dc1576 SW |
41 | #endif |
42 | ||
651bb2e9 MZ |
43 | enum arch_timer_erratum_match_type { |
44 | ate_match_dt, | |
0064030c | 45 | ate_match_local_cap_id, |
5a38bcac | 46 | ate_match_acpi_oem_info, |
651bb2e9 | 47 | }; |
f6dc1576 | 48 | |
01d3e3ff MZ |
49 | struct clock_event_device; |
50 | ||
16d10ef2 | 51 | struct arch_timer_erratum_workaround { |
651bb2e9 MZ |
52 | enum arch_timer_erratum_match_type match_type; |
53 | const void *id; | |
54 | const char *desc; | |
f2e600c1 | 55 | u64 (*read_cntpct_el0)(void); |
16d10ef2 | 56 | u64 (*read_cntvct_el0)(void); |
01d3e3ff MZ |
57 | int (*set_next_event_phys)(unsigned long, struct clock_event_device *); |
58 | int (*set_next_event_virt)(unsigned long, struct clock_event_device *); | |
c1fbec4a | 59 | bool disable_compat_vdso; |
16d10ef2 DT |
60 | }; |
61 | ||
6acc71cc MZ |
62 | DECLARE_PER_CPU(const struct arch_timer_erratum_workaround *, |
63 | timer_unstable_counter_workaround); | |
f6dc1576 | 64 | |
57f27666 MZ |
65 | static inline notrace u64 arch_timer_read_cntpct_el0(void) |
66 | { | |
67 | return read_sysreg(cntpct_el0); | |
68 | } | |
69 | ||
70 | static inline notrace u64 arch_timer_read_cntvct_el0(void) | |
71 | { | |
72 | return read_sysreg(cntvct_el0); | |
73 | } | |
74 | ||
6acc71cc | 75 | #define arch_timer_reg_read_stable(reg) \ |
57f27666 MZ |
76 | ({ \ |
77 | u64 _val; \ | |
78 | \ | |
adb4f11e | 79 | preempt_disable_notrace(); \ |
57f27666 | 80 | _val = erratum_handler(read_ ## reg)(); \ |
adb4f11e | 81 | preempt_enable_notrace(); \ |
57f27666 MZ |
82 | \ |
83 | _val; \ | |
84 | }) | |
f6dc1576 | 85 | |
e09f3cc0 SB |
86 | /* |
87 | * These register accessors are marked inline so the compiler can | |
88 | * nicely work out which register we want, and chuck away the rest of | |
89 | * the code. | |
90 | */ | |
91 | static __always_inline | |
1e8d9292 | 92 | void arch_timer_reg_write_cp15(int access, enum arch_timer_reg reg, u64 val) |
1aee5d7a MR |
93 | { |
94 | if (access == ARCH_TIMER_PHYS_ACCESS) { | |
95 | switch (reg) { | |
96 | case ARCH_TIMER_REG_CTRL: | |
cd5f22d7 | 97 | write_sysreg(val, cntp_ctl_el0); |
1aee5d7a | 98 | break; |
a38b71b0 MZ |
99 | case ARCH_TIMER_REG_CVAL: |
100 | write_sysreg(val, cntp_cval_el0); | |
1aee5d7a | 101 | break; |
4775bc63 MZ |
102 | default: |
103 | BUILD_BUG(); | |
1aee5d7a MR |
104 | } |
105 | } else if (access == ARCH_TIMER_VIRT_ACCESS) { | |
106 | switch (reg) { | |
107 | case ARCH_TIMER_REG_CTRL: | |
cd5f22d7 | 108 | write_sysreg(val, cntv_ctl_el0); |
1aee5d7a | 109 | break; |
a38b71b0 MZ |
110 | case ARCH_TIMER_REG_CVAL: |
111 | write_sysreg(val, cntv_cval_el0); | |
1aee5d7a | 112 | break; |
4775bc63 MZ |
113 | default: |
114 | BUILD_BUG(); | |
1aee5d7a | 115 | } |
4775bc63 MZ |
116 | } else { |
117 | BUILD_BUG(); | |
1aee5d7a MR |
118 | } |
119 | ||
120 | isb(); | |
121 | } | |
122 | ||
e09f3cc0 | 123 | static __always_inline |
a38b71b0 | 124 | u64 arch_timer_reg_read_cp15(int access, enum arch_timer_reg reg) |
1aee5d7a | 125 | { |
1aee5d7a MR |
126 | if (access == ARCH_TIMER_PHYS_ACCESS) { |
127 | switch (reg) { | |
128 | case ARCH_TIMER_REG_CTRL: | |
cd5f22d7 | 129 | return read_sysreg(cntp_ctl_el0); |
4775bc63 MZ |
130 | default: |
131 | BUILD_BUG(); | |
1aee5d7a MR |
132 | } |
133 | } else if (access == ARCH_TIMER_VIRT_ACCESS) { | |
134 | switch (reg) { | |
135 | case ARCH_TIMER_REG_CTRL: | |
cd5f22d7 | 136 | return read_sysreg(cntv_ctl_el0); |
4775bc63 MZ |
137 | default: |
138 | BUILD_BUG(); | |
1aee5d7a | 139 | } |
1aee5d7a MR |
140 | } |
141 | ||
4775bc63 MZ |
142 | BUILD_BUG(); |
143 | unreachable(); | |
1aee5d7a MR |
144 | } |
145 | ||
146 | static inline u32 arch_timer_get_cntfrq(void) | |
147 | { | |
cd5f22d7 | 148 | return read_sysreg(cntfrq_el0); |
1aee5d7a MR |
149 | } |
150 | ||
46efe547 | 151 | static inline u32 arch_timer_get_cntkctl(void) |
1aee5d7a | 152 | { |
cd5f22d7 | 153 | return read_sysreg(cntkctl_el1); |
46efe547 SK |
154 | } |
155 | ||
156 | static inline void arch_timer_set_cntkctl(u32 cntkctl) | |
157 | { | |
cd5f22d7 | 158 | write_sysreg(cntkctl, cntkctl_el1); |
ec5c8e42 | 159 | isb(); |
46efe547 SK |
160 | } |
161 | ||
f31e98bf | 162 | static __always_inline u64 __arch_counter_get_cntpct_stable(void) |
0b46b8a7 | 163 | { |
75a19a02 WD |
164 | u64 cnt; |
165 | ||
f2e600c1 | 166 | isb(); |
75a19a02 WD |
167 | cnt = arch_timer_reg_read_stable(cntpct_el0); |
168 | arch_counter_enforce_ordering(cnt); | |
169 | return cnt; | |
0b46b8a7 SR |
170 | } |
171 | ||
f31e98bf | 172 | static __always_inline u64 __arch_counter_get_cntpct(void) |
0ea41539 | 173 | { |
24cf262d WD |
174 | u64 cnt; |
175 | ||
0ea41539 | 176 | isb(); |
24cf262d WD |
177 | cnt = read_sysreg(cntpct_el0); |
178 | arch_counter_enforce_ordering(cnt); | |
179 | return cnt; | |
0ea41539 MZ |
180 | } |
181 | ||
f31e98bf | 182 | static __always_inline u64 __arch_counter_get_cntvct_stable(void) |
1aee5d7a | 183 | { |
75a19a02 WD |
184 | u64 cnt; |
185 | ||
1aee5d7a | 186 | isb(); |
75a19a02 WD |
187 | cnt = arch_timer_reg_read_stable(cntvct_el0); |
188 | arch_counter_enforce_ordering(cnt); | |
189 | return cnt; | |
1aee5d7a MR |
190 | } |
191 | ||
f31e98bf | 192 | static __always_inline u64 __arch_counter_get_cntvct(void) |
0ea41539 | 193 | { |
24cf262d WD |
194 | u64 cnt; |
195 | ||
0ea41539 | 196 | isb(); |
24cf262d WD |
197 | cnt = read_sysreg(cntvct_el0); |
198 | arch_counter_enforce_ordering(cnt); | |
199 | return cnt; | |
0ea41539 MZ |
200 | } |
201 | ||
0583fe47 RH |
202 | static inline int arch_timer_arch_init(void) |
203 | { | |
204 | return 0; | |
205 | } | |
206 | ||
5a354412 AM |
207 | static inline void arch_timer_set_evtstrm_feature(void) |
208 | { | |
209 | cpu_set_named_feature(EVTSTRM); | |
210 | #ifdef CONFIG_COMPAT | |
211 | compat_elf_hwcap |= COMPAT_HWCAP_EVTSTRM; | |
212 | #endif | |
213 | } | |
214 | ||
215 | static inline bool arch_timer_have_evtstrm_feature(void) | |
216 | { | |
217 | return cpu_have_named_feature(EVTSTRM); | |
218 | } | |
1aee5d7a | 219 | #endif |