summaryrefslogtreecommitdiff
path: root/arch/arm/mach-msm/timer.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-10-02 05:28:06 +0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-10-02 05:28:06 +0400
commit2a2bf85f05e42b12ea6bfe821e2d19221cf93555 (patch)
tree11abcdaef6e4f8307574056998d306d21558b6ed /arch/arm/mach-msm/timer.c
parent11801e9de26992d37cb869cc74f389b6a7677e0e (diff)
parent99261fbad0a16f105b262d7525801697588ba526 (diff)
downloadlinux-2a2bf85f05e42b12ea6bfe821e2d19221cf93555.tar.xz
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 @@
/*
*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -20,15 +20,16 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include <asm/mach/time.h>
#include <asm/hardware/gic.h>
#include <asm/localtimer.h>
#include <asm/sched_clock.h>
-#include <mach/msm_iomap.h>
-#include <mach/cpu.h>
-#include <mach/board.h>
+#include "common.h"
#define TIMER_MATCH_VAL 0x0000
#define TIMER_COUNT_VAL 0x0004
@@ -36,7 +37,6 @@
#define TIMER_ENABLE_CLR_ON_MATCH_EN BIT(1)
#define TIMER_ENABLE_EN BIT(0)
#define TIMER_CLEAR 0x000C
-#define DGT_CLK_CTL 0x0034
#define DGT_CLK_CTL_DIV_4 0x3
#define GPT_HZ 32768
@@ -151,7 +151,7 @@ static int __cpuinit msm_local_timer_setup(struct clock_event_device *evt)
*__this_cpu_ptr(msm_evt.percpu_evt) = evt;
clockevents_register_device(evt);
- enable_percpu_irq(evt->irq, 0);
+ enable_percpu_irq(evt->irq, IRQ_TYPE_EDGE_RISING);
return 0;
}
@@ -172,44 +172,21 @@ static notrace u32 msm_sched_clock_read(void)
return msm_clocksource.read(&msm_clocksource);
}
-static void __init msm_timer_init(void)
+static void __init msm_timer_init(u32 dgt_hz, int sched_bits, int irq,
+ bool percpu)
{
struct clock_event_device *ce = &msm_clockevent;
struct clocksource *cs = &msm_clocksource;
int res;
- u32 dgt_hz;
-
- if (cpu_is_msm7x01()) {
- event_base = MSM_CSR_BASE;
- source_base = MSM_CSR_BASE + 0x10;
- dgt_hz = 19200000 >> MSM_DGT_SHIFT; /* 600 KHz */
- cs->read = msm_read_timer_count_shift;
- cs->mask = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT));
- } else if (cpu_is_msm7x30()) {
- event_base = MSM_CSR_BASE + 0x04;
- source_base = MSM_CSR_BASE + 0x24;
- dgt_hz = 24576000 / 4;
- } else if (cpu_is_qsd8x50()) {
- event_base = MSM_CSR_BASE;
- source_base = MSM_CSR_BASE + 0x10;
- dgt_hz = 19200000 / 4;
- } else if (cpu_is_msm8x60() || cpu_is_msm8960()) {
- event_base = MSM_TMR_BASE + 0x04;
- /* Use CPU0's timer as the global clock source. */
- source_base = MSM_TMR0_BASE + 0x24;
- dgt_hz = 27000000 / 4;
- writel_relaxed(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
- } else
- BUG();
writel_relaxed(0, event_base + TIMER_ENABLE);
writel_relaxed(0, event_base + TIMER_CLEAR);
writel_relaxed(~0, event_base + TIMER_MATCH_VAL);
ce->cpumask = cpumask_of(0);
+ ce->irq = irq;
- ce->irq = INT_GP_TIMER_EXP;
clockevents_config_and_register(ce, GPT_HZ, 4, 0xffffffff);
- if (cpu_is_msm8x60() || cpu_is_msm8960()) {
+ if (percpu) {
msm_evt.percpu_evt = alloc_percpu(struct clock_event_device *);
if (!msm_evt.percpu_evt) {
pr_err("memory allocation failed for %s\n", ce->name);
@@ -219,7 +196,7 @@ static void __init msm_timer_init(void)
res = request_percpu_irq(ce->irq, msm_timer_interrupt,
ce->name, msm_evt.percpu_evt);
if (!res) {
- enable_percpu_irq(ce->irq, 0);
+ enable_percpu_irq(ce->irq, IRQ_TYPE_EDGE_RISING);
#ifdef CONFIG_LOCAL_TIMERS
local_timer_register(&msm_local_timer_ops);
#endif
@@ -238,10 +215,143 @@ err:
res = clocksource_register_hz(cs, dgt_hz);
if (res)
pr_err("clocksource_register failed\n");
- setup_sched_clock(msm_sched_clock_read,
- cpu_is_msm7x01() ? 32 - MSM_DGT_SHIFT : 32, dgt_hz);
+ setup_sched_clock(msm_sched_clock_read, sched_bits, dgt_hz);
}
-struct sys_timer msm_timer = {
- .init = msm_timer_init
+#ifdef CONFIG_OF
+static const struct of_device_id msm_dgt_match[] __initconst = {
+ { .compatible = "qcom,msm-dgt" },
+ { },
+};
+
+static const struct of_device_id msm_gpt_match[] __initconst = {
+ { .compatible = "qcom,msm-gpt" },
+ { },
+};
+
+static void __init msm_dt_timer_init(void)
+{
+ struct device_node *np;
+ u32 freq;
+ int irq;
+ struct resource res;
+ u32 percpu_offset;
+ void __iomem *dgt_clk_ctl;
+
+ np = of_find_matching_node(NULL, msm_gpt_match);
+ if (!np) {
+ pr_err("Can't find GPT DT node\n");
+ return;
+ }
+
+ event_base = of_iomap(np, 0);
+ if (!event_base) {
+ pr_err("Failed to map event base\n");
+ return;
+ }
+
+ irq = irq_of_parse_and_map(np, 0);
+ if (irq <= 0) {
+ pr_err("Can't get irq\n");
+ return;
+ }
+ of_node_put(np);
+
+ np = of_find_matching_node(NULL, msm_dgt_match);
+ if (!np) {
+ pr_err("Can't find DGT DT node\n");
+ return;
+ }
+
+ if (of_property_read_u32(np, "cpu-offset", &percpu_offset))
+ percpu_offset = 0;
+
+ if (of_address_to_resource(np, 0, &res)) {
+ pr_err("Failed to parse DGT resource\n");
+ return;
+ }
+
+ source_base = ioremap(res.start + percpu_offset, resource_size(&res));
+ if (!source_base) {
+ pr_err("Failed to map source base\n");
+ return;
+ }
+
+ if (!of_address_to_resource(np, 1, &res)) {
+ dgt_clk_ctl = ioremap(res.start + percpu_offset,
+ resource_size(&res));
+ if (!dgt_clk_ctl) {
+ pr_err("Failed to map DGT control base\n");
+ return;
+ }
+ writel_relaxed(DGT_CLK_CTL_DIV_4, dgt_clk_ctl);
+ iounmap(dgt_clk_ctl);
+ }
+
+ if (of_property_read_u32(np, "clock-frequency", &freq)) {
+ pr_err("Unknown frequency\n");
+ return;
+ }
+ of_node_put(np);
+
+ msm_timer_init(freq, 32, irq, !!percpu_offset);
+}
+
+struct sys_timer msm_dt_timer = {
+ .init = msm_dt_timer_init
+};
+#endif
+
+static int __init msm_timer_map(phys_addr_t event, phys_addr_t source)
+{
+ event_base = ioremap(event, SZ_64);
+ if (!event_base) {
+ pr_err("Failed to map event base\n");
+ return 1;
+ }
+ source_base = ioremap(source, SZ_64);
+ if (!source_base) {
+ pr_err("Failed to map source base\n");
+ return 1;
+ }
+ return 0;
+}
+
+static void __init msm7x01_timer_init(void)
+{
+ struct clocksource *cs = &msm_clocksource;
+
+ if (msm_timer_map(0xc0100000, 0xc0100010))
+ return;
+ cs->read = msm_read_timer_count_shift;
+ cs->mask = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT));
+ /* 600 KHz */
+ msm_timer_init(19200000 >> MSM_DGT_SHIFT, 32 - MSM_DGT_SHIFT, 7,
+ false);
+}
+
+struct sys_timer msm7x01_timer = {
+ .init = msm7x01_timer_init
+};
+
+static void __init msm7x30_timer_init(void)
+{
+ if (msm_timer_map(0xc0100004, 0xc0100024))
+ return;
+ msm_timer_init(24576000 / 4, 32, 1, false);
+}
+
+struct sys_timer msm7x30_timer = {
+ .init = msm7x30_timer_init
+};
+
+static void __init qsd8x50_timer_init(void)
+{
+ if (msm_timer_map(0xAC100000, 0xAC100010))
+ return;
+ msm_timer_init(19200000 / 4, 32, 7, false);
+}
+
+struct sys_timer qsd8x50_timer = {
+ .init = qsd8x50_timer_init
};