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 extern struct static_key_false arch_timer_read_ool_enabled; 4916d10ef2SDing Tianhong #define needs_unstable_timer_counter_workaround() \ 50f6dc1576SScott Wood static_branch_unlikely(&arch_timer_read_ool_enabled) 51f6dc1576SScott Wood #else 525ef19a16SMarc Zyngier #define has_erratum_handler(h) false 535ef19a16SMarc Zyngier #define erratum_handler(h) (arch_timer_##h) 5416d10ef2SDing Tianhong #define needs_unstable_timer_counter_workaround() false 55f6dc1576SScott Wood #endif 56f6dc1576SScott Wood 57651bb2e9SMarc Zyngier enum arch_timer_erratum_match_type { 58651bb2e9SMarc Zyngier ate_match_dt, 590064030cSMarc Zyngier ate_match_local_cap_id, 605a38bcacSMarc Zyngier ate_match_acpi_oem_info, 61651bb2e9SMarc Zyngier }; 62f6dc1576SScott Wood 6301d3e3ffSMarc Zyngier struct clock_event_device; 6401d3e3ffSMarc Zyngier 6516d10ef2SDing Tianhong struct arch_timer_erratum_workaround { 66651bb2e9SMarc Zyngier enum arch_timer_erratum_match_type match_type; 67651bb2e9SMarc Zyngier const void *id; 68651bb2e9SMarc Zyngier const char *desc; 6916d10ef2SDing Tianhong u32 (*read_cntp_tval_el0)(void); 7016d10ef2SDing Tianhong u32 (*read_cntv_tval_el0)(void); 71f2e600c1SChristoffer Dall u64 (*read_cntpct_el0)(void); 7216d10ef2SDing Tianhong u64 (*read_cntvct_el0)(void); 7301d3e3ffSMarc Zyngier int (*set_next_event_phys)(unsigned long, struct clock_event_device *); 7401d3e3ffSMarc Zyngier int (*set_next_event_virt)(unsigned long, struct clock_event_device *); 7516d10ef2SDing Tianhong }; 7616d10ef2SDing Tianhong 776acc71ccSMarc Zyngier DECLARE_PER_CPU(const struct arch_timer_erratum_workaround *, 786acc71ccSMarc Zyngier timer_unstable_counter_workaround); 79f6dc1576SScott Wood 80*57f27666SMarc Zyngier /* inline sysreg accessors that make erratum_handler() work */ 81*57f27666SMarc Zyngier static inline notrace u32 arch_timer_read_cntp_tval_el0(void) 82*57f27666SMarc Zyngier { 83*57f27666SMarc Zyngier return read_sysreg(cntp_tval_el0); 84*57f27666SMarc Zyngier } 85*57f27666SMarc Zyngier 86*57f27666SMarc Zyngier static inline notrace u32 arch_timer_read_cntv_tval_el0(void) 87*57f27666SMarc Zyngier { 88*57f27666SMarc Zyngier return read_sysreg(cntv_tval_el0); 89*57f27666SMarc Zyngier } 90*57f27666SMarc Zyngier 91*57f27666SMarc Zyngier static inline notrace u64 arch_timer_read_cntpct_el0(void) 92*57f27666SMarc Zyngier { 93*57f27666SMarc Zyngier return read_sysreg(cntpct_el0); 94*57f27666SMarc Zyngier } 95*57f27666SMarc Zyngier 96*57f27666SMarc Zyngier static inline notrace u64 arch_timer_read_cntvct_el0(void) 97*57f27666SMarc Zyngier { 98*57f27666SMarc Zyngier return read_sysreg(cntvct_el0); 99*57f27666SMarc Zyngier } 100*57f27666SMarc Zyngier 101f6dc1576SScott Wood #define arch_timer_reg_read_stable(reg) \ 102f6dc1576SScott Wood ({ \ 103f6dc1576SScott Wood u64 _val; \ 104*57f27666SMarc Zyngier \ 105adb4f11eSDing Tianhong preempt_disable_notrace(); \ 106*57f27666SMarc Zyngier _val = erratum_handler(read_ ## reg)(); \ 107adb4f11eSDing Tianhong preempt_enable_notrace(); \ 108*57f27666SMarc Zyngier \ 109f6dc1576SScott Wood _val; \ 110f6dc1576SScott Wood }) 111f6dc1576SScott Wood 112e09f3cc0SStephen Boyd /* 113e09f3cc0SStephen Boyd * These register accessors are marked inline so the compiler can 114e09f3cc0SStephen Boyd * nicely work out which register we want, and chuck away the rest of 115e09f3cc0SStephen Boyd * the code. 116e09f3cc0SStephen Boyd */ 117e09f3cc0SStephen Boyd static __always_inline 11860faddf6SStephen Boyd void arch_timer_reg_write_cp15(int access, enum arch_timer_reg reg, u32 val) 1191aee5d7aSMark Rutland { 1201aee5d7aSMark Rutland if (access == ARCH_TIMER_PHYS_ACCESS) { 1211aee5d7aSMark Rutland switch (reg) { 1221aee5d7aSMark Rutland case ARCH_TIMER_REG_CTRL: 123cd5f22d7SMark Rutland write_sysreg(val, cntp_ctl_el0); 1241aee5d7aSMark Rutland break; 1251aee5d7aSMark Rutland case ARCH_TIMER_REG_TVAL: 126cd5f22d7SMark Rutland write_sysreg(val, cntp_tval_el0); 1271aee5d7aSMark Rutland break; 1281aee5d7aSMark Rutland } 1291aee5d7aSMark Rutland } else if (access == ARCH_TIMER_VIRT_ACCESS) { 1301aee5d7aSMark Rutland switch (reg) { 1311aee5d7aSMark Rutland case ARCH_TIMER_REG_CTRL: 132cd5f22d7SMark Rutland write_sysreg(val, cntv_ctl_el0); 1331aee5d7aSMark Rutland break; 1341aee5d7aSMark Rutland case ARCH_TIMER_REG_TVAL: 135cd5f22d7SMark Rutland write_sysreg(val, cntv_tval_el0); 1361aee5d7aSMark Rutland break; 1371aee5d7aSMark Rutland } 1381aee5d7aSMark Rutland } 1391aee5d7aSMark Rutland 1401aee5d7aSMark Rutland isb(); 1411aee5d7aSMark Rutland } 1421aee5d7aSMark Rutland 143e09f3cc0SStephen Boyd static __always_inline 14460faddf6SStephen Boyd u32 arch_timer_reg_read_cp15(int access, enum arch_timer_reg reg) 1451aee5d7aSMark Rutland { 1461aee5d7aSMark Rutland if (access == ARCH_TIMER_PHYS_ACCESS) { 1471aee5d7aSMark Rutland switch (reg) { 1481aee5d7aSMark Rutland case ARCH_TIMER_REG_CTRL: 149cd5f22d7SMark Rutland return read_sysreg(cntp_ctl_el0); 1501aee5d7aSMark Rutland case ARCH_TIMER_REG_TVAL: 151f6dc1576SScott Wood return arch_timer_reg_read_stable(cntp_tval_el0); 1521aee5d7aSMark Rutland } 1531aee5d7aSMark Rutland } else if (access == ARCH_TIMER_VIRT_ACCESS) { 1541aee5d7aSMark Rutland switch (reg) { 1551aee5d7aSMark Rutland case ARCH_TIMER_REG_CTRL: 156cd5f22d7SMark Rutland return read_sysreg(cntv_ctl_el0); 1571aee5d7aSMark Rutland case ARCH_TIMER_REG_TVAL: 158f6dc1576SScott Wood return arch_timer_reg_read_stable(cntv_tval_el0); 1591aee5d7aSMark Rutland } 1601aee5d7aSMark Rutland } 1611aee5d7aSMark Rutland 162cd5f22d7SMark Rutland BUG(); 1631aee5d7aSMark Rutland } 1641aee5d7aSMark Rutland 1651aee5d7aSMark Rutland static inline u32 arch_timer_get_cntfrq(void) 1661aee5d7aSMark Rutland { 167cd5f22d7SMark Rutland return read_sysreg(cntfrq_el0); 1681aee5d7aSMark Rutland } 1691aee5d7aSMark Rutland 17046efe547SSudeep KarkadaNagesha static inline u32 arch_timer_get_cntkctl(void) 1711aee5d7aSMark Rutland { 172cd5f22d7SMark Rutland return read_sysreg(cntkctl_el1); 17346efe547SSudeep KarkadaNagesha } 17446efe547SSudeep KarkadaNagesha 17546efe547SSudeep KarkadaNagesha static inline void arch_timer_set_cntkctl(u32 cntkctl) 17646efe547SSudeep KarkadaNagesha { 177cd5f22d7SMark Rutland write_sysreg(cntkctl, cntkctl_el1); 178ec5c8e42SJulien Thierry isb(); 17946efe547SSudeep KarkadaNagesha } 18046efe547SSudeep KarkadaNagesha 1810b46b8a7SSonny Rao static inline u64 arch_counter_get_cntpct(void) 1820b46b8a7SSonny Rao { 183f2e600c1SChristoffer Dall isb(); 184f2e600c1SChristoffer Dall return arch_timer_reg_read_stable(cntpct_el0); 1850b46b8a7SSonny Rao } 1860b46b8a7SSonny Rao 1871aee5d7aSMark Rutland static inline u64 arch_counter_get_cntvct(void) 1881aee5d7aSMark Rutland { 1891aee5d7aSMark Rutland isb(); 190f6dc1576SScott Wood return arch_timer_reg_read_stable(cntvct_el0); 1911aee5d7aSMark Rutland } 1921aee5d7aSMark Rutland 1930583fe47SRob Herring static inline int arch_timer_arch_init(void) 1940583fe47SRob Herring { 1950583fe47SRob Herring return 0; 1960583fe47SRob Herring } 1970583fe47SRob Herring 1981aee5d7aSMark Rutland #endif 199