diff options
Diffstat (limited to 'arch/blackfin/kernel/time-ts.c')
| -rw-r--r-- | arch/blackfin/kernel/time-ts.c | 78 |
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; |
