aboutsummaryrefslogtreecommitdiff
path: root/arch/blackfin/kernel/time-ts.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/blackfin/kernel/time-ts.c')
-rw-r--r--arch/blackfin/kernel/time-ts.c78
1 files changed, 37 insertions, 41 deletions
diff --git a/arch/blackfin/kernel/time-ts.c b/arch/blackfin/kernel/time-ts.c
index 8c9a43daf80..cb0a4845339 100644
--- a/arch/blackfin/kernel/time-ts.c
+++ b/arch/blackfin/kernel/time-ts.c
@@ -23,29 +23,6 @@
#include <asm/gptimers.h>
#include <asm/nmi.h>
-/* Accelerators for sched_clock()
- * convert from cycles(64bits) => nanoseconds (64bits)
- * basic equation:
- * ns = cycles / (freq / ns_per_sec)
- * ns = cycles * (ns_per_sec / freq)
- * ns = cycles * (10^9 / (cpu_khz * 10^3))
- * ns = cycles * (10^6 / cpu_khz)
- *
- * Then we use scaling math (suggested by george@mvista.com) to get:
- * ns = cycles * (10^6 * SC / cpu_khz) / SC
- * ns = cycles * cyc2ns_scale / SC
- *
- * And since SC is a constant power of two, we can convert the div
- * into a shift.
- *
- * We can use khz divisor instead of mhz to keep a better precision, since
- * cyc2ns_scale is limited to 10^6 * 2^10, which fits in 32 bits.
- * (mathieu.desnoyers@polymtl.ca)
- *
- * -johnstul@us.ibm.com "math is hard, lets go shopping!"
- */
-
-#define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */
#if defined(CONFIG_CYCLES_CLOCKSOURCE)
@@ -63,7 +40,6 @@ static struct clocksource bfin_cs_cycles = {
.rating = 400,
.read = bfin_read_cycles,
.mask = CLOCKSOURCE_MASK(64),
- .shift = CYC2NS_SCALE_FACTOR,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
@@ -75,10 +51,7 @@ static inline unsigned long long bfin_cs_cycles_sched_clock(void)
static int __init bfin_cs_cycles_init(void)
{
- bfin_cs_cycles.mult = \
- clocksource_hz2mult(get_cclk(), bfin_cs_cycles.shift);
-
- if (clocksource_register(&bfin_cs_cycles))
+ if (clocksource_register_hz(&bfin_cs_cycles, get_cclk()))
panic("failed to register clocksource");
return 0;
@@ -93,8 +66,14 @@ void __init setup_gptimer0(void)
{
disable_gptimers(TIMER0bit);
+#ifdef CONFIG_BF60x
+ bfin_write16(TIMER_DATA_IMSK, 0);
+ set_gptimer_config(TIMER0_id, TIMER_OUT_DIS
+ | TIMER_MODE_PWM_CONT | TIMER_PULSE_HI | TIMER_IRQ_PER);
+#else
set_gptimer_config(TIMER0_id, \
TIMER_OUT_DIS | TIMER_PERIOD_CNT | TIMER_MODE_PWM);
+#endif
set_gptimer_period(TIMER0_id, -1);
set_gptimer_pwidth(TIMER0_id, -2);
SSYNC();
@@ -111,7 +90,6 @@ static struct clocksource bfin_cs_gptimer0 = {
.rating = 350,
.read = bfin_read_gptimer0,
.mask = CLOCKSOURCE_MASK(32),
- .shift = CYC2NS_SCALE_FACTOR,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
@@ -125,10 +103,7 @@ static int __init bfin_cs_gptimer0_init(void)
{
setup_gptimer0();
- bfin_cs_gptimer0.mult = \
- clocksource_hz2mult(get_sclk(), bfin_cs_gptimer0.shift);
-
- if (clocksource_register(&bfin_cs_gptimer0))
+ if (clocksource_register_hz(&bfin_cs_gptimer0, get_sclk()))
panic("failed to register clocksource");
return 0;
@@ -166,9 +141,15 @@ static void bfin_gptmr0_set_mode(enum clock_event_mode mode,
{
switch (mode) {
case CLOCK_EVT_MODE_PERIODIC: {
+#ifndef CONFIG_BF60x
set_gptimer_config(TIMER0_id, \
TIMER_OUT_DIS | TIMER_IRQ_ENA | \
TIMER_PERIOD_CNT | TIMER_MODE_PWM);
+#else
+ set_gptimer_config(TIMER0_id, TIMER_OUT_DIS
+ | TIMER_MODE_PWM_CONT | TIMER_PULSE_HI | TIMER_IRQ_PER);
+#endif
+
set_gptimer_period(TIMER0_id, get_sclk() / HZ);
set_gptimer_pwidth(TIMER0_id, get_sclk() / HZ - 1);
enable_gptimers(TIMER0bit);
@@ -176,8 +157,14 @@ static void bfin_gptmr0_set_mode(enum clock_event_mode mode,
}
case CLOCK_EVT_MODE_ONESHOT:
disable_gptimers(TIMER0bit);
+#ifndef CONFIG_BF60x
set_gptimer_config(TIMER0_id, \
TIMER_OUT_DIS | TIMER_IRQ_ENA | TIMER_MODE_PWM);
+#else
+ set_gptimer_config(TIMER0_id, TIMER_OUT_DIS | TIMER_MODE_PWM
+ | TIMER_PULSE_HI | TIMER_IRQ_WID_DLY);
+#endif
+
set_gptimer_period(TIMER0_id, 0);
break;
case CLOCK_EVT_MODE_UNUSED:
@@ -191,7 +178,7 @@ static void bfin_gptmr0_set_mode(enum clock_event_mode mode,
static void bfin_gptmr0_ack(void)
{
- set_gptimer_status(TIMER_GROUP1, TIMER_STATUS_TIMIL0);
+ clear_gptimer_intr(TIMER0_id);
}
static void __init bfin_gptmr0_init(void)
@@ -206,15 +193,20 @@ irqreturn_t bfin_gptmr0_interrupt(int irq, void *dev_id)
{
struct clock_event_device *evt = dev_id;
smp_mb();
- evt->event_handler(evt);
+ /*
+ * We want to ACK before we handle so that we can handle smaller timer
+ * intervals. This way if the timer expires again while we're handling
+ * things, we're more likely to see that 2nd int rather than swallowing
+ * it by ACKing the int at the end of this handler.
+ */
bfin_gptmr0_ack();
+ evt->event_handler(evt);
return IRQ_HANDLED;
}
static struct irqaction gptmr0_irq = {
.name = "Blackfin GPTimer0",
- .flags = IRQF_DISABLED | IRQF_TIMER | \
- IRQF_IRQPOLL | IRQF_PERCPU,
+ .flags = IRQF_TIMER | IRQF_IRQPOLL | IRQF_PERCPU,
.handler = bfin_gptmr0_interrupt,
};
@@ -223,7 +215,7 @@ static struct clock_event_device clockevent_gptmr0 = {
.rating = 300,
.irq = IRQ_TIMER0,
.shift = 32,
- .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
.set_next_event = bfin_gptmr0_set_next_event,
.set_mode = bfin_gptmr0_set_mode,
};
@@ -245,7 +237,7 @@ static void __init bfin_gptmr0_clockevent_init(struct clock_event_device *evt)
#if defined(CONFIG_TICKSOURCE_CORETMR)
/* per-cpu local core timer */
-static DEFINE_PER_CPU(struct clock_event_device, coretmr_events);
+DEFINE_PER_CPU(struct clock_event_device, coretmr_events);
static int bfin_coretmr_set_next_event(unsigned long cycles,
struct clock_event_device *evt)
@@ -307,6 +299,7 @@ void bfin_coretmr_init(void)
#ifdef CONFIG_CORE_TIMER_IRQ_L1
__attribute__((l1_text))
#endif
+
irqreturn_t bfin_coretmr_interrupt(int irq, void *dev_id)
{
int cpu = smp_processor_id();
@@ -322,8 +315,7 @@ irqreturn_t bfin_coretmr_interrupt(int irq, void *dev_id)
static struct irqaction coretmr_irq = {
.name = "Blackfin CoreTimer",
- .flags = IRQF_DISABLED | IRQF_TIMER | \
- IRQF_IRQPOLL | IRQF_PERCPU,
+ .flags = IRQF_TIMER | IRQF_IRQPOLL | IRQF_PERCPU,
.handler = bfin_coretmr_interrupt,
};
@@ -333,6 +325,10 @@ void bfin_coretmr_clockevent_init(void)
unsigned int cpu = smp_processor_id();
struct clock_event_device *evt = &per_cpu(coretmr_events, cpu);
+#ifdef CONFIG_SMP
+ evt->broadcast = smp_timer_broadcast;
+#endif
+
evt->name = "bfin_core_timer";
evt->rating = 350;
evt->irq = -1;