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