]> Pileus Git - ~andy/linux/blob - arch/arm/mach-msm/timer.c
msm: timer: Fix ONESHOT mode interrupts
[~andy/linux] / arch / arm / mach-msm / timer.c
1 /*
2  *
3  * Copyright (C) 2007 Google, Inc.
4  * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
5  *
6  * This software is licensed under the terms of the GNU General Public
7  * License version 2, as published by the Free Software Foundation, and
8  * may be copied, distributed, and modified under those terms.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  */
16
17 #include <linux/clocksource.h>
18 #include <linux/clockchips.h>
19 #include <linux/init.h>
20 #include <linux/interrupt.h>
21 #include <linux/irq.h>
22 #include <linux/io.h>
23
24 #include <asm/mach/time.h>
25 #include <asm/hardware/gic.h>
26 #include <asm/localtimer.h>
27
28 #include <mach/msm_iomap.h>
29 #include <mach/cpu.h>
30 #include <mach/board.h>
31
32 #define TIMER_MATCH_VAL         0x0000
33 #define TIMER_COUNT_VAL         0x0004
34 #define TIMER_ENABLE            0x0008
35 #define TIMER_ENABLE_CLR_ON_MATCH_EN    BIT(1)
36 #define TIMER_ENABLE_EN                 BIT(0)
37 #define TIMER_CLEAR             0x000C
38 #define DGT_CLK_CTL             0x0034
39 #define DGT_CLK_CTL_DIV_4       0x3
40
41 #define GPT_HZ 32768
42
43 #define MSM_GLOBAL_TIMER MSM_CLOCK_GPT
44
45 /* TODO: Remove these ifdefs */
46 #if defined(CONFIG_ARCH_QSD8X50)
47 #define DGT_HZ (19200000 / 4) /* 19.2 MHz / 4 by default */
48 #define MSM_DGT_SHIFT (0)
49 #elif defined(CONFIG_ARCH_MSM7X30)
50 #define DGT_HZ (24576000 / 4) /* 24.576 MHz (LPXO) / 4 by default */
51 #define MSM_DGT_SHIFT (0)
52 #elif defined(CONFIG_ARCH_MSM8X60) || defined(CONFIG_ARCH_MSM8960)
53 #define DGT_HZ (27000000 / 4) /* 27 MHz (PXO) / 4 by default */
54 #define MSM_DGT_SHIFT (0)
55 #else
56 #define DGT_HZ 19200000 /* 19.2 MHz or 600 KHz after shift */
57 #define MSM_DGT_SHIFT (5)
58 #endif
59
60 struct msm_clock {
61         struct clock_event_device   clockevent;
62         struct clocksource          clocksource;
63         unsigned int                irq;
64         void __iomem                *regbase;
65         uint32_t                    freq;
66         uint32_t                    shift;
67         void __iomem                *global_counter;
68         void __iomem                *local_counter;
69         union {
70                 struct clock_event_device               *evt;
71                 struct clock_event_device __percpu      **percpu_evt;
72         };              
73 };
74
75 enum {
76         MSM_CLOCK_GPT,
77         MSM_CLOCK_DGT,
78         NR_TIMERS,
79 };
80
81
82 static struct msm_clock msm_clocks[];
83
84 static struct msm_clock *clockevent_to_clock(struct clock_event_device *evt);
85
86 static irqreturn_t msm_timer_interrupt(int irq, void *dev_id)
87 {
88         struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
89         if (evt->event_handler == NULL)
90                 return IRQ_HANDLED;
91         /* Stop the timer tick */
92         if (evt->mode == CLOCK_EVT_MODE_ONESHOT) {
93                 struct msm_clock *clock = clockevent_to_clock(evt);
94                 u32 ctrl = readl_relaxed(clock->regbase + TIMER_ENABLE);
95                 ctrl &= ~TIMER_ENABLE_EN;
96                 writel_relaxed(ctrl, clock->regbase + TIMER_ENABLE);
97         }
98         evt->event_handler(evt);
99         return IRQ_HANDLED;
100 }
101
102 static cycle_t msm_read_timer_count(struct clocksource *cs)
103 {
104         struct msm_clock *clk = container_of(cs, struct msm_clock, clocksource);
105
106         /*
107          * Shift timer count down by a constant due to unreliable lower bits
108          * on some targets.
109          */
110         return readl(clk->global_counter) >> clk->shift;
111 }
112
113 static struct msm_clock *clockevent_to_clock(struct clock_event_device *evt)
114 {
115 #ifdef CONFIG_SMP
116         int i;
117         for (i = 0; i < NR_TIMERS; i++)
118                 if (evt == &(msm_clocks[i].clockevent))
119                         return &msm_clocks[i];
120         return &msm_clocks[MSM_GLOBAL_TIMER];
121 #else
122         return container_of(evt, struct msm_clock, clockevent);
123 #endif
124 }
125
126 static int msm_timer_set_next_event(unsigned long cycles,
127                                     struct clock_event_device *evt)
128 {
129         struct msm_clock *clock = clockevent_to_clock(evt);
130         u32 match = cycles << clock->shift;
131         u32 ctrl = readl_relaxed(clock->regbase + TIMER_ENABLE);
132
133         writel_relaxed(0, clock->regbase + TIMER_CLEAR);
134         writel_relaxed(match, clock->regbase + TIMER_MATCH_VAL);
135         writel_relaxed(ctrl | TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE);
136         return 0;
137 }
138
139 static void msm_timer_set_mode(enum clock_event_mode mode,
140                               struct clock_event_device *evt)
141 {
142         struct msm_clock *clock = clockevent_to_clock(evt);
143         u32 ctrl;
144
145         ctrl = readl_relaxed(clock->regbase + TIMER_ENABLE);
146         ctrl &= ~(TIMER_ENABLE_EN | TIMER_ENABLE_CLR_ON_MATCH_EN);
147
148         switch (mode) {
149         case CLOCK_EVT_MODE_RESUME:
150         case CLOCK_EVT_MODE_PERIODIC:
151                 break;
152         case CLOCK_EVT_MODE_ONESHOT:
153                 /* Timer is enabled in set_next_event */
154                 break;
155         case CLOCK_EVT_MODE_UNUSED:
156         case CLOCK_EVT_MODE_SHUTDOWN:
157                 break;
158         }
159         writel_relaxed(ctrl, clock->regbase + TIMER_ENABLE);
160 }
161
162 static struct msm_clock msm_clocks[] = {
163         [MSM_CLOCK_GPT] = {
164                 .clockevent = {
165                         .name           = "gp_timer",
166                         .features       = CLOCK_EVT_FEAT_ONESHOT,
167                         .shift          = 32,
168                         .rating         = 200,
169                         .set_next_event = msm_timer_set_next_event,
170                         .set_mode       = msm_timer_set_mode,
171                 },
172                 .irq = INT_GP_TIMER_EXP,
173                 .freq = GPT_HZ,
174         },
175         [MSM_CLOCK_DGT] = {
176                 .clocksource = {
177                         .name           = "dg_timer",
178                         .rating         = 300,
179                         .read           = msm_read_timer_count,
180                         .mask           = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT)),
181                         .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
182                 },
183                 .freq = DGT_HZ >> MSM_DGT_SHIFT,
184                 .shift = MSM_DGT_SHIFT,
185         }
186 };
187
188 static void __init msm_timer_init(void)
189 {
190         struct msm_clock *clock;
191         struct clock_event_device *ce = &msm_clocks[MSM_CLOCK_GPT].clockevent;
192         struct clocksource *cs = &msm_clocks[MSM_CLOCK_DGT].clocksource;
193         int res;
194         int global_offset = 0;
195
196
197         if (cpu_is_msm7x01()) {
198                 msm_clocks[MSM_CLOCK_GPT].regbase = MSM_CSR_BASE;
199                 msm_clocks[MSM_CLOCK_DGT].regbase = MSM_CSR_BASE + 0x10;
200         } else if (cpu_is_msm7x30()) {
201                 msm_clocks[MSM_CLOCK_GPT].regbase = MSM_CSR_BASE + 0x04;
202                 msm_clocks[MSM_CLOCK_DGT].regbase = MSM_CSR_BASE + 0x24;
203         } else if (cpu_is_qsd8x50()) {
204                 msm_clocks[MSM_CLOCK_GPT].regbase = MSM_CSR_BASE;
205                 msm_clocks[MSM_CLOCK_DGT].regbase = MSM_CSR_BASE + 0x10;
206         } else if (cpu_is_msm8x60() || cpu_is_msm8960()) {
207                 msm_clocks[MSM_CLOCK_GPT].regbase = MSM_TMR_BASE + 0x04;
208                 msm_clocks[MSM_CLOCK_DGT].regbase = MSM_TMR_BASE + 0x24;
209
210                 /* Use CPU0's timer as the global timer. */
211                 global_offset = MSM_TMR0_BASE - MSM_TMR_BASE;
212         } else
213                 BUG();
214
215 #ifdef CONFIG_ARCH_MSM_SCORPIONMP
216         writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
217 #endif
218
219         clock = &msm_clocks[MSM_CLOCK_GPT];
220         clock->local_counter = clock->regbase + TIMER_COUNT_VAL;
221
222         writel_relaxed(0, clock->regbase + TIMER_ENABLE);
223         writel_relaxed(0, clock->regbase + TIMER_CLEAR);
224         writel_relaxed(~0, clock->regbase + TIMER_MATCH_VAL);
225         ce->mult = div_sc(clock->freq, NSEC_PER_SEC, ce->shift);
226         /*
227          * allow at least 10 seconds to notice that the timer
228          * wrapped
229          */
230         ce->max_delta_ns =
231                 clockevent_delta2ns(0xf0000000 >> clock->shift, ce);
232         /* 4 gets rounded down to 3 */
233         ce->min_delta_ns = clockevent_delta2ns(4, ce);
234         ce->cpumask = cpumask_of(0);
235
236         ce->irq = clock->irq;
237         if (cpu_is_msm8x60() || cpu_is_msm8960()) {
238                 clock->percpu_evt = alloc_percpu(struct clock_event_device *);
239                 if (!clock->percpu_evt) {
240                         pr_err("memory allocation failed for %s\n", ce->name);
241                         goto err;
242                 }
243
244                 *__this_cpu_ptr(clock->percpu_evt) = ce;
245                 res = request_percpu_irq(ce->irq, msm_timer_interrupt,
246                                          ce->name, clock->percpu_evt);
247                 if (!res)
248                         enable_percpu_irq(ce->irq, 0);
249         } else {
250                 clock->evt = ce;
251                 res = request_irq(ce->irq, msm_timer_interrupt,
252                                   IRQF_TIMER | IRQF_NOBALANCING |
253                                   IRQF_TRIGGER_RISING, ce->name, &clock->evt);
254         }
255
256         if (res)
257                 pr_err("request_irq failed for %s\n", ce->name);
258
259         clockevents_register_device(ce);
260 err:
261         clock = &msm_clocks[MSM_CLOCK_DGT];
262         clock->local_counter = clock->regbase + TIMER_COUNT_VAL;
263         clock->global_counter = clock->local_counter + global_offset;
264         writel_relaxed(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE);
265         res = clocksource_register_hz(cs, clock->freq);
266         if (res)
267                 pr_err("clocksource_register failed for %s\n", cs->name);
268 }
269
270 #ifdef CONFIG_LOCAL_TIMERS
271 int __cpuinit local_timer_setup(struct clock_event_device *evt)
272 {
273         static bool local_timer_inited;
274         struct msm_clock *clock = &msm_clocks[MSM_GLOBAL_TIMER];
275
276         /* Use existing clock_event for cpu 0 */
277         if (!smp_processor_id())
278                 return 0;
279
280         if (!local_timer_inited) {
281                 writel(0, clock->regbase  + TIMER_ENABLE);
282                 writel(0, clock->regbase + TIMER_CLEAR);
283                 writel(~0, clock->regbase + TIMER_MATCH_VAL);
284                 local_timer_inited = true;
285         }
286         evt->irq = clock->irq;
287         evt->name = "local_timer";
288         evt->features = CLOCK_EVT_FEAT_ONESHOT;
289         evt->rating = clock->clockevent.rating;
290         evt->set_mode = msm_timer_set_mode;
291         evt->set_next_event = msm_timer_set_next_event;
292         evt->shift = clock->clockevent.shift;
293         evt->mult = div_sc(clock->freq, NSEC_PER_SEC, evt->shift);
294         evt->max_delta_ns =
295                 clockevent_delta2ns(0xf0000000 >> clock->shift, evt);
296         evt->min_delta_ns = clockevent_delta2ns(4, evt);
297
298         *__this_cpu_ptr(clock->percpu_evt) = evt;
299         enable_percpu_irq(evt->irq, 0);
300
301         clockevents_register_device(evt);
302         return 0;
303 }
304
305 void local_timer_stop(struct clock_event_device *evt)
306 {
307         evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
308         disable_percpu_irq(evt->irq);
309 }
310 #endif /* CONFIG_LOCAL_TIMERS */
311
312 struct sys_timer msm_timer = {
313         .init = msm_timer_init
314 };