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