1 /* 2 * arch/arm64/include/asm/arch_timer.h 3 * 4 * Copyright (C) 2012 ARM Ltd. 5 * Author: Marc Zyngier <marc.zyngier@arm.com> 6 * 7 * This program is free software: you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 #ifndef __ASM_ARCH_TIMER_H 20 #define __ASM_ARCH_TIMER_H 21 22 #include <asm/barrier.h> 23 #include <asm/sysreg.h> 24 25 #include <linux/bug.h> 26 #include <linux/init.h> 27 #include <linux/jump_label.h> 28 #include <linux/smp.h> 29 #include <linux/types.h> 30 31 #include <clocksource/arm_arch_timer.h> 32 33 #if IS_ENABLED(CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND) 34 extern struct static_key_false arch_timer_read_ool_enabled; 35 #define needs_unstable_timer_counter_workaround() \ 36 static_branch_unlikely(&arch_timer_read_ool_enabled) 37 #else 38 #define needs_unstable_timer_counter_workaround() false 39 #endif 40 41 enum arch_timer_erratum_match_type { 42 ate_match_dt, 43 ate_match_local_cap_id, 44 ate_match_acpi_oem_info, 45 }; 46 47 struct clock_event_device; 48 49 struct arch_timer_erratum_workaround { 50 enum arch_timer_erratum_match_type match_type; 51 const void *id; 52 const char *desc; 53 u32 (*read_cntp_tval_el0)(void); 54 u32 (*read_cntv_tval_el0)(void); 55 u64 (*read_cntpct_el0)(void); 56 u64 (*read_cntvct_el0)(void); 57 int (*set_next_event_phys)(unsigned long, struct clock_event_device *); 58 int (*set_next_event_virt)(unsigned long, struct clock_event_device *); 59 }; 60 61 DECLARE_PER_CPU(const struct arch_timer_erratum_workaround *, 62 timer_unstable_counter_workaround); 63 64 #define arch_timer_reg_read_stable(reg) \ 65 ({ \ 66 u64 _val; \ 67 if (needs_unstable_timer_counter_workaround()) { \ 68 const struct arch_timer_erratum_workaround *wa; \ 69 preempt_disable_notrace(); \ 70 wa = __this_cpu_read(timer_unstable_counter_workaround); \ 71 if (wa && wa->read_##reg) \ 72 _val = wa->read_##reg(); \ 73 else \ 74 _val = read_sysreg(reg); \ 75 preempt_enable_notrace(); \ 76 } else { \ 77 _val = read_sysreg(reg); \ 78 } \ 79 _val; \ 80 }) 81 82 /* 83 * These register accessors are marked inline so the compiler can 84 * nicely work out which register we want, and chuck away the rest of 85 * the code. 86 */ 87 static __always_inline 88 void arch_timer_reg_write_cp15(int access, enum arch_timer_reg reg, u32 val) 89 { 90 if (access == ARCH_TIMER_PHYS_ACCESS) { 91 switch (reg) { 92 case ARCH_TIMER_REG_CTRL: 93 write_sysreg(val, cntp_ctl_el0); 94 break; 95 case ARCH_TIMER_REG_TVAL: 96 write_sysreg(val, cntp_tval_el0); 97 break; 98 } 99 } else if (access == ARCH_TIMER_VIRT_ACCESS) { 100 switch (reg) { 101 case ARCH_TIMER_REG_CTRL: 102 write_sysreg(val, cntv_ctl_el0); 103 break; 104 case ARCH_TIMER_REG_TVAL: 105 write_sysreg(val, cntv_tval_el0); 106 break; 107 } 108 } 109 110 isb(); 111 } 112 113 static __always_inline 114 u32 arch_timer_reg_read_cp15(int access, enum arch_timer_reg reg) 115 { 116 if (access == ARCH_TIMER_PHYS_ACCESS) { 117 switch (reg) { 118 case ARCH_TIMER_REG_CTRL: 119 return read_sysreg(cntp_ctl_el0); 120 case ARCH_TIMER_REG_TVAL: 121 return arch_timer_reg_read_stable(cntp_tval_el0); 122 } 123 } else if (access == ARCH_TIMER_VIRT_ACCESS) { 124 switch (reg) { 125 case ARCH_TIMER_REG_CTRL: 126 return read_sysreg(cntv_ctl_el0); 127 case ARCH_TIMER_REG_TVAL: 128 return arch_timer_reg_read_stable(cntv_tval_el0); 129 } 130 } 131 132 BUG(); 133 } 134 135 static inline u32 arch_timer_get_cntfrq(void) 136 { 137 return read_sysreg(cntfrq_el0); 138 } 139 140 static inline u32 arch_timer_get_cntkctl(void) 141 { 142 return read_sysreg(cntkctl_el1); 143 } 144 145 static inline void arch_timer_set_cntkctl(u32 cntkctl) 146 { 147 write_sysreg(cntkctl, cntkctl_el1); 148 isb(); 149 } 150 151 static inline u64 arch_counter_get_cntpct(void) 152 { 153 isb(); 154 return arch_timer_reg_read_stable(cntpct_el0); 155 } 156 157 static inline u64 arch_counter_get_cntvct(void) 158 { 159 isb(); 160 return arch_timer_reg_read_stable(cntvct_el0); 161 } 162 163 static inline int arch_timer_arch_init(void) 164 { 165 return 0; 166 } 167 168 #endif 169