msm: timer: Use GPT for clockevents and DGT for clocksource
[platform/adaptation/renesas_rcar/renesas_kernel.git] / 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 irqreturn_t msm_timer_interrupt(int irq, void *dev_id)
85 {
86         struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
87         if (evt->event_handler == NULL)
88                 return IRQ_HANDLED;
89         evt->event_handler(evt);
90         return IRQ_HANDLED;
91 }
92
93 static cycle_t msm_read_timer_count(struct clocksource *cs)
94 {
95         struct msm_clock *clk = container_of(cs, struct msm_clock, clocksource);
96
97         /*
98          * Shift timer count down by a constant due to unreliable lower bits
99          * on some targets.
100          */
101         return readl(clk->global_counter) >> clk->shift;
102 }
103
104 static struct msm_clock *clockevent_to_clock(struct clock_event_device *evt)
105 {
106 #ifdef CONFIG_SMP
107         int i;
108         for (i = 0; i < NR_TIMERS; i++)
109                 if (evt == &(msm_clocks[i].clockevent))
110                         return &msm_clocks[i];
111         return &msm_clocks[MSM_GLOBAL_TIMER];
112 #else
113         return container_of(evt, struct msm_clock, clockevent);
114 #endif
115 }
116
117 static int msm_timer_set_next_event(unsigned long cycles,
118                                     struct clock_event_device *evt)
119 {
120         struct msm_clock *clock = clockevent_to_clock(evt);
121         uint32_t now = readl(clock->local_counter);
122         uint32_t alarm = now + (cycles << clock->shift);
123
124         writel(alarm, clock->regbase + TIMER_MATCH_VAL);
125         return 0;
126 }
127
128 static void msm_timer_set_mode(enum clock_event_mode mode,
129                               struct clock_event_device *evt)
130 {
131         struct msm_clock *clock = clockevent_to_clock(evt);
132
133         switch (mode) {
134         case CLOCK_EVT_MODE_RESUME:
135         case CLOCK_EVT_MODE_PERIODIC:
136                 break;
137         case CLOCK_EVT_MODE_ONESHOT:
138                 writel(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE);
139                 break;
140         case CLOCK_EVT_MODE_UNUSED:
141         case CLOCK_EVT_MODE_SHUTDOWN:
142                 writel(0, clock->regbase + TIMER_ENABLE);
143                 break;
144         }
145 }
146
147 static struct msm_clock msm_clocks[] = {
148         [MSM_CLOCK_GPT] = {
149                 .clockevent = {
150                         .name           = "gp_timer",
151                         .features       = CLOCK_EVT_FEAT_ONESHOT,
152                         .shift          = 32,
153                         .rating         = 200,
154                         .set_next_event = msm_timer_set_next_event,
155                         .set_mode       = msm_timer_set_mode,
156                 },
157                 .irq = INT_GP_TIMER_EXP,
158                 .freq = GPT_HZ,
159         },
160         [MSM_CLOCK_DGT] = {
161                 .clocksource = {
162                         .name           = "dg_timer",
163                         .rating         = 300,
164                         .read           = msm_read_timer_count,
165                         .mask           = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT)),
166                         .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
167                 },
168                 .freq = DGT_HZ >> MSM_DGT_SHIFT,
169                 .shift = MSM_DGT_SHIFT,
170         }
171 };
172
173 static void __init msm_timer_init(void)
174 {
175         struct msm_clock *clock;
176         struct clock_event_device *ce = &msm_clocks[MSM_CLOCK_GPT].clockevent;
177         struct clocksource *cs = &msm_clocks[MSM_CLOCK_DGT].clocksource;
178         int res;
179         int global_offset = 0;
180
181
182         if (cpu_is_msm7x01()) {
183                 msm_clocks[MSM_CLOCK_GPT].regbase = MSM_CSR_BASE;
184                 msm_clocks[MSM_CLOCK_DGT].regbase = MSM_CSR_BASE + 0x10;
185         } else if (cpu_is_msm7x30()) {
186                 msm_clocks[MSM_CLOCK_GPT].regbase = MSM_CSR_BASE + 0x04;
187                 msm_clocks[MSM_CLOCK_DGT].regbase = MSM_CSR_BASE + 0x24;
188         } else if (cpu_is_qsd8x50()) {
189                 msm_clocks[MSM_CLOCK_GPT].regbase = MSM_CSR_BASE;
190                 msm_clocks[MSM_CLOCK_DGT].regbase = MSM_CSR_BASE + 0x10;
191         } else if (cpu_is_msm8x60() || cpu_is_msm8960()) {
192                 msm_clocks[MSM_CLOCK_GPT].regbase = MSM_TMR_BASE + 0x04;
193                 msm_clocks[MSM_CLOCK_DGT].regbase = MSM_TMR_BASE + 0x24;
194
195                 /* Use CPU0's timer as the global timer. */
196                 global_offset = MSM_TMR0_BASE - MSM_TMR_BASE;
197         } else
198                 BUG();
199
200 #ifdef CONFIG_ARCH_MSM_SCORPIONMP
201         writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
202 #endif
203
204         clock = &msm_clocks[MSM_CLOCK_GPT];
205         clock->local_counter = clock->regbase + TIMER_COUNT_VAL;
206
207         writel_relaxed(0, clock->regbase + TIMER_ENABLE);
208         writel_relaxed(0, clock->regbase + TIMER_CLEAR);
209         writel_relaxed(~0, clock->regbase + TIMER_MATCH_VAL);
210         ce->mult = div_sc(clock->freq, NSEC_PER_SEC, ce->shift);
211         /*
212          * allow at least 10 seconds to notice that the timer
213          * wrapped
214          */
215         ce->max_delta_ns =
216                 clockevent_delta2ns(0xf0000000 >> clock->shift, ce);
217         /* 4 gets rounded down to 3 */
218         ce->min_delta_ns = clockevent_delta2ns(4, ce);
219         ce->cpumask = cpumask_of(0);
220
221         ce->irq = clock->irq;
222         if (cpu_is_msm8x60() || cpu_is_msm8960()) {
223                 clock->percpu_evt = alloc_percpu(struct clock_event_device *);
224                 if (!clock->percpu_evt) {
225                         pr_err("memory allocation failed for %s\n", ce->name);
226                         goto err;
227                 }
228
229                 *__this_cpu_ptr(clock->percpu_evt) = ce;
230                 res = request_percpu_irq(ce->irq, msm_timer_interrupt,
231                                          ce->name, clock->percpu_evt);
232                 if (!res)
233                         enable_percpu_irq(ce->irq, 0);
234         } else {
235                 clock->evt = ce;
236                 res = request_irq(ce->irq, msm_timer_interrupt,
237                                   IRQF_TIMER | IRQF_NOBALANCING |
238                                   IRQF_TRIGGER_RISING, ce->name, &clock->evt);
239         }
240
241         if (res)
242                 pr_err("request_irq failed for %s\n", ce->name);
243
244         clockevents_register_device(ce);
245 err:
246         clock = &msm_clocks[MSM_CLOCK_DGT];
247         clock->local_counter = clock->regbase + TIMER_COUNT_VAL;
248         clock->global_counter = clock->local_counter + global_offset;
249         writel_relaxed(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE);
250         res = clocksource_register_hz(cs, clock->freq);
251         if (res)
252                 pr_err("clocksource_register failed for %s\n", cs->name);
253 }
254
255 #ifdef CONFIG_LOCAL_TIMERS
256 int __cpuinit local_timer_setup(struct clock_event_device *evt)
257 {
258         static bool local_timer_inited;
259         struct msm_clock *clock = &msm_clocks[MSM_GLOBAL_TIMER];
260
261         /* Use existing clock_event for cpu 0 */
262         if (!smp_processor_id())
263                 return 0;
264
265         if (!local_timer_inited) {
266                 writel(0, clock->regbase  + TIMER_ENABLE);
267                 writel(0, clock->regbase + TIMER_CLEAR);
268                 writel(~0, clock->regbase + TIMER_MATCH_VAL);
269                 local_timer_inited = true;
270         }
271         evt->irq = clock->irq;
272         evt->name = "local_timer";
273         evt->features = CLOCK_EVT_FEAT_ONESHOT;
274         evt->rating = clock->clockevent.rating;
275         evt->set_mode = msm_timer_set_mode;
276         evt->set_next_event = msm_timer_set_next_event;
277         evt->shift = clock->clockevent.shift;
278         evt->mult = div_sc(clock->freq, NSEC_PER_SEC, evt->shift);
279         evt->max_delta_ns =
280                 clockevent_delta2ns(0xf0000000 >> clock->shift, evt);
281         evt->min_delta_ns = clockevent_delta2ns(4, evt);
282
283         *__this_cpu_ptr(clock->percpu_evt) = evt;
284         enable_percpu_irq(evt->irq, 0);
285
286         clockevents_register_device(evt);
287         return 0;
288 }
289
290 void local_timer_stop(struct clock_event_device *evt)
291 {
292         evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
293         disable_percpu_irq(evt->irq);
294 }
295 #endif /* CONFIG_LOCAL_TIMERS */
296
297 struct sys_timer msm_timer = {
298         .init = msm_timer_init
299 };