xref: /openbmc/linux/arch/arm64/include/asm/arch_timer.h (revision 24cf262da1ad303fc940c798aab0bd1bd50e3fc2)
11aee5d7aSMark Rutland /*
21aee5d7aSMark Rutland  * arch/arm64/include/asm/arch_timer.h
31aee5d7aSMark Rutland  *
41aee5d7aSMark Rutland  * Copyright (C) 2012 ARM Ltd.
51aee5d7aSMark Rutland  * Author: Marc Zyngier <marc.zyngier@arm.com>
61aee5d7aSMark Rutland  *
71aee5d7aSMark Rutland  * This program is free software: you can redistribute it and/or modify
81aee5d7aSMark Rutland  * it under the terms of the GNU General Public License version 2 as
91aee5d7aSMark Rutland  * published by the Free Software Foundation.
101aee5d7aSMark Rutland  *
111aee5d7aSMark Rutland  * This program is distributed in the hope that it will be useful,
121aee5d7aSMark Rutland  * but WITHOUT ANY WARRANTY; without even the implied warranty of
131aee5d7aSMark Rutland  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
141aee5d7aSMark Rutland  * GNU General Public License for more details.
151aee5d7aSMark Rutland  *
161aee5d7aSMark Rutland  * You should have received a copy of the GNU General Public License
171aee5d7aSMark Rutland  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
181aee5d7aSMark Rutland  */
191aee5d7aSMark Rutland #ifndef __ASM_ARCH_TIMER_H
201aee5d7aSMark Rutland #define __ASM_ARCH_TIMER_H
211aee5d7aSMark Rutland 
221aee5d7aSMark Rutland #include <asm/barrier.h>
23cd5f22d7SMark Rutland #include <asm/sysreg.h>
241aee5d7aSMark Rutland 
25082471a8SPaul Walmsley #include <linux/bug.h>
261aee5d7aSMark Rutland #include <linux/init.h>
27f6dc1576SScott Wood #include <linux/jump_label.h>
286acc71ccSMarc Zyngier #include <linux/smp.h>
291aee5d7aSMark Rutland #include <linux/types.h>
301aee5d7aSMark Rutland 
311aee5d7aSMark Rutland #include <clocksource/arm_arch_timer.h>
321aee5d7aSMark Rutland 
3316d10ef2SDing Tianhong #if IS_ENABLED(CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND)
345ef19a16SMarc Zyngier #define has_erratum_handler(h)						\
355ef19a16SMarc Zyngier 	({								\
365ef19a16SMarc Zyngier 		const struct arch_timer_erratum_workaround *__wa;	\
375ef19a16SMarc Zyngier 		__wa = __this_cpu_read(timer_unstable_counter_workaround); \
385ef19a16SMarc Zyngier 		(__wa && __wa->h);					\
395ef19a16SMarc Zyngier 	})
405ef19a16SMarc Zyngier 
415ef19a16SMarc Zyngier #define erratum_handler(h)						\
425ef19a16SMarc Zyngier 	({								\
435ef19a16SMarc Zyngier 		const struct arch_timer_erratum_workaround *__wa;	\
445ef19a16SMarc Zyngier 		__wa = __this_cpu_read(timer_unstable_counter_workaround); \
455ef19a16SMarc Zyngier 		(__wa && __wa->h) ? __wa->h : arch_timer_##h;		\
465ef19a16SMarc Zyngier 	})
475ef19a16SMarc Zyngier 
48f6dc1576SScott Wood #else
495ef19a16SMarc Zyngier #define has_erratum_handler(h)			   false
505ef19a16SMarc Zyngier #define erratum_handler(h)			   (arch_timer_##h)
51f6dc1576SScott Wood #endif
52f6dc1576SScott Wood 
53651bb2e9SMarc Zyngier enum arch_timer_erratum_match_type {
54651bb2e9SMarc Zyngier 	ate_match_dt,
550064030cSMarc Zyngier 	ate_match_local_cap_id,
565a38bcacSMarc Zyngier 	ate_match_acpi_oem_info,
57651bb2e9SMarc Zyngier };
58f6dc1576SScott Wood 
5901d3e3ffSMarc Zyngier struct clock_event_device;
6001d3e3ffSMarc Zyngier 
6116d10ef2SDing Tianhong struct arch_timer_erratum_workaround {
62651bb2e9SMarc Zyngier 	enum arch_timer_erratum_match_type match_type;
63651bb2e9SMarc Zyngier 	const void *id;
64651bb2e9SMarc Zyngier 	const char *desc;
6516d10ef2SDing Tianhong 	u32 (*read_cntp_tval_el0)(void);
6616d10ef2SDing Tianhong 	u32 (*read_cntv_tval_el0)(void);
67f2e600c1SChristoffer Dall 	u64 (*read_cntpct_el0)(void);
6816d10ef2SDing Tianhong 	u64 (*read_cntvct_el0)(void);
6901d3e3ffSMarc Zyngier 	int (*set_next_event_phys)(unsigned long, struct clock_event_device *);
7001d3e3ffSMarc Zyngier 	int (*set_next_event_virt)(unsigned long, struct clock_event_device *);
7116d10ef2SDing Tianhong };
7216d10ef2SDing Tianhong 
736acc71ccSMarc Zyngier DECLARE_PER_CPU(const struct arch_timer_erratum_workaround *,
746acc71ccSMarc Zyngier 		timer_unstable_counter_workaround);
75f6dc1576SScott Wood 
7657f27666SMarc Zyngier /* inline sysreg accessors that make erratum_handler() work */
7757f27666SMarc Zyngier static inline notrace u32 arch_timer_read_cntp_tval_el0(void)
7857f27666SMarc Zyngier {
7957f27666SMarc Zyngier 	return read_sysreg(cntp_tval_el0);
8057f27666SMarc Zyngier }
8157f27666SMarc Zyngier 
8257f27666SMarc Zyngier static inline notrace u32 arch_timer_read_cntv_tval_el0(void)
8357f27666SMarc Zyngier {
8457f27666SMarc Zyngier 	return read_sysreg(cntv_tval_el0);
8557f27666SMarc Zyngier }
8657f27666SMarc Zyngier 
8757f27666SMarc Zyngier static inline notrace u64 arch_timer_read_cntpct_el0(void)
8857f27666SMarc Zyngier {
8957f27666SMarc Zyngier 	return read_sysreg(cntpct_el0);
9057f27666SMarc Zyngier }
9157f27666SMarc Zyngier 
9257f27666SMarc Zyngier static inline notrace u64 arch_timer_read_cntvct_el0(void)
9357f27666SMarc Zyngier {
9457f27666SMarc Zyngier 	return read_sysreg(cntvct_el0);
9557f27666SMarc Zyngier }
9657f27666SMarc Zyngier 
97f6dc1576SScott Wood #define arch_timer_reg_read_stable(reg)					\
98f6dc1576SScott Wood 	({								\
99f6dc1576SScott Wood 		u64 _val;						\
10057f27666SMarc Zyngier 									\
101adb4f11eSDing Tianhong 		preempt_disable_notrace();				\
10257f27666SMarc Zyngier 		_val = erratum_handler(read_ ## reg)();			\
103adb4f11eSDing Tianhong 		preempt_enable_notrace();				\
10457f27666SMarc Zyngier 									\
105f6dc1576SScott Wood 		_val;							\
106f6dc1576SScott Wood 	})
107f6dc1576SScott Wood 
108e09f3cc0SStephen Boyd /*
109e09f3cc0SStephen Boyd  * These register accessors are marked inline so the compiler can
110e09f3cc0SStephen Boyd  * nicely work out which register we want, and chuck away the rest of
111e09f3cc0SStephen Boyd  * the code.
112e09f3cc0SStephen Boyd  */
113e09f3cc0SStephen Boyd static __always_inline
11460faddf6SStephen Boyd void arch_timer_reg_write_cp15(int access, enum arch_timer_reg reg, u32 val)
1151aee5d7aSMark Rutland {
1161aee5d7aSMark Rutland 	if (access == ARCH_TIMER_PHYS_ACCESS) {
1171aee5d7aSMark Rutland 		switch (reg) {
1181aee5d7aSMark Rutland 		case ARCH_TIMER_REG_CTRL:
119cd5f22d7SMark Rutland 			write_sysreg(val, cntp_ctl_el0);
1201aee5d7aSMark Rutland 			break;
1211aee5d7aSMark Rutland 		case ARCH_TIMER_REG_TVAL:
122cd5f22d7SMark Rutland 			write_sysreg(val, cntp_tval_el0);
1231aee5d7aSMark Rutland 			break;
1241aee5d7aSMark Rutland 		}
1251aee5d7aSMark Rutland 	} else if (access == ARCH_TIMER_VIRT_ACCESS) {
1261aee5d7aSMark Rutland 		switch (reg) {
1271aee5d7aSMark Rutland 		case ARCH_TIMER_REG_CTRL:
128cd5f22d7SMark Rutland 			write_sysreg(val, cntv_ctl_el0);
1291aee5d7aSMark Rutland 			break;
1301aee5d7aSMark Rutland 		case ARCH_TIMER_REG_TVAL:
131cd5f22d7SMark Rutland 			write_sysreg(val, cntv_tval_el0);
1321aee5d7aSMark Rutland 			break;
1331aee5d7aSMark Rutland 		}
1341aee5d7aSMark Rutland 	}
1351aee5d7aSMark Rutland 
1361aee5d7aSMark Rutland 	isb();
1371aee5d7aSMark Rutland }
1381aee5d7aSMark Rutland 
139e09f3cc0SStephen Boyd static __always_inline
14060faddf6SStephen Boyd u32 arch_timer_reg_read_cp15(int access, enum arch_timer_reg reg)
1411aee5d7aSMark Rutland {
1421aee5d7aSMark Rutland 	if (access == ARCH_TIMER_PHYS_ACCESS) {
1431aee5d7aSMark Rutland 		switch (reg) {
1441aee5d7aSMark Rutland 		case ARCH_TIMER_REG_CTRL:
145cd5f22d7SMark Rutland 			return read_sysreg(cntp_ctl_el0);
1461aee5d7aSMark Rutland 		case ARCH_TIMER_REG_TVAL:
147f6dc1576SScott Wood 			return arch_timer_reg_read_stable(cntp_tval_el0);
1481aee5d7aSMark Rutland 		}
1491aee5d7aSMark Rutland 	} else if (access == ARCH_TIMER_VIRT_ACCESS) {
1501aee5d7aSMark Rutland 		switch (reg) {
1511aee5d7aSMark Rutland 		case ARCH_TIMER_REG_CTRL:
152cd5f22d7SMark Rutland 			return read_sysreg(cntv_ctl_el0);
1531aee5d7aSMark Rutland 		case ARCH_TIMER_REG_TVAL:
154f6dc1576SScott Wood 			return arch_timer_reg_read_stable(cntv_tval_el0);
1551aee5d7aSMark Rutland 		}
1561aee5d7aSMark Rutland 	}
1571aee5d7aSMark Rutland 
158cd5f22d7SMark Rutland 	BUG();
1591aee5d7aSMark Rutland }
1601aee5d7aSMark Rutland 
1611aee5d7aSMark Rutland static inline u32 arch_timer_get_cntfrq(void)
1621aee5d7aSMark Rutland {
163cd5f22d7SMark Rutland 	return read_sysreg(cntfrq_el0);
1641aee5d7aSMark Rutland }
1651aee5d7aSMark Rutland 
16646efe547SSudeep KarkadaNagesha static inline u32 arch_timer_get_cntkctl(void)
1671aee5d7aSMark Rutland {
168cd5f22d7SMark Rutland 	return read_sysreg(cntkctl_el1);
16946efe547SSudeep KarkadaNagesha }
17046efe547SSudeep KarkadaNagesha 
17146efe547SSudeep KarkadaNagesha static inline void arch_timer_set_cntkctl(u32 cntkctl)
17246efe547SSudeep KarkadaNagesha {
173cd5f22d7SMark Rutland 	write_sysreg(cntkctl, cntkctl_el1);
174ec5c8e42SJulien Thierry 	isb();
17546efe547SSudeep KarkadaNagesha }
17646efe547SSudeep KarkadaNagesha 
17775a19a02SWill Deacon /*
17875a19a02SWill Deacon  * Ensure that reads of the counter are treated the same as memory reads
17975a19a02SWill Deacon  * for the purposes of ordering by subsequent memory barriers.
18075a19a02SWill Deacon  *
18175a19a02SWill Deacon  * This insanity brought to you by speculative system register reads,
18275a19a02SWill Deacon  * out-of-order memory accesses, sequence locks and Thomas Gleixner.
18375a19a02SWill Deacon  *
18475a19a02SWill Deacon  * http://lists.infradead.org/pipermail/linux-arm-kernel/2019-February/631195.html
18575a19a02SWill Deacon  */
18675a19a02SWill Deacon #define arch_counter_enforce_ordering(val) do {				\
18775a19a02SWill Deacon 	u64 tmp, _val = (val);						\
18875a19a02SWill Deacon 									\
18975a19a02SWill Deacon 	asm volatile(							\
19075a19a02SWill Deacon 	"	eor	%0, %1, %1\n"					\
19175a19a02SWill Deacon 	"	add	%0, sp, %0\n"					\
19275a19a02SWill Deacon 	"	ldr	xzr, [%0]"					\
19375a19a02SWill Deacon 	: "=r" (tmp) : "r" (_val));					\
19475a19a02SWill Deacon } while (0)
19575a19a02SWill Deacon 
1960ea41539SMarc Zyngier static inline u64 __arch_counter_get_cntpct_stable(void)
1970b46b8a7SSonny Rao {
19875a19a02SWill Deacon 	u64 cnt;
19975a19a02SWill Deacon 
200f2e600c1SChristoffer Dall 	isb();
20175a19a02SWill Deacon 	cnt = arch_timer_reg_read_stable(cntpct_el0);
20275a19a02SWill Deacon 	arch_counter_enforce_ordering(cnt);
20375a19a02SWill Deacon 	return cnt;
2040b46b8a7SSonny Rao }
2050b46b8a7SSonny Rao 
2060ea41539SMarc Zyngier static inline u64 __arch_counter_get_cntpct(void)
2070ea41539SMarc Zyngier {
208*24cf262dSWill Deacon 	u64 cnt;
209*24cf262dSWill Deacon 
2100ea41539SMarc Zyngier 	isb();
211*24cf262dSWill Deacon 	cnt = read_sysreg(cntpct_el0);
212*24cf262dSWill Deacon 	arch_counter_enforce_ordering(cnt);
213*24cf262dSWill Deacon 	return cnt;
2140ea41539SMarc Zyngier }
2150ea41539SMarc Zyngier 
2160ea41539SMarc Zyngier static inline u64 __arch_counter_get_cntvct_stable(void)
2171aee5d7aSMark Rutland {
21875a19a02SWill Deacon 	u64 cnt;
21975a19a02SWill Deacon 
2201aee5d7aSMark Rutland 	isb();
22175a19a02SWill Deacon 	cnt = arch_timer_reg_read_stable(cntvct_el0);
22275a19a02SWill Deacon 	arch_counter_enforce_ordering(cnt);
22375a19a02SWill Deacon 	return cnt;
2241aee5d7aSMark Rutland }
2251aee5d7aSMark Rutland 
2260ea41539SMarc Zyngier static inline u64 __arch_counter_get_cntvct(void)
2270ea41539SMarc Zyngier {
228*24cf262dSWill Deacon 	u64 cnt;
229*24cf262dSWill Deacon 
2300ea41539SMarc Zyngier 	isb();
231*24cf262dSWill Deacon 	cnt = read_sysreg(cntvct_el0);
232*24cf262dSWill Deacon 	arch_counter_enforce_ordering(cnt);
233*24cf262dSWill Deacon 	return cnt;
2340ea41539SMarc Zyngier }
2350ea41539SMarc Zyngier 
23675a19a02SWill Deacon #undef arch_counter_enforce_ordering
23775a19a02SWill Deacon 
2380583fe47SRob Herring static inline int arch_timer_arch_init(void)
2390583fe47SRob Herring {
2400583fe47SRob Herring 	return 0;
2410583fe47SRob Herring }
2420583fe47SRob Herring 
2431aee5d7aSMark Rutland #endif
244