xref: /openbmc/linux/arch/arm64/include/asm/arch_timer.h (revision caab277b1de0a22b675c4c95fc7b285ec2eb5bf5)
1*caab277bSThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-only */
21aee5d7aSMark Rutland /*
31aee5d7aSMark Rutland  * arch/arm64/include/asm/arch_timer.h
41aee5d7aSMark Rutland  *
51aee5d7aSMark Rutland  * Copyright (C) 2012 ARM Ltd.
61aee5d7aSMark Rutland  * Author: Marc Zyngier <marc.zyngier@arm.com>
71aee5d7aSMark Rutland  */
81aee5d7aSMark Rutland #ifndef __ASM_ARCH_TIMER_H
91aee5d7aSMark Rutland #define __ASM_ARCH_TIMER_H
101aee5d7aSMark Rutland 
111aee5d7aSMark Rutland #include <asm/barrier.h>
12cd5f22d7SMark Rutland #include <asm/sysreg.h>
131aee5d7aSMark Rutland 
14082471a8SPaul Walmsley #include <linux/bug.h>
151aee5d7aSMark Rutland #include <linux/init.h>
16f6dc1576SScott Wood #include <linux/jump_label.h>
176acc71ccSMarc Zyngier #include <linux/smp.h>
181aee5d7aSMark Rutland #include <linux/types.h>
191aee5d7aSMark Rutland 
201aee5d7aSMark Rutland #include <clocksource/arm_arch_timer.h>
211aee5d7aSMark Rutland 
2216d10ef2SDing Tianhong #if IS_ENABLED(CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND)
235ef19a16SMarc Zyngier #define has_erratum_handler(h)						\
245ef19a16SMarc Zyngier 	({								\
255ef19a16SMarc Zyngier 		const struct arch_timer_erratum_workaround *__wa;	\
265ef19a16SMarc Zyngier 		__wa = __this_cpu_read(timer_unstable_counter_workaround); \
275ef19a16SMarc Zyngier 		(__wa && __wa->h);					\
285ef19a16SMarc Zyngier 	})
295ef19a16SMarc Zyngier 
305ef19a16SMarc Zyngier #define erratum_handler(h)						\
315ef19a16SMarc Zyngier 	({								\
325ef19a16SMarc Zyngier 		const struct arch_timer_erratum_workaround *__wa;	\
335ef19a16SMarc Zyngier 		__wa = __this_cpu_read(timer_unstable_counter_workaround); \
345ef19a16SMarc Zyngier 		(__wa && __wa->h) ? __wa->h : arch_timer_##h;		\
355ef19a16SMarc Zyngier 	})
365ef19a16SMarc Zyngier 
37f6dc1576SScott Wood #else
385ef19a16SMarc Zyngier #define has_erratum_handler(h)			   false
395ef19a16SMarc Zyngier #define erratum_handler(h)			   (arch_timer_##h)
40f6dc1576SScott Wood #endif
41f6dc1576SScott Wood 
42651bb2e9SMarc Zyngier enum arch_timer_erratum_match_type {
43651bb2e9SMarc Zyngier 	ate_match_dt,
440064030cSMarc Zyngier 	ate_match_local_cap_id,
455a38bcacSMarc Zyngier 	ate_match_acpi_oem_info,
46651bb2e9SMarc Zyngier };
47f6dc1576SScott Wood 
4801d3e3ffSMarc Zyngier struct clock_event_device;
4901d3e3ffSMarc Zyngier 
5016d10ef2SDing Tianhong struct arch_timer_erratum_workaround {
51651bb2e9SMarc Zyngier 	enum arch_timer_erratum_match_type match_type;
52651bb2e9SMarc Zyngier 	const void *id;
53651bb2e9SMarc Zyngier 	const char *desc;
5416d10ef2SDing Tianhong 	u32 (*read_cntp_tval_el0)(void);
5516d10ef2SDing Tianhong 	u32 (*read_cntv_tval_el0)(void);
56f2e600c1SChristoffer Dall 	u64 (*read_cntpct_el0)(void);
5716d10ef2SDing Tianhong 	u64 (*read_cntvct_el0)(void);
5801d3e3ffSMarc Zyngier 	int (*set_next_event_phys)(unsigned long, struct clock_event_device *);
5901d3e3ffSMarc Zyngier 	int (*set_next_event_virt)(unsigned long, struct clock_event_device *);
6016d10ef2SDing Tianhong };
6116d10ef2SDing Tianhong 
626acc71ccSMarc Zyngier DECLARE_PER_CPU(const struct arch_timer_erratum_workaround *,
636acc71ccSMarc Zyngier 		timer_unstable_counter_workaround);
64f6dc1576SScott Wood 
6557f27666SMarc Zyngier /* inline sysreg accessors that make erratum_handler() work */
6657f27666SMarc Zyngier static inline notrace u32 arch_timer_read_cntp_tval_el0(void)
6757f27666SMarc Zyngier {
6857f27666SMarc Zyngier 	return read_sysreg(cntp_tval_el0);
6957f27666SMarc Zyngier }
7057f27666SMarc Zyngier 
7157f27666SMarc Zyngier static inline notrace u32 arch_timer_read_cntv_tval_el0(void)
7257f27666SMarc Zyngier {
7357f27666SMarc Zyngier 	return read_sysreg(cntv_tval_el0);
7457f27666SMarc Zyngier }
7557f27666SMarc Zyngier 
7657f27666SMarc Zyngier static inline notrace u64 arch_timer_read_cntpct_el0(void)
7757f27666SMarc Zyngier {
7857f27666SMarc Zyngier 	return read_sysreg(cntpct_el0);
7957f27666SMarc Zyngier }
8057f27666SMarc Zyngier 
8157f27666SMarc Zyngier static inline notrace u64 arch_timer_read_cntvct_el0(void)
8257f27666SMarc Zyngier {
8357f27666SMarc Zyngier 	return read_sysreg(cntvct_el0);
8457f27666SMarc Zyngier }
8557f27666SMarc Zyngier 
86f6dc1576SScott Wood #define arch_timer_reg_read_stable(reg)					\
87f6dc1576SScott Wood 	({								\
88f6dc1576SScott Wood 		u64 _val;						\
8957f27666SMarc Zyngier 									\
90adb4f11eSDing Tianhong 		preempt_disable_notrace();				\
9157f27666SMarc Zyngier 		_val = erratum_handler(read_ ## reg)();			\
92adb4f11eSDing Tianhong 		preempt_enable_notrace();				\
9357f27666SMarc Zyngier 									\
94f6dc1576SScott Wood 		_val;							\
95f6dc1576SScott Wood 	})
96f6dc1576SScott Wood 
97e09f3cc0SStephen Boyd /*
98e09f3cc0SStephen Boyd  * These register accessors are marked inline so the compiler can
99e09f3cc0SStephen Boyd  * nicely work out which register we want, and chuck away the rest of
100e09f3cc0SStephen Boyd  * the code.
101e09f3cc0SStephen Boyd  */
102e09f3cc0SStephen Boyd static __always_inline
10360faddf6SStephen Boyd void arch_timer_reg_write_cp15(int access, enum arch_timer_reg reg, u32 val)
1041aee5d7aSMark Rutland {
1051aee5d7aSMark Rutland 	if (access == ARCH_TIMER_PHYS_ACCESS) {
1061aee5d7aSMark Rutland 		switch (reg) {
1071aee5d7aSMark Rutland 		case ARCH_TIMER_REG_CTRL:
108cd5f22d7SMark Rutland 			write_sysreg(val, cntp_ctl_el0);
1091aee5d7aSMark Rutland 			break;
1101aee5d7aSMark Rutland 		case ARCH_TIMER_REG_TVAL:
111cd5f22d7SMark Rutland 			write_sysreg(val, cntp_tval_el0);
1121aee5d7aSMark Rutland 			break;
1131aee5d7aSMark Rutland 		}
1141aee5d7aSMark Rutland 	} else if (access == ARCH_TIMER_VIRT_ACCESS) {
1151aee5d7aSMark Rutland 		switch (reg) {
1161aee5d7aSMark Rutland 		case ARCH_TIMER_REG_CTRL:
117cd5f22d7SMark Rutland 			write_sysreg(val, cntv_ctl_el0);
1181aee5d7aSMark Rutland 			break;
1191aee5d7aSMark Rutland 		case ARCH_TIMER_REG_TVAL:
120cd5f22d7SMark Rutland 			write_sysreg(val, cntv_tval_el0);
1211aee5d7aSMark Rutland 			break;
1221aee5d7aSMark Rutland 		}
1231aee5d7aSMark Rutland 	}
1241aee5d7aSMark Rutland 
1251aee5d7aSMark Rutland 	isb();
1261aee5d7aSMark Rutland }
1271aee5d7aSMark Rutland 
128e09f3cc0SStephen Boyd static __always_inline
12960faddf6SStephen Boyd u32 arch_timer_reg_read_cp15(int access, enum arch_timer_reg reg)
1301aee5d7aSMark Rutland {
1311aee5d7aSMark Rutland 	if (access == ARCH_TIMER_PHYS_ACCESS) {
1321aee5d7aSMark Rutland 		switch (reg) {
1331aee5d7aSMark Rutland 		case ARCH_TIMER_REG_CTRL:
134cd5f22d7SMark Rutland 			return read_sysreg(cntp_ctl_el0);
1351aee5d7aSMark Rutland 		case ARCH_TIMER_REG_TVAL:
136f6dc1576SScott Wood 			return arch_timer_reg_read_stable(cntp_tval_el0);
1371aee5d7aSMark Rutland 		}
1381aee5d7aSMark Rutland 	} else if (access == ARCH_TIMER_VIRT_ACCESS) {
1391aee5d7aSMark Rutland 		switch (reg) {
1401aee5d7aSMark Rutland 		case ARCH_TIMER_REG_CTRL:
141cd5f22d7SMark Rutland 			return read_sysreg(cntv_ctl_el0);
1421aee5d7aSMark Rutland 		case ARCH_TIMER_REG_TVAL:
143f6dc1576SScott Wood 			return arch_timer_reg_read_stable(cntv_tval_el0);
1441aee5d7aSMark Rutland 		}
1451aee5d7aSMark Rutland 	}
1461aee5d7aSMark Rutland 
147cd5f22d7SMark Rutland 	BUG();
1481aee5d7aSMark Rutland }
1491aee5d7aSMark Rutland 
1501aee5d7aSMark Rutland static inline u32 arch_timer_get_cntfrq(void)
1511aee5d7aSMark Rutland {
152cd5f22d7SMark Rutland 	return read_sysreg(cntfrq_el0);
1531aee5d7aSMark Rutland }
1541aee5d7aSMark Rutland 
15546efe547SSudeep KarkadaNagesha static inline u32 arch_timer_get_cntkctl(void)
1561aee5d7aSMark Rutland {
157cd5f22d7SMark Rutland 	return read_sysreg(cntkctl_el1);
15846efe547SSudeep KarkadaNagesha }
15946efe547SSudeep KarkadaNagesha 
16046efe547SSudeep KarkadaNagesha static inline void arch_timer_set_cntkctl(u32 cntkctl)
16146efe547SSudeep KarkadaNagesha {
162cd5f22d7SMark Rutland 	write_sysreg(cntkctl, cntkctl_el1);
163ec5c8e42SJulien Thierry 	isb();
16446efe547SSudeep KarkadaNagesha }
16546efe547SSudeep KarkadaNagesha 
16675a19a02SWill Deacon /*
16775a19a02SWill Deacon  * Ensure that reads of the counter are treated the same as memory reads
16875a19a02SWill Deacon  * for the purposes of ordering by subsequent memory barriers.
16975a19a02SWill Deacon  *
17075a19a02SWill Deacon  * This insanity brought to you by speculative system register reads,
17175a19a02SWill Deacon  * out-of-order memory accesses, sequence locks and Thomas Gleixner.
17275a19a02SWill Deacon  *
17375a19a02SWill Deacon  * http://lists.infradead.org/pipermail/linux-arm-kernel/2019-February/631195.html
17475a19a02SWill Deacon  */
17575a19a02SWill Deacon #define arch_counter_enforce_ordering(val) do {				\
17675a19a02SWill Deacon 	u64 tmp, _val = (val);						\
17775a19a02SWill Deacon 									\
17875a19a02SWill Deacon 	asm volatile(							\
17975a19a02SWill Deacon 	"	eor	%0, %1, %1\n"					\
18075a19a02SWill Deacon 	"	add	%0, sp, %0\n"					\
18175a19a02SWill Deacon 	"	ldr	xzr, [%0]"					\
18275a19a02SWill Deacon 	: "=r" (tmp) : "r" (_val));					\
18375a19a02SWill Deacon } while (0)
18475a19a02SWill Deacon 
185f31e98bfSAnders Roxell static __always_inline u64 __arch_counter_get_cntpct_stable(void)
1860b46b8a7SSonny Rao {
18775a19a02SWill Deacon 	u64 cnt;
18875a19a02SWill Deacon 
189f2e600c1SChristoffer Dall 	isb();
19075a19a02SWill Deacon 	cnt = arch_timer_reg_read_stable(cntpct_el0);
19175a19a02SWill Deacon 	arch_counter_enforce_ordering(cnt);
19275a19a02SWill Deacon 	return cnt;
1930b46b8a7SSonny Rao }
1940b46b8a7SSonny Rao 
195f31e98bfSAnders Roxell static __always_inline u64 __arch_counter_get_cntpct(void)
1960ea41539SMarc Zyngier {
19724cf262dSWill Deacon 	u64 cnt;
19824cf262dSWill Deacon 
1990ea41539SMarc Zyngier 	isb();
20024cf262dSWill Deacon 	cnt = read_sysreg(cntpct_el0);
20124cf262dSWill Deacon 	arch_counter_enforce_ordering(cnt);
20224cf262dSWill Deacon 	return cnt;
2030ea41539SMarc Zyngier }
2040ea41539SMarc Zyngier 
205f31e98bfSAnders Roxell static __always_inline u64 __arch_counter_get_cntvct_stable(void)
2061aee5d7aSMark Rutland {
20775a19a02SWill Deacon 	u64 cnt;
20875a19a02SWill Deacon 
2091aee5d7aSMark Rutland 	isb();
21075a19a02SWill Deacon 	cnt = arch_timer_reg_read_stable(cntvct_el0);
21175a19a02SWill Deacon 	arch_counter_enforce_ordering(cnt);
21275a19a02SWill Deacon 	return cnt;
2131aee5d7aSMark Rutland }
2141aee5d7aSMark Rutland 
215f31e98bfSAnders Roxell static __always_inline u64 __arch_counter_get_cntvct(void)
2160ea41539SMarc Zyngier {
21724cf262dSWill Deacon 	u64 cnt;
21824cf262dSWill Deacon 
2190ea41539SMarc Zyngier 	isb();
22024cf262dSWill Deacon 	cnt = read_sysreg(cntvct_el0);
22124cf262dSWill Deacon 	arch_counter_enforce_ordering(cnt);
22224cf262dSWill Deacon 	return cnt;
2230ea41539SMarc Zyngier }
2240ea41539SMarc Zyngier 
22575a19a02SWill Deacon #undef arch_counter_enforce_ordering
22675a19a02SWill Deacon 
2270583fe47SRob Herring static inline int arch_timer_arch_init(void)
2280583fe47SRob Herring {
2290583fe47SRob Herring 	return 0;
2300583fe47SRob Herring }
2310583fe47SRob Herring 
2321aee5d7aSMark Rutland #endif
233