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 #else 495ef19a16SMarc Zyngier #define has_erratum_handler(h) false 505ef19a16SMarc Zyngier #define erratum_handler(h) (arch_timer_##h) 51f6dc1576SScott Wood #endif 52f6dc1576SScott Wood 53651bb2e9SMarc Zyngier enum arch_timer_erratum_match_type { 54651bb2e9SMarc Zyngier ate_match_dt, 550064030cSMarc Zyngier ate_match_local_cap_id, 565a38bcacSMarc Zyngier ate_match_acpi_oem_info, 57651bb2e9SMarc Zyngier }; 58f6dc1576SScott Wood 5901d3e3ffSMarc Zyngier struct clock_event_device; 6001d3e3ffSMarc Zyngier 6116d10ef2SDing Tianhong struct arch_timer_erratum_workaround { 62651bb2e9SMarc Zyngier enum arch_timer_erratum_match_type match_type; 63651bb2e9SMarc Zyngier const void *id; 64651bb2e9SMarc Zyngier const char *desc; 6516d10ef2SDing Tianhong u32 (*read_cntp_tval_el0)(void); 6616d10ef2SDing Tianhong u32 (*read_cntv_tval_el0)(void); 67f2e600c1SChristoffer Dall u64 (*read_cntpct_el0)(void); 6816d10ef2SDing Tianhong u64 (*read_cntvct_el0)(void); 6901d3e3ffSMarc Zyngier int (*set_next_event_phys)(unsigned long, struct clock_event_device *); 7001d3e3ffSMarc Zyngier int (*set_next_event_virt)(unsigned long, struct clock_event_device *); 7116d10ef2SDing Tianhong }; 7216d10ef2SDing Tianhong 736acc71ccSMarc Zyngier DECLARE_PER_CPU(const struct arch_timer_erratum_workaround *, 746acc71ccSMarc Zyngier timer_unstable_counter_workaround); 75f6dc1576SScott Wood 7657f27666SMarc Zyngier /* inline sysreg accessors that make erratum_handler() work */ 7757f27666SMarc Zyngier static inline notrace u32 arch_timer_read_cntp_tval_el0(void) 7857f27666SMarc Zyngier { 7957f27666SMarc Zyngier return read_sysreg(cntp_tval_el0); 8057f27666SMarc Zyngier } 8157f27666SMarc Zyngier 8257f27666SMarc Zyngier static inline notrace u32 arch_timer_read_cntv_tval_el0(void) 8357f27666SMarc Zyngier { 8457f27666SMarc Zyngier return read_sysreg(cntv_tval_el0); 8557f27666SMarc Zyngier } 8657f27666SMarc Zyngier 8757f27666SMarc Zyngier static inline notrace u64 arch_timer_read_cntpct_el0(void) 8857f27666SMarc Zyngier { 8957f27666SMarc Zyngier return read_sysreg(cntpct_el0); 9057f27666SMarc Zyngier } 9157f27666SMarc Zyngier 9257f27666SMarc Zyngier static inline notrace u64 arch_timer_read_cntvct_el0(void) 9357f27666SMarc Zyngier { 9457f27666SMarc Zyngier return read_sysreg(cntvct_el0); 9557f27666SMarc Zyngier } 9657f27666SMarc Zyngier 97f6dc1576SScott Wood #define arch_timer_reg_read_stable(reg) \ 98f6dc1576SScott Wood ({ \ 99f6dc1576SScott Wood u64 _val; \ 10057f27666SMarc Zyngier \ 101adb4f11eSDing Tianhong preempt_disable_notrace(); \ 10257f27666SMarc Zyngier _val = erratum_handler(read_ ## reg)(); \ 103adb4f11eSDing Tianhong preempt_enable_notrace(); \ 10457f27666SMarc Zyngier \ 105f6dc1576SScott Wood _val; \ 106f6dc1576SScott Wood }) 107f6dc1576SScott Wood 108e09f3cc0SStephen Boyd /* 109e09f3cc0SStephen Boyd * These register accessors are marked inline so the compiler can 110e09f3cc0SStephen Boyd * nicely work out which register we want, and chuck away the rest of 111e09f3cc0SStephen Boyd * the code. 112e09f3cc0SStephen Boyd */ 113e09f3cc0SStephen Boyd static __always_inline 11460faddf6SStephen Boyd void arch_timer_reg_write_cp15(int access, enum arch_timer_reg reg, u32 val) 1151aee5d7aSMark Rutland { 1161aee5d7aSMark Rutland if (access == ARCH_TIMER_PHYS_ACCESS) { 1171aee5d7aSMark Rutland switch (reg) { 1181aee5d7aSMark Rutland case ARCH_TIMER_REG_CTRL: 119cd5f22d7SMark Rutland write_sysreg(val, cntp_ctl_el0); 1201aee5d7aSMark Rutland break; 1211aee5d7aSMark Rutland case ARCH_TIMER_REG_TVAL: 122cd5f22d7SMark Rutland write_sysreg(val, cntp_tval_el0); 1231aee5d7aSMark Rutland break; 1241aee5d7aSMark Rutland } 1251aee5d7aSMark Rutland } else if (access == ARCH_TIMER_VIRT_ACCESS) { 1261aee5d7aSMark Rutland switch (reg) { 1271aee5d7aSMark Rutland case ARCH_TIMER_REG_CTRL: 128cd5f22d7SMark Rutland write_sysreg(val, cntv_ctl_el0); 1291aee5d7aSMark Rutland break; 1301aee5d7aSMark Rutland case ARCH_TIMER_REG_TVAL: 131cd5f22d7SMark Rutland write_sysreg(val, cntv_tval_el0); 1321aee5d7aSMark Rutland break; 1331aee5d7aSMark Rutland } 1341aee5d7aSMark Rutland } 1351aee5d7aSMark Rutland 1361aee5d7aSMark Rutland isb(); 1371aee5d7aSMark Rutland } 1381aee5d7aSMark Rutland 139e09f3cc0SStephen Boyd static __always_inline 14060faddf6SStephen Boyd u32 arch_timer_reg_read_cp15(int access, enum arch_timer_reg reg) 1411aee5d7aSMark Rutland { 1421aee5d7aSMark Rutland if (access == ARCH_TIMER_PHYS_ACCESS) { 1431aee5d7aSMark Rutland switch (reg) { 1441aee5d7aSMark Rutland case ARCH_TIMER_REG_CTRL: 145cd5f22d7SMark Rutland return read_sysreg(cntp_ctl_el0); 1461aee5d7aSMark Rutland case ARCH_TIMER_REG_TVAL: 147f6dc1576SScott Wood return arch_timer_reg_read_stable(cntp_tval_el0); 1481aee5d7aSMark Rutland } 1491aee5d7aSMark Rutland } else if (access == ARCH_TIMER_VIRT_ACCESS) { 1501aee5d7aSMark Rutland switch (reg) { 1511aee5d7aSMark Rutland case ARCH_TIMER_REG_CTRL: 152cd5f22d7SMark Rutland return read_sysreg(cntv_ctl_el0); 1531aee5d7aSMark Rutland case ARCH_TIMER_REG_TVAL: 154f6dc1576SScott Wood return arch_timer_reg_read_stable(cntv_tval_el0); 1551aee5d7aSMark Rutland } 1561aee5d7aSMark Rutland } 1571aee5d7aSMark Rutland 158cd5f22d7SMark Rutland BUG(); 1591aee5d7aSMark Rutland } 1601aee5d7aSMark Rutland 1611aee5d7aSMark Rutland static inline u32 arch_timer_get_cntfrq(void) 1621aee5d7aSMark Rutland { 163cd5f22d7SMark Rutland return read_sysreg(cntfrq_el0); 1641aee5d7aSMark Rutland } 1651aee5d7aSMark Rutland 16646efe547SSudeep KarkadaNagesha static inline u32 arch_timer_get_cntkctl(void) 1671aee5d7aSMark Rutland { 168cd5f22d7SMark Rutland return read_sysreg(cntkctl_el1); 16946efe547SSudeep KarkadaNagesha } 17046efe547SSudeep KarkadaNagesha 17146efe547SSudeep KarkadaNagesha static inline void arch_timer_set_cntkctl(u32 cntkctl) 17246efe547SSudeep KarkadaNagesha { 173cd5f22d7SMark Rutland write_sysreg(cntkctl, cntkctl_el1); 174ec5c8e42SJulien Thierry isb(); 17546efe547SSudeep KarkadaNagesha } 17646efe547SSudeep KarkadaNagesha 17775a19a02SWill Deacon /* 17875a19a02SWill Deacon * Ensure that reads of the counter are treated the same as memory reads 17975a19a02SWill Deacon * for the purposes of ordering by subsequent memory barriers. 18075a19a02SWill Deacon * 18175a19a02SWill Deacon * This insanity brought to you by speculative system register reads, 18275a19a02SWill Deacon * out-of-order memory accesses, sequence locks and Thomas Gleixner. 18375a19a02SWill Deacon * 18475a19a02SWill Deacon * http://lists.infradead.org/pipermail/linux-arm-kernel/2019-February/631195.html 18575a19a02SWill Deacon */ 18675a19a02SWill Deacon #define arch_counter_enforce_ordering(val) do { \ 18775a19a02SWill Deacon u64 tmp, _val = (val); \ 18875a19a02SWill Deacon \ 18975a19a02SWill Deacon asm volatile( \ 19075a19a02SWill Deacon " eor %0, %1, %1\n" \ 19175a19a02SWill Deacon " add %0, sp, %0\n" \ 19275a19a02SWill Deacon " ldr xzr, [%0]" \ 19375a19a02SWill Deacon : "=r" (tmp) : "r" (_val)); \ 19475a19a02SWill Deacon } while (0) 19575a19a02SWill Deacon 1960ea41539SMarc Zyngier static inline u64 __arch_counter_get_cntpct_stable(void) 1970b46b8a7SSonny Rao { 19875a19a02SWill Deacon u64 cnt; 19975a19a02SWill Deacon 200f2e600c1SChristoffer Dall isb(); 20175a19a02SWill Deacon cnt = arch_timer_reg_read_stable(cntpct_el0); 20275a19a02SWill Deacon arch_counter_enforce_ordering(cnt); 20375a19a02SWill Deacon return cnt; 2040b46b8a7SSonny Rao } 2050b46b8a7SSonny Rao 2060ea41539SMarc Zyngier static inline u64 __arch_counter_get_cntpct(void) 2070ea41539SMarc Zyngier { 208*24cf262dSWill Deacon u64 cnt; 209*24cf262dSWill Deacon 2100ea41539SMarc Zyngier isb(); 211*24cf262dSWill Deacon cnt = read_sysreg(cntpct_el0); 212*24cf262dSWill Deacon arch_counter_enforce_ordering(cnt); 213*24cf262dSWill Deacon return cnt; 2140ea41539SMarc Zyngier } 2150ea41539SMarc Zyngier 2160ea41539SMarc Zyngier static inline u64 __arch_counter_get_cntvct_stable(void) 2171aee5d7aSMark Rutland { 21875a19a02SWill Deacon u64 cnt; 21975a19a02SWill Deacon 2201aee5d7aSMark Rutland isb(); 22175a19a02SWill Deacon cnt = arch_timer_reg_read_stable(cntvct_el0); 22275a19a02SWill Deacon arch_counter_enforce_ordering(cnt); 22375a19a02SWill Deacon return cnt; 2241aee5d7aSMark Rutland } 2251aee5d7aSMark Rutland 2260ea41539SMarc Zyngier static inline u64 __arch_counter_get_cntvct(void) 2270ea41539SMarc Zyngier { 228*24cf262dSWill Deacon u64 cnt; 229*24cf262dSWill Deacon 2300ea41539SMarc Zyngier isb(); 231*24cf262dSWill Deacon cnt = read_sysreg(cntvct_el0); 232*24cf262dSWill Deacon arch_counter_enforce_ordering(cnt); 233*24cf262dSWill Deacon return cnt; 2340ea41539SMarc Zyngier } 2350ea41539SMarc Zyngier 23675a19a02SWill Deacon #undef arch_counter_enforce_ordering 23775a19a02SWill Deacon 2380583fe47SRob Herring static inline int arch_timer_arch_init(void) 2390583fe47SRob Herring { 2400583fe47SRob Herring return 0; 2410583fe47SRob Herring } 2420583fe47SRob Herring 2431aee5d7aSMark Rutland #endif 244