Commit | Line | Data |
---|---|---|
022c03a2 MZ |
1 | #ifndef __ASMARM_ARCH_TIMER_H |
2 | #define __ASMARM_ARCH_TIMER_H | |
3 | ||
ec944c93 | 4 | #include <asm/barrier.h> |
923df96b | 5 | #include <asm/errno.h> |
a1b2dde7 | 6 | #include <linux/clocksource.h> |
ec944c93 | 7 | #include <linux/types.h> |
923df96b | 8 | |
022c03a2 | 9 | #ifdef CONFIG_ARM_ARCH_TIMER |
0075242b | 10 | int arch_timer_of_register(void); |
fb8a99f9 | 11 | int arch_timer_sched_clock_init(void); |
a1b2dde7 | 12 | struct timecounter *arch_timer_get_timecounter(void); |
ec944c93 MR |
13 | |
14 | #define ARCH_TIMER_CTRL_ENABLE (1 << 0) | |
15 | #define ARCH_TIMER_CTRL_IT_MASK (1 << 1) | |
16 | #define ARCH_TIMER_CTRL_IT_STAT (1 << 2) | |
17 | ||
18 | #define ARCH_TIMER_REG_CTRL 0 | |
19 | #define ARCH_TIMER_REG_TVAL 1 | |
20 | ||
21 | #define ARCH_TIMER_PHYS_ACCESS 0 | |
22 | #define ARCH_TIMER_VIRT_ACCESS 1 | |
23 | ||
24 | /* | |
25 | * These register accessors are marked inline so the compiler can | |
26 | * nicely work out which register we want, and chuck away the rest of | |
27 | * the code. At least it does so with a recent GCC (4.6.3). | |
28 | */ | |
29 | static inline void arch_timer_reg_write(const int access, const int reg, u32 val) | |
30 | { | |
31 | if (access == ARCH_TIMER_PHYS_ACCESS) { | |
32 | switch (reg) { | |
33 | case ARCH_TIMER_REG_CTRL: | |
34 | asm volatile("mcr p15, 0, %0, c14, c2, 1" : : "r" (val)); | |
35 | break; | |
36 | case ARCH_TIMER_REG_TVAL: | |
37 | asm volatile("mcr p15, 0, %0, c14, c2, 0" : : "r" (val)); | |
38 | break; | |
39 | } | |
40 | } | |
41 | ||
42 | if (access == ARCH_TIMER_VIRT_ACCESS) { | |
43 | switch (reg) { | |
44 | case ARCH_TIMER_REG_CTRL: | |
45 | asm volatile("mcr p15, 0, %0, c14, c3, 1" : : "r" (val)); | |
46 | break; | |
47 | case ARCH_TIMER_REG_TVAL: | |
48 | asm volatile("mcr p15, 0, %0, c14, c3, 0" : : "r" (val)); | |
49 | break; | |
50 | } | |
51 | } | |
45801042 MR |
52 | |
53 | isb(); | |
ec944c93 MR |
54 | } |
55 | ||
56 | static inline u32 arch_timer_reg_read(const int access, const int reg) | |
57 | { | |
58 | u32 val = 0; | |
59 | ||
60 | if (access == ARCH_TIMER_PHYS_ACCESS) { | |
61 | switch (reg) { | |
62 | case ARCH_TIMER_REG_CTRL: | |
63 | asm volatile("mrc p15, 0, %0, c14, c2, 1" : "=r" (val)); | |
64 | break; | |
65 | case ARCH_TIMER_REG_TVAL: | |
66 | asm volatile("mrc p15, 0, %0, c14, c2, 0" : "=r" (val)); | |
67 | break; | |
68 | } | |
69 | } | |
70 | ||
71 | if (access == ARCH_TIMER_VIRT_ACCESS) { | |
72 | switch (reg) { | |
73 | case ARCH_TIMER_REG_CTRL: | |
74 | asm volatile("mrc p15, 0, %0, c14, c3, 1" : "=r" (val)); | |
75 | break; | |
76 | case ARCH_TIMER_REG_TVAL: | |
77 | asm volatile("mrc p15, 0, %0, c14, c3, 0" : "=r" (val)); | |
78 | break; | |
79 | } | |
80 | } | |
81 | ||
82 | return val; | |
83 | } | |
84 | ||
85 | static inline u32 arch_timer_get_cntfrq(void) | |
86 | { | |
87 | u32 val; | |
88 | asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (val)); | |
89 | return val; | |
90 | } | |
91 | ||
92 | static inline u64 arch_counter_get_cntpct(void) | |
93 | { | |
94 | u64 cval; | |
95 | ||
45801042 | 96 | isb(); |
ec944c93 MR |
97 | asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (cval)); |
98 | return cval; | |
99 | } | |
100 | ||
101 | static inline u64 arch_counter_get_cntvct(void) | |
102 | { | |
103 | u64 cval; | |
104 | ||
45801042 | 105 | isb(); |
ec944c93 MR |
106 | asm volatile("mrrc p15, 1, %Q0, %R0, c14" : "=r" (cval)); |
107 | return cval; | |
108 | } | |
022c03a2 | 109 | #else |
0075242b MZ |
110 | static inline int arch_timer_of_register(void) |
111 | { | |
112 | return -ENXIO; | |
113 | } | |
114 | ||
3f61c80e MZ |
115 | static inline int arch_timer_sched_clock_init(void) |
116 | { | |
117 | return -ENXIO; | |
118 | } | |
a1b2dde7 MZ |
119 | |
120 | static inline struct timecounter *arch_timer_get_timecounter(void) | |
121 | { | |
122 | return NULL; | |
123 | } | |
022c03a2 MZ |
124 | #endif |
125 | ||
126 | #endif |