xref: /openbmc/linux/arch/arm64/include/asm/arch_timer.h (revision 57f27666f91a85431492b092f5db53ecab1a0739)
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 extern struct static_key_false arch_timer_read_ool_enabled;
4916d10ef2SDing Tianhong #define needs_unstable_timer_counter_workaround() \
50f6dc1576SScott Wood 	static_branch_unlikely(&arch_timer_read_ool_enabled)
51f6dc1576SScott Wood #else
525ef19a16SMarc Zyngier #define has_erratum_handler(h)			   false
535ef19a16SMarc Zyngier #define erratum_handler(h)			   (arch_timer_##h)
5416d10ef2SDing Tianhong #define needs_unstable_timer_counter_workaround()  false
55f6dc1576SScott Wood #endif
56f6dc1576SScott Wood 
57651bb2e9SMarc Zyngier enum arch_timer_erratum_match_type {
58651bb2e9SMarc Zyngier 	ate_match_dt,
590064030cSMarc Zyngier 	ate_match_local_cap_id,
605a38bcacSMarc Zyngier 	ate_match_acpi_oem_info,
61651bb2e9SMarc Zyngier };
62f6dc1576SScott Wood 
6301d3e3ffSMarc Zyngier struct clock_event_device;
6401d3e3ffSMarc Zyngier 
6516d10ef2SDing Tianhong struct arch_timer_erratum_workaround {
66651bb2e9SMarc Zyngier 	enum arch_timer_erratum_match_type match_type;
67651bb2e9SMarc Zyngier 	const void *id;
68651bb2e9SMarc Zyngier 	const char *desc;
6916d10ef2SDing Tianhong 	u32 (*read_cntp_tval_el0)(void);
7016d10ef2SDing Tianhong 	u32 (*read_cntv_tval_el0)(void);
71f2e600c1SChristoffer Dall 	u64 (*read_cntpct_el0)(void);
7216d10ef2SDing Tianhong 	u64 (*read_cntvct_el0)(void);
7301d3e3ffSMarc Zyngier 	int (*set_next_event_phys)(unsigned long, struct clock_event_device *);
7401d3e3ffSMarc Zyngier 	int (*set_next_event_virt)(unsigned long, struct clock_event_device *);
7516d10ef2SDing Tianhong };
7616d10ef2SDing Tianhong 
776acc71ccSMarc Zyngier DECLARE_PER_CPU(const struct arch_timer_erratum_workaround *,
786acc71ccSMarc Zyngier 		timer_unstable_counter_workaround);
79f6dc1576SScott Wood 
80*57f27666SMarc Zyngier /* inline sysreg accessors that make erratum_handler() work */
81*57f27666SMarc Zyngier static inline notrace u32 arch_timer_read_cntp_tval_el0(void)
82*57f27666SMarc Zyngier {
83*57f27666SMarc Zyngier 	return read_sysreg(cntp_tval_el0);
84*57f27666SMarc Zyngier }
85*57f27666SMarc Zyngier 
86*57f27666SMarc Zyngier static inline notrace u32 arch_timer_read_cntv_tval_el0(void)
87*57f27666SMarc Zyngier {
88*57f27666SMarc Zyngier 	return read_sysreg(cntv_tval_el0);
89*57f27666SMarc Zyngier }
90*57f27666SMarc Zyngier 
91*57f27666SMarc Zyngier static inline notrace u64 arch_timer_read_cntpct_el0(void)
92*57f27666SMarc Zyngier {
93*57f27666SMarc Zyngier 	return read_sysreg(cntpct_el0);
94*57f27666SMarc Zyngier }
95*57f27666SMarc Zyngier 
96*57f27666SMarc Zyngier static inline notrace u64 arch_timer_read_cntvct_el0(void)
97*57f27666SMarc Zyngier {
98*57f27666SMarc Zyngier 	return read_sysreg(cntvct_el0);
99*57f27666SMarc Zyngier }
100*57f27666SMarc Zyngier 
101f6dc1576SScott Wood #define arch_timer_reg_read_stable(reg)					\
102f6dc1576SScott Wood 	({								\
103f6dc1576SScott Wood 		u64 _val;						\
104*57f27666SMarc Zyngier 									\
105adb4f11eSDing Tianhong 		preempt_disable_notrace();				\
106*57f27666SMarc Zyngier 		_val = erratum_handler(read_ ## reg)();			\
107adb4f11eSDing Tianhong 		preempt_enable_notrace();				\
108*57f27666SMarc Zyngier 									\
109f6dc1576SScott Wood 		_val;							\
110f6dc1576SScott Wood 	})
111f6dc1576SScott Wood 
112e09f3cc0SStephen Boyd /*
113e09f3cc0SStephen Boyd  * These register accessors are marked inline so the compiler can
114e09f3cc0SStephen Boyd  * nicely work out which register we want, and chuck away the rest of
115e09f3cc0SStephen Boyd  * the code.
116e09f3cc0SStephen Boyd  */
117e09f3cc0SStephen Boyd static __always_inline
11860faddf6SStephen Boyd void arch_timer_reg_write_cp15(int access, enum arch_timer_reg reg, u32 val)
1191aee5d7aSMark Rutland {
1201aee5d7aSMark Rutland 	if (access == ARCH_TIMER_PHYS_ACCESS) {
1211aee5d7aSMark Rutland 		switch (reg) {
1221aee5d7aSMark Rutland 		case ARCH_TIMER_REG_CTRL:
123cd5f22d7SMark Rutland 			write_sysreg(val, cntp_ctl_el0);
1241aee5d7aSMark Rutland 			break;
1251aee5d7aSMark Rutland 		case ARCH_TIMER_REG_TVAL:
126cd5f22d7SMark Rutland 			write_sysreg(val, cntp_tval_el0);
1271aee5d7aSMark Rutland 			break;
1281aee5d7aSMark Rutland 		}
1291aee5d7aSMark Rutland 	} else if (access == ARCH_TIMER_VIRT_ACCESS) {
1301aee5d7aSMark Rutland 		switch (reg) {
1311aee5d7aSMark Rutland 		case ARCH_TIMER_REG_CTRL:
132cd5f22d7SMark Rutland 			write_sysreg(val, cntv_ctl_el0);
1331aee5d7aSMark Rutland 			break;
1341aee5d7aSMark Rutland 		case ARCH_TIMER_REG_TVAL:
135cd5f22d7SMark Rutland 			write_sysreg(val, cntv_tval_el0);
1361aee5d7aSMark Rutland 			break;
1371aee5d7aSMark Rutland 		}
1381aee5d7aSMark Rutland 	}
1391aee5d7aSMark Rutland 
1401aee5d7aSMark Rutland 	isb();
1411aee5d7aSMark Rutland }
1421aee5d7aSMark Rutland 
143e09f3cc0SStephen Boyd static __always_inline
14460faddf6SStephen Boyd u32 arch_timer_reg_read_cp15(int access, enum arch_timer_reg reg)
1451aee5d7aSMark Rutland {
1461aee5d7aSMark Rutland 	if (access == ARCH_TIMER_PHYS_ACCESS) {
1471aee5d7aSMark Rutland 		switch (reg) {
1481aee5d7aSMark Rutland 		case ARCH_TIMER_REG_CTRL:
149cd5f22d7SMark Rutland 			return read_sysreg(cntp_ctl_el0);
1501aee5d7aSMark Rutland 		case ARCH_TIMER_REG_TVAL:
151f6dc1576SScott Wood 			return arch_timer_reg_read_stable(cntp_tval_el0);
1521aee5d7aSMark Rutland 		}
1531aee5d7aSMark Rutland 	} else if (access == ARCH_TIMER_VIRT_ACCESS) {
1541aee5d7aSMark Rutland 		switch (reg) {
1551aee5d7aSMark Rutland 		case ARCH_TIMER_REG_CTRL:
156cd5f22d7SMark Rutland 			return read_sysreg(cntv_ctl_el0);
1571aee5d7aSMark Rutland 		case ARCH_TIMER_REG_TVAL:
158f6dc1576SScott Wood 			return arch_timer_reg_read_stable(cntv_tval_el0);
1591aee5d7aSMark Rutland 		}
1601aee5d7aSMark Rutland 	}
1611aee5d7aSMark Rutland 
162cd5f22d7SMark Rutland 	BUG();
1631aee5d7aSMark Rutland }
1641aee5d7aSMark Rutland 
1651aee5d7aSMark Rutland static inline u32 arch_timer_get_cntfrq(void)
1661aee5d7aSMark Rutland {
167cd5f22d7SMark Rutland 	return read_sysreg(cntfrq_el0);
1681aee5d7aSMark Rutland }
1691aee5d7aSMark Rutland 
17046efe547SSudeep KarkadaNagesha static inline u32 arch_timer_get_cntkctl(void)
1711aee5d7aSMark Rutland {
172cd5f22d7SMark Rutland 	return read_sysreg(cntkctl_el1);
17346efe547SSudeep KarkadaNagesha }
17446efe547SSudeep KarkadaNagesha 
17546efe547SSudeep KarkadaNagesha static inline void arch_timer_set_cntkctl(u32 cntkctl)
17646efe547SSudeep KarkadaNagesha {
177cd5f22d7SMark Rutland 	write_sysreg(cntkctl, cntkctl_el1);
178ec5c8e42SJulien Thierry 	isb();
17946efe547SSudeep KarkadaNagesha }
18046efe547SSudeep KarkadaNagesha 
1810b46b8a7SSonny Rao static inline u64 arch_counter_get_cntpct(void)
1820b46b8a7SSonny Rao {
183f2e600c1SChristoffer Dall 	isb();
184f2e600c1SChristoffer Dall 	return arch_timer_reg_read_stable(cntpct_el0);
1850b46b8a7SSonny Rao }
1860b46b8a7SSonny Rao 
1871aee5d7aSMark Rutland static inline u64 arch_counter_get_cntvct(void)
1881aee5d7aSMark Rutland {
1891aee5d7aSMark Rutland 	isb();
190f6dc1576SScott Wood 	return arch_timer_reg_read_stable(cntvct_el0);
1911aee5d7aSMark Rutland }
1921aee5d7aSMark Rutland 
1930583fe47SRob Herring static inline int arch_timer_arch_init(void)
1940583fe47SRob Herring {
1950583fe47SRob Herring 	return 0;
1960583fe47SRob Herring }
1970583fe47SRob Herring 
1981aee5d7aSMark Rutland #endif
199