xref: /openbmc/linux/arch/arm64/include/asm/arch_timer.h (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
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); \
35db26f8f2SMarc Zyngier 		(__wa && __wa->h) ? ({ isb(); __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 
arch_timer_read_cntpct_el0(void)6557f27666SMarc Zyngier static inline notrace u64 arch_timer_read_cntpct_el0(void)
6657f27666SMarc Zyngier {
679ee840a9SMarc Zyngier 	u64 cnt;
689ee840a9SMarc Zyngier 
699ee840a9SMarc Zyngier 	asm volatile(ALTERNATIVE("isb\n mrs %0, cntpct_el0",
709ee840a9SMarc Zyngier 				 "nop\n" __mrs_s("%0", SYS_CNTPCTSS_EL0),
719ee840a9SMarc Zyngier 				 ARM64_HAS_ECV)
729ee840a9SMarc Zyngier 		     : "=r" (cnt));
739ee840a9SMarc Zyngier 
749ee840a9SMarc Zyngier 	return cnt;
7557f27666SMarc Zyngier }
7657f27666SMarc Zyngier 
arch_timer_read_cntvct_el0(void)7757f27666SMarc Zyngier static inline notrace u64 arch_timer_read_cntvct_el0(void)
7857f27666SMarc Zyngier {
799ee840a9SMarc Zyngier 	u64 cnt;
809ee840a9SMarc Zyngier 
819ee840a9SMarc Zyngier 	asm volatile(ALTERNATIVE("isb\n mrs %0, cntvct_el0",
829ee840a9SMarc Zyngier 				 "nop\n" __mrs_s("%0", SYS_CNTVCTSS_EL0),
839ee840a9SMarc Zyngier 				 ARM64_HAS_ECV)
849ee840a9SMarc Zyngier 		     : "=r" (cnt));
859ee840a9SMarc Zyngier 
869ee840a9SMarc Zyngier 	return cnt;
8757f27666SMarc Zyngier }
8857f27666SMarc Zyngier 
89f6dc1576SScott Wood #define arch_timer_reg_read_stable(reg)					\
90f6dc1576SScott Wood 	({								\
91*24ee7607SPeter Zijlstra 		erratum_handler(read_ ## reg)();			\
92f6dc1576SScott Wood 	})
93f6dc1576SScott Wood 
94e09f3cc0SStephen Boyd /*
95e09f3cc0SStephen Boyd  * These register accessors are marked inline so the compiler can
96e09f3cc0SStephen Boyd  * nicely work out which register we want, and chuck away the rest of
97e09f3cc0SStephen Boyd  * the code.
98e09f3cc0SStephen Boyd  */
99e09f3cc0SStephen Boyd static __always_inline
arch_timer_reg_write_cp15(int access,enum arch_timer_reg reg,u64 val)1001e8d9292SMarc Zyngier void arch_timer_reg_write_cp15(int access, enum arch_timer_reg reg, u64 val)
1011aee5d7aSMark Rutland {
1021aee5d7aSMark Rutland 	if (access == ARCH_TIMER_PHYS_ACCESS) {
1031aee5d7aSMark Rutland 		switch (reg) {
1041aee5d7aSMark Rutland 		case ARCH_TIMER_REG_CTRL:
105cd5f22d7SMark Rutland 			write_sysreg(val, cntp_ctl_el0);
106ec8f7f33SMarc Zyngier 			isb();
1071aee5d7aSMark Rutland 			break;
108a38b71b0SMarc Zyngier 		case ARCH_TIMER_REG_CVAL:
109a38b71b0SMarc Zyngier 			write_sysreg(val, cntp_cval_el0);
1101aee5d7aSMark Rutland 			break;
1114775bc63SMarc Zyngier 		default:
1124775bc63SMarc Zyngier 			BUILD_BUG();
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);
118ec8f7f33SMarc Zyngier 			isb();
1191aee5d7aSMark Rutland 			break;
120a38b71b0SMarc Zyngier 		case ARCH_TIMER_REG_CVAL:
121a38b71b0SMarc Zyngier 			write_sysreg(val, cntv_cval_el0);
1221aee5d7aSMark Rutland 			break;
1234775bc63SMarc Zyngier 		default:
1244775bc63SMarc Zyngier 			BUILD_BUG();
1251aee5d7aSMark Rutland 		}
1264775bc63SMarc Zyngier 	} else {
1274775bc63SMarc Zyngier 		BUILD_BUG();
1281aee5d7aSMark Rutland 	}
1291aee5d7aSMark Rutland }
1301aee5d7aSMark Rutland 
131e09f3cc0SStephen Boyd static __always_inline
arch_timer_reg_read_cp15(int access,enum arch_timer_reg reg)132a38b71b0SMarc Zyngier u64 arch_timer_reg_read_cp15(int access, enum arch_timer_reg reg)
1331aee5d7aSMark Rutland {
1341aee5d7aSMark Rutland 	if (access == ARCH_TIMER_PHYS_ACCESS) {
1351aee5d7aSMark Rutland 		switch (reg) {
1361aee5d7aSMark Rutland 		case ARCH_TIMER_REG_CTRL:
137cd5f22d7SMark Rutland 			return read_sysreg(cntp_ctl_el0);
1384775bc63SMarc Zyngier 		default:
1394775bc63SMarc Zyngier 			BUILD_BUG();
1401aee5d7aSMark Rutland 		}
1411aee5d7aSMark Rutland 	} else if (access == ARCH_TIMER_VIRT_ACCESS) {
1421aee5d7aSMark Rutland 		switch (reg) {
1431aee5d7aSMark Rutland 		case ARCH_TIMER_REG_CTRL:
144cd5f22d7SMark Rutland 			return read_sysreg(cntv_ctl_el0);
1454775bc63SMarc Zyngier 		default:
1464775bc63SMarc Zyngier 			BUILD_BUG();
1471aee5d7aSMark Rutland 		}
1481aee5d7aSMark Rutland 	}
1491aee5d7aSMark Rutland 
1504775bc63SMarc Zyngier 	BUILD_BUG();
1514775bc63SMarc Zyngier 	unreachable();
1521aee5d7aSMark Rutland }
1531aee5d7aSMark Rutland 
arch_timer_get_cntfrq(void)1541aee5d7aSMark Rutland static inline u32 arch_timer_get_cntfrq(void)
1551aee5d7aSMark Rutland {
156cd5f22d7SMark Rutland 	return read_sysreg(cntfrq_el0);
1571aee5d7aSMark Rutland }
1581aee5d7aSMark Rutland 
arch_timer_get_cntkctl(void)15946efe547SSudeep KarkadaNagesha static inline u32 arch_timer_get_cntkctl(void)
1601aee5d7aSMark Rutland {
161cd5f22d7SMark Rutland 	return read_sysreg(cntkctl_el1);
16246efe547SSudeep KarkadaNagesha }
16346efe547SSudeep KarkadaNagesha 
arch_timer_set_cntkctl(u32 cntkctl)16446efe547SSudeep KarkadaNagesha static inline void arch_timer_set_cntkctl(u32 cntkctl)
16546efe547SSudeep KarkadaNagesha {
166cd5f22d7SMark Rutland 	write_sysreg(cntkctl, cntkctl_el1);
167ec5c8e42SJulien Thierry 	isb();
16846efe547SSudeep KarkadaNagesha }
16946efe547SSudeep KarkadaNagesha 
__arch_counter_get_cntpct_stable(void)170f31e98bfSAnders Roxell static __always_inline u64 __arch_counter_get_cntpct_stable(void)
1710b46b8a7SSonny Rao {
17275a19a02SWill Deacon 	u64 cnt;
17375a19a02SWill Deacon 
17475a19a02SWill Deacon 	cnt = arch_timer_reg_read_stable(cntpct_el0);
17575a19a02SWill Deacon 	arch_counter_enforce_ordering(cnt);
17675a19a02SWill Deacon 	return cnt;
1770b46b8a7SSonny Rao }
1780b46b8a7SSonny Rao 
__arch_counter_get_cntpct(void)179f31e98bfSAnders Roxell static __always_inline u64 __arch_counter_get_cntpct(void)
1800ea41539SMarc Zyngier {
18124cf262dSWill Deacon 	u64 cnt;
18224cf262dSWill Deacon 
1839ee840a9SMarc Zyngier 	asm volatile(ALTERNATIVE("isb\n mrs %0, cntpct_el0",
1849ee840a9SMarc Zyngier 				 "nop\n" __mrs_s("%0", SYS_CNTPCTSS_EL0),
1859ee840a9SMarc Zyngier 				 ARM64_HAS_ECV)
1869ee840a9SMarc Zyngier 		     : "=r" (cnt));
18724cf262dSWill Deacon 	arch_counter_enforce_ordering(cnt);
18824cf262dSWill Deacon 	return cnt;
1890ea41539SMarc Zyngier }
1900ea41539SMarc Zyngier 
__arch_counter_get_cntvct_stable(void)191f31e98bfSAnders Roxell static __always_inline u64 __arch_counter_get_cntvct_stable(void)
1921aee5d7aSMark Rutland {
19375a19a02SWill Deacon 	u64 cnt;
19475a19a02SWill Deacon 
19575a19a02SWill Deacon 	cnt = arch_timer_reg_read_stable(cntvct_el0);
19675a19a02SWill Deacon 	arch_counter_enforce_ordering(cnt);
19775a19a02SWill Deacon 	return cnt;
1981aee5d7aSMark Rutland }
1991aee5d7aSMark Rutland 
__arch_counter_get_cntvct(void)200f31e98bfSAnders Roxell static __always_inline u64 __arch_counter_get_cntvct(void)
2010ea41539SMarc Zyngier {
20224cf262dSWill Deacon 	u64 cnt;
20324cf262dSWill Deacon 
2049ee840a9SMarc Zyngier 	asm volatile(ALTERNATIVE("isb\n mrs %0, cntvct_el0",
2059ee840a9SMarc Zyngier 				 "nop\n" __mrs_s("%0", SYS_CNTVCTSS_EL0),
2069ee840a9SMarc Zyngier 				 ARM64_HAS_ECV)
2079ee840a9SMarc Zyngier 		     : "=r" (cnt));
20824cf262dSWill Deacon 	arch_counter_enforce_ordering(cnt);
20924cf262dSWill Deacon 	return cnt;
2100ea41539SMarc Zyngier }
2110ea41539SMarc Zyngier 
arch_timer_arch_init(void)2120583fe47SRob Herring static inline int arch_timer_arch_init(void)
2130583fe47SRob Herring {
2140583fe47SRob Herring 	return 0;
2150583fe47SRob Herring }
2160583fe47SRob Herring 
arch_timer_set_evtstrm_feature(void)2175a354412SAndrew Murray static inline void arch_timer_set_evtstrm_feature(void)
2185a354412SAndrew Murray {
2195a354412SAndrew Murray 	cpu_set_named_feature(EVTSTRM);
2205a354412SAndrew Murray #ifdef CONFIG_COMPAT
2215a354412SAndrew Murray 	compat_elf_hwcap |= COMPAT_HWCAP_EVTSTRM;
2225a354412SAndrew Murray #endif
2235a354412SAndrew Murray }
2245a354412SAndrew Murray 
arch_timer_have_evtstrm_feature(void)2255a354412SAndrew Murray static inline bool arch_timer_have_evtstrm_feature(void)
2265a354412SAndrew Murray {
2275a354412SAndrew Murray 	return cpu_have_named_feature(EVTSTRM);
2285a354412SAndrew Murray }
2291aee5d7aSMark Rutland #endif
230