linux/arch/blackfin/kernel/time-ts.c
<<
>>
Prefs
   1/*
   2 * Based on arm clockevents implementation and old bfin time tick.
   3 *
   4 * Copyright 2008-2009 Analog Devics Inc.
   5 *                2008 GeoTechnologies
   6 *                     Vitja Makarov
   7 *
   8 * Licensed under the GPL-2
   9 */
  10
  11#include <linux/module.h>
  12#include <linux/profile.h>
  13#include <linux/interrupt.h>
  14#include <linux/time.h>
  15#include <linux/timex.h>
  16#include <linux/irq.h>
  17#include <linux/clocksource.h>
  18#include <linux/clockchips.h>
  19#include <linux/cpufreq.h>
  20
  21#include <asm/blackfin.h>
  22#include <asm/time.h>
  23#include <asm/gptimers.h>
  24#include <asm/nmi.h>
  25
  26
  27#if defined(CONFIG_CYCLES_CLOCKSOURCE)
  28
  29static notrace cycle_t bfin_read_cycles(struct clocksource *cs)
  30{
  31#ifdef CONFIG_CPU_FREQ
  32        return __bfin_cycles_off + (get_cycles() << __bfin_cycles_mod);
  33#else
  34        return get_cycles();
  35#endif
  36}
  37
  38static struct clocksource bfin_cs_cycles = {
  39        .name           = "bfin_cs_cycles",
  40        .rating         = 400,
  41        .read           = bfin_read_cycles,
  42        .mask           = CLOCKSOURCE_MASK(64),
  43        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
  44};
  45
  46static inline unsigned long long bfin_cs_cycles_sched_clock(void)
  47{
  48        return clocksource_cyc2ns(bfin_read_cycles(&bfin_cs_cycles),
  49                bfin_cs_cycles.mult, bfin_cs_cycles.shift);
  50}
  51
  52static int __init bfin_cs_cycles_init(void)
  53{
  54        if (clocksource_register_hz(&bfin_cs_cycles, get_cclk()))
  55                panic("failed to register clocksource");
  56
  57        return 0;
  58}
  59#else
  60# define bfin_cs_cycles_init()
  61#endif
  62
  63#ifdef CONFIG_GPTMR0_CLOCKSOURCE
  64
  65void __init setup_gptimer0(void)
  66{
  67        disable_gptimers(TIMER0bit);
  68
  69#ifdef CONFIG_BF60x
  70        bfin_write16(TIMER_DATA_IMSK, 0);
  71        set_gptimer_config(TIMER0_id,  TIMER_OUT_DIS
  72                | TIMER_MODE_PWM_CONT | TIMER_PULSE_HI | TIMER_IRQ_PER);
  73#else
  74        set_gptimer_config(TIMER0_id, \
  75                TIMER_OUT_DIS | TIMER_PERIOD_CNT | TIMER_MODE_PWM);
  76#endif
  77        set_gptimer_period(TIMER0_id, -1);
  78        set_gptimer_pwidth(TIMER0_id, -2);
  79        SSYNC();
  80        enable_gptimers(TIMER0bit);
  81}
  82
  83static cycle_t bfin_read_gptimer0(struct clocksource *cs)
  84{
  85        return bfin_read_TIMER0_COUNTER();
  86}
  87
  88static struct clocksource bfin_cs_gptimer0 = {
  89        .name           = "bfin_cs_gptimer0",
  90        .rating         = 350,
  91        .read           = bfin_read_gptimer0,
  92        .mask           = CLOCKSOURCE_MASK(32),
  93        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
  94};
  95
  96static inline unsigned long long bfin_cs_gptimer0_sched_clock(void)
  97{
  98        return clocksource_cyc2ns(bfin_read_TIMER0_COUNTER(),
  99                bfin_cs_gptimer0.mult, bfin_cs_gptimer0.shift);
 100}
 101
 102static int __init bfin_cs_gptimer0_init(void)
 103{
 104        setup_gptimer0();
 105
 106        if (clocksource_register_hz(&bfin_cs_gptimer0, get_sclk()))
 107                panic("failed to register clocksource");
 108
 109        return 0;
 110}
 111#else
 112# define bfin_cs_gptimer0_init()
 113#endif
 114
 115#if defined(CONFIG_GPTMR0_CLOCKSOURCE) || defined(CONFIG_CYCLES_CLOCKSOURCE)
 116/* prefer to use cycles since it has higher rating */
 117notrace unsigned long long sched_clock(void)
 118{
 119#if defined(CONFIG_CYCLES_CLOCKSOURCE)
 120        return bfin_cs_cycles_sched_clock();
 121#else
 122        return bfin_cs_gptimer0_sched_clock();
 123#endif
 124}
 125#endif
 126
 127#if defined(CONFIG_TICKSOURCE_GPTMR0)
 128static int bfin_gptmr0_set_next_event(unsigned long cycles,
 129                                     struct clock_event_device *evt)
 130{
 131        disable_gptimers(TIMER0bit);
 132
 133        /* it starts counting three SCLK cycles after the TIMENx bit is set */
 134        set_gptimer_pwidth(TIMER0_id, cycles - 3);
 135        enable_gptimers(TIMER0bit);
 136        return 0;
 137}
 138
 139static int bfin_gptmr0_set_periodic(struct clock_event_device *evt)
 140{
 141#ifndef CONFIG_BF60x
 142        set_gptimer_config(TIMER0_id,
 143                           TIMER_OUT_DIS | TIMER_IRQ_ENA |
 144                           TIMER_PERIOD_CNT | TIMER_MODE_PWM);
 145#else
 146        set_gptimer_config(TIMER0_id,
 147                           TIMER_OUT_DIS | TIMER_MODE_PWM_CONT |
 148                           TIMER_PULSE_HI | TIMER_IRQ_PER);
 149#endif
 150
 151        set_gptimer_period(TIMER0_id, get_sclk() / HZ);
 152        set_gptimer_pwidth(TIMER0_id, get_sclk() / HZ - 1);
 153        enable_gptimers(TIMER0bit);
 154        return 0;
 155}
 156
 157static int bfin_gptmr0_set_oneshot(struct clock_event_device *evt)
 158{
 159        disable_gptimers(TIMER0bit);
 160#ifndef CONFIG_BF60x
 161        set_gptimer_config(TIMER0_id,
 162                           TIMER_OUT_DIS | TIMER_IRQ_ENA | TIMER_MODE_PWM);
 163#else
 164        set_gptimer_config(TIMER0_id,
 165                           TIMER_OUT_DIS | TIMER_MODE_PWM | TIMER_PULSE_HI |
 166                           TIMER_IRQ_WID_DLY);
 167#endif
 168
 169        set_gptimer_period(TIMER0_id, 0);
 170        return 0;
 171}
 172
 173static int bfin_gptmr0_shutdown(struct clock_event_device *evt)
 174{
 175        disable_gptimers(TIMER0bit);
 176        return 0;
 177}
 178
 179static void bfin_gptmr0_ack(void)
 180{
 181        clear_gptimer_intr(TIMER0_id);
 182}
 183
 184static void __init bfin_gptmr0_init(void)
 185{
 186        disable_gptimers(TIMER0bit);
 187}
 188
 189#ifdef CONFIG_CORE_TIMER_IRQ_L1
 190__attribute__((l1_text))
 191#endif
 192irqreturn_t bfin_gptmr0_interrupt(int irq, void *dev_id)
 193{
 194        struct clock_event_device *evt = dev_id;
 195        smp_mb();
 196        /*
 197         * We want to ACK before we handle so that we can handle smaller timer
 198         * intervals.  This way if the timer expires again while we're handling
 199         * things, we're more likely to see that 2nd int rather than swallowing
 200         * it by ACKing the int at the end of this handler.
 201         */
 202        bfin_gptmr0_ack();
 203        evt->event_handler(evt);
 204        return IRQ_HANDLED;
 205}
 206
 207static struct irqaction gptmr0_irq = {
 208        .name           = "Blackfin GPTimer0",
 209        .flags          = IRQF_TIMER | IRQF_IRQPOLL | IRQF_PERCPU,
 210        .handler        = bfin_gptmr0_interrupt,
 211};
 212
 213static struct clock_event_device clockevent_gptmr0 = {
 214        .name                   = "bfin_gptimer0",
 215        .rating                 = 300,
 216        .irq                    = IRQ_TIMER0,
 217        .shift                  = 32,
 218        .features               = CLOCK_EVT_FEAT_PERIODIC |
 219                                  CLOCK_EVT_FEAT_ONESHOT,
 220        .set_next_event         = bfin_gptmr0_set_next_event,
 221        .set_state_shutdown     = bfin_gptmr0_shutdown,
 222        .set_state_periodic     = bfin_gptmr0_set_periodic,
 223        .set_state_oneshot      = bfin_gptmr0_set_oneshot,
 224};
 225
 226static void __init bfin_gptmr0_clockevent_init(struct clock_event_device *evt)
 227{
 228        unsigned long clock_tick;
 229
 230        clock_tick = get_sclk();
 231        evt->mult = div_sc(clock_tick, NSEC_PER_SEC, evt->shift);
 232        evt->max_delta_ns = clockevent_delta2ns(-1, evt);
 233        evt->min_delta_ns = clockevent_delta2ns(100, evt);
 234
 235        evt->cpumask = cpumask_of(0);
 236
 237        clockevents_register_device(evt);
 238}
 239#endif /* CONFIG_TICKSOURCE_GPTMR0 */
 240
 241#if defined(CONFIG_TICKSOURCE_CORETMR)
 242/* per-cpu local core timer */
 243DEFINE_PER_CPU(struct clock_event_device, coretmr_events);
 244
 245static int bfin_coretmr_set_next_event(unsigned long cycles,
 246                                struct clock_event_device *evt)
 247{
 248        bfin_write_TCNTL(TMPWR);
 249        CSYNC();
 250        bfin_write_TCOUNT(cycles);
 251        CSYNC();
 252        bfin_write_TCNTL(TMPWR | TMREN);
 253        return 0;
 254}
 255
 256static int bfin_coretmr_set_periodic(struct clock_event_device *evt)
 257{
 258        unsigned long tcount = ((get_cclk() / (HZ * TIME_SCALE)) - 1);
 259
 260        bfin_write_TCNTL(TMPWR);
 261        CSYNC();
 262        bfin_write_TSCALE(TIME_SCALE - 1);
 263        bfin_write_TPERIOD(tcount);
 264        bfin_write_TCOUNT(tcount);
 265        CSYNC();
 266        bfin_write_TCNTL(TMPWR | TMREN | TAUTORLD);
 267        return 0;
 268}
 269
 270static int bfin_coretmr_set_oneshot(struct clock_event_device *evt)
 271{
 272        bfin_write_TCNTL(TMPWR);
 273        CSYNC();
 274        bfin_write_TSCALE(TIME_SCALE - 1);
 275        bfin_write_TPERIOD(0);
 276        bfin_write_TCOUNT(0);
 277        return 0;
 278}
 279
 280static int bfin_coretmr_shutdown(struct clock_event_device *evt)
 281{
 282        bfin_write_TCNTL(0);
 283        CSYNC();
 284        return 0;
 285}
 286
 287void bfin_coretmr_init(void)
 288{
 289        /* power up the timer, but don't enable it just yet */
 290        bfin_write_TCNTL(TMPWR);
 291        CSYNC();
 292
 293        /* the TSCALE prescaler counter. */
 294        bfin_write_TSCALE(TIME_SCALE - 1);
 295        bfin_write_TPERIOD(0);
 296        bfin_write_TCOUNT(0);
 297
 298        CSYNC();
 299}
 300
 301#ifdef CONFIG_CORE_TIMER_IRQ_L1
 302__attribute__((l1_text))
 303#endif
 304
 305irqreturn_t bfin_coretmr_interrupt(int irq, void *dev_id)
 306{
 307        int cpu = smp_processor_id();
 308        struct clock_event_device *evt = &per_cpu(coretmr_events, cpu);
 309
 310        smp_mb();
 311        evt->event_handler(evt);
 312
 313        touch_nmi_watchdog();
 314
 315        return IRQ_HANDLED;
 316}
 317
 318static struct irqaction coretmr_irq = {
 319        .name           = "Blackfin CoreTimer",
 320        .flags          = IRQF_TIMER | IRQF_IRQPOLL | IRQF_PERCPU,
 321        .handler        = bfin_coretmr_interrupt,
 322};
 323
 324void bfin_coretmr_clockevent_init(void)
 325{
 326        unsigned long clock_tick;
 327        unsigned int cpu = smp_processor_id();
 328        struct clock_event_device *evt = &per_cpu(coretmr_events, cpu);
 329
 330#ifdef CONFIG_SMP
 331        evt->broadcast = smp_timer_broadcast;
 332#endif
 333
 334        evt->name = "bfin_core_timer";
 335        evt->rating = 350;
 336        evt->irq = -1;
 337        evt->shift = 32;
 338        evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
 339        evt->set_next_event = bfin_coretmr_set_next_event;
 340        evt->set_state_shutdown = bfin_coretmr_shutdown;
 341        evt->set_state_periodic = bfin_coretmr_set_periodic;
 342        evt->set_state_oneshot = bfin_coretmr_set_oneshot;
 343
 344        clock_tick = get_cclk() / TIME_SCALE;
 345        evt->mult = div_sc(clock_tick, NSEC_PER_SEC, evt->shift);
 346        evt->max_delta_ns = clockevent_delta2ns(-1, evt);
 347        evt->min_delta_ns = clockevent_delta2ns(100, evt);
 348
 349        evt->cpumask = cpumask_of(cpu);
 350
 351        clockevents_register_device(evt);
 352}
 353#endif /* CONFIG_TICKSOURCE_CORETMR */
 354
 355
 356void read_persistent_clock(struct timespec *ts)
 357{
 358        time_t secs_since_1970 = (365 * 37 + 9) * 24 * 60 * 60; /* 1 Jan 2007 */
 359        ts->tv_sec = secs_since_1970;
 360        ts->tv_nsec = 0;
 361}
 362
 363void __init time_init(void)
 364{
 365
 366#ifdef CONFIG_RTC_DRV_BFIN
 367        /* [#2663] hack to filter junk RTC values that would cause
 368         * userspace to have to deal with time values greater than
 369         * 2^31 seconds (which uClibc cannot cope with yet)
 370         */
 371        if ((bfin_read_RTC_STAT() & 0xC0000000) == 0xC0000000) {
 372                printk(KERN_NOTICE "bfin-rtc: invalid date; resetting\n");
 373                bfin_write_RTC_STAT(0);
 374        }
 375#endif
 376
 377        bfin_cs_cycles_init();
 378        bfin_cs_gptimer0_init();
 379
 380#if defined(CONFIG_TICKSOURCE_CORETMR)
 381        bfin_coretmr_init();
 382        setup_irq(IRQ_CORETMR, &coretmr_irq);
 383        bfin_coretmr_clockevent_init();
 384#endif
 385
 386#if defined(CONFIG_TICKSOURCE_GPTMR0)
 387        bfin_gptmr0_init();
 388        setup_irq(IRQ_TIMER0, &gptmr0_irq);
 389        gptmr0_irq.dev_id = &clockevent_gptmr0;
 390        bfin_gptmr0_clockevent_init(&clockevent_gptmr0);
 391#endif
 392
 393#if !defined(CONFIG_TICKSOURCE_CORETMR) && !defined(CONFIG_TICKSOURCE_GPTMR0)
 394# error at least one clock event device is required
 395#endif
 396}
 397