Commit | Line | Data |
---|---|---|
b2441318 | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
022c03a2 MZ |
2 | #ifndef __ASMARM_ARCH_TIMER_H |
3 | #define __ASMARM_ARCH_TIMER_H | |
4 | ||
ec944c93 | 5 | #include <asm/barrier.h> |
923df96b | 6 | #include <asm/errno.h> |
a1b2dde7 | 7 | #include <linux/clocksource.h> |
8a4da6e3 | 8 | #include <linux/init.h> |
ec944c93 | 9 | #include <linux/types.h> |
923df96b | 10 | |
8a4da6e3 MR |
11 | #include <clocksource/arm_arch_timer.h> |
12 | ||
022c03a2 | 13 | #ifdef CONFIG_ARM_ARCH_TIMER |
0583fe47 | 14 | int arch_timer_arch_init(void); |
ec944c93 MR |
15 | |
16 | /* | |
17 | * These register accessors are marked inline so the compiler can | |
18 | * nicely work out which register we want, and chuck away the rest of | |
19 | * the code. At least it does so with a recent GCC (4.6.3). | |
20 | */ | |
e09f3cc0 | 21 | static __always_inline |
60faddf6 | 22 | void arch_timer_reg_write_cp15(int access, enum arch_timer_reg reg, u32 val) |
ec944c93 MR |
23 | { |
24 | if (access == ARCH_TIMER_PHYS_ACCESS) { | |
25 | switch (reg) { | |
26 | case ARCH_TIMER_REG_CTRL: | |
27 | asm volatile("mcr p15, 0, %0, c14, c2, 1" : : "r" (val)); | |
28 | break; | |
29 | case ARCH_TIMER_REG_TVAL: | |
30 | asm volatile("mcr p15, 0, %0, c14, c2, 0" : : "r" (val)); | |
31 | break; | |
32 | } | |
e09f3cc0 | 33 | } else if (access == ARCH_TIMER_VIRT_ACCESS) { |
ec944c93 MR |
34 | switch (reg) { |
35 | case ARCH_TIMER_REG_CTRL: | |
36 | asm volatile("mcr p15, 0, %0, c14, c3, 1" : : "r" (val)); | |
37 | break; | |
38 | case ARCH_TIMER_REG_TVAL: | |
39 | asm volatile("mcr p15, 0, %0, c14, c3, 0" : : "r" (val)); | |
40 | break; | |
41 | } | |
42 | } | |
45801042 MR |
43 | |
44 | isb(); | |
ec944c93 MR |
45 | } |
46 | ||
e09f3cc0 | 47 | static __always_inline |
60faddf6 | 48 | u32 arch_timer_reg_read_cp15(int access, enum arch_timer_reg reg) |
ec944c93 MR |
49 | { |
50 | u32 val = 0; | |
51 | ||
52 | if (access == ARCH_TIMER_PHYS_ACCESS) { | |
53 | switch (reg) { | |
54 | case ARCH_TIMER_REG_CTRL: | |
55 | asm volatile("mrc p15, 0, %0, c14, c2, 1" : "=r" (val)); | |
56 | break; | |
57 | case ARCH_TIMER_REG_TVAL: | |
58 | asm volatile("mrc p15, 0, %0, c14, c2, 0" : "=r" (val)); | |
59 | break; | |
60 | } | |
e09f3cc0 | 61 | } else if (access == ARCH_TIMER_VIRT_ACCESS) { |
ec944c93 MR |
62 | switch (reg) { |
63 | case ARCH_TIMER_REG_CTRL: | |
64 | asm volatile("mrc p15, 0, %0, c14, c3, 1" : "=r" (val)); | |
65 | break; | |
66 | case ARCH_TIMER_REG_TVAL: | |
67 | asm volatile("mrc p15, 0, %0, c14, c3, 0" : "=r" (val)); | |
68 | break; | |
69 | } | |
70 | } | |
71 | ||
72 | return val; | |
73 | } | |
74 | ||
75 | static inline u32 arch_timer_get_cntfrq(void) | |
76 | { | |
77 | u32 val; | |
78 | asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (val)); | |
79 | return val; | |
80 | } | |
81 | ||
0b46b8a7 SR |
82 | static inline u64 arch_counter_get_cntpct(void) |
83 | { | |
84 | u64 cval; | |
85 | ||
86 | isb(); | |
87 | asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (cval)); | |
88 | return cval; | |
89 | } | |
90 | ||
ec944c93 MR |
91 | static inline u64 arch_counter_get_cntvct(void) |
92 | { | |
93 | u64 cval; | |
94 | ||
45801042 | 95 | isb(); |
ec944c93 MR |
96 | asm volatile("mrrc p15, 1, %Q0, %R0, c14" : "=r" (cval)); |
97 | return cval; | |
98 | } | |
b2deabe3 | 99 | |
e9faebc6 | 100 | static inline u32 arch_timer_get_cntkctl(void) |
b2deabe3 MR |
101 | { |
102 | u32 cntkctl; | |
b2deabe3 | 103 | asm volatile("mrc p15, 0, %0, c14, c1, 0" : "=r" (cntkctl)); |
e9faebc6 SK |
104 | return cntkctl; |
105 | } | |
106 | ||
107 | static inline void arch_timer_set_cntkctl(u32 cntkctl) | |
108 | { | |
109 | asm volatile("mcr p15, 0, %0, c14, c1, 0" : : "r" (cntkctl)); | |
110 | } | |
111 | ||
022c03a2 MZ |
112 | #endif |
113 | ||
114 | #endif |