From: Jeff Ohlstein <johlstei@codeaurora.org>
To: Russell King <linux@arm.linux.org.uk>
Cc: linux-arm-msm@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org,
Daniel Walker <dwalker@codeaurora.org>,
Jeff Ohlstein <johlstei@codeaurora.org>,
David Brown <davidb@codeaurora.org>,
Bryan Huntsman <bryanh@codeaurora.org>,
Stepan Moskovchenko <stepanm@codeaurora.org>,
Gregory Bean <gbean@codeaurora.org>,
Steve Muckle <smuckle@codeaurora.org>
Subject: [PATCH 08/24] msm: timer: support 8x60 timers
Date: Tue, 24 Aug 2010 21:57:37 -0700 [thread overview]
Message-ID: <1282712273-344-9-git-send-email-johlstei@codeaurora.org> (raw)
In-Reply-To: <1282712273-344-1-git-send-email-johlstei@codeaurora.org>
Signed-off-by: Jeff Ohlstein <johlstei@codeaurora.org>
---
arch/arm/mach-msm/include/mach/msm_iomap-8x60.h | 10 +-
arch/arm/mach-msm/timer.c | 226 +++++++++++++++++------
2 files changed, 177 insertions(+), 59 deletions(-)
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h b/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
index ee58da5..1f15bbb 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
@@ -35,7 +35,6 @@
*
*/
-
#define MSM_QGIC_DIST_BASE IOMEM(0xF0000000)
#define MSM_QGIC_DIST_PHYS 0x02080000
#define MSM_QGIC_DIST_SIZE SZ_4K
@@ -56,7 +55,14 @@
#define MSM_TLMM_PHYS 0x00800000
#define MSM_TLMM_SIZE SZ_16K
-#define MSM_SHARED_RAM_BASE IOMEM(0xF0100000)
+#define MSM_TMR_BASE IOMEM(0xF0100000)
+#define MSM_TMR_PHYS 0x02000000
+#define MSM_TMR_SIZE (SZ_1M)
+
+#define MSM_GPT_BASE (MSM_TMR_BASE + 0x4)
+#define MSM_DGT_BASE (MSM_TMR_BASE + 0x24)
+
+#define MSM_SHARED_RAM_BASE IOMEM(0xF0200000)
#define MSM_SHARED_RAM_SIZE SZ_1M
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index dec5ca6..e76d869 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -1,6 +1,6 @@
-/* linux/arch/arm/mach-msm/timer.c
- *
+/*
* Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2009-2010, Code Aurora Forum. 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
@@ -21,6 +21,7 @@
#include <linux/clockchips.h>
#include <linux/delay.h>
#include <linux/io.h>
+#include <linux/percpu.h>
#include <asm/mach/time.h>
#include <mach/msm_iomap.h>
@@ -28,7 +29,20 @@
#ifndef MSM_DGT_BASE
#define MSM_DGT_BASE (MSM_GPT_BASE + 0x10)
#endif
+
+#ifdef CONFIG_MSM7X00A_USE_GP_TIMER
+ #define DG_TIMER_RATING 100
+ #define MSM_GLOBAL_TIMER MSM_CLOCK_GPT
+#else
+ #define DG_TIMER_RATING 300
+ #define MSM_GLOBAL_TIMER MSM_CLOCK_DGT
+#endif
+
+#if defined(CONFIG_ARCH_MSM_ARM11)
#define MSM_DGT_SHIFT (5)
+#else
+#define MSM_DGT_SHIFT (0)
+#endif
#define TIMER_MATCH_VAL 0x0000
#define TIMER_COUNT_VAL 0x0004
@@ -40,8 +54,32 @@
#define CSR_PROTECTION 0x0020
#define CSR_PROTECTION_EN 1
+#define LOCAL_TIMER 0
+#define GLOBAL_TIMER 1
+
+#ifdef CONFIG_ARCH_MSM8X60
+#define MSM_TMR_BASE_CPU0 0x40000
+#else
+#define MSM_TMR_BASE_CPU0 0
+#endif
+
+#define NR_TIMERS ARRAY_SIZE(msm_clocks)
+
#define GPT_HZ 32768
-#define DGT_HZ 19200000 /* 19.2 MHz or 600 KHz after shift */
+
+#if defined(CONFIG_ARCH_QSD8X50) || defined(CONFIG_ARCH_MSM8X60)
+#define DGT_HZ 4800000 /* Uses TCXO/4 (19.2 MHz / 4) */
+#else
+#define DGT_HZ 19200000 /* Uses TCXO (19.2 MHz) */
+#endif
+
+static irqreturn_t msm_timer_interrupt(int irq, void *dev_id);
+static cycle_t msm_gpt_read(struct clocksource *cs);
+static cycle_t msm_dgt_read(struct clocksource *cs);
+static void msm_timer_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt);
+static int msm_timer_set_next_event(unsigned long cycles,
+ struct clock_event_device *evt);
struct msm_clock {
struct clock_event_device clockevent;
@@ -52,60 +90,10 @@ struct msm_clock {
uint32_t shift;
};
-static irqreturn_t msm_timer_interrupt(int irq, void *dev_id)
-{
- struct clock_event_device *evt = dev_id;
- evt->event_handler(evt);
- return IRQ_HANDLED;
-}
-
-static cycle_t msm_gpt_read(struct clocksource *cs)
-{
- return readl(MSM_GPT_BASE + TIMER_COUNT_VAL);
-}
-
-static cycle_t msm_dgt_read(struct clocksource *cs)
-{
- return readl(MSM_DGT_BASE + TIMER_COUNT_VAL) >> MSM_DGT_SHIFT;
-}
-
-static int msm_timer_set_next_event(unsigned long cycles,
- struct clock_event_device *evt)
-{
- struct msm_clock *clock = container_of(evt, struct msm_clock, clockevent);
- uint32_t now = readl(clock->regbase + TIMER_COUNT_VAL);
- uint32_t alarm = now + (cycles << clock->shift);
- int late;
-
- writel(alarm, clock->regbase + TIMER_MATCH_VAL);
- now = readl(clock->regbase + TIMER_COUNT_VAL);
- late = now - alarm;
- if (late >= (-2 << clock->shift) && late < DGT_HZ*5) {
- printk(KERN_NOTICE "msm_timer_set_next_event(%lu) clock %s, "
- "alarm already expired, now %x, alarm %x, late %d\n",
- cycles, clock->clockevent.name, now, alarm, late);
- return -ETIME;
- }
- return 0;
-}
-
-static void msm_timer_set_mode(enum clock_event_mode mode,
- struct clock_event_device *evt)
-{
- struct msm_clock *clock = container_of(evt, struct msm_clock, clockevent);
- switch (mode) {
- case CLOCK_EVT_MODE_RESUME:
- case CLOCK_EVT_MODE_PERIODIC:
- break;
- case CLOCK_EVT_MODE_ONESHOT:
- writel(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE);
- break;
- case CLOCK_EVT_MODE_UNUSED:
- case CLOCK_EVT_MODE_SHUTDOWN:
- writel(0, clock->regbase + TIMER_ENABLE);
- break;
- }
-}
+enum {
+ MSM_CLOCK_GPT,
+ MSM_CLOCK_DGT,
+};
static struct msm_clock msm_clocks[] = {
{
@@ -165,6 +153,89 @@ static struct msm_clock msm_clocks[] = {
}
};
+static struct clock_event_device *local_clock_event;
+
+static irqreturn_t msm_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = dev_id;
+ if (smp_processor_id() != 0)
+ evt = local_clock_event;
+ if (evt->event_handler == NULL)
+ return IRQ_HANDLED;
+ evt->event_handler(evt);
+ return IRQ_HANDLED;
+}
+
+static cycle_t msm_gpt_read(struct clocksource *cs)
+{
+ struct msm_clock *clock =
+ container_of(cs, struct msm_clock, clocksource);
+ return readl(clock->regbase + TIMER_COUNT_VAL + MSM_TMR_BASE_CPU0);
+}
+
+static cycle_t msm_dgt_read(struct clocksource *cs)
+{
+ struct msm_clock *clock =
+ container_of(cs, struct msm_clock, clocksource);
+ return readl(clock->regbase + TIMER_COUNT_VAL + MSM_TMR_BASE_CPU0)
+ >> MSM_DGT_SHIFT;
+}
+
+static int msm_timer_set_next_event(unsigned long cycles,
+ struct clock_event_device *evt)
+{
+ struct msm_clock *clock;
+ uint32_t now;
+ uint32_t alarm;
+ int late;
+
+#ifdef CONFIG_SMP
+ clock = &msm_clocks[MSM_GLOBAL_TIMER];
+#else
+ clock = container_of(evt, struct msm_clock, clockevent);
+#endif
+ now = readl(clock->regbase + TIMER_COUNT_VAL);
+ alarm = now + (cycles << clock->shift);
+ writel(alarm, clock->regbase + TIMER_MATCH_VAL);
+ late = now - alarm;
+ if (late >= (-2 << clock->shift) && late < DGT_HZ*5) {
+ printk(KERN_NOTICE "msm_timer_set_next_event(%lu) clock %s, "
+ "alarm already expired, now %x, alarm %x, late %d\n",
+ cycles, clock->clockevent.name, now, alarm, late);
+ return -ETIME;
+ }
+ return 0;
+}
+
+static void msm_timer_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ struct msm_clock *clock;
+ unsigned long irq_flags;
+
+#ifdef CONFIG_SMP
+ clock = &msm_clocks[MSM_GLOBAL_TIMER];
+#else
+ clock = container_of(evt, struct msm_clock, clockevent);
+#endif
+ local_irq_save(irq_flags);
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_RESUME:
+ case CLOCK_EVT_MODE_PERIODIC:
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ writel(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE);
+ break;
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ writel(0, clock->regbase + TIMER_ENABLE);
+ break;
+ }
+
+ local_irq_restore(irq_flags);
+}
+
static void __init msm_timer_init(void)
{
int i;
@@ -201,6 +272,47 @@ static void __init msm_timer_init(void)
}
}
+#ifdef CONFIG_SMP
+void local_timer_setup(struct clock_event_device *evt)
+{
+ unsigned long flags;
+ struct msm_clock *clock = &msm_clocks[MSM_GLOBAL_TIMER];
+
+ if (!local_clock_event) {
+ writel(0, clock->regbase + TIMER_ENABLE);
+ writel(1, clock->regbase + TIMER_CLEAR);
+ writel(0, clock->regbase + TIMER_COUNT_VAL);
+ writel(~0, clock->regbase + TIMER_MATCH_VAL);
+ }
+ evt->irq = clock->irq.irq;
+ evt->name = "local_timer";
+ evt->features = CLOCK_EVT_FEAT_ONESHOT;
+ evt->rating = clock->clockevent.rating;
+ evt->set_mode = msm_timer_set_mode;
+ evt->set_next_event = msm_timer_set_next_event;
+ evt->shift = clock->clockevent.shift;
+ evt->mult = div_sc(clock->freq, NSEC_PER_SEC, evt->shift);
+ evt->max_delta_ns =
+ clockevent_delta2ns(0xf0000000 >> clock->shift, evt);
+ evt->min_delta_ns = clockevent_delta2ns(4, evt);
+ evt->cpumask = cpumask_of(smp_processor_id());
+
+ local_clock_event = evt;
+
+ local_irq_save(flags);
+ get_irq_chip(clock->irq.irq)->unmask(clock->irq.irq);
+ local_irq_restore(flags);
+
+ clockevents_register_device(evt);
+}
+
+int local_timer_ack(void)
+{
+ return 1;
+}
+
+#endif
+
struct sys_timer msm_timer = {
.init = msm_timer_init
};
--
1.7.2.1
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
WARNING: multiple messages have this Message-ID (diff)
From: johlstei@codeaurora.org (Jeff Ohlstein)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH 08/24] msm: timer: support 8x60 timers
Date: Tue, 24 Aug 2010 21:57:37 -0700 [thread overview]
Message-ID: <1282712273-344-9-git-send-email-johlstei@codeaurora.org> (raw)
In-Reply-To: <1282712273-344-1-git-send-email-johlstei@codeaurora.org>
Signed-off-by: Jeff Ohlstein <johlstei@codeaurora.org>
---
arch/arm/mach-msm/include/mach/msm_iomap-8x60.h | 10 +-
arch/arm/mach-msm/timer.c | 226 +++++++++++++++++------
2 files changed, 177 insertions(+), 59 deletions(-)
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h b/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
index ee58da5..1f15bbb 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
@@ -35,7 +35,6 @@
*
*/
-
#define MSM_QGIC_DIST_BASE IOMEM(0xF0000000)
#define MSM_QGIC_DIST_PHYS 0x02080000
#define MSM_QGIC_DIST_SIZE SZ_4K
@@ -56,7 +55,14 @@
#define MSM_TLMM_PHYS 0x00800000
#define MSM_TLMM_SIZE SZ_16K
-#define MSM_SHARED_RAM_BASE IOMEM(0xF0100000)
+#define MSM_TMR_BASE IOMEM(0xF0100000)
+#define MSM_TMR_PHYS 0x02000000
+#define MSM_TMR_SIZE (SZ_1M)
+
+#define MSM_GPT_BASE (MSM_TMR_BASE + 0x4)
+#define MSM_DGT_BASE (MSM_TMR_BASE + 0x24)
+
+#define MSM_SHARED_RAM_BASE IOMEM(0xF0200000)
#define MSM_SHARED_RAM_SIZE SZ_1M
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index dec5ca6..e76d869 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -1,6 +1,6 @@
-/* linux/arch/arm/mach-msm/timer.c
- *
+/*
* Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2009-2010, Code Aurora Forum. 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
@@ -21,6 +21,7 @@
#include <linux/clockchips.h>
#include <linux/delay.h>
#include <linux/io.h>
+#include <linux/percpu.h>
#include <asm/mach/time.h>
#include <mach/msm_iomap.h>
@@ -28,7 +29,20 @@
#ifndef MSM_DGT_BASE
#define MSM_DGT_BASE (MSM_GPT_BASE + 0x10)
#endif
+
+#ifdef CONFIG_MSM7X00A_USE_GP_TIMER
+ #define DG_TIMER_RATING 100
+ #define MSM_GLOBAL_TIMER MSM_CLOCK_GPT
+#else
+ #define DG_TIMER_RATING 300
+ #define MSM_GLOBAL_TIMER MSM_CLOCK_DGT
+#endif
+
+#if defined(CONFIG_ARCH_MSM_ARM11)
#define MSM_DGT_SHIFT (5)
+#else
+#define MSM_DGT_SHIFT (0)
+#endif
#define TIMER_MATCH_VAL 0x0000
#define TIMER_COUNT_VAL 0x0004
@@ -40,8 +54,32 @@
#define CSR_PROTECTION 0x0020
#define CSR_PROTECTION_EN 1
+#define LOCAL_TIMER 0
+#define GLOBAL_TIMER 1
+
+#ifdef CONFIG_ARCH_MSM8X60
+#define MSM_TMR_BASE_CPU0 0x40000
+#else
+#define MSM_TMR_BASE_CPU0 0
+#endif
+
+#define NR_TIMERS ARRAY_SIZE(msm_clocks)
+
#define GPT_HZ 32768
-#define DGT_HZ 19200000 /* 19.2 MHz or 600 KHz after shift */
+
+#if defined(CONFIG_ARCH_QSD8X50) || defined(CONFIG_ARCH_MSM8X60)
+#define DGT_HZ 4800000 /* Uses TCXO/4 (19.2 MHz / 4) */
+#else
+#define DGT_HZ 19200000 /* Uses TCXO (19.2 MHz) */
+#endif
+
+static irqreturn_t msm_timer_interrupt(int irq, void *dev_id);
+static cycle_t msm_gpt_read(struct clocksource *cs);
+static cycle_t msm_dgt_read(struct clocksource *cs);
+static void msm_timer_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt);
+static int msm_timer_set_next_event(unsigned long cycles,
+ struct clock_event_device *evt);
struct msm_clock {
struct clock_event_device clockevent;
@@ -52,60 +90,10 @@ struct msm_clock {
uint32_t shift;
};
-static irqreturn_t msm_timer_interrupt(int irq, void *dev_id)
-{
- struct clock_event_device *evt = dev_id;
- evt->event_handler(evt);
- return IRQ_HANDLED;
-}
-
-static cycle_t msm_gpt_read(struct clocksource *cs)
-{
- return readl(MSM_GPT_BASE + TIMER_COUNT_VAL);
-}
-
-static cycle_t msm_dgt_read(struct clocksource *cs)
-{
- return readl(MSM_DGT_BASE + TIMER_COUNT_VAL) >> MSM_DGT_SHIFT;
-}
-
-static int msm_timer_set_next_event(unsigned long cycles,
- struct clock_event_device *evt)
-{
- struct msm_clock *clock = container_of(evt, struct msm_clock, clockevent);
- uint32_t now = readl(clock->regbase + TIMER_COUNT_VAL);
- uint32_t alarm = now + (cycles << clock->shift);
- int late;
-
- writel(alarm, clock->regbase + TIMER_MATCH_VAL);
- now = readl(clock->regbase + TIMER_COUNT_VAL);
- late = now - alarm;
- if (late >= (-2 << clock->shift) && late < DGT_HZ*5) {
- printk(KERN_NOTICE "msm_timer_set_next_event(%lu) clock %s, "
- "alarm already expired, now %x, alarm %x, late %d\n",
- cycles, clock->clockevent.name, now, alarm, late);
- return -ETIME;
- }
- return 0;
-}
-
-static void msm_timer_set_mode(enum clock_event_mode mode,
- struct clock_event_device *evt)
-{
- struct msm_clock *clock = container_of(evt, struct msm_clock, clockevent);
- switch (mode) {
- case CLOCK_EVT_MODE_RESUME:
- case CLOCK_EVT_MODE_PERIODIC:
- break;
- case CLOCK_EVT_MODE_ONESHOT:
- writel(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE);
- break;
- case CLOCK_EVT_MODE_UNUSED:
- case CLOCK_EVT_MODE_SHUTDOWN:
- writel(0, clock->regbase + TIMER_ENABLE);
- break;
- }
-}
+enum {
+ MSM_CLOCK_GPT,
+ MSM_CLOCK_DGT,
+};
static struct msm_clock msm_clocks[] = {
{
@@ -165,6 +153,89 @@ static struct msm_clock msm_clocks[] = {
}
};
+static struct clock_event_device *local_clock_event;
+
+static irqreturn_t msm_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = dev_id;
+ if (smp_processor_id() != 0)
+ evt = local_clock_event;
+ if (evt->event_handler == NULL)
+ return IRQ_HANDLED;
+ evt->event_handler(evt);
+ return IRQ_HANDLED;
+}
+
+static cycle_t msm_gpt_read(struct clocksource *cs)
+{
+ struct msm_clock *clock =
+ container_of(cs, struct msm_clock, clocksource);
+ return readl(clock->regbase + TIMER_COUNT_VAL + MSM_TMR_BASE_CPU0);
+}
+
+static cycle_t msm_dgt_read(struct clocksource *cs)
+{
+ struct msm_clock *clock =
+ container_of(cs, struct msm_clock, clocksource);
+ return readl(clock->regbase + TIMER_COUNT_VAL + MSM_TMR_BASE_CPU0)
+ >> MSM_DGT_SHIFT;
+}
+
+static int msm_timer_set_next_event(unsigned long cycles,
+ struct clock_event_device *evt)
+{
+ struct msm_clock *clock;
+ uint32_t now;
+ uint32_t alarm;
+ int late;
+
+#ifdef CONFIG_SMP
+ clock = &msm_clocks[MSM_GLOBAL_TIMER];
+#else
+ clock = container_of(evt, struct msm_clock, clockevent);
+#endif
+ now = readl(clock->regbase + TIMER_COUNT_VAL);
+ alarm = now + (cycles << clock->shift);
+ writel(alarm, clock->regbase + TIMER_MATCH_VAL);
+ late = now - alarm;
+ if (late >= (-2 << clock->shift) && late < DGT_HZ*5) {
+ printk(KERN_NOTICE "msm_timer_set_next_event(%lu) clock %s, "
+ "alarm already expired, now %x, alarm %x, late %d\n",
+ cycles, clock->clockevent.name, now, alarm, late);
+ return -ETIME;
+ }
+ return 0;
+}
+
+static void msm_timer_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ struct msm_clock *clock;
+ unsigned long irq_flags;
+
+#ifdef CONFIG_SMP
+ clock = &msm_clocks[MSM_GLOBAL_TIMER];
+#else
+ clock = container_of(evt, struct msm_clock, clockevent);
+#endif
+ local_irq_save(irq_flags);
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_RESUME:
+ case CLOCK_EVT_MODE_PERIODIC:
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ writel(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE);
+ break;
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ writel(0, clock->regbase + TIMER_ENABLE);
+ break;
+ }
+
+ local_irq_restore(irq_flags);
+}
+
static void __init msm_timer_init(void)
{
int i;
@@ -201,6 +272,47 @@ static void __init msm_timer_init(void)
}
}
+#ifdef CONFIG_SMP
+void local_timer_setup(struct clock_event_device *evt)
+{
+ unsigned long flags;
+ struct msm_clock *clock = &msm_clocks[MSM_GLOBAL_TIMER];
+
+ if (!local_clock_event) {
+ writel(0, clock->regbase + TIMER_ENABLE);
+ writel(1, clock->regbase + TIMER_CLEAR);
+ writel(0, clock->regbase + TIMER_COUNT_VAL);
+ writel(~0, clock->regbase + TIMER_MATCH_VAL);
+ }
+ evt->irq = clock->irq.irq;
+ evt->name = "local_timer";
+ evt->features = CLOCK_EVT_FEAT_ONESHOT;
+ evt->rating = clock->clockevent.rating;
+ evt->set_mode = msm_timer_set_mode;
+ evt->set_next_event = msm_timer_set_next_event;
+ evt->shift = clock->clockevent.shift;
+ evt->mult = div_sc(clock->freq, NSEC_PER_SEC, evt->shift);
+ evt->max_delta_ns =
+ clockevent_delta2ns(0xf0000000 >> clock->shift, evt);
+ evt->min_delta_ns = clockevent_delta2ns(4, evt);
+ evt->cpumask = cpumask_of(smp_processor_id());
+
+ local_clock_event = evt;
+
+ local_irq_save(flags);
+ get_irq_chip(clock->irq.irq)->unmask(clock->irq.irq);
+ local_irq_restore(flags);
+
+ clockevents_register_device(evt);
+}
+
+int local_timer_ack(void)
+{
+ return 1;
+}
+
+#endif
+
struct sys_timer msm_timer = {
.init = msm_timer_init
};
--
1.7.2.1
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
WARNING: multiple messages have this Message-ID (diff)
From: Jeff Ohlstein <johlstei@codeaurora.org>
To: Russell King <linux@arm.linux.org.uk>
Cc: linux-arm-msm@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org,
Daniel Walker <dwalker@codeaurora.org>,
Jeff Ohlstein <johlstei@codeaurora.org>,
David Brown <davidb@codeaurora.org>,
Bryan Huntsman <bryanh@codeaurora.org>,
Russell King <linux@arm.linux.org.uk>,
Stepan Moskovchenko <stepanm@codeaurora.org>,
Gregory Bean <gbean@codeaurora.org>,
Steve Muckle <smuckle@codeaurora.org>
Subject: [PATCH 08/24] msm: timer: support 8x60 timers
Date: Tue, 24 Aug 2010 21:57:37 -0700 [thread overview]
Message-ID: <1282712273-344-9-git-send-email-johlstei@codeaurora.org> (raw)
In-Reply-To: <1282712273-344-1-git-send-email-johlstei@codeaurora.org>
Signed-off-by: Jeff Ohlstein <johlstei@codeaurora.org>
---
arch/arm/mach-msm/include/mach/msm_iomap-8x60.h | 10 +-
arch/arm/mach-msm/timer.c | 226 +++++++++++++++++------
2 files changed, 177 insertions(+), 59 deletions(-)
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h b/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
index ee58da5..1f15bbb 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
@@ -35,7 +35,6 @@
*
*/
-
#define MSM_QGIC_DIST_BASE IOMEM(0xF0000000)
#define MSM_QGIC_DIST_PHYS 0x02080000
#define MSM_QGIC_DIST_SIZE SZ_4K
@@ -56,7 +55,14 @@
#define MSM_TLMM_PHYS 0x00800000
#define MSM_TLMM_SIZE SZ_16K
-#define MSM_SHARED_RAM_BASE IOMEM(0xF0100000)
+#define MSM_TMR_BASE IOMEM(0xF0100000)
+#define MSM_TMR_PHYS 0x02000000
+#define MSM_TMR_SIZE (SZ_1M)
+
+#define MSM_GPT_BASE (MSM_TMR_BASE + 0x4)
+#define MSM_DGT_BASE (MSM_TMR_BASE + 0x24)
+
+#define MSM_SHARED_RAM_BASE IOMEM(0xF0200000)
#define MSM_SHARED_RAM_SIZE SZ_1M
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index dec5ca6..e76d869 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -1,6 +1,6 @@
-/* linux/arch/arm/mach-msm/timer.c
- *
+/*
* Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2009-2010, Code Aurora Forum. 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
@@ -21,6 +21,7 @@
#include <linux/clockchips.h>
#include <linux/delay.h>
#include <linux/io.h>
+#include <linux/percpu.h>
#include <asm/mach/time.h>
#include <mach/msm_iomap.h>
@@ -28,7 +29,20 @@
#ifndef MSM_DGT_BASE
#define MSM_DGT_BASE (MSM_GPT_BASE + 0x10)
#endif
+
+#ifdef CONFIG_MSM7X00A_USE_GP_TIMER
+ #define DG_TIMER_RATING 100
+ #define MSM_GLOBAL_TIMER MSM_CLOCK_GPT
+#else
+ #define DG_TIMER_RATING 300
+ #define MSM_GLOBAL_TIMER MSM_CLOCK_DGT
+#endif
+
+#if defined(CONFIG_ARCH_MSM_ARM11)
#define MSM_DGT_SHIFT (5)
+#else
+#define MSM_DGT_SHIFT (0)
+#endif
#define TIMER_MATCH_VAL 0x0000
#define TIMER_COUNT_VAL 0x0004
@@ -40,8 +54,32 @@
#define CSR_PROTECTION 0x0020
#define CSR_PROTECTION_EN 1
+#define LOCAL_TIMER 0
+#define GLOBAL_TIMER 1
+
+#ifdef CONFIG_ARCH_MSM8X60
+#define MSM_TMR_BASE_CPU0 0x40000
+#else
+#define MSM_TMR_BASE_CPU0 0
+#endif
+
+#define NR_TIMERS ARRAY_SIZE(msm_clocks)
+
#define GPT_HZ 32768
-#define DGT_HZ 19200000 /* 19.2 MHz or 600 KHz after shift */
+
+#if defined(CONFIG_ARCH_QSD8X50) || defined(CONFIG_ARCH_MSM8X60)
+#define DGT_HZ 4800000 /* Uses TCXO/4 (19.2 MHz / 4) */
+#else
+#define DGT_HZ 19200000 /* Uses TCXO (19.2 MHz) */
+#endif
+
+static irqreturn_t msm_timer_interrupt(int irq, void *dev_id);
+static cycle_t msm_gpt_read(struct clocksource *cs);
+static cycle_t msm_dgt_read(struct clocksource *cs);
+static void msm_timer_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt);
+static int msm_timer_set_next_event(unsigned long cycles,
+ struct clock_event_device *evt);
struct msm_clock {
struct clock_event_device clockevent;
@@ -52,60 +90,10 @@ struct msm_clock {
uint32_t shift;
};
-static irqreturn_t msm_timer_interrupt(int irq, void *dev_id)
-{
- struct clock_event_device *evt = dev_id;
- evt->event_handler(evt);
- return IRQ_HANDLED;
-}
-
-static cycle_t msm_gpt_read(struct clocksource *cs)
-{
- return readl(MSM_GPT_BASE + TIMER_COUNT_VAL);
-}
-
-static cycle_t msm_dgt_read(struct clocksource *cs)
-{
- return readl(MSM_DGT_BASE + TIMER_COUNT_VAL) >> MSM_DGT_SHIFT;
-}
-
-static int msm_timer_set_next_event(unsigned long cycles,
- struct clock_event_device *evt)
-{
- struct msm_clock *clock = container_of(evt, struct msm_clock, clockevent);
- uint32_t now = readl(clock->regbase + TIMER_COUNT_VAL);
- uint32_t alarm = now + (cycles << clock->shift);
- int late;
-
- writel(alarm, clock->regbase + TIMER_MATCH_VAL);
- now = readl(clock->regbase + TIMER_COUNT_VAL);
- late = now - alarm;
- if (late >= (-2 << clock->shift) && late < DGT_HZ*5) {
- printk(KERN_NOTICE "msm_timer_set_next_event(%lu) clock %s, "
- "alarm already expired, now %x, alarm %x, late %d\n",
- cycles, clock->clockevent.name, now, alarm, late);
- return -ETIME;
- }
- return 0;
-}
-
-static void msm_timer_set_mode(enum clock_event_mode mode,
- struct clock_event_device *evt)
-{
- struct msm_clock *clock = container_of(evt, struct msm_clock, clockevent);
- switch (mode) {
- case CLOCK_EVT_MODE_RESUME:
- case CLOCK_EVT_MODE_PERIODIC:
- break;
- case CLOCK_EVT_MODE_ONESHOT:
- writel(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE);
- break;
- case CLOCK_EVT_MODE_UNUSED:
- case CLOCK_EVT_MODE_SHUTDOWN:
- writel(0, clock->regbase + TIMER_ENABLE);
- break;
- }
-}
+enum {
+ MSM_CLOCK_GPT,
+ MSM_CLOCK_DGT,
+};
static struct msm_clock msm_clocks[] = {
{
@@ -165,6 +153,89 @@ static struct msm_clock msm_clocks[] = {
}
};
+static struct clock_event_device *local_clock_event;
+
+static irqreturn_t msm_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = dev_id;
+ if (smp_processor_id() != 0)
+ evt = local_clock_event;
+ if (evt->event_handler == NULL)
+ return IRQ_HANDLED;
+ evt->event_handler(evt);
+ return IRQ_HANDLED;
+}
+
+static cycle_t msm_gpt_read(struct clocksource *cs)
+{
+ struct msm_clock *clock =
+ container_of(cs, struct msm_clock, clocksource);
+ return readl(clock->regbase + TIMER_COUNT_VAL + MSM_TMR_BASE_CPU0);
+}
+
+static cycle_t msm_dgt_read(struct clocksource *cs)
+{
+ struct msm_clock *clock =
+ container_of(cs, struct msm_clock, clocksource);
+ return readl(clock->regbase + TIMER_COUNT_VAL + MSM_TMR_BASE_CPU0)
+ >> MSM_DGT_SHIFT;
+}
+
+static int msm_timer_set_next_event(unsigned long cycles,
+ struct clock_event_device *evt)
+{
+ struct msm_clock *clock;
+ uint32_t now;
+ uint32_t alarm;
+ int late;
+
+#ifdef CONFIG_SMP
+ clock = &msm_clocks[MSM_GLOBAL_TIMER];
+#else
+ clock = container_of(evt, struct msm_clock, clockevent);
+#endif
+ now = readl(clock->regbase + TIMER_COUNT_VAL);
+ alarm = now + (cycles << clock->shift);
+ writel(alarm, clock->regbase + TIMER_MATCH_VAL);
+ late = now - alarm;
+ if (late >= (-2 << clock->shift) && late < DGT_HZ*5) {
+ printk(KERN_NOTICE "msm_timer_set_next_event(%lu) clock %s, "
+ "alarm already expired, now %x, alarm %x, late %d\n",
+ cycles, clock->clockevent.name, now, alarm, late);
+ return -ETIME;
+ }
+ return 0;
+}
+
+static void msm_timer_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ struct msm_clock *clock;
+ unsigned long irq_flags;
+
+#ifdef CONFIG_SMP
+ clock = &msm_clocks[MSM_GLOBAL_TIMER];
+#else
+ clock = container_of(evt, struct msm_clock, clockevent);
+#endif
+ local_irq_save(irq_flags);
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_RESUME:
+ case CLOCK_EVT_MODE_PERIODIC:
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ writel(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE);
+ break;
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ writel(0, clock->regbase + TIMER_ENABLE);
+ break;
+ }
+
+ local_irq_restore(irq_flags);
+}
+
static void __init msm_timer_init(void)
{
int i;
@@ -201,6 +272,47 @@ static void __init msm_timer_init(void)
}
}
+#ifdef CONFIG_SMP
+void local_timer_setup(struct clock_event_device *evt)
+{
+ unsigned long flags;
+ struct msm_clock *clock = &msm_clocks[MSM_GLOBAL_TIMER];
+
+ if (!local_clock_event) {
+ writel(0, clock->regbase + TIMER_ENABLE);
+ writel(1, clock->regbase + TIMER_CLEAR);
+ writel(0, clock->regbase + TIMER_COUNT_VAL);
+ writel(~0, clock->regbase + TIMER_MATCH_VAL);
+ }
+ evt->irq = clock->irq.irq;
+ evt->name = "local_timer";
+ evt->features = CLOCK_EVT_FEAT_ONESHOT;
+ evt->rating = clock->clockevent.rating;
+ evt->set_mode = msm_timer_set_mode;
+ evt->set_next_event = msm_timer_set_next_event;
+ evt->shift = clock->clockevent.shift;
+ evt->mult = div_sc(clock->freq, NSEC_PER_SEC, evt->shift);
+ evt->max_delta_ns =
+ clockevent_delta2ns(0xf0000000 >> clock->shift, evt);
+ evt->min_delta_ns = clockevent_delta2ns(4, evt);
+ evt->cpumask = cpumask_of(smp_processor_id());
+
+ local_clock_event = evt;
+
+ local_irq_save(flags);
+ get_irq_chip(clock->irq.irq)->unmask(clock->irq.irq);
+ local_irq_restore(flags);
+
+ clockevents_register_device(evt);
+}
+
+int local_timer_ack(void)
+{
+ return 1;
+}
+
+#endif
+
struct sys_timer msm_timer = {
.init = msm_timer_init
};
--
1.7.2.1
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
next prev parent reply other threads:[~2010-08-25 4:58 UTC|newest]
Thread overview: 124+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-08-25 4:57 [PATCH 00/24] Support for Qualcomm msm8660 target Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` [PATCH 01/24] msm: create config option for proc-comm Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` [PATCH 02/24] arm: Kconfig option for ARCH_MSM_SCORPIONMP Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` [PATCH 03/24] arm: mm: add proc info for ScorpionMP Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-27 13:54 ` Catalin Marinas
2010-08-27 13:54 ` Catalin Marinas
2010-08-27 15:29 ` Daniel Walker
2010-08-27 15:29 ` Daniel Walker
2010-08-27 16:04 ` Catalin Marinas
2010-08-27 16:04 ` Catalin Marinas
2010-08-27 16:33 ` Daniel Walker
2010-08-27 16:33 ` Daniel Walker
2010-08-27 16:49 ` Catalin Marinas
2010-08-27 16:49 ` Catalin Marinas
2010-08-27 19:53 ` Daniel Walker
2010-08-27 19:53 ` Daniel Walker
2010-08-31 12:18 ` Catalin Marinas
2010-08-31 12:18 ` Catalin Marinas
2010-08-31 16:44 ` Daniel Walker
2010-08-31 16:44 ` Daniel Walker
2010-09-01 5:56 ` Shilimkar, Santosh
2010-09-01 5:56 ` Shilimkar, Santosh
2010-09-04 14:32 ` Russell King - ARM Linux
2010-09-04 14:32 ` Russell King - ARM Linux
2010-09-06 22:22 ` Daniel Walker
2010-09-06 22:22 ` Daniel Walker
2010-09-04 14:31 ` Russell King - ARM Linux
2010-09-04 14:31 ` Russell King - ARM Linux
2010-08-25 4:57 ` [PATCH 04/24] GIC: Dont disable INT in ack callback Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` [PATCH 05/24] msm: io: MSM8X60 io support Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` [PATCH 06/24] msm: initial irq definitions for MSM8X60 Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` [PATCH 07/24] msm: irqs-8x60: interrupt map Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein [this message]
2010-08-25 4:57 ` [PATCH 08/24] msm: timer: support 8x60 timers Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` [PATCH 09/24] msm: MSM8X60 RUMI3 board support Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-09-02 11:08 ` Russell King - ARM Linux
2010-09-02 11:08 ` Russell King - ARM Linux
2010-09-09 3:15 ` Jeff Ohlstein
2010-09-09 3:15 ` Jeff Ohlstein
2010-08-25 4:57 ` [PATCH 10/24] msm: irq: rename existing entry-macro to entry-macro-vic Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-09-02 11:10 ` Russell King - ARM Linux
2010-09-02 11:10 ` Russell King - ARM Linux
2010-08-25 4:57 ` [PATCH 11/24] msm: 8x60: gic initialization fixup for RUMI Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` [PATCH 12/24] msm: clock: add dummy clock driver Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` [PATCH 13/24] dma: add stub functions for dma features not yet present on 8x60 Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` [PATCH 14/24] msm: add hotplug stub functions Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-09-02 11:11 ` Russell King - ARM Linux
2010-09-02 11:11 ` Russell King - ARM Linux
2010-09-02 16:49 ` Daniel Walker
2010-09-02 16:49 ` Daniel Walker
2010-09-02 17:12 ` Russell King - ARM Linux
2010-09-02 17:12 ` Russell King - ARM Linux
2010-09-02 22:25 ` Daniel Walker
2010-09-02 22:25 ` Daniel Walker
2010-09-02 22:36 ` Daniel Walker
2010-09-02 22:36 ` Daniel Walker
2010-09-03 7:31 ` Russell King - ARM Linux
2010-09-03 7:31 ` Russell King - ARM Linux
2010-09-03 16:23 ` Daniel Walker
2010-09-03 16:23 ` Daniel Walker
2010-08-25 4:57 ` [PATCH 15/24] msm: allow uart to be conditionally disabled Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` [PATCH 16/24] msm: add build support for msm8x60 target Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` [PATCH 17/24] msm: 8x60: setup correct handlers for private interrupts Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` [PATCH 18/24] msm: physical offset for MSM8X60 Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` [PATCH 19/24] msm: add msm8x60_surf machine Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` [PATCH 20/24] msm: MSM8X60 simulator board support Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-09-02 11:13 ` Russell King - ARM Linux
2010-09-02 11:13 ` Russell King - ARM Linux
2010-09-02 18:19 ` David Brown
2010-09-02 18:19 ` David Brown
2010-09-02 18:52 ` Russell King - ARM Linux
2010-09-02 18:52 ` Russell King - ARM Linux
2010-08-25 4:57 ` [PATCH 21/24] msm: add MSM8x60 FFA support Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` [PATCH 22/24] msm: Add MSM IOMMU support Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` [PATCH 23/24] msm: Platform initialization for the IOMMU driver Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` [PATCH 24/24] msm: Platform data for msm8x60 IOMMUs Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
2010-08-25 4:57 ` Jeff Ohlstein
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1282712273-344-9-git-send-email-johlstei@codeaurora.org \
--to=johlstei@codeaurora.org \
--cc=bryanh@codeaurora.org \
--cc=davidb@codeaurora.org \
--cc=dwalker@codeaurora.org \
--cc=gbean@codeaurora.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux@arm.linux.org.uk \
--cc=smuckle@codeaurora.org \
--cc=stepanm@codeaurora.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.