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