aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-msm/timer.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-10-01 21:28:06 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-10-01 21:28:06 -0400
commit2a2bf85f05e42b12ea6bfe821e2d19221cf93555 (patch)
tree11abcdaef6e4f8307574056998d306d21558b6ed /arch/arm/mach-msm/timer.c
parent11801e9de26992d37cb869cc74f389b6a7677e0e (diff)
parent99261fbad0a16f105b262d7525801697588ba526 (diff)
Merge tag 'dt' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM soc device tree updates from Olof Johansson: "Device tree conversion and enablement branch. Mostly a bunch of new bindings and setup for various platforms, but the Via/Winchip VT8500 platform is also converted over from being 100% legacy to now use device tree for probing. More of that will come for 3.8." Trivial conflicts due to removal of vt8500 files, and one documentation file that was added with slightly different contents both here and in the USb tree. * tag 'dt' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (212 commits) arm: vt8500: Fixup for missing gpio.h ARM: LPC32xx: LED fix in PHY3250 DTS file ARM: dt: mmp-dma: add binding file arm: vt8500: Update arch-vt8500 to devicetree support. arm: vt8500: gpio: Devicetree support for arch-vt8500 arm: vt8500: doc: Add device tree bindings for arch-vt8500 devices arm: vt8500: clk: Add Common Clock Framework support video: vt8500: Add devicetree support for vt8500-fb and wm8505-fb serial: vt8500: Add devicetree support for vt8500-serial rtc: vt8500: Add devicetree support for vt8500-rtc arm: vt8500: Add device tree files for VIA/Wondermedia SoC's ARM: tegra: Add Avionic Design Tamonten Evaluation Carrier support ARM: tegra: Add Avionic Design Medcom-Wide support ARM: tegra: Add Avionic Design Plutux support ARM: tegra: Add Avionic Design Tamonten support ARM: tegra: dts: Add pwm label ARM: ux500: Fix SSP register address format ARM: ux500: Apply tc3589x's GPIO/IRQ properties to HREF's DT ARM: ux500: Remove redundant #gpio-cell properties from Snowball DT ARM: ux500: Add all encompassing sound node to the HREF Device Tree ...
Diffstat (limited to 'arch/arm/mach-msm/timer.c')
-rw-r--r--arch/arm/mach-msm/timer.c186
1 files changed, 148 insertions, 38 deletions
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index 004f93515a4e..476549a8a709 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * 2 *
3 * Copyright (C) 2007 Google, Inc. 3 * Copyright (C) 2007 Google, Inc.
4 * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved. 4 * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
5 * 5 *
6 * This software is licensed under the terms of the GNU General Public 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 7 * License version 2, as published by the Free Software Foundation, and
@@ -20,15 +20,16 @@
20#include <linux/interrupt.h> 20#include <linux/interrupt.h>
21#include <linux/irq.h> 21#include <linux/irq.h>
22#include <linux/io.h> 22#include <linux/io.h>
23#include <linux/of.h>
24#include <linux/of_address.h>
25#include <linux/of_irq.h>
23 26
24#include <asm/mach/time.h> 27#include <asm/mach/time.h>
25#include <asm/hardware/gic.h> 28#include <asm/hardware/gic.h>
26#include <asm/localtimer.h> 29#include <asm/localtimer.h>
27#include <asm/sched_clock.h> 30#include <asm/sched_clock.h>
28 31
29#include <mach/msm_iomap.h> 32#include "common.h"
30#include <mach/cpu.h>
31#include <mach/board.h>
32 33
33#define TIMER_MATCH_VAL 0x0000 34#define TIMER_MATCH_VAL 0x0000
34#define TIMER_COUNT_VAL 0x0004 35#define TIMER_COUNT_VAL 0x0004
@@ -36,7 +37,6 @@
36#define TIMER_ENABLE_CLR_ON_MATCH_EN BIT(1) 37#define TIMER_ENABLE_CLR_ON_MATCH_EN BIT(1)
37#define TIMER_ENABLE_EN BIT(0) 38#define TIMER_ENABLE_EN BIT(0)
38#define TIMER_CLEAR 0x000C 39#define TIMER_CLEAR 0x000C
39#define DGT_CLK_CTL 0x0034
40#define DGT_CLK_CTL_DIV_4 0x3 40#define DGT_CLK_CTL_DIV_4 0x3
41 41
42#define GPT_HZ 32768 42#define GPT_HZ 32768
@@ -151,7 +151,7 @@ static int __cpuinit msm_local_timer_setup(struct clock_event_device *evt)
151 151
152 *__this_cpu_ptr(msm_evt.percpu_evt) = evt; 152 *__this_cpu_ptr(msm_evt.percpu_evt) = evt;
153 clockevents_register_device(evt); 153 clockevents_register_device(evt);
154 enable_percpu_irq(evt->irq, 0); 154 enable_percpu_irq(evt->irq, IRQ_TYPE_EDGE_RISING);
155 return 0; 155 return 0;
156} 156}
157 157
@@ -172,44 +172,21 @@ static notrace u32 msm_sched_clock_read(void)
172 return msm_clocksource.read(&msm_clocksource); 172 return msm_clocksource.read(&msm_clocksource);
173} 173}
174 174
175static void __init msm_timer_init(void) 175static void __init msm_timer_init(u32 dgt_hz, int sched_bits, int irq,
176 bool percpu)
176{ 177{
177 struct clock_event_device *ce = &msm_clockevent; 178 struct clock_event_device *ce = &msm_clockevent;
178 struct clocksource *cs = &msm_clocksource; 179 struct clocksource *cs = &msm_clocksource;
179 int res; 180 int res;
180 u32 dgt_hz;
181
182 if (cpu_is_msm7x01()) {
183 event_base = MSM_CSR_BASE;
184 source_base = MSM_CSR_BASE + 0x10;
185 dgt_hz = 19200000 >> MSM_DGT_SHIFT; /* 600 KHz */
186 cs->read = msm_read_timer_count_shift;
187 cs->mask = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT));
188 } else if (cpu_is_msm7x30()) {
189 event_base = MSM_CSR_BASE + 0x04;
190 source_base = MSM_CSR_BASE + 0x24;
191 dgt_hz = 24576000 / 4;
192 } else if (cpu_is_qsd8x50()) {
193 event_base = MSM_CSR_BASE;
194 source_base = MSM_CSR_BASE + 0x10;
195 dgt_hz = 19200000 / 4;
196 } else if (cpu_is_msm8x60() || cpu_is_msm8960()) {
197 event_base = MSM_TMR_BASE + 0x04;
198 /* Use CPU0's timer as the global clock source. */
199 source_base = MSM_TMR0_BASE + 0x24;
200 dgt_hz = 27000000 / 4;
201 writel_relaxed(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
202 } else
203 BUG();
204 181
205 writel_relaxed(0, event_base + TIMER_ENABLE); 182 writel_relaxed(0, event_base + TIMER_ENABLE);
206 writel_relaxed(0, event_base + TIMER_CLEAR); 183 writel_relaxed(0, event_base + TIMER_CLEAR);
207 writel_relaxed(~0, event_base + TIMER_MATCH_VAL); 184 writel_relaxed(~0, event_base + TIMER_MATCH_VAL);
208 ce->cpumask = cpumask_of(0); 185 ce->cpumask = cpumask_of(0);
186 ce->irq = irq;
209 187
210 ce->irq = INT_GP_TIMER_EXP;
211 clockevents_config_and_register(ce, GPT_HZ, 4, 0xffffffff); 188 clockevents_config_and_register(ce, GPT_HZ, 4, 0xffffffff);
212 if (cpu_is_msm8x60() || cpu_is_msm8960()) { 189 if (percpu) {
213 msm_evt.percpu_evt = alloc_percpu(struct clock_event_device *); 190 msm_evt.percpu_evt = alloc_percpu(struct clock_event_device *);
214 if (!msm_evt.percpu_evt) { 191 if (!msm_evt.percpu_evt) {
215 pr_err("memory allocation failed for %s\n", ce->name); 192 pr_err("memory allocation failed for %s\n", ce->name);
@@ -219,7 +196,7 @@ static void __init msm_timer_init(void)
219 res = request_percpu_irq(ce->irq, msm_timer_interrupt, 196 res = request_percpu_irq(ce->irq, msm_timer_interrupt,
220 ce->name, msm_evt.percpu_evt); 197 ce->name, msm_evt.percpu_evt);
221 if (!res) { 198 if (!res) {
222 enable_percpu_irq(ce->irq, 0); 199 enable_percpu_irq(ce->irq, IRQ_TYPE_EDGE_RISING);
223#ifdef CONFIG_LOCAL_TIMERS 200#ifdef CONFIG_LOCAL_TIMERS
224 local_timer_register(&msm_local_timer_ops); 201 local_timer_register(&msm_local_timer_ops);
225#endif 202#endif
@@ -238,10 +215,143 @@ err:
238 res = clocksource_register_hz(cs, dgt_hz); 215 res = clocksource_register_hz(cs, dgt_hz);
239 if (res) 216 if (res)
240 pr_err("clocksource_register failed\n"); 217 pr_err("clocksource_register failed\n");
241 setup_sched_clock(msm_sched_clock_read, 218 setup_sched_clock(msm_sched_clock_read, sched_bits, dgt_hz);
242 cpu_is_msm7x01() ? 32 - MSM_DGT_SHIFT : 32, dgt_hz);
243} 219}
244 220
245struct sys_timer msm_timer = { 221#ifdef CONFIG_OF
246 .init = msm_timer_init 222static const struct of_device_id msm_dgt_match[] __initconst = {
223 { .compatible = "qcom,msm-dgt" },
224 { },
225};
226
227static const struct of_device_id msm_gpt_match[] __initconst = {
228 { .compatible = "qcom,msm-gpt" },
229 { },
230};
231
232static void __init msm_dt_timer_init(void)
233{
234 struct device_node *np;
235 u32 freq;
236 int irq;
237 struct resource res;
238 u32 percpu_offset;
239 void __iomem *dgt_clk_ctl;
240
241 np = of_find_matching_node(NULL, msm_gpt_match);
242 if (!np) {
243 pr_err("Can't find GPT DT node\n");
244 return;
245 }
246
247 event_base = of_iomap(np, 0);
248 if (!event_base) {
249 pr_err("Failed to map event base\n");
250 return;
251 }
252
253 irq = irq_of_parse_and_map(np, 0);
254 if (irq <= 0) {
255 pr_err("Can't get irq\n");
256 return;
257 }
258 of_node_put(np);
259
260 np = of_find_matching_node(NULL, msm_dgt_match);
261 if (!np) {
262 pr_err("Can't find DGT DT node\n");
263 return;
264 }
265
266 if (of_property_read_u32(np, "cpu-offset", &percpu_offset))
267 percpu_offset = 0;
268
269 if (of_address_to_resource(np, 0, &res)) {
270 pr_err("Failed to parse DGT resource\n");
271 return;
272 }
273
274 source_base = ioremap(res.start + percpu_offset, resource_size(&res));
275 if (!source_base) {
276 pr_err("Failed to map source base\n");
277 return;
278 }
279
280 if (!of_address_to_resource(np, 1, &res)) {
281 dgt_clk_ctl = ioremap(res.start + percpu_offset,
282 resource_size(&res));
283 if (!dgt_clk_ctl) {
284 pr_err("Failed to map DGT control base\n");
285 return;
286 }
287 writel_relaxed(DGT_CLK_CTL_DIV_4, dgt_clk_ctl);
288 iounmap(dgt_clk_ctl);
289 }
290
291 if (of_property_read_u32(np, "clock-frequency", &freq)) {
292 pr_err("Unknown frequency\n");
293 return;
294 }
295 of_node_put(np);
296
297 msm_timer_init(freq, 32, irq, !!percpu_offset);
298}
299
300struct sys_timer msm_dt_timer = {
301 .init = msm_dt_timer_init
302};
303#endif
304
305static int __init msm_timer_map(phys_addr_t event, phys_addr_t source)
306{
307 event_base = ioremap(event, SZ_64);
308 if (!event_base) {
309 pr_err("Failed to map event base\n");
310 return 1;
311 }
312 source_base = ioremap(source, SZ_64);
313 if (!source_base) {
314 pr_err("Failed to map source base\n");
315 return 1;
316 }
317 return 0;
318}
319
320static void __init msm7x01_timer_init(void)
321{
322 struct clocksource *cs = &msm_clocksource;
323
324 if (msm_timer_map(0xc0100000, 0xc0100010))
325 return;
326 cs->read = msm_read_timer_count_shift;
327 cs->mask = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT));
328 /* 600 KHz */
329 msm_timer_init(19200000 >> MSM_DGT_SHIFT, 32 - MSM_DGT_SHIFT, 7,
330 false);
331}
332
333struct sys_timer msm7x01_timer = {
334 .init = msm7x01_timer_init
335};
336
337static void __init msm7x30_timer_init(void)
338{
339 if (msm_timer_map(0xc0100004, 0xc0100024))
340 return;
341 msm_timer_init(24576000 / 4, 32, 1, false);
342}
343
344struct sys_timer msm7x30_timer = {
345 .init = msm7x30_timer_init
346};
347
348static void __init qsd8x50_timer_init(void)
349{
350 if (msm_timer_map(0xAC100000, 0xAC100010))
351 return;
352 msm_timer_init(19200000 / 4, 32, 7, false);
353}
354
355struct sys_timer qsd8x50_timer = {
356 .init = qsd8x50_timer_init
247}; 357};