From: Jeff Ohlstein <johlstei@codeaurora.org>
To: Daniel Walker <dwalker@codeaurora.org>,
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,
"Jeff Ohlstein" <johlstei@codeaurora.org>,
"Brian Swetland" <swetland@google.com>,
"Dima Zavin" <dima@android.com>,
"Arve Hj�nnev�g" <arve@android.com>,
"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 v2 4/6] msm: timer: SMP timer support for msm
Date: Tue, 7 Dec 2010 20:28:19 -0800 [thread overview]
Message-ID: <1291782501-3909-5-git-send-email-johlstei@codeaurora.org> (raw)
In-Reply-To: <1291782501-3909-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 | 6 +-
arch/arm/mach-msm/io.c | 1 +
arch/arm/mach-msm/timer.c | 130 +++++++++++++++++++----
3 files changed, 115 insertions(+), 22 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 45bab50..873e0b7 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
@@ -60,7 +60,11 @@
#define MSM_TMR_BASE IOMEM(0xF0200000)
#define MSM_TMR_PHYS 0x02000000
-#define MSM_TMR_SIZE (SZ_1M)
+#define MSM_TMR_SIZE SZ_4K
+
+#define MSM_TMR0_BASE IOMEM(0xF0201000)
+#define MSM_TMR0_PHYS 0x02040000
+#define MSM_TMR0_SIZE SZ_4K
#define MSM_GPT_BASE (MSM_TMR_BASE + 0x4)
#define MSM_DGT_BASE (MSM_TMR_BASE + 0x24)
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index d36b610..b826b6b 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -105,6 +105,7 @@ static struct map_desc msm8x60_io_desc[] __initdata = {
MSM_DEVICE(QGIC_DIST),
MSM_DEVICE(QGIC_CPU),
MSM_DEVICE(TMR),
+ MSM_DEVICE(TMR0),
MSM_DEVICE(ACC),
MSM_DEVICE(GCC),
};
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index 950100f..92ac220 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -47,6 +47,19 @@ enum {
#define GPT_HZ 32768
+enum timer_location {
+ LOCAL_TIMER = 0,
+ GLOBAL_TIMER = 1,
+};
+
+#ifdef MSM_TMR0_BASE
+#define MSM_TMR_GLOBAL (MSM_TMR0_BASE - MSM_TMR_BASE)
+#else
+#define MSM_TMR_GLOBAL 0
+#endif
+
+#define MSM_GLOBAL_TIMER MSM_CLOCK_DGT
+
#if defined(CONFIG_ARCH_QSD8X50)
#define DGT_HZ (19200000 / 4) /* 19.2 MHz / 4 by default */
#define MSM_DGT_SHIFT (0)
@@ -65,49 +78,67 @@ struct msm_clock {
void __iomem *regbase;
uint32_t freq;
uint32_t shift;
+ void *global_counter;
+ void *local_counter;
};
+enum {
+ MSM_CLOCK_GPT,
+ MSM_CLOCK_DGT,
+ NR_TIMERS,
+};
+
+
+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)
+static cycle_t msm_read_timer_count(struct clocksource *cs)
{
- return readl(MSM_GPT_BASE + TIMER_COUNT_VAL);
+ struct msm_clock *clk = container_of(cs, struct msm_clock, clocksource);
+
+ return readl(clk->global_counter) >> clk->shift;
}
-static cycle_t msm_dgt_read(struct clocksource *cs)
+static struct msm_clock *clockevent_to_clock(struct clock_event_device *evt)
{
- return readl(MSM_DGT_BASE + TIMER_COUNT_VAL) >> MSM_DGT_SHIFT;
+#ifdef CONFIG_SMP
+ int i;
+ for (i = 0; i < NR_TIMERS; i++)
+ if (evt == &(msm_clocks[i].clockevent))
+ return &msm_clocks[i];
+ return &msm_clocks[MSM_GLOBAL_TIMER];
+#else
+ return container_of(evt, struct msm_clock, clockevent);
+#endif
}
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);
+ struct msm_clock *clock = clockevent_to_clock(evt);
+ uint32_t now = readl(clock->local_counter);
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);
+ struct msm_clock *clock = clockevent_to_clock(evt);
+
switch (mode) {
case CLOCK_EVT_MODE_RESUME:
case CLOCK_EVT_MODE_PERIODIC:
@@ -135,7 +166,7 @@ static struct msm_clock msm_clocks[] = {
.clocksource = {
.name = "gp_timer",
.rating = 200,
- .read = msm_gpt_read,
+ .read = msm_read_timer_count,
.mask = CLOCKSOURCE_MASK(32),
.shift = 17,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
@@ -148,7 +179,10 @@ static struct msm_clock msm_clocks[] = {
.irq = INT_GP_TIMER_EXP
},
.regbase = MSM_GPT_BASE,
- .freq = GPT_HZ
+ .freq = GPT_HZ,
+ .local_counter = MSM_GPT_BASE + TIMER_COUNT_VAL,
+ .global_counter = MSM_GPT_BASE + TIMER_COUNT_VAL +
+ MSM_TMR_GLOBAL,
},
{
.clockevent = {
@@ -162,7 +196,7 @@ static struct msm_clock msm_clocks[] = {
.clocksource = {
.name = "dg_timer",
.rating = 300,
- .read = msm_dgt_read,
+ .read = msm_read_timer_count,
.mask = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT)),
.shift = 24 - MSM_DGT_SHIFT,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
@@ -176,7 +210,10 @@ static struct msm_clock msm_clocks[] = {
},
.regbase = MSM_DGT_BASE,
.freq = DGT_HZ >> MSM_DGT_SHIFT,
- .shift = MSM_DGT_SHIFT
+ .shift = MSM_DGT_SHIFT,
+ .local_counter = MSM_DGT_BASE + TIMER_COUNT_VAL,
+ .global_counter = MSM_DGT_BASE + TIMER_COUNT_VAL +
+ MSM_TMR_GLOBAL,
}
};
@@ -185,7 +222,7 @@ static void __init msm_timer_init(void)
int i;
int res;
-#ifdef CONFIG_ARCH_MSM8X60
+#ifdef CONFIG_ARCH_MSM_SCORPIONMP
writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
#endif
@@ -220,6 +257,57 @@ 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];
+
+ writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
+
+ if (!local_clock_event) {
+ writel(0, clock->regbase + TIMER_ENABLE);
+ writel(0, clock->regbase + TIMER_CLEAR);
+ 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);
+}
+
+inline int local_timer_ack(void)
+{
+ return 1;
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+void __cpuexit local_timer_stop(void)
+{
+ struct msm_clock *clock = clockevent_to_clock(local_clock_event);
+ writel(0, clock->regbase + TIMER_MATCH_VAL);
+ writel(0, clock->regbase + TIMER_ENABLE);
+ get_irq_chip(local_clock_event->irq)->mask(local_clock_event->irq);
+}
+#endif
+#endif
+
struct sys_timer msm_timer = {
.init = msm_timer_init
};
--
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 v2 4/6] msm: timer: SMP timer support for msm
Date: Tue, 7 Dec 2010 20:28:19 -0800 [thread overview]
Message-ID: <1291782501-3909-5-git-send-email-johlstei@codeaurora.org> (raw)
In-Reply-To: <1291782501-3909-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 | 6 +-
arch/arm/mach-msm/io.c | 1 +
arch/arm/mach-msm/timer.c | 130 +++++++++++++++++++----
3 files changed, 115 insertions(+), 22 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 45bab50..873e0b7 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
@@ -60,7 +60,11 @@
#define MSM_TMR_BASE IOMEM(0xF0200000)
#define MSM_TMR_PHYS 0x02000000
-#define MSM_TMR_SIZE (SZ_1M)
+#define MSM_TMR_SIZE SZ_4K
+
+#define MSM_TMR0_BASE IOMEM(0xF0201000)
+#define MSM_TMR0_PHYS 0x02040000
+#define MSM_TMR0_SIZE SZ_4K
#define MSM_GPT_BASE (MSM_TMR_BASE + 0x4)
#define MSM_DGT_BASE (MSM_TMR_BASE + 0x24)
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index d36b610..b826b6b 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -105,6 +105,7 @@ static struct map_desc msm8x60_io_desc[] __initdata = {
MSM_DEVICE(QGIC_DIST),
MSM_DEVICE(QGIC_CPU),
MSM_DEVICE(TMR),
+ MSM_DEVICE(TMR0),
MSM_DEVICE(ACC),
MSM_DEVICE(GCC),
};
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index 950100f..92ac220 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -47,6 +47,19 @@ enum {
#define GPT_HZ 32768
+enum timer_location {
+ LOCAL_TIMER = 0,
+ GLOBAL_TIMER = 1,
+};
+
+#ifdef MSM_TMR0_BASE
+#define MSM_TMR_GLOBAL (MSM_TMR0_BASE - MSM_TMR_BASE)
+#else
+#define MSM_TMR_GLOBAL 0
+#endif
+
+#define MSM_GLOBAL_TIMER MSM_CLOCK_DGT
+
#if defined(CONFIG_ARCH_QSD8X50)
#define DGT_HZ (19200000 / 4) /* 19.2 MHz / 4 by default */
#define MSM_DGT_SHIFT (0)
@@ -65,49 +78,67 @@ struct msm_clock {
void __iomem *regbase;
uint32_t freq;
uint32_t shift;
+ void *global_counter;
+ void *local_counter;
};
+enum {
+ MSM_CLOCK_GPT,
+ MSM_CLOCK_DGT,
+ NR_TIMERS,
+};
+
+
+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)
+static cycle_t msm_read_timer_count(struct clocksource *cs)
{
- return readl(MSM_GPT_BASE + TIMER_COUNT_VAL);
+ struct msm_clock *clk = container_of(cs, struct msm_clock, clocksource);
+
+ return readl(clk->global_counter) >> clk->shift;
}
-static cycle_t msm_dgt_read(struct clocksource *cs)
+static struct msm_clock *clockevent_to_clock(struct clock_event_device *evt)
{
- return readl(MSM_DGT_BASE + TIMER_COUNT_VAL) >> MSM_DGT_SHIFT;
+#ifdef CONFIG_SMP
+ int i;
+ for (i = 0; i < NR_TIMERS; i++)
+ if (evt == &(msm_clocks[i].clockevent))
+ return &msm_clocks[i];
+ return &msm_clocks[MSM_GLOBAL_TIMER];
+#else
+ return container_of(evt, struct msm_clock, clockevent);
+#endif
}
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);
+ struct msm_clock *clock = clockevent_to_clock(evt);
+ uint32_t now = readl(clock->local_counter);
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);
+ struct msm_clock *clock = clockevent_to_clock(evt);
+
switch (mode) {
case CLOCK_EVT_MODE_RESUME:
case CLOCK_EVT_MODE_PERIODIC:
@@ -135,7 +166,7 @@ static struct msm_clock msm_clocks[] = {
.clocksource = {
.name = "gp_timer",
.rating = 200,
- .read = msm_gpt_read,
+ .read = msm_read_timer_count,
.mask = CLOCKSOURCE_MASK(32),
.shift = 17,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
@@ -148,7 +179,10 @@ static struct msm_clock msm_clocks[] = {
.irq = INT_GP_TIMER_EXP
},
.regbase = MSM_GPT_BASE,
- .freq = GPT_HZ
+ .freq = GPT_HZ,
+ .local_counter = MSM_GPT_BASE + TIMER_COUNT_VAL,
+ .global_counter = MSM_GPT_BASE + TIMER_COUNT_VAL +
+ MSM_TMR_GLOBAL,
},
{
.clockevent = {
@@ -162,7 +196,7 @@ static struct msm_clock msm_clocks[] = {
.clocksource = {
.name = "dg_timer",
.rating = 300,
- .read = msm_dgt_read,
+ .read = msm_read_timer_count,
.mask = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT)),
.shift = 24 - MSM_DGT_SHIFT,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
@@ -176,7 +210,10 @@ static struct msm_clock msm_clocks[] = {
},
.regbase = MSM_DGT_BASE,
.freq = DGT_HZ >> MSM_DGT_SHIFT,
- .shift = MSM_DGT_SHIFT
+ .shift = MSM_DGT_SHIFT,
+ .local_counter = MSM_DGT_BASE + TIMER_COUNT_VAL,
+ .global_counter = MSM_DGT_BASE + TIMER_COUNT_VAL +
+ MSM_TMR_GLOBAL,
}
};
@@ -185,7 +222,7 @@ static void __init msm_timer_init(void)
int i;
int res;
-#ifdef CONFIG_ARCH_MSM8X60
+#ifdef CONFIG_ARCH_MSM_SCORPIONMP
writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
#endif
@@ -220,6 +257,57 @@ 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];
+
+ writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
+
+ if (!local_clock_event) {
+ writel(0, clock->regbase + TIMER_ENABLE);
+ writel(0, clock->regbase + TIMER_CLEAR);
+ 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);
+}
+
+inline int local_timer_ack(void)
+{
+ return 1;
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+void __cpuexit local_timer_stop(void)
+{
+ struct msm_clock *clock = clockevent_to_clock(local_clock_event);
+ writel(0, clock->regbase + TIMER_MATCH_VAL);
+ writel(0, clock->regbase + TIMER_ENABLE);
+ get_irq_chip(local_clock_event->irq)->mask(local_clock_event->irq);
+}
+#endif
+#endif
+
struct sys_timer msm_timer = {
.init = msm_timer_init
};
--
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: Daniel Walker <dwalker@codeaurora.org>,
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,
"Jeff Ohlstein" <johlstei@codeaurora.org>,
"Brian Swetland" <swetland@google.com>,
"Dima Zavin" <dima@android.com>,
"Arve Hj�nnev�g" <arve@android.com>,
"David Brown" <davidb@codeaurora.org>,
"Daniel Walker" <dwalker@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 v2 4/6] msm: timer: SMP timer support for msm
Date: Tue, 7 Dec 2010 20:28:19 -0800 [thread overview]
Message-ID: <1291782501-3909-5-git-send-email-johlstei@codeaurora.org> (raw)
In-Reply-To: <1291782501-3909-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 | 6 +-
arch/arm/mach-msm/io.c | 1 +
arch/arm/mach-msm/timer.c | 130 +++++++++++++++++++----
3 files changed, 115 insertions(+), 22 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 45bab50..873e0b7 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
@@ -60,7 +60,11 @@
#define MSM_TMR_BASE IOMEM(0xF0200000)
#define MSM_TMR_PHYS 0x02000000
-#define MSM_TMR_SIZE (SZ_1M)
+#define MSM_TMR_SIZE SZ_4K
+
+#define MSM_TMR0_BASE IOMEM(0xF0201000)
+#define MSM_TMR0_PHYS 0x02040000
+#define MSM_TMR0_SIZE SZ_4K
#define MSM_GPT_BASE (MSM_TMR_BASE + 0x4)
#define MSM_DGT_BASE (MSM_TMR_BASE + 0x24)
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index d36b610..b826b6b 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -105,6 +105,7 @@ static struct map_desc msm8x60_io_desc[] __initdata = {
MSM_DEVICE(QGIC_DIST),
MSM_DEVICE(QGIC_CPU),
MSM_DEVICE(TMR),
+ MSM_DEVICE(TMR0),
MSM_DEVICE(ACC),
MSM_DEVICE(GCC),
};
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index 950100f..92ac220 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -47,6 +47,19 @@ enum {
#define GPT_HZ 32768
+enum timer_location {
+ LOCAL_TIMER = 0,
+ GLOBAL_TIMER = 1,
+};
+
+#ifdef MSM_TMR0_BASE
+#define MSM_TMR_GLOBAL (MSM_TMR0_BASE - MSM_TMR_BASE)
+#else
+#define MSM_TMR_GLOBAL 0
+#endif
+
+#define MSM_GLOBAL_TIMER MSM_CLOCK_DGT
+
#if defined(CONFIG_ARCH_QSD8X50)
#define DGT_HZ (19200000 / 4) /* 19.2 MHz / 4 by default */
#define MSM_DGT_SHIFT (0)
@@ -65,49 +78,67 @@ struct msm_clock {
void __iomem *regbase;
uint32_t freq;
uint32_t shift;
+ void *global_counter;
+ void *local_counter;
};
+enum {
+ MSM_CLOCK_GPT,
+ MSM_CLOCK_DGT,
+ NR_TIMERS,
+};
+
+
+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)
+static cycle_t msm_read_timer_count(struct clocksource *cs)
{
- return readl(MSM_GPT_BASE + TIMER_COUNT_VAL);
+ struct msm_clock *clk = container_of(cs, struct msm_clock, clocksource);
+
+ return readl(clk->global_counter) >> clk->shift;
}
-static cycle_t msm_dgt_read(struct clocksource *cs)
+static struct msm_clock *clockevent_to_clock(struct clock_event_device *evt)
{
- return readl(MSM_DGT_BASE + TIMER_COUNT_VAL) >> MSM_DGT_SHIFT;
+#ifdef CONFIG_SMP
+ int i;
+ for (i = 0; i < NR_TIMERS; i++)
+ if (evt == &(msm_clocks[i].clockevent))
+ return &msm_clocks[i];
+ return &msm_clocks[MSM_GLOBAL_TIMER];
+#else
+ return container_of(evt, struct msm_clock, clockevent);
+#endif
}
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);
+ struct msm_clock *clock = clockevent_to_clock(evt);
+ uint32_t now = readl(clock->local_counter);
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);
+ struct msm_clock *clock = clockevent_to_clock(evt);
+
switch (mode) {
case CLOCK_EVT_MODE_RESUME:
case CLOCK_EVT_MODE_PERIODIC:
@@ -135,7 +166,7 @@ static struct msm_clock msm_clocks[] = {
.clocksource = {
.name = "gp_timer",
.rating = 200,
- .read = msm_gpt_read,
+ .read = msm_read_timer_count,
.mask = CLOCKSOURCE_MASK(32),
.shift = 17,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
@@ -148,7 +179,10 @@ static struct msm_clock msm_clocks[] = {
.irq = INT_GP_TIMER_EXP
},
.regbase = MSM_GPT_BASE,
- .freq = GPT_HZ
+ .freq = GPT_HZ,
+ .local_counter = MSM_GPT_BASE + TIMER_COUNT_VAL,
+ .global_counter = MSM_GPT_BASE + TIMER_COUNT_VAL +
+ MSM_TMR_GLOBAL,
},
{
.clockevent = {
@@ -162,7 +196,7 @@ static struct msm_clock msm_clocks[] = {
.clocksource = {
.name = "dg_timer",
.rating = 300,
- .read = msm_dgt_read,
+ .read = msm_read_timer_count,
.mask = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT)),
.shift = 24 - MSM_DGT_SHIFT,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
@@ -176,7 +210,10 @@ static struct msm_clock msm_clocks[] = {
},
.regbase = MSM_DGT_BASE,
.freq = DGT_HZ >> MSM_DGT_SHIFT,
- .shift = MSM_DGT_SHIFT
+ .shift = MSM_DGT_SHIFT,
+ .local_counter = MSM_DGT_BASE + TIMER_COUNT_VAL,
+ .global_counter = MSM_DGT_BASE + TIMER_COUNT_VAL +
+ MSM_TMR_GLOBAL,
}
};
@@ -185,7 +222,7 @@ static void __init msm_timer_init(void)
int i;
int res;
-#ifdef CONFIG_ARCH_MSM8X60
+#ifdef CONFIG_ARCH_MSM_SCORPIONMP
writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
#endif
@@ -220,6 +257,57 @@ 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];
+
+ writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
+
+ if (!local_clock_event) {
+ writel(0, clock->regbase + TIMER_ENABLE);
+ writel(0, clock->regbase + TIMER_CLEAR);
+ 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);
+}
+
+inline int local_timer_ack(void)
+{
+ return 1;
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+void __cpuexit local_timer_stop(void)
+{
+ struct msm_clock *clock = clockevent_to_clock(local_clock_event);
+ writel(0, clock->regbase + TIMER_MATCH_VAL);
+ writel(0, clock->regbase + TIMER_ENABLE);
+ get_irq_chip(local_clock_event->irq)->mask(local_clock_event->irq);
+}
+#endif
+#endif
+
struct sys_timer msm_timer = {
.init = msm_timer_init
};
--
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-12-08 4:28 UTC|newest]
Thread overview: 40+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-12-08 4:28 [PATCH v2 0/6] SMP support for msm Jeff Ohlstein
2010-12-08 4:28 ` Jeff Ohlstein
2010-12-08 4:28 ` [PATCH v2 1/6] arm: dma-mapping: move consistent_init to early_initcall Jeff Ohlstein
2010-12-08 4:28 ` Jeff Ohlstein
2010-12-08 4:28 ` Jeff Ohlstein
2010-12-08 4:28 ` [PATCH v2 2/6] msm: Secure Channel Manager (SCM) support Jeff Ohlstein
2010-12-08 4:28 ` Jeff Ohlstein
2010-12-08 4:28 ` Jeff Ohlstein
2010-12-08 16:53 ` Russell King - ARM Linux
2010-12-08 16:53 ` Russell King - ARM Linux
2010-12-08 19:59 ` Stephen Boyd
2010-12-08 19:59 ` Stephen Boyd
2010-12-08 4:28 ` [PATCH v2 3/6] msm: scm-boot: Support for setting cold/warm boot addresses Jeff Ohlstein
2010-12-08 4:28 ` Jeff Ohlstein
2010-12-08 4:28 ` Jeff Ohlstein
2010-12-08 4:28 ` Jeff Ohlstein [this message]
2010-12-08 4:28 ` [PATCH v2 4/6] msm: timer: SMP timer support for msm Jeff Ohlstein
2010-12-08 4:28 ` Jeff Ohlstein
2010-12-08 16:39 ` Russell King - ARM Linux
2010-12-08 16:39 ` Russell King - ARM Linux
2010-12-09 4:22 ` Jeff Ohlstein
2010-12-09 4:22 ` Jeff Ohlstein
2010-12-10 2:07 ` Jeff Ohlstein
2010-12-10 2:07 ` Jeff Ohlstein
2010-12-10 2:24 ` Thomas Gleixner
2010-12-10 2:24 ` Thomas Gleixner
2010-12-08 4:28 ` [PATCH v2 5/6] msm: hotplug: support cpu hotplug on msm Jeff Ohlstein
2010-12-08 4:28 ` Jeff Ohlstein
2010-12-08 4:28 ` Jeff Ohlstein
2010-12-08 15:14 ` Russell King - ARM Linux
2010-12-08 15:14 ` Russell King - ARM Linux
2010-12-08 15:23 ` Russell King - ARM Linux
2010-12-08 15:23 ` Russell King - ARM Linux
2010-12-08 4:28 ` [PATCH v2 6/6] msm: add SMP support for msm Jeff Ohlstein
2010-12-08 4:28 ` Jeff Ohlstein
2010-12-08 4:28 ` Jeff Ohlstein
2010-12-08 15:21 ` Russell King - ARM Linux
2010-12-08 15:21 ` Russell King - ARM Linux
2010-12-09 3:41 ` Jeff Ohlstein
2010-12-09 3:41 ` 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=1291782501-3909-5-git-send-email-johlstei@codeaurora.org \
--to=johlstei@codeaurora.org \
--cc=arve@android.com \
--cc=bryanh@codeaurora.org \
--cc=davidb@codeaurora.org \
--cc=dima@android.com \
--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 \
--cc=swetland@google.com \
/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.