xref: /openbmc/linux/arch/arm64/include/asm/arch_timer.h (revision 46efe547aca8498d51b64460c02366ae4032ca32)
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>
231aee5d7aSMark Rutland 
241aee5d7aSMark Rutland #include <linux/init.h>
251aee5d7aSMark Rutland #include <linux/types.h>
261aee5d7aSMark Rutland 
271aee5d7aSMark Rutland #include <clocksource/arm_arch_timer.h>
281aee5d7aSMark Rutland 
29e09f3cc0SStephen Boyd /*
30e09f3cc0SStephen Boyd  * These register accessors are marked inline so the compiler can
31e09f3cc0SStephen Boyd  * nicely work out which register we want, and chuck away the rest of
32e09f3cc0SStephen Boyd  * the code.
33e09f3cc0SStephen Boyd  */
34e09f3cc0SStephen Boyd static __always_inline
3560faddf6SStephen Boyd void arch_timer_reg_write_cp15(int access, enum arch_timer_reg reg, u32 val)
361aee5d7aSMark Rutland {
371aee5d7aSMark Rutland 	if (access == ARCH_TIMER_PHYS_ACCESS) {
381aee5d7aSMark Rutland 		switch (reg) {
391aee5d7aSMark Rutland 		case ARCH_TIMER_REG_CTRL:
401aee5d7aSMark Rutland 			asm volatile("msr cntp_ctl_el0,  %0" : : "r" (val));
411aee5d7aSMark Rutland 			break;
421aee5d7aSMark Rutland 		case ARCH_TIMER_REG_TVAL:
431aee5d7aSMark Rutland 			asm volatile("msr cntp_tval_el0, %0" : : "r" (val));
441aee5d7aSMark Rutland 			break;
451aee5d7aSMark Rutland 		}
461aee5d7aSMark Rutland 	} else if (access == ARCH_TIMER_VIRT_ACCESS) {
471aee5d7aSMark Rutland 		switch (reg) {
481aee5d7aSMark Rutland 		case ARCH_TIMER_REG_CTRL:
491aee5d7aSMark Rutland 			asm volatile("msr cntv_ctl_el0,  %0" : : "r" (val));
501aee5d7aSMark Rutland 			break;
511aee5d7aSMark Rutland 		case ARCH_TIMER_REG_TVAL:
521aee5d7aSMark Rutland 			asm volatile("msr cntv_tval_el0, %0" : : "r" (val));
531aee5d7aSMark Rutland 			break;
541aee5d7aSMark Rutland 		}
551aee5d7aSMark Rutland 	}
561aee5d7aSMark Rutland 
571aee5d7aSMark Rutland 	isb();
581aee5d7aSMark Rutland }
591aee5d7aSMark Rutland 
60e09f3cc0SStephen Boyd static __always_inline
6160faddf6SStephen Boyd u32 arch_timer_reg_read_cp15(int access, enum arch_timer_reg reg)
621aee5d7aSMark Rutland {
631aee5d7aSMark Rutland 	u32 val;
641aee5d7aSMark Rutland 
651aee5d7aSMark Rutland 	if (access == ARCH_TIMER_PHYS_ACCESS) {
661aee5d7aSMark Rutland 		switch (reg) {
671aee5d7aSMark Rutland 		case ARCH_TIMER_REG_CTRL:
681aee5d7aSMark Rutland 			asm volatile("mrs %0,  cntp_ctl_el0" : "=r" (val));
691aee5d7aSMark Rutland 			break;
701aee5d7aSMark Rutland 		case ARCH_TIMER_REG_TVAL:
711aee5d7aSMark Rutland 			asm volatile("mrs %0, cntp_tval_el0" : "=r" (val));
721aee5d7aSMark Rutland 			break;
731aee5d7aSMark Rutland 		}
741aee5d7aSMark Rutland 	} else if (access == ARCH_TIMER_VIRT_ACCESS) {
751aee5d7aSMark Rutland 		switch (reg) {
761aee5d7aSMark Rutland 		case ARCH_TIMER_REG_CTRL:
771aee5d7aSMark Rutland 			asm volatile("mrs %0,  cntv_ctl_el0" : "=r" (val));
781aee5d7aSMark Rutland 			break;
791aee5d7aSMark Rutland 		case ARCH_TIMER_REG_TVAL:
801aee5d7aSMark Rutland 			asm volatile("mrs %0, cntv_tval_el0" : "=r" (val));
811aee5d7aSMark Rutland 			break;
821aee5d7aSMark Rutland 		}
831aee5d7aSMark Rutland 	}
841aee5d7aSMark Rutland 
851aee5d7aSMark Rutland 	return val;
861aee5d7aSMark Rutland }
871aee5d7aSMark Rutland 
881aee5d7aSMark Rutland static inline u32 arch_timer_get_cntfrq(void)
891aee5d7aSMark Rutland {
901aee5d7aSMark Rutland 	u32 val;
911aee5d7aSMark Rutland 	asm volatile("mrs %0,   cntfrq_el0" : "=r" (val));
921aee5d7aSMark Rutland 	return val;
931aee5d7aSMark Rutland }
941aee5d7aSMark Rutland 
95*46efe547SSudeep KarkadaNagesha static inline u32 arch_timer_get_cntkctl(void)
961aee5d7aSMark Rutland {
971aee5d7aSMark Rutland 	u32 cntkctl;
981aee5d7aSMark Rutland 	asm volatile("mrs	%0, cntkctl_el1" : "=r" (cntkctl));
99*46efe547SSudeep KarkadaNagesha 	return cntkctl;
100*46efe547SSudeep KarkadaNagesha }
101*46efe547SSudeep KarkadaNagesha 
102*46efe547SSudeep KarkadaNagesha static inline void arch_timer_set_cntkctl(u32 cntkctl)
103*46efe547SSudeep KarkadaNagesha {
104*46efe547SSudeep KarkadaNagesha 	asm volatile("msr	cntkctl_el1, %0" : : "r" (cntkctl));
105*46efe547SSudeep KarkadaNagesha }
106*46efe547SSudeep KarkadaNagesha 
107*46efe547SSudeep KarkadaNagesha static inline void arch_counter_set_user_access(void)
108*46efe547SSudeep KarkadaNagesha {
109*46efe547SSudeep KarkadaNagesha 	u32 cntkctl = arch_timer_get_cntkctl();
1101aee5d7aSMark Rutland 
11128061758SSudeep KarkadaNagesha 	/* Disable user access to the timers and the physical counter */
112*46efe547SSudeep KarkadaNagesha 	/* Also disable virtual event stream */
11328061758SSudeep KarkadaNagesha 	cntkctl &= ~(ARCH_TIMER_USR_PT_ACCESS_EN
11428061758SSudeep KarkadaNagesha 			| ARCH_TIMER_USR_VT_ACCESS_EN
115*46efe547SSudeep KarkadaNagesha 			| ARCH_TIMER_VIRT_EVT_EN
11628061758SSudeep KarkadaNagesha 			| ARCH_TIMER_USR_PCT_ACCESS_EN);
11728061758SSudeep KarkadaNagesha 
11828061758SSudeep KarkadaNagesha 	/* Enable user access to the virtual counter */
11928061758SSudeep KarkadaNagesha 	cntkctl |= ARCH_TIMER_USR_VCT_ACCESS_EN;
12028061758SSudeep KarkadaNagesha 
121*46efe547SSudeep KarkadaNagesha 	arch_timer_set_cntkctl(cntkctl);
122*46efe547SSudeep KarkadaNagesha }
123*46efe547SSudeep KarkadaNagesha 
124*46efe547SSudeep KarkadaNagesha static inline void arch_timer_evtstrm_enable(int divider)
125*46efe547SSudeep KarkadaNagesha {
126*46efe547SSudeep KarkadaNagesha 	u32 cntkctl = arch_timer_get_cntkctl();
127*46efe547SSudeep KarkadaNagesha 	cntkctl &= ~ARCH_TIMER_EVT_TRIGGER_MASK;
128*46efe547SSudeep KarkadaNagesha 	/* Set the divider and enable virtual event stream */
129*46efe547SSudeep KarkadaNagesha 	cntkctl |= (divider << ARCH_TIMER_EVT_TRIGGER_SHIFT)
130*46efe547SSudeep KarkadaNagesha 			| ARCH_TIMER_VIRT_EVT_EN;
131*46efe547SSudeep KarkadaNagesha 	arch_timer_set_cntkctl(cntkctl);
132*46efe547SSudeep KarkadaNagesha 	elf_hwcap |= HWCAP_EVTSTRM;
133*46efe547SSudeep KarkadaNagesha #ifdef CONFIG_COMPAT
134*46efe547SSudeep KarkadaNagesha 	compat_elf_hwcap |= COMPAT_HWCAP_EVTSTRM;
135*46efe547SSudeep KarkadaNagesha #endif
1361aee5d7aSMark Rutland }
1371aee5d7aSMark Rutland 
1381aee5d7aSMark Rutland static inline u64 arch_counter_get_cntvct(void)
1391aee5d7aSMark Rutland {
1401aee5d7aSMark Rutland 	u64 cval;
1411aee5d7aSMark Rutland 
1421aee5d7aSMark Rutland 	isb();
1431aee5d7aSMark Rutland 	asm volatile("mrs %0, cntvct_el0" : "=r" (cval));
1441aee5d7aSMark Rutland 
1451aee5d7aSMark Rutland 	return cval;
1461aee5d7aSMark Rutland }
1471aee5d7aSMark Rutland 
1480583fe47SRob Herring static inline int arch_timer_arch_init(void)
1490583fe47SRob Herring {
1500583fe47SRob Herring 	return 0;
1510583fe47SRob Herring }
1520583fe47SRob Herring 
1531aee5d7aSMark Rutland #endif
154