blob: 0704e0cf557146da78c086079daeec8c0112d326 [file] [log] [blame]
Marc Zyngier022c03a2012-01-11 17:25:17 +00001#ifndef __ASMARM_ARCH_TIMER_H
2#define __ASMARM_ARCH_TIMER_H
3
Mark Rutlandec944c92012-11-12 16:18:00 +00004#include <asm/barrier.h>
Will Deacon923df96b2012-07-06 15:46:45 +01005#include <asm/errno.h>
Marc Zyngiera1b2dde2012-09-07 18:09:58 +01006#include <linux/clocksource.h>
Mark Rutland8a4da6e2012-11-12 14:33:44 +00007#include <linux/init.h>
Mark Rutlandec944c92012-11-12 16:18:00 +00008#include <linux/types.h>
Will Deacon923df96b2012-07-06 15:46:45 +01009
Mark Rutland8a4da6e2012-11-12 14:33:44 +000010#include <clocksource/arm_arch_timer.h>
11
Marc Zyngier022c03a2012-01-11 17:25:17 +000012#ifdef CONFIG_ARM_ARCH_TIMER
Rob Herring0583fe42013-04-10 18:27:51 -050013int arch_timer_arch_init(void);
Mark Rutlandec944c92012-11-12 16:18:00 +000014
15/*
16 * These register accessors are marked inline so the compiler can
17 * nicely work out which register we want, and chuck away the rest of
18 * the code. At least it does so with a recent GCC (4.6.3).
19 */
Stephen Boyde09f3cc2013-07-18 16:59:28 -070020static __always_inline
Stephen Boyd60faddf2013-07-18 16:59:31 -070021void arch_timer_reg_write_cp15(int access, enum arch_timer_reg reg, u32 val)
Mark Rutlandec944c92012-11-12 16:18:00 +000022{
23 if (access == ARCH_TIMER_PHYS_ACCESS) {
24 switch (reg) {
25 case ARCH_TIMER_REG_CTRL:
26 asm volatile("mcr p15, 0, %0, c14, c2, 1" : : "r" (val));
27 break;
28 case ARCH_TIMER_REG_TVAL:
29 asm volatile("mcr p15, 0, %0, c14, c2, 0" : : "r" (val));
30 break;
31 }
Stephen Boyde09f3cc2013-07-18 16:59:28 -070032 } else if (access == ARCH_TIMER_VIRT_ACCESS) {
Mark Rutlandec944c92012-11-12 16:18:00 +000033 switch (reg) {
34 case ARCH_TIMER_REG_CTRL:
35 asm volatile("mcr p15, 0, %0, c14, c3, 1" : : "r" (val));
36 break;
37 case ARCH_TIMER_REG_TVAL:
38 asm volatile("mcr p15, 0, %0, c14, c3, 0" : : "r" (val));
39 break;
40 }
41 }
Mark Rutland45801042013-01-11 14:32:33 +000042
43 isb();
Mark Rutlandec944c92012-11-12 16:18:00 +000044}
45
Stephen Boyde09f3cc2013-07-18 16:59:28 -070046static __always_inline
Stephen Boyd60faddf2013-07-18 16:59:31 -070047u32 arch_timer_reg_read_cp15(int access, enum arch_timer_reg reg)
Mark Rutlandec944c92012-11-12 16:18:00 +000048{
49 u32 val = 0;
50
51 if (access == ARCH_TIMER_PHYS_ACCESS) {
52 switch (reg) {
53 case ARCH_TIMER_REG_CTRL:
54 asm volatile("mrc p15, 0, %0, c14, c2, 1" : "=r" (val));
55 break;
56 case ARCH_TIMER_REG_TVAL:
57 asm volatile("mrc p15, 0, %0, c14, c2, 0" : "=r" (val));
58 break;
59 }
Stephen Boyde09f3cc2013-07-18 16:59:28 -070060 } else if (access == ARCH_TIMER_VIRT_ACCESS) {
Mark Rutlandec944c92012-11-12 16:18:00 +000061 switch (reg) {
62 case ARCH_TIMER_REG_CTRL:
63 asm volatile("mrc p15, 0, %0, c14, c3, 1" : "=r" (val));
64 break;
65 case ARCH_TIMER_REG_TVAL:
66 asm volatile("mrc p15, 0, %0, c14, c3, 0" : "=r" (val));
67 break;
68 }
69 }
70
71 return val;
72}
73
74static inline u32 arch_timer_get_cntfrq(void)
75{
76 u32 val;
77 asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (val));
78 return val;
79}
80
Mark Rutlandec944c92012-11-12 16:18:00 +000081static inline u64 arch_counter_get_cntvct(void)
82{
83 u64 cval;
84
Mark Rutland45801042013-01-11 14:32:33 +000085 isb();
Mark Rutlandec944c92012-11-12 16:18:00 +000086 asm volatile("mrrc p15, 1, %Q0, %R0, c14" : "=r" (cval));
87 return cval;
88}
Mark Rutlandb2deabe2012-11-14 10:32:24 +000089
Sudeep KarkadaNageshae9faebc2013-08-13 14:30:32 +010090static inline u32 arch_timer_get_cntkctl(void)
Mark Rutlandb2deabe2012-11-14 10:32:24 +000091{
92 u32 cntkctl;
Mark Rutlandb2deabe2012-11-14 10:32:24 +000093 asm volatile("mrc p15, 0, %0, c14, c1, 0" : "=r" (cntkctl));
Sudeep KarkadaNageshae9faebc2013-08-13 14:30:32 +010094 return cntkctl;
95}
96
97static inline void arch_timer_set_cntkctl(u32 cntkctl)
98{
99 asm volatile("mcr p15, 0, %0, c14, c1, 0" : : "r" (cntkctl));
100}
101
102static inline void arch_counter_set_user_access(void)
103{
104 u32 cntkctl = arch_timer_get_cntkctl();
Mark Rutlandb2deabe2012-11-14 10:32:24 +0000105
Sudeep KarkadaNagesha28061752013-08-13 13:43:26 +0100106 /* Disable user access to both physical/virtual counters/timers */
107 /* Also disable virtual event stream */
108 cntkctl &= ~(ARCH_TIMER_USR_PT_ACCESS_EN
109 | ARCH_TIMER_USR_VT_ACCESS_EN
110 | ARCH_TIMER_VIRT_EVT_EN
111 | ARCH_TIMER_USR_VCT_ACCESS_EN
112 | ARCH_TIMER_USR_PCT_ACCESS_EN);
Sudeep KarkadaNageshae9faebc2013-08-13 14:30:32 +0100113 arch_timer_set_cntkctl(cntkctl);
Mark Rutlandb2deabe2012-11-14 10:32:24 +0000114}
Sudeep KarkadaNageshae9faebc2013-08-13 14:30:32 +0100115
116static inline void arch_timer_evtstrm_enable(int divider)
117{
118 u32 cntkctl = arch_timer_get_cntkctl();
119 cntkctl &= ~ARCH_TIMER_EVT_TRIGGER_MASK;
120 /* Set the divider and enable virtual event stream */
121 cntkctl |= (divider << ARCH_TIMER_EVT_TRIGGER_SHIFT)
122 | ARCH_TIMER_VIRT_EVT_EN;
123 arch_timer_set_cntkctl(cntkctl);
124 elf_hwcap |= HWCAP_EVTSTRM;
125}
126
Marc Zyngier022c03a2012-01-11 17:25:17 +0000127#endif
128
129#endif