xref: /openbmc/linux/arch/arm64/include/asm/arch_timer.h (revision a38b71b0833eb2fabd2b1fa37d665c0a88b8b7e4)
1caab277bSThomas 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>
125a354412SAndrew Murray #include <asm/hwcap.h>
13cd5f22d7SMark Rutland #include <asm/sysreg.h>
141aee5d7aSMark Rutland 
15082471a8SPaul Walmsley #include <linux/bug.h>
161aee5d7aSMark Rutland #include <linux/init.h>
17f6dc1576SScott Wood #include <linux/jump_label.h>
186acc71ccSMarc Zyngier #include <linux/smp.h>
191aee5d7aSMark Rutland #include <linux/types.h>
201aee5d7aSMark Rutland 
211aee5d7aSMark Rutland #include <clocksource/arm_arch_timer.h>
221aee5d7aSMark Rutland 
2316d10ef2SDing Tianhong #if IS_ENABLED(CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND)
245ef19a16SMarc Zyngier #define has_erratum_handler(h)						\
255ef19a16SMarc Zyngier 	({								\
265ef19a16SMarc Zyngier 		const struct arch_timer_erratum_workaround *__wa;	\
275ef19a16SMarc Zyngier 		__wa = __this_cpu_read(timer_unstable_counter_workaround); \
285ef19a16SMarc Zyngier 		(__wa && __wa->h);					\
295ef19a16SMarc Zyngier 	})
305ef19a16SMarc Zyngier 
315ef19a16SMarc Zyngier #define erratum_handler(h)						\
325ef19a16SMarc Zyngier 	({								\
335ef19a16SMarc Zyngier 		const struct arch_timer_erratum_workaround *__wa;	\
345ef19a16SMarc Zyngier 		__wa = __this_cpu_read(timer_unstable_counter_workaround); \
355ef19a16SMarc Zyngier 		(__wa && __wa->h) ? __wa->h : arch_timer_##h;		\
365ef19a16SMarc Zyngier 	})
375ef19a16SMarc Zyngier 
38f6dc1576SScott Wood #else
395ef19a16SMarc Zyngier #define has_erratum_handler(h)			   false
405ef19a16SMarc Zyngier #define erratum_handler(h)			   (arch_timer_##h)
41f6dc1576SScott Wood #endif
42f6dc1576SScott Wood 
43651bb2e9SMarc Zyngier enum arch_timer_erratum_match_type {
44651bb2e9SMarc Zyngier 	ate_match_dt,
450064030cSMarc Zyngier 	ate_match_local_cap_id,
465a38bcacSMarc Zyngier 	ate_match_acpi_oem_info,
47651bb2e9SMarc Zyngier };
48f6dc1576SScott Wood 
4901d3e3ffSMarc Zyngier struct clock_event_device;
5001d3e3ffSMarc Zyngier 
5116d10ef2SDing Tianhong struct arch_timer_erratum_workaround {
52651bb2e9SMarc Zyngier 	enum arch_timer_erratum_match_type match_type;
53651bb2e9SMarc Zyngier 	const void *id;
54651bb2e9SMarc Zyngier 	const char *desc;
55f2e600c1SChristoffer Dall 	u64 (*read_cntpct_el0)(void);
5616d10ef2SDing Tianhong 	u64 (*read_cntvct_el0)(void);
5701d3e3ffSMarc Zyngier 	int (*set_next_event_phys)(unsigned long, struct clock_event_device *);
5801d3e3ffSMarc Zyngier 	int (*set_next_event_virt)(unsigned long, struct clock_event_device *);
59c1fbec4aSMarc Zyngier 	bool disable_compat_vdso;
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 static inline notrace u64 arch_timer_read_cntpct_el0(void)
6657f27666SMarc Zyngier {
6757f27666SMarc Zyngier 	return read_sysreg(cntpct_el0);
6857f27666SMarc Zyngier }
6957f27666SMarc Zyngier 
7057f27666SMarc Zyngier static inline notrace u64 arch_timer_read_cntvct_el0(void)
7157f27666SMarc Zyngier {
7257f27666SMarc Zyngier 	return read_sysreg(cntvct_el0);
7357f27666SMarc Zyngier }
7457f27666SMarc Zyngier 
75f6dc1576SScott Wood #define arch_timer_reg_read_stable(reg)					\
76f6dc1576SScott Wood 	({								\
77f6dc1576SScott Wood 		u64 _val;						\
7857f27666SMarc Zyngier 									\
79adb4f11eSDing Tianhong 		preempt_disable_notrace();				\
8057f27666SMarc Zyngier 		_val = erratum_handler(read_ ## reg)();			\
81adb4f11eSDing Tianhong 		preempt_enable_notrace();				\
8257f27666SMarc Zyngier 									\
83f6dc1576SScott Wood 		_val;							\
84f6dc1576SScott Wood 	})
85f6dc1576SScott Wood 
86e09f3cc0SStephen Boyd /*
87e09f3cc0SStephen Boyd  * These register accessors are marked inline so the compiler can
88e09f3cc0SStephen Boyd  * nicely work out which register we want, and chuck away the rest of
89e09f3cc0SStephen Boyd  * the code.
90e09f3cc0SStephen Boyd  */
91e09f3cc0SStephen Boyd static __always_inline
921e8d9292SMarc Zyngier void arch_timer_reg_write_cp15(int access, enum arch_timer_reg reg, u64 val)
931aee5d7aSMark Rutland {
941aee5d7aSMark Rutland 	if (access == ARCH_TIMER_PHYS_ACCESS) {
951aee5d7aSMark Rutland 		switch (reg) {
961aee5d7aSMark Rutland 		case ARCH_TIMER_REG_CTRL:
97cd5f22d7SMark Rutland 			write_sysreg(val, cntp_ctl_el0);
981aee5d7aSMark Rutland 			break;
99*a38b71b0SMarc Zyngier 		case ARCH_TIMER_REG_CVAL:
100*a38b71b0SMarc Zyngier 			write_sysreg(val, cntp_cval_el0);
1011aee5d7aSMark Rutland 			break;
1024775bc63SMarc Zyngier 		default:
1034775bc63SMarc Zyngier 			BUILD_BUG();
1041aee5d7aSMark Rutland 		}
1051aee5d7aSMark Rutland 	} else if (access == ARCH_TIMER_VIRT_ACCESS) {
1061aee5d7aSMark Rutland 		switch (reg) {
1071aee5d7aSMark Rutland 		case ARCH_TIMER_REG_CTRL:
108cd5f22d7SMark Rutland 			write_sysreg(val, cntv_ctl_el0);
1091aee5d7aSMark Rutland 			break;
110*a38b71b0SMarc Zyngier 		case ARCH_TIMER_REG_CVAL:
111*a38b71b0SMarc Zyngier 			write_sysreg(val, cntv_cval_el0);
1121aee5d7aSMark Rutland 			break;
1134775bc63SMarc Zyngier 		default:
1144775bc63SMarc Zyngier 			BUILD_BUG();
1151aee5d7aSMark Rutland 		}
1164775bc63SMarc Zyngier 	} else {
1174775bc63SMarc Zyngier 		BUILD_BUG();
1181aee5d7aSMark Rutland 	}
1191aee5d7aSMark Rutland 
1201aee5d7aSMark Rutland 	isb();
1211aee5d7aSMark Rutland }
1221aee5d7aSMark Rutland 
123e09f3cc0SStephen Boyd static __always_inline
124*a38b71b0SMarc Zyngier u64 arch_timer_reg_read_cp15(int access, enum arch_timer_reg reg)
1251aee5d7aSMark Rutland {
1261aee5d7aSMark Rutland 	if (access == ARCH_TIMER_PHYS_ACCESS) {
1271aee5d7aSMark Rutland 		switch (reg) {
1281aee5d7aSMark Rutland 		case ARCH_TIMER_REG_CTRL:
129cd5f22d7SMark Rutland 			return read_sysreg(cntp_ctl_el0);
1304775bc63SMarc Zyngier 		default:
1314775bc63SMarc Zyngier 			BUILD_BUG();
1321aee5d7aSMark Rutland 		}
1331aee5d7aSMark Rutland 	} else if (access == ARCH_TIMER_VIRT_ACCESS) {
1341aee5d7aSMark Rutland 		switch (reg) {
1351aee5d7aSMark Rutland 		case ARCH_TIMER_REG_CTRL:
136cd5f22d7SMark Rutland 			return read_sysreg(cntv_ctl_el0);
1374775bc63SMarc Zyngier 		default:
1384775bc63SMarc Zyngier 			BUILD_BUG();
1391aee5d7aSMark Rutland 		}
1401aee5d7aSMark Rutland 	}
1411aee5d7aSMark Rutland 
1424775bc63SMarc Zyngier 	BUILD_BUG();
1434775bc63SMarc Zyngier 	unreachable();
1441aee5d7aSMark Rutland }
1451aee5d7aSMark Rutland 
1461aee5d7aSMark Rutland static inline u32 arch_timer_get_cntfrq(void)
1471aee5d7aSMark Rutland {
148cd5f22d7SMark Rutland 	return read_sysreg(cntfrq_el0);
1491aee5d7aSMark Rutland }
1501aee5d7aSMark Rutland 
15146efe547SSudeep KarkadaNagesha static inline u32 arch_timer_get_cntkctl(void)
1521aee5d7aSMark Rutland {
153cd5f22d7SMark Rutland 	return read_sysreg(cntkctl_el1);
15446efe547SSudeep KarkadaNagesha }
15546efe547SSudeep KarkadaNagesha 
15646efe547SSudeep KarkadaNagesha static inline void arch_timer_set_cntkctl(u32 cntkctl)
15746efe547SSudeep KarkadaNagesha {
158cd5f22d7SMark Rutland 	write_sysreg(cntkctl, cntkctl_el1);
159ec5c8e42SJulien Thierry 	isb();
16046efe547SSudeep KarkadaNagesha }
16146efe547SSudeep KarkadaNagesha 
162f31e98bfSAnders Roxell static __always_inline u64 __arch_counter_get_cntpct_stable(void)
1630b46b8a7SSonny Rao {
16475a19a02SWill Deacon 	u64 cnt;
16575a19a02SWill Deacon 
166f2e600c1SChristoffer Dall 	isb();
16775a19a02SWill Deacon 	cnt = arch_timer_reg_read_stable(cntpct_el0);
16875a19a02SWill Deacon 	arch_counter_enforce_ordering(cnt);
16975a19a02SWill Deacon 	return cnt;
1700b46b8a7SSonny Rao }
1710b46b8a7SSonny Rao 
172f31e98bfSAnders Roxell static __always_inline u64 __arch_counter_get_cntpct(void)
1730ea41539SMarc Zyngier {
17424cf262dSWill Deacon 	u64 cnt;
17524cf262dSWill Deacon 
1760ea41539SMarc Zyngier 	isb();
17724cf262dSWill Deacon 	cnt = read_sysreg(cntpct_el0);
17824cf262dSWill Deacon 	arch_counter_enforce_ordering(cnt);
17924cf262dSWill Deacon 	return cnt;
1800ea41539SMarc Zyngier }
1810ea41539SMarc Zyngier 
182f31e98bfSAnders Roxell static __always_inline u64 __arch_counter_get_cntvct_stable(void)
1831aee5d7aSMark Rutland {
18475a19a02SWill Deacon 	u64 cnt;
18575a19a02SWill Deacon 
1861aee5d7aSMark Rutland 	isb();
18775a19a02SWill Deacon 	cnt = arch_timer_reg_read_stable(cntvct_el0);
18875a19a02SWill Deacon 	arch_counter_enforce_ordering(cnt);
18975a19a02SWill Deacon 	return cnt;
1901aee5d7aSMark Rutland }
1911aee5d7aSMark Rutland 
192f31e98bfSAnders Roxell static __always_inline u64 __arch_counter_get_cntvct(void)
1930ea41539SMarc Zyngier {
19424cf262dSWill Deacon 	u64 cnt;
19524cf262dSWill Deacon 
1960ea41539SMarc Zyngier 	isb();
19724cf262dSWill Deacon 	cnt = read_sysreg(cntvct_el0);
19824cf262dSWill Deacon 	arch_counter_enforce_ordering(cnt);
19924cf262dSWill Deacon 	return cnt;
2000ea41539SMarc Zyngier }
2010ea41539SMarc Zyngier 
2020583fe47SRob Herring static inline int arch_timer_arch_init(void)
2030583fe47SRob Herring {
2040583fe47SRob Herring 	return 0;
2050583fe47SRob Herring }
2060583fe47SRob Herring 
2075a354412SAndrew Murray static inline void arch_timer_set_evtstrm_feature(void)
2085a354412SAndrew Murray {
2095a354412SAndrew Murray 	cpu_set_named_feature(EVTSTRM);
2105a354412SAndrew Murray #ifdef CONFIG_COMPAT
2115a354412SAndrew Murray 	compat_elf_hwcap |= COMPAT_HWCAP_EVTSTRM;
2125a354412SAndrew Murray #endif
2135a354412SAndrew Murray }
2145a354412SAndrew Murray 
2155a354412SAndrew Murray static inline bool arch_timer_have_evtstrm_feature(void)
2165a354412SAndrew Murray {
2175a354412SAndrew Murray 	return cpu_have_named_feature(EVTSTRM);
2185a354412SAndrew Murray }
2191aee5d7aSMark Rutland #endif
220