]> Pileus Git - ~andy/linux/blob - arch/arm/kernel/smp_twd.c
Merge branch 'drm-next-3.9' of git://people.freedesktop.org/~agd5f/linux into drm...
[~andy/linux] / arch / arm / kernel / smp_twd.c
1 /*
2  *  linux/arch/arm/kernel/smp_twd.c
3  *
4  *  Copyright (C) 2002 ARM Ltd.
5  *  All Rights Reserved
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  */
11 #include <linux/init.h>
12 #include <linux/kernel.h>
13 #include <linux/clk.h>
14 #include <linux/delay.h>
15 #include <linux/device.h>
16 #include <linux/err.h>
17 #include <linux/smp.h>
18 #include <linux/jiffies.h>
19 #include <linux/clockchips.h>
20 #include <linux/interrupt.h>
21 #include <linux/io.h>
22 #include <linux/of_irq.h>
23 #include <linux/of_address.h>
24
25 #include <asm/smp_twd.h>
26 #include <asm/localtimer.h>
27 #include <asm/hardware/gic.h>
28
29 /* set up by the platform code */
30 static void __iomem *twd_base;
31
32 static struct clk *twd_clk;
33 static unsigned long twd_timer_rate;
34 static bool common_setup_called;
35 static DEFINE_PER_CPU(bool, percpu_setup_called);
36
37 static struct clock_event_device __percpu **twd_evt;
38 static int twd_ppi;
39
40 static void twd_set_mode(enum clock_event_mode mode,
41                         struct clock_event_device *clk)
42 {
43         unsigned long ctrl;
44
45         switch (mode) {
46         case CLOCK_EVT_MODE_PERIODIC:
47                 ctrl = TWD_TIMER_CONTROL_ENABLE | TWD_TIMER_CONTROL_IT_ENABLE
48                         | TWD_TIMER_CONTROL_PERIODIC;
49                 __raw_writel(DIV_ROUND_CLOSEST(twd_timer_rate, HZ),
50                         twd_base + TWD_TIMER_LOAD);
51                 break;
52         case CLOCK_EVT_MODE_ONESHOT:
53                 /* period set, and timer enabled in 'next_event' hook */
54                 ctrl = TWD_TIMER_CONTROL_IT_ENABLE | TWD_TIMER_CONTROL_ONESHOT;
55                 break;
56         case CLOCK_EVT_MODE_UNUSED:
57         case CLOCK_EVT_MODE_SHUTDOWN:
58         default:
59                 ctrl = 0;
60         }
61
62         __raw_writel(ctrl, twd_base + TWD_TIMER_CONTROL);
63 }
64
65 static int twd_set_next_event(unsigned long evt,
66                         struct clock_event_device *unused)
67 {
68         unsigned long ctrl = __raw_readl(twd_base + TWD_TIMER_CONTROL);
69
70         ctrl |= TWD_TIMER_CONTROL_ENABLE;
71
72         __raw_writel(evt, twd_base + TWD_TIMER_COUNTER);
73         __raw_writel(ctrl, twd_base + TWD_TIMER_CONTROL);
74
75         return 0;
76 }
77
78 /*
79  * local_timer_ack: checks for a local timer interrupt.
80  *
81  * If a local timer interrupt has occurred, acknowledge and return 1.
82  * Otherwise, return 0.
83  */
84 static int twd_timer_ack(void)
85 {
86         if (__raw_readl(twd_base + TWD_TIMER_INTSTAT)) {
87                 __raw_writel(1, twd_base + TWD_TIMER_INTSTAT);
88                 return 1;
89         }
90
91         return 0;
92 }
93
94 static void twd_timer_stop(struct clock_event_device *clk)
95 {
96         twd_set_mode(CLOCK_EVT_MODE_UNUSED, clk);
97         disable_percpu_irq(clk->irq);
98 }
99
100 #ifdef CONFIG_COMMON_CLK
101
102 /*
103  * Updates clockevent frequency when the cpu frequency changes.
104  * Called on the cpu that is changing frequency with interrupts disabled.
105  */
106 static void twd_update_frequency(void *new_rate)
107 {
108         twd_timer_rate = *((unsigned long *) new_rate);
109
110         clockevents_update_freq(*__this_cpu_ptr(twd_evt), twd_timer_rate);
111 }
112
113 static int twd_rate_change(struct notifier_block *nb,
114         unsigned long flags, void *data)
115 {
116         struct clk_notifier_data *cnd = data;
117
118         /*
119          * The twd clock events must be reprogrammed to account for the new
120          * frequency.  The timer is local to a cpu, so cross-call to the
121          * changing cpu.
122          */
123         if (flags == POST_RATE_CHANGE)
124                 smp_call_function(twd_update_frequency,
125                                   (void *)&cnd->new_rate, 1);
126
127         return NOTIFY_OK;
128 }
129
130 static struct notifier_block twd_clk_nb = {
131         .notifier_call = twd_rate_change,
132 };
133
134 static int twd_clk_init(void)
135 {
136         if (twd_evt && *__this_cpu_ptr(twd_evt) && !IS_ERR(twd_clk))
137                 return clk_notifier_register(twd_clk, &twd_clk_nb);
138
139         return 0;
140 }
141 core_initcall(twd_clk_init);
142
143 #elif defined (CONFIG_CPU_FREQ)
144
145 #include <linux/cpufreq.h>
146
147 /*
148  * Updates clockevent frequency when the cpu frequency changes.
149  * Called on the cpu that is changing frequency with interrupts disabled.
150  */
151 static void twd_update_frequency(void *data)
152 {
153         twd_timer_rate = clk_get_rate(twd_clk);
154
155         clockevents_update_freq(*__this_cpu_ptr(twd_evt), twd_timer_rate);
156 }
157
158 static int twd_cpufreq_transition(struct notifier_block *nb,
159         unsigned long state, void *data)
160 {
161         struct cpufreq_freqs *freqs = data;
162
163         /*
164          * The twd clock events must be reprogrammed to account for the new
165          * frequency.  The timer is local to a cpu, so cross-call to the
166          * changing cpu.
167          */
168         if (state == CPUFREQ_POSTCHANGE || state == CPUFREQ_RESUMECHANGE)
169                 smp_call_function_single(freqs->cpu, twd_update_frequency,
170                         NULL, 1);
171
172         return NOTIFY_OK;
173 }
174
175 static struct notifier_block twd_cpufreq_nb = {
176         .notifier_call = twd_cpufreq_transition,
177 };
178
179 static int twd_cpufreq_init(void)
180 {
181         if (twd_evt && *__this_cpu_ptr(twd_evt) && !IS_ERR(twd_clk))
182                 return cpufreq_register_notifier(&twd_cpufreq_nb,
183                         CPUFREQ_TRANSITION_NOTIFIER);
184
185         return 0;
186 }
187 core_initcall(twd_cpufreq_init);
188
189 #endif
190
191 static void __cpuinit twd_calibrate_rate(void)
192 {
193         unsigned long count;
194         u64 waitjiffies;
195
196         /*
197          * If this is the first time round, we need to work out how fast
198          * the timer ticks
199          */
200         if (twd_timer_rate == 0) {
201                 printk(KERN_INFO "Calibrating local timer... ");
202
203                 /* Wait for a tick to start */
204                 waitjiffies = get_jiffies_64() + 1;
205
206                 while (get_jiffies_64() < waitjiffies)
207                         udelay(10);
208
209                 /* OK, now the tick has started, let's get the timer going */
210                 waitjiffies += 5;
211
212                                  /* enable, no interrupt or reload */
213                 __raw_writel(0x1, twd_base + TWD_TIMER_CONTROL);
214
215                                  /* maximum value */
216                 __raw_writel(0xFFFFFFFFU, twd_base + TWD_TIMER_COUNTER);
217
218                 while (get_jiffies_64() < waitjiffies)
219                         udelay(10);
220
221                 count = __raw_readl(twd_base + TWD_TIMER_COUNTER);
222
223                 twd_timer_rate = (0xFFFFFFFFU - count) * (HZ / 5);
224
225                 printk("%lu.%02luMHz.\n", twd_timer_rate / 1000000,
226                         (twd_timer_rate / 10000) % 100);
227         }
228 }
229
230 static irqreturn_t twd_handler(int irq, void *dev_id)
231 {
232         struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
233
234         if (twd_timer_ack()) {
235                 evt->event_handler(evt);
236                 return IRQ_HANDLED;
237         }
238
239         return IRQ_NONE;
240 }
241
242 static struct clk *twd_get_clock(void)
243 {
244         struct clk *clk;
245         int err;
246
247         clk = clk_get_sys("smp_twd", NULL);
248         if (IS_ERR(clk)) {
249                 pr_err("smp_twd: clock not found: %d\n", (int)PTR_ERR(clk));
250                 return clk;
251         }
252
253         err = clk_prepare_enable(clk);
254         if (err) {
255                 pr_err("smp_twd: clock failed to prepare+enable: %d\n", err);
256                 clk_put(clk);
257                 return ERR_PTR(err);
258         }
259
260         return clk;
261 }
262
263 /*
264  * Setup the local clock events for a CPU.
265  */
266 static int __cpuinit twd_timer_setup(struct clock_event_device *clk)
267 {
268         struct clock_event_device **this_cpu_clk;
269         int cpu = smp_processor_id();
270
271         /*
272          * If the basic setup for this CPU has been done before don't
273          * bother with the below.
274          */
275         if (per_cpu(percpu_setup_called, cpu)) {
276                 __raw_writel(0, twd_base + TWD_TIMER_CONTROL);
277                 clockevents_register_device(*__this_cpu_ptr(twd_evt));
278                 enable_percpu_irq(clk->irq, 0);
279                 return 0;
280         }
281         per_cpu(percpu_setup_called, cpu) = true;
282
283         /*
284          * This stuff only need to be done once for the entire TWD cluster
285          * during the runtime of the system.
286          */
287         if (!common_setup_called) {
288                 twd_clk = twd_get_clock();
289
290                 /*
291                  * We use IS_ERR_OR_NULL() here, because if the clock stubs
292                  * are active we will get a valid clk reference which is
293                  * however NULL and will return the rate 0. In that case we
294                  * need to calibrate the rate instead.
295                  */
296                 if (!IS_ERR_OR_NULL(twd_clk))
297                         twd_timer_rate = clk_get_rate(twd_clk);
298                 else
299                         twd_calibrate_rate();
300
301                 common_setup_called = true;
302         }
303
304         /*
305          * The following is done once per CPU the first time .setup() is
306          * called.
307          */
308         __raw_writel(0, twd_base + TWD_TIMER_CONTROL);
309
310         clk->name = "local_timer";
311         clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT |
312                         CLOCK_EVT_FEAT_C3STOP;
313         clk->rating = 350;
314         clk->set_mode = twd_set_mode;
315         clk->set_next_event = twd_set_next_event;
316         clk->irq = twd_ppi;
317
318         this_cpu_clk = __this_cpu_ptr(twd_evt);
319         *this_cpu_clk = clk;
320
321         clockevents_config_and_register(clk, twd_timer_rate,
322                                         0xf, 0xffffffff);
323         enable_percpu_irq(clk->irq, 0);
324
325         return 0;
326 }
327
328 static struct local_timer_ops twd_lt_ops __cpuinitdata = {
329         .setup  = twd_timer_setup,
330         .stop   = twd_timer_stop,
331 };
332
333 static int __init twd_local_timer_common_register(void)
334 {
335         int err;
336
337         twd_evt = alloc_percpu(struct clock_event_device *);
338         if (!twd_evt) {
339                 err = -ENOMEM;
340                 goto out_free;
341         }
342
343         err = request_percpu_irq(twd_ppi, twd_handler, "twd", twd_evt);
344         if (err) {
345                 pr_err("twd: can't register interrupt %d (%d)\n", twd_ppi, err);
346                 goto out_free;
347         }
348
349         err = local_timer_register(&twd_lt_ops);
350         if (err)
351                 goto out_irq;
352
353         return 0;
354
355 out_irq:
356         free_percpu_irq(twd_ppi, twd_evt);
357 out_free:
358         iounmap(twd_base);
359         twd_base = NULL;
360         free_percpu(twd_evt);
361
362         return err;
363 }
364
365 int __init twd_local_timer_register(struct twd_local_timer *tlt)
366 {
367         if (twd_base || twd_evt)
368                 return -EBUSY;
369
370         twd_ppi = tlt->res[1].start;
371
372         twd_base = ioremap(tlt->res[0].start, resource_size(&tlt->res[0]));
373         if (!twd_base)
374                 return -ENOMEM;
375
376         return twd_local_timer_common_register();
377 }
378
379 #ifdef CONFIG_OF
380 const static struct of_device_id twd_of_match[] __initconst = {
381         { .compatible = "arm,cortex-a9-twd-timer",      },
382         { .compatible = "arm,cortex-a5-twd-timer",      },
383         { .compatible = "arm,arm11mp-twd-timer",        },
384         { },
385 };
386
387 void __init twd_local_timer_of_register(void)
388 {
389         struct device_node *np;
390         int err;
391
392         np = of_find_matching_node(NULL, twd_of_match);
393         if (!np)
394                 return;
395
396         twd_ppi = irq_of_parse_and_map(np, 0);
397         if (!twd_ppi) {
398                 err = -EINVAL;
399                 goto out;
400         }
401
402         twd_base = of_iomap(np, 0);
403         if (!twd_base) {
404                 err = -ENOMEM;
405                 goto out;
406         }
407
408         err = twd_local_timer_common_register();
409
410 out:
411         WARN(err, "twd_local_timer_of_register failed (%d)\n", err);
412 }
413 #endif