1*caab277bSThomas 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> 12cd5f22d7SMark Rutland #include <asm/sysreg.h> 131aee5d7aSMark Rutland 14082471a8SPaul Walmsley #include <linux/bug.h> 151aee5d7aSMark Rutland #include <linux/init.h> 16f6dc1576SScott Wood #include <linux/jump_label.h> 176acc71ccSMarc Zyngier #include <linux/smp.h> 181aee5d7aSMark Rutland #include <linux/types.h> 191aee5d7aSMark Rutland 201aee5d7aSMark Rutland #include <clocksource/arm_arch_timer.h> 211aee5d7aSMark Rutland 2216d10ef2SDing Tianhong #if IS_ENABLED(CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND) 235ef19a16SMarc Zyngier #define has_erratum_handler(h) \ 245ef19a16SMarc Zyngier ({ \ 255ef19a16SMarc Zyngier const struct arch_timer_erratum_workaround *__wa; \ 265ef19a16SMarc Zyngier __wa = __this_cpu_read(timer_unstable_counter_workaround); \ 275ef19a16SMarc Zyngier (__wa && __wa->h); \ 285ef19a16SMarc Zyngier }) 295ef19a16SMarc Zyngier 305ef19a16SMarc Zyngier #define erratum_handler(h) \ 315ef19a16SMarc Zyngier ({ \ 325ef19a16SMarc Zyngier const struct arch_timer_erratum_workaround *__wa; \ 335ef19a16SMarc Zyngier __wa = __this_cpu_read(timer_unstable_counter_workaround); \ 345ef19a16SMarc Zyngier (__wa && __wa->h) ? __wa->h : arch_timer_##h; \ 355ef19a16SMarc Zyngier }) 365ef19a16SMarc Zyngier 37f6dc1576SScott Wood #else 385ef19a16SMarc Zyngier #define has_erratum_handler(h) false 395ef19a16SMarc Zyngier #define erratum_handler(h) (arch_timer_##h) 40f6dc1576SScott Wood #endif 41f6dc1576SScott Wood 42651bb2e9SMarc Zyngier enum arch_timer_erratum_match_type { 43651bb2e9SMarc Zyngier ate_match_dt, 440064030cSMarc Zyngier ate_match_local_cap_id, 455a38bcacSMarc Zyngier ate_match_acpi_oem_info, 46651bb2e9SMarc Zyngier }; 47f6dc1576SScott Wood 4801d3e3ffSMarc Zyngier struct clock_event_device; 4901d3e3ffSMarc Zyngier 5016d10ef2SDing Tianhong struct arch_timer_erratum_workaround { 51651bb2e9SMarc Zyngier enum arch_timer_erratum_match_type match_type; 52651bb2e9SMarc Zyngier const void *id; 53651bb2e9SMarc Zyngier const char *desc; 5416d10ef2SDing Tianhong u32 (*read_cntp_tval_el0)(void); 5516d10ef2SDing Tianhong u32 (*read_cntv_tval_el0)(void); 56f2e600c1SChristoffer Dall u64 (*read_cntpct_el0)(void); 5716d10ef2SDing Tianhong u64 (*read_cntvct_el0)(void); 5801d3e3ffSMarc Zyngier int (*set_next_event_phys)(unsigned long, struct clock_event_device *); 5901d3e3ffSMarc Zyngier int (*set_next_event_virt)(unsigned long, struct clock_event_device *); 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 /* inline sysreg accessors that make erratum_handler() work */ 6657f27666SMarc Zyngier static inline notrace u32 arch_timer_read_cntp_tval_el0(void) 6757f27666SMarc Zyngier { 6857f27666SMarc Zyngier return read_sysreg(cntp_tval_el0); 6957f27666SMarc Zyngier } 7057f27666SMarc Zyngier 7157f27666SMarc Zyngier static inline notrace u32 arch_timer_read_cntv_tval_el0(void) 7257f27666SMarc Zyngier { 7357f27666SMarc Zyngier return read_sysreg(cntv_tval_el0); 7457f27666SMarc Zyngier } 7557f27666SMarc Zyngier 7657f27666SMarc Zyngier static inline notrace u64 arch_timer_read_cntpct_el0(void) 7757f27666SMarc Zyngier { 7857f27666SMarc Zyngier return read_sysreg(cntpct_el0); 7957f27666SMarc Zyngier } 8057f27666SMarc Zyngier 8157f27666SMarc Zyngier static inline notrace u64 arch_timer_read_cntvct_el0(void) 8257f27666SMarc Zyngier { 8357f27666SMarc Zyngier return read_sysreg(cntvct_el0); 8457f27666SMarc Zyngier } 8557f27666SMarc Zyngier 86f6dc1576SScott Wood #define arch_timer_reg_read_stable(reg) \ 87f6dc1576SScott Wood ({ \ 88f6dc1576SScott Wood u64 _val; \ 8957f27666SMarc Zyngier \ 90adb4f11eSDing Tianhong preempt_disable_notrace(); \ 9157f27666SMarc Zyngier _val = erratum_handler(read_ ## reg)(); \ 92adb4f11eSDing Tianhong preempt_enable_notrace(); \ 9357f27666SMarc Zyngier \ 94f6dc1576SScott Wood _val; \ 95f6dc1576SScott Wood }) 96f6dc1576SScott Wood 97e09f3cc0SStephen Boyd /* 98e09f3cc0SStephen Boyd * These register accessors are marked inline so the compiler can 99e09f3cc0SStephen Boyd * nicely work out which register we want, and chuck away the rest of 100e09f3cc0SStephen Boyd * the code. 101e09f3cc0SStephen Boyd */ 102e09f3cc0SStephen Boyd static __always_inline 10360faddf6SStephen Boyd void arch_timer_reg_write_cp15(int access, enum arch_timer_reg reg, u32 val) 1041aee5d7aSMark Rutland { 1051aee5d7aSMark Rutland if (access == ARCH_TIMER_PHYS_ACCESS) { 1061aee5d7aSMark Rutland switch (reg) { 1071aee5d7aSMark Rutland case ARCH_TIMER_REG_CTRL: 108cd5f22d7SMark Rutland write_sysreg(val, cntp_ctl_el0); 1091aee5d7aSMark Rutland break; 1101aee5d7aSMark Rutland case ARCH_TIMER_REG_TVAL: 111cd5f22d7SMark Rutland write_sysreg(val, cntp_tval_el0); 1121aee5d7aSMark Rutland break; 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); 1181aee5d7aSMark Rutland break; 1191aee5d7aSMark Rutland case ARCH_TIMER_REG_TVAL: 120cd5f22d7SMark Rutland write_sysreg(val, cntv_tval_el0); 1211aee5d7aSMark Rutland break; 1221aee5d7aSMark Rutland } 1231aee5d7aSMark Rutland } 1241aee5d7aSMark Rutland 1251aee5d7aSMark Rutland isb(); 1261aee5d7aSMark Rutland } 1271aee5d7aSMark Rutland 128e09f3cc0SStephen Boyd static __always_inline 12960faddf6SStephen Boyd u32 arch_timer_reg_read_cp15(int access, enum arch_timer_reg reg) 1301aee5d7aSMark Rutland { 1311aee5d7aSMark Rutland if (access == ARCH_TIMER_PHYS_ACCESS) { 1321aee5d7aSMark Rutland switch (reg) { 1331aee5d7aSMark Rutland case ARCH_TIMER_REG_CTRL: 134cd5f22d7SMark Rutland return read_sysreg(cntp_ctl_el0); 1351aee5d7aSMark Rutland case ARCH_TIMER_REG_TVAL: 136f6dc1576SScott Wood return arch_timer_reg_read_stable(cntp_tval_el0); 1371aee5d7aSMark Rutland } 1381aee5d7aSMark Rutland } else if (access == ARCH_TIMER_VIRT_ACCESS) { 1391aee5d7aSMark Rutland switch (reg) { 1401aee5d7aSMark Rutland case ARCH_TIMER_REG_CTRL: 141cd5f22d7SMark Rutland return read_sysreg(cntv_ctl_el0); 1421aee5d7aSMark Rutland case ARCH_TIMER_REG_TVAL: 143f6dc1576SScott Wood return arch_timer_reg_read_stable(cntv_tval_el0); 1441aee5d7aSMark Rutland } 1451aee5d7aSMark Rutland } 1461aee5d7aSMark Rutland 147cd5f22d7SMark Rutland BUG(); 1481aee5d7aSMark Rutland } 1491aee5d7aSMark Rutland 1501aee5d7aSMark Rutland static inline u32 arch_timer_get_cntfrq(void) 1511aee5d7aSMark Rutland { 152cd5f22d7SMark Rutland return read_sysreg(cntfrq_el0); 1531aee5d7aSMark Rutland } 1541aee5d7aSMark Rutland 15546efe547SSudeep KarkadaNagesha static inline u32 arch_timer_get_cntkctl(void) 1561aee5d7aSMark Rutland { 157cd5f22d7SMark Rutland return read_sysreg(cntkctl_el1); 15846efe547SSudeep KarkadaNagesha } 15946efe547SSudeep KarkadaNagesha 16046efe547SSudeep KarkadaNagesha static inline void arch_timer_set_cntkctl(u32 cntkctl) 16146efe547SSudeep KarkadaNagesha { 162cd5f22d7SMark Rutland write_sysreg(cntkctl, cntkctl_el1); 163ec5c8e42SJulien Thierry isb(); 16446efe547SSudeep KarkadaNagesha } 16546efe547SSudeep KarkadaNagesha 16675a19a02SWill Deacon /* 16775a19a02SWill Deacon * Ensure that reads of the counter are treated the same as memory reads 16875a19a02SWill Deacon * for the purposes of ordering by subsequent memory barriers. 16975a19a02SWill Deacon * 17075a19a02SWill Deacon * This insanity brought to you by speculative system register reads, 17175a19a02SWill Deacon * out-of-order memory accesses, sequence locks and Thomas Gleixner. 17275a19a02SWill Deacon * 17375a19a02SWill Deacon * http://lists.infradead.org/pipermail/linux-arm-kernel/2019-February/631195.html 17475a19a02SWill Deacon */ 17575a19a02SWill Deacon #define arch_counter_enforce_ordering(val) do { \ 17675a19a02SWill Deacon u64 tmp, _val = (val); \ 17775a19a02SWill Deacon \ 17875a19a02SWill Deacon asm volatile( \ 17975a19a02SWill Deacon " eor %0, %1, %1\n" \ 18075a19a02SWill Deacon " add %0, sp, %0\n" \ 18175a19a02SWill Deacon " ldr xzr, [%0]" \ 18275a19a02SWill Deacon : "=r" (tmp) : "r" (_val)); \ 18375a19a02SWill Deacon } while (0) 18475a19a02SWill Deacon 185f31e98bfSAnders Roxell static __always_inline u64 __arch_counter_get_cntpct_stable(void) 1860b46b8a7SSonny Rao { 18775a19a02SWill Deacon u64 cnt; 18875a19a02SWill Deacon 189f2e600c1SChristoffer Dall isb(); 19075a19a02SWill Deacon cnt = arch_timer_reg_read_stable(cntpct_el0); 19175a19a02SWill Deacon arch_counter_enforce_ordering(cnt); 19275a19a02SWill Deacon return cnt; 1930b46b8a7SSonny Rao } 1940b46b8a7SSonny Rao 195f31e98bfSAnders Roxell static __always_inline u64 __arch_counter_get_cntpct(void) 1960ea41539SMarc Zyngier { 19724cf262dSWill Deacon u64 cnt; 19824cf262dSWill Deacon 1990ea41539SMarc Zyngier isb(); 20024cf262dSWill Deacon cnt = read_sysreg(cntpct_el0); 20124cf262dSWill Deacon arch_counter_enforce_ordering(cnt); 20224cf262dSWill Deacon return cnt; 2030ea41539SMarc Zyngier } 2040ea41539SMarc Zyngier 205f31e98bfSAnders Roxell static __always_inline u64 __arch_counter_get_cntvct_stable(void) 2061aee5d7aSMark Rutland { 20775a19a02SWill Deacon u64 cnt; 20875a19a02SWill Deacon 2091aee5d7aSMark Rutland isb(); 21075a19a02SWill Deacon cnt = arch_timer_reg_read_stable(cntvct_el0); 21175a19a02SWill Deacon arch_counter_enforce_ordering(cnt); 21275a19a02SWill Deacon return cnt; 2131aee5d7aSMark Rutland } 2141aee5d7aSMark Rutland 215f31e98bfSAnders Roxell static __always_inline u64 __arch_counter_get_cntvct(void) 2160ea41539SMarc Zyngier { 21724cf262dSWill Deacon u64 cnt; 21824cf262dSWill Deacon 2190ea41539SMarc Zyngier isb(); 22024cf262dSWill Deacon cnt = read_sysreg(cntvct_el0); 22124cf262dSWill Deacon arch_counter_enforce_ordering(cnt); 22224cf262dSWill Deacon return cnt; 2230ea41539SMarc Zyngier } 2240ea41539SMarc Zyngier 22575a19a02SWill Deacon #undef arch_counter_enforce_ordering 22675a19a02SWill Deacon 2270583fe47SRob Herring static inline int arch_timer_arch_init(void) 2280583fe47SRob Herring { 2290583fe47SRob Herring return 0; 2300583fe47SRob Herring } 2310583fe47SRob Herring 2321aee5d7aSMark Rutland #endif 233