xref: /openbmc/linux/arch/arm64/include/asm/arch_timer.h (revision 5a354412567d7de81d69b6ac61c3b7fcebbe497e)
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>
23*5a354412SAndrew Murray #include <asm/hwcap.h>
24cd5f22d7SMark Rutland #include <asm/sysreg.h>
251aee5d7aSMark Rutland 
26082471a8SPaul Walmsley #include <linux/bug.h>
271aee5d7aSMark Rutland #include <linux/init.h>
28f6dc1576SScott Wood #include <linux/jump_label.h>
296acc71ccSMarc Zyngier #include <linux/smp.h>
301aee5d7aSMark Rutland #include <linux/types.h>
311aee5d7aSMark Rutland 
321aee5d7aSMark Rutland #include <clocksource/arm_arch_timer.h>
331aee5d7aSMark Rutland 
3416d10ef2SDing Tianhong #if IS_ENABLED(CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND)
355ef19a16SMarc Zyngier #define has_erratum_handler(h)						\
365ef19a16SMarc Zyngier 	({								\
375ef19a16SMarc Zyngier 		const struct arch_timer_erratum_workaround *__wa;	\
385ef19a16SMarc Zyngier 		__wa = __this_cpu_read(timer_unstable_counter_workaround); \
395ef19a16SMarc Zyngier 		(__wa && __wa->h);					\
405ef19a16SMarc Zyngier 	})
415ef19a16SMarc Zyngier 
425ef19a16SMarc Zyngier #define erratum_handler(h)						\
435ef19a16SMarc Zyngier 	({								\
445ef19a16SMarc Zyngier 		const struct arch_timer_erratum_workaround *__wa;	\
455ef19a16SMarc Zyngier 		__wa = __this_cpu_read(timer_unstable_counter_workaround); \
465ef19a16SMarc Zyngier 		(__wa && __wa->h) ? __wa->h : arch_timer_##h;		\
475ef19a16SMarc Zyngier 	})
485ef19a16SMarc Zyngier 
49f6dc1576SScott Wood #else
505ef19a16SMarc Zyngier #define has_erratum_handler(h)			   false
515ef19a16SMarc Zyngier #define erratum_handler(h)			   (arch_timer_##h)
52f6dc1576SScott Wood #endif
53f6dc1576SScott Wood 
54651bb2e9SMarc Zyngier enum arch_timer_erratum_match_type {
55651bb2e9SMarc Zyngier 	ate_match_dt,
560064030cSMarc Zyngier 	ate_match_local_cap_id,
575a38bcacSMarc Zyngier 	ate_match_acpi_oem_info,
58651bb2e9SMarc Zyngier };
59f6dc1576SScott Wood 
6001d3e3ffSMarc Zyngier struct clock_event_device;
6101d3e3ffSMarc Zyngier 
6216d10ef2SDing Tianhong struct arch_timer_erratum_workaround {
63651bb2e9SMarc Zyngier 	enum arch_timer_erratum_match_type match_type;
64651bb2e9SMarc Zyngier 	const void *id;
65651bb2e9SMarc Zyngier 	const char *desc;
6616d10ef2SDing Tianhong 	u32 (*read_cntp_tval_el0)(void);
6716d10ef2SDing Tianhong 	u32 (*read_cntv_tval_el0)(void);
68f2e600c1SChristoffer Dall 	u64 (*read_cntpct_el0)(void);
6916d10ef2SDing Tianhong 	u64 (*read_cntvct_el0)(void);
7001d3e3ffSMarc Zyngier 	int (*set_next_event_phys)(unsigned long, struct clock_event_device *);
7101d3e3ffSMarc Zyngier 	int (*set_next_event_virt)(unsigned long, struct clock_event_device *);
7216d10ef2SDing Tianhong };
7316d10ef2SDing Tianhong 
746acc71ccSMarc Zyngier DECLARE_PER_CPU(const struct arch_timer_erratum_workaround *,
756acc71ccSMarc Zyngier 		timer_unstable_counter_workaround);
76f6dc1576SScott Wood 
7757f27666SMarc Zyngier /* inline sysreg accessors that make erratum_handler() work */
7857f27666SMarc Zyngier static inline notrace u32 arch_timer_read_cntp_tval_el0(void)
7957f27666SMarc Zyngier {
8057f27666SMarc Zyngier 	return read_sysreg(cntp_tval_el0);
8157f27666SMarc Zyngier }
8257f27666SMarc Zyngier 
8357f27666SMarc Zyngier static inline notrace u32 arch_timer_read_cntv_tval_el0(void)
8457f27666SMarc Zyngier {
8557f27666SMarc Zyngier 	return read_sysreg(cntv_tval_el0);
8657f27666SMarc Zyngier }
8757f27666SMarc Zyngier 
8857f27666SMarc Zyngier static inline notrace u64 arch_timer_read_cntpct_el0(void)
8957f27666SMarc Zyngier {
9057f27666SMarc Zyngier 	return read_sysreg(cntpct_el0);
9157f27666SMarc Zyngier }
9257f27666SMarc Zyngier 
9357f27666SMarc Zyngier static inline notrace u64 arch_timer_read_cntvct_el0(void)
9457f27666SMarc Zyngier {
9557f27666SMarc Zyngier 	return read_sysreg(cntvct_el0);
9657f27666SMarc Zyngier }
9757f27666SMarc Zyngier 
98f6dc1576SScott Wood #define arch_timer_reg_read_stable(reg)					\
99f6dc1576SScott Wood 	({								\
100f6dc1576SScott Wood 		u64 _val;						\
10157f27666SMarc Zyngier 									\
102adb4f11eSDing Tianhong 		preempt_disable_notrace();				\
10357f27666SMarc Zyngier 		_val = erratum_handler(read_ ## reg)();			\
104adb4f11eSDing Tianhong 		preempt_enable_notrace();				\
10557f27666SMarc Zyngier 									\
106f6dc1576SScott Wood 		_val;							\
107f6dc1576SScott Wood 	})
108f6dc1576SScott Wood 
109e09f3cc0SStephen Boyd /*
110e09f3cc0SStephen Boyd  * These register accessors are marked inline so the compiler can
111e09f3cc0SStephen Boyd  * nicely work out which register we want, and chuck away the rest of
112e09f3cc0SStephen Boyd  * the code.
113e09f3cc0SStephen Boyd  */
114e09f3cc0SStephen Boyd static __always_inline
11560faddf6SStephen Boyd void arch_timer_reg_write_cp15(int access, enum arch_timer_reg reg, u32 val)
1161aee5d7aSMark Rutland {
1171aee5d7aSMark Rutland 	if (access == ARCH_TIMER_PHYS_ACCESS) {
1181aee5d7aSMark Rutland 		switch (reg) {
1191aee5d7aSMark Rutland 		case ARCH_TIMER_REG_CTRL:
120cd5f22d7SMark Rutland 			write_sysreg(val, cntp_ctl_el0);
1211aee5d7aSMark Rutland 			break;
1221aee5d7aSMark Rutland 		case ARCH_TIMER_REG_TVAL:
123cd5f22d7SMark Rutland 			write_sysreg(val, cntp_tval_el0);
1241aee5d7aSMark Rutland 			break;
1251aee5d7aSMark Rutland 		}
1261aee5d7aSMark Rutland 	} else if (access == ARCH_TIMER_VIRT_ACCESS) {
1271aee5d7aSMark Rutland 		switch (reg) {
1281aee5d7aSMark Rutland 		case ARCH_TIMER_REG_CTRL:
129cd5f22d7SMark Rutland 			write_sysreg(val, cntv_ctl_el0);
1301aee5d7aSMark Rutland 			break;
1311aee5d7aSMark Rutland 		case ARCH_TIMER_REG_TVAL:
132cd5f22d7SMark Rutland 			write_sysreg(val, cntv_tval_el0);
1331aee5d7aSMark Rutland 			break;
1341aee5d7aSMark Rutland 		}
1351aee5d7aSMark Rutland 	}
1361aee5d7aSMark Rutland 
1371aee5d7aSMark Rutland 	isb();
1381aee5d7aSMark Rutland }
1391aee5d7aSMark Rutland 
140e09f3cc0SStephen Boyd static __always_inline
14160faddf6SStephen Boyd u32 arch_timer_reg_read_cp15(int access, enum arch_timer_reg reg)
1421aee5d7aSMark Rutland {
1431aee5d7aSMark Rutland 	if (access == ARCH_TIMER_PHYS_ACCESS) {
1441aee5d7aSMark Rutland 		switch (reg) {
1451aee5d7aSMark Rutland 		case ARCH_TIMER_REG_CTRL:
146cd5f22d7SMark Rutland 			return read_sysreg(cntp_ctl_el0);
1471aee5d7aSMark Rutland 		case ARCH_TIMER_REG_TVAL:
148f6dc1576SScott Wood 			return arch_timer_reg_read_stable(cntp_tval_el0);
1491aee5d7aSMark Rutland 		}
1501aee5d7aSMark Rutland 	} else if (access == ARCH_TIMER_VIRT_ACCESS) {
1511aee5d7aSMark Rutland 		switch (reg) {
1521aee5d7aSMark Rutland 		case ARCH_TIMER_REG_CTRL:
153cd5f22d7SMark Rutland 			return read_sysreg(cntv_ctl_el0);
1541aee5d7aSMark Rutland 		case ARCH_TIMER_REG_TVAL:
155f6dc1576SScott Wood 			return arch_timer_reg_read_stable(cntv_tval_el0);
1561aee5d7aSMark Rutland 		}
1571aee5d7aSMark Rutland 	}
1581aee5d7aSMark Rutland 
159cd5f22d7SMark Rutland 	BUG();
1601aee5d7aSMark Rutland }
1611aee5d7aSMark Rutland 
1621aee5d7aSMark Rutland static inline u32 arch_timer_get_cntfrq(void)
1631aee5d7aSMark Rutland {
164cd5f22d7SMark Rutland 	return read_sysreg(cntfrq_el0);
1651aee5d7aSMark Rutland }
1661aee5d7aSMark Rutland 
16746efe547SSudeep KarkadaNagesha static inline u32 arch_timer_get_cntkctl(void)
1681aee5d7aSMark Rutland {
169cd5f22d7SMark Rutland 	return read_sysreg(cntkctl_el1);
17046efe547SSudeep KarkadaNagesha }
17146efe547SSudeep KarkadaNagesha 
17246efe547SSudeep KarkadaNagesha static inline void arch_timer_set_cntkctl(u32 cntkctl)
17346efe547SSudeep KarkadaNagesha {
174cd5f22d7SMark Rutland 	write_sysreg(cntkctl, cntkctl_el1);
175ec5c8e42SJulien Thierry 	isb();
17646efe547SSudeep KarkadaNagesha }
17746efe547SSudeep KarkadaNagesha 
17875a19a02SWill Deacon /*
17975a19a02SWill Deacon  * Ensure that reads of the counter are treated the same as memory reads
18075a19a02SWill Deacon  * for the purposes of ordering by subsequent memory barriers.
18175a19a02SWill Deacon  *
18275a19a02SWill Deacon  * This insanity brought to you by speculative system register reads,
18375a19a02SWill Deacon  * out-of-order memory accesses, sequence locks and Thomas Gleixner.
18475a19a02SWill Deacon  *
18575a19a02SWill Deacon  * http://lists.infradead.org/pipermail/linux-arm-kernel/2019-February/631195.html
18675a19a02SWill Deacon  */
18775a19a02SWill Deacon #define arch_counter_enforce_ordering(val) do {				\
18875a19a02SWill Deacon 	u64 tmp, _val = (val);						\
18975a19a02SWill Deacon 									\
19075a19a02SWill Deacon 	asm volatile(							\
19175a19a02SWill Deacon 	"	eor	%0, %1, %1\n"					\
19275a19a02SWill Deacon 	"	add	%0, sp, %0\n"					\
19375a19a02SWill Deacon 	"	ldr	xzr, [%0]"					\
19475a19a02SWill Deacon 	: "=r" (tmp) : "r" (_val));					\
19575a19a02SWill Deacon } while (0)
19675a19a02SWill Deacon 
197f31e98bfSAnders Roxell static __always_inline u64 __arch_counter_get_cntpct_stable(void)
1980b46b8a7SSonny Rao {
19975a19a02SWill Deacon 	u64 cnt;
20075a19a02SWill Deacon 
201f2e600c1SChristoffer Dall 	isb();
20275a19a02SWill Deacon 	cnt = arch_timer_reg_read_stable(cntpct_el0);
20375a19a02SWill Deacon 	arch_counter_enforce_ordering(cnt);
20475a19a02SWill Deacon 	return cnt;
2050b46b8a7SSonny Rao }
2060b46b8a7SSonny Rao 
207f31e98bfSAnders Roxell static __always_inline u64 __arch_counter_get_cntpct(void)
2080ea41539SMarc Zyngier {
20924cf262dSWill Deacon 	u64 cnt;
21024cf262dSWill Deacon 
2110ea41539SMarc Zyngier 	isb();
21224cf262dSWill Deacon 	cnt = read_sysreg(cntpct_el0);
21324cf262dSWill Deacon 	arch_counter_enforce_ordering(cnt);
21424cf262dSWill Deacon 	return cnt;
2150ea41539SMarc Zyngier }
2160ea41539SMarc Zyngier 
217f31e98bfSAnders Roxell static __always_inline u64 __arch_counter_get_cntvct_stable(void)
2181aee5d7aSMark Rutland {
21975a19a02SWill Deacon 	u64 cnt;
22075a19a02SWill Deacon 
2211aee5d7aSMark Rutland 	isb();
22275a19a02SWill Deacon 	cnt = arch_timer_reg_read_stable(cntvct_el0);
22375a19a02SWill Deacon 	arch_counter_enforce_ordering(cnt);
22475a19a02SWill Deacon 	return cnt;
2251aee5d7aSMark Rutland }
2261aee5d7aSMark Rutland 
227f31e98bfSAnders Roxell static __always_inline u64 __arch_counter_get_cntvct(void)
2280ea41539SMarc Zyngier {
22924cf262dSWill Deacon 	u64 cnt;
23024cf262dSWill Deacon 
2310ea41539SMarc Zyngier 	isb();
23224cf262dSWill Deacon 	cnt = read_sysreg(cntvct_el0);
23324cf262dSWill Deacon 	arch_counter_enforce_ordering(cnt);
23424cf262dSWill Deacon 	return cnt;
2350ea41539SMarc Zyngier }
2360ea41539SMarc Zyngier 
23775a19a02SWill Deacon #undef arch_counter_enforce_ordering
23875a19a02SWill Deacon 
2390583fe47SRob Herring static inline int arch_timer_arch_init(void)
2400583fe47SRob Herring {
2410583fe47SRob Herring 	return 0;
2420583fe47SRob Herring }
2430583fe47SRob Herring 
244*5a354412SAndrew Murray static inline void arch_timer_set_evtstrm_feature(void)
245*5a354412SAndrew Murray {
246*5a354412SAndrew Murray 	cpu_set_named_feature(EVTSTRM);
247*5a354412SAndrew Murray #ifdef CONFIG_COMPAT
248*5a354412SAndrew Murray 	compat_elf_hwcap |= COMPAT_HWCAP_EVTSTRM;
249*5a354412SAndrew Murray #endif
250*5a354412SAndrew Murray }
251*5a354412SAndrew Murray 
252*5a354412SAndrew Murray static inline bool arch_timer_have_evtstrm_feature(void)
253*5a354412SAndrew Murray {
254*5a354412SAndrew Murray 	return cpu_have_named_feature(EVTSTRM);
255*5a354412SAndrew Murray }
2561aee5d7aSMark Rutland #endif
257