linux/arch/arm/mach-davinci/time.c
<<
>>
Prefs
   1/*
   2 * DaVinci timer subsystem
   3 *
   4 * Author: Kevin Hilman, MontaVista Software, Inc. <source@mvista.com>
   5 *
   6 * 2007 (c) MontaVista Software, Inc. This file is licensed under
   7 * the terms of the GNU General Public License version 2. This program
   8 * is licensed "as is" without any warranty of any kind, whether express
   9 * or implied.
  10 */
  11#include <linux/kernel.h>
  12#include <linux/init.h>
  13#include <linux/types.h>
  14#include <linux/interrupt.h>
  15#include <linux/clocksource.h>
  16#include <linux/clockchips.h>
  17#include <linux/spinlock.h>
  18
  19#include <asm/io.h>
  20#include <asm/hardware.h>
  21#include <asm/system.h>
  22#include <asm/irq.h>
  23#include <asm/mach/irq.h>
  24#include <asm/mach/time.h>
  25#include <asm/errno.h>
  26#include <asm/arch/io.h>
  27
  28static struct clock_event_device clockevent_davinci;
  29
  30#define DAVINCI_TIMER0_BASE (IO_PHYS + 0x21400)
  31#define DAVINCI_TIMER1_BASE (IO_PHYS + 0x21800)
  32#define DAVINCI_WDOG_BASE   (IO_PHYS + 0x21C00)
  33
  34enum {
  35        T0_BOT = 0, T0_TOP, T1_BOT, T1_TOP, NUM_TIMERS,
  36};
  37
  38#define IS_TIMER1(id)    (id & 0x2)
  39#define IS_TIMER0(id)    (!IS_TIMER1(id))
  40#define IS_TIMER_TOP(id) ((id & 0x1))
  41#define IS_TIMER_BOT(id) (!IS_TIMER_TOP(id))
  42
  43static int timer_irqs[NUM_TIMERS] = {
  44        IRQ_TINT0_TINT12,
  45        IRQ_TINT0_TINT34,
  46        IRQ_TINT1_TINT12,
  47        IRQ_TINT1_TINT34,
  48};
  49
  50/*
  51 * This driver configures the 2 64-bit count-up timers as 4 independent
  52 * 32-bit count-up timers used as follows:
  53 *
  54 * T0_BOT: Timer 0, bottom:  clockevent source for hrtimers
  55 * T0_TOP: Timer 0, top   :  clocksource for generic timekeeping
  56 * T1_BOT: Timer 1, bottom:  (used by DSP in TI DSPLink code)
  57 * T1_TOP: Timer 1, top   :  <unused>
  58 */
  59#define TID_CLOCKEVENT  T0_BOT
  60#define TID_CLOCKSOURCE T0_TOP
  61
  62/* Timer register offsets */
  63#define PID12                        0x0
  64#define TIM12                        0x10
  65#define TIM34                        0x14
  66#define PRD12                        0x18
  67#define PRD34                        0x1c
  68#define TCR                          0x20
  69#define TGCR                         0x24
  70#define WDTCR                        0x28
  71
  72/* Timer register bitfields */
  73#define TCR_ENAMODE_DISABLE          0x0
  74#define TCR_ENAMODE_ONESHOT          0x1
  75#define TCR_ENAMODE_PERIODIC         0x2
  76#define TCR_ENAMODE_MASK             0x3
  77
  78#define TGCR_TIMMODE_SHIFT           2
  79#define TGCR_TIMMODE_64BIT_GP        0x0
  80#define TGCR_TIMMODE_32BIT_UNCHAINED 0x1
  81#define TGCR_TIMMODE_64BIT_WDOG      0x2
  82#define TGCR_TIMMODE_32BIT_CHAINED   0x3
  83
  84#define TGCR_TIM12RS_SHIFT           0
  85#define TGCR_TIM34RS_SHIFT           1
  86#define TGCR_RESET                   0x0
  87#define TGCR_UNRESET                 0x1
  88#define TGCR_RESET_MASK              0x3
  89
  90#define WDTCR_WDEN_SHIFT             14
  91#define WDTCR_WDEN_DISABLE           0x0
  92#define WDTCR_WDEN_ENABLE            0x1
  93#define WDTCR_WDKEY_SHIFT            16
  94#define WDTCR_WDKEY_SEQ0             0xa5c6
  95#define WDTCR_WDKEY_SEQ1             0xda7e
  96
  97struct timer_s {
  98        char *name;
  99        unsigned int id;
 100        unsigned long period;
 101        unsigned long opts;
 102        unsigned long reg_base;
 103        unsigned long tim_reg;
 104        unsigned long prd_reg;
 105        unsigned long enamode_shift;
 106        struct irqaction irqaction;
 107};
 108static struct timer_s timers[];
 109
 110/* values for 'opts' field of struct timer_s */
 111#define TIMER_OPTS_DISABLED   0x00
 112#define TIMER_OPTS_ONESHOT    0x01
 113#define TIMER_OPTS_PERIODIC   0x02
 114
 115static int timer32_config(struct timer_s *t)
 116{
 117        u32 tcr = davinci_readl(t->reg_base + TCR);
 118
 119        /* disable timer */
 120        tcr &= ~(TCR_ENAMODE_MASK << t->enamode_shift);
 121        davinci_writel(tcr, t->reg_base + TCR);
 122
 123        /* reset counter to zero, set new period */
 124        davinci_writel(0, t->tim_reg);
 125        davinci_writel(t->period, t->prd_reg);
 126
 127        /* Set enable mode */
 128        if (t->opts & TIMER_OPTS_ONESHOT) {
 129                tcr |= TCR_ENAMODE_ONESHOT << t->enamode_shift;
 130        } else if (t->opts & TIMER_OPTS_PERIODIC) {
 131                tcr |= TCR_ENAMODE_PERIODIC << t->enamode_shift;
 132        }
 133
 134        davinci_writel(tcr, t->reg_base + TCR);
 135        return 0;
 136}
 137
 138static inline u32 timer32_read(struct timer_s *t)
 139{
 140        return davinci_readl(t->tim_reg);
 141}
 142
 143static irqreturn_t timer_interrupt(int irq, void *dev_id)
 144{
 145        struct clock_event_device *evt = &clockevent_davinci;
 146
 147        evt->event_handler(evt);
 148        return IRQ_HANDLED;
 149}
 150
 151/* called when 32-bit counter wraps */
 152static irqreturn_t freerun_interrupt(int irq, void *dev_id)
 153{
 154        return IRQ_HANDLED;
 155}
 156
 157static struct timer_s timers[] = {
 158        [TID_CLOCKEVENT] = {
 159                .name      = "clockevent",
 160                .opts      = TIMER_OPTS_DISABLED,
 161                .irqaction = {
 162                        .flags   = IRQF_DISABLED | IRQF_TIMER,
 163                        .handler = timer_interrupt,
 164                }
 165        },
 166        [TID_CLOCKSOURCE] = {
 167                .name       = "free-run counter",
 168                .period     = ~0,
 169                .opts       = TIMER_OPTS_PERIODIC,
 170                .irqaction = {
 171                        .flags   = IRQF_DISABLED | IRQF_TIMER,
 172                        .handler = freerun_interrupt,
 173                }
 174        },
 175};
 176
 177static void __init timer_init(void)
 178{
 179        u32 bases[] = {DAVINCI_TIMER0_BASE, DAVINCI_TIMER1_BASE};
 180        int i;
 181
 182        /* Global init of each 64-bit timer as a whole */
 183        for(i=0; i<2; i++) {
 184                u32 tgcr, base = bases[i];
 185
 186                /* Disabled, Internal clock source */
 187                davinci_writel(0, base + TCR);
 188
 189                /* reset both timers, no pre-scaler for timer34 */
 190                tgcr = 0;
 191                davinci_writel(tgcr, base + TGCR);
 192
 193                /* Set both timers to unchained 32-bit */
 194                tgcr = TGCR_TIMMODE_32BIT_UNCHAINED << TGCR_TIMMODE_SHIFT;
 195                davinci_writel(tgcr, base + TGCR);
 196
 197                /* Unreset timers */
 198                tgcr |= (TGCR_UNRESET << TGCR_TIM12RS_SHIFT) |
 199                        (TGCR_UNRESET << TGCR_TIM34RS_SHIFT);
 200                davinci_writel(tgcr, base + TGCR);
 201
 202                /* Init both counters to zero */
 203                davinci_writel(0, base + TIM12);
 204                davinci_writel(0, base + TIM34);
 205        }
 206
 207        /* Init of each timer as a 32-bit timer */
 208        for (i=0; i< ARRAY_SIZE(timers); i++) {
 209                struct timer_s *t = &timers[i];
 210
 211                if (t->name) {
 212                        t->id = i;
 213                        t->reg_base = (IS_TIMER1(t->id) ?
 214                               DAVINCI_TIMER1_BASE : DAVINCI_TIMER0_BASE);
 215
 216                        if (IS_TIMER_BOT(t->id)) {
 217                                t->enamode_shift = 6;
 218                                t->tim_reg = t->reg_base + TIM12;
 219                                t->prd_reg = t->reg_base + PRD12;
 220                        } else {
 221                                t->enamode_shift = 22;
 222                                t->tim_reg = t->reg_base + TIM34;
 223                                t->prd_reg = t->reg_base + PRD34;
 224                        }
 225
 226                        /* Register interrupt */
 227                        t->irqaction.name = t->name;
 228                        t->irqaction.dev_id = (void *)t;
 229                        if (t->irqaction.handler != NULL) {
 230                                setup_irq(timer_irqs[t->id], &t->irqaction);
 231                        }
 232
 233                        timer32_config(&timers[i]);
 234                }
 235        }
 236}
 237
 238/*
 239 * clocksource
 240 */
 241static cycle_t read_cycles(void)
 242{
 243        struct timer_s *t = &timers[TID_CLOCKSOURCE];
 244
 245        return (cycles_t)timer32_read(t);
 246}
 247
 248static struct clocksource clocksource_davinci = {
 249        .name           = "timer0_1",
 250        .rating         = 300,
 251        .read           = read_cycles,
 252        .mask           = CLOCKSOURCE_MASK(32),
 253        .shift          = 24,
 254        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 255};
 256
 257/*
 258 * clockevent
 259 */
 260static int davinci_set_next_event(unsigned long cycles,
 261                                  struct clock_event_device *evt)
 262{
 263        struct timer_s *t = &timers[TID_CLOCKEVENT];
 264
 265        t->period = cycles;
 266        timer32_config(t);
 267        return 0;
 268}
 269
 270static void davinci_set_mode(enum clock_event_mode mode,
 271                             struct clock_event_device *evt)
 272{
 273        struct timer_s *t = &timers[TID_CLOCKEVENT];
 274
 275        switch (mode) {
 276        case CLOCK_EVT_MODE_PERIODIC:
 277                t->period = CLOCK_TICK_RATE / (HZ);
 278                t->opts = TIMER_OPTS_PERIODIC;
 279                timer32_config(t);
 280                break;
 281        case CLOCK_EVT_MODE_ONESHOT:
 282                t->opts = TIMER_OPTS_ONESHOT;
 283                break;
 284        case CLOCK_EVT_MODE_UNUSED:
 285        case CLOCK_EVT_MODE_SHUTDOWN:
 286                t->opts = TIMER_OPTS_DISABLED;
 287                break;
 288        case CLOCK_EVT_MODE_RESUME:
 289                break;
 290        }
 291}
 292
 293static struct clock_event_device clockevent_davinci = {
 294        .name           = "timer0_0",
 295        .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
 296        .shift          = 32,
 297        .set_next_event = davinci_set_next_event,
 298        .set_mode       = davinci_set_mode,
 299};
 300
 301
 302static void __init davinci_timer_init(void)
 303{
 304        static char err[] __initdata = KERN_ERR
 305                "%s: can't register clocksource!\n";
 306
 307        /* init timer hw */
 308        timer_init();
 309
 310        /* setup clocksource */
 311        clocksource_davinci.mult =
 312                clocksource_khz2mult(CLOCK_TICK_RATE/1000,
 313                                     clocksource_davinci.shift);
 314        if (clocksource_register(&clocksource_davinci))
 315                printk(err, clocksource_davinci.name);
 316
 317        /* setup clockevent */
 318        clockevent_davinci.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC,
 319                                         clockevent_davinci.shift);
 320        clockevent_davinci.max_delta_ns =
 321                clockevent_delta2ns(0xfffffffe, &clockevent_davinci);
 322        clockevent_davinci.min_delta_ns =
 323                clockevent_delta2ns(1, &clockevent_davinci);
 324
 325        clockevent_davinci.cpumask = cpumask_of_cpu(0);
 326        clockevents_register_device(&clockevent_davinci);
 327}
 328
 329struct sys_timer davinci_timer = {
 330        .init   = davinci_timer_init,
 331};
 332
 333
 334/* reset board using watchdog timer */
 335void davinci_watchdog_reset(void) {
 336        u32 tgcr, wdtcr, base = DAVINCI_WDOG_BASE;
 337
 338        /* disable, internal clock source */
 339        davinci_writel(0, base + TCR);
 340
 341        /* reset timer, set mode to 64-bit watchdog, and unreset */
 342        tgcr = 0;
 343        davinci_writel(tgcr, base + TCR);
 344        tgcr = TGCR_TIMMODE_64BIT_WDOG << TGCR_TIMMODE_SHIFT;
 345        tgcr |= (TGCR_UNRESET << TGCR_TIM12RS_SHIFT) |
 346                (TGCR_UNRESET << TGCR_TIM34RS_SHIFT);
 347        davinci_writel(tgcr, base + TCR);
 348
 349        /* clear counter and period regs */
 350        davinci_writel(0, base + TIM12);
 351        davinci_writel(0, base + TIM34);
 352        davinci_writel(0, base + PRD12);
 353        davinci_writel(0, base + PRD34);
 354
 355        /* enable */
 356        wdtcr = davinci_readl(base + WDTCR);
 357        wdtcr |= WDTCR_WDEN_ENABLE << WDTCR_WDEN_SHIFT;
 358        davinci_writel(wdtcr, base + WDTCR);
 359
 360        /* put watchdog in pre-active state */
 361        wdtcr = (WDTCR_WDKEY_SEQ0 << WDTCR_WDKEY_SHIFT) |
 362                (WDTCR_WDEN_ENABLE << WDTCR_WDEN_SHIFT);
 363        davinci_writel(wdtcr, base + WDTCR);
 364
 365        /* put watchdog in active state */
 366        wdtcr = (WDTCR_WDKEY_SEQ1 << WDTCR_WDKEY_SHIFT) |
 367                (WDTCR_WDEN_ENABLE << WDTCR_WDEN_SHIFT);
 368        davinci_writel(wdtcr, base + WDTCR);
 369
 370        /* write an invalid value to the WDKEY field to trigger
 371         * a watchdog reset */
 372        wdtcr = 0x00004000;
 373        davinci_writel(wdtcr, base + WDTCR);
 374}
 375