linux/arch/arm/mach-gemini/time.c
<<
>>
Prefs
   1/*
   2 *  Copyright (C) 2001-2006 Storlink, Corp.
   3 *  Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License as published by
   7 * the Free Software Foundation; either version 2 of the License, or
   8 * (at your option) any later version.
   9 */
  10#include <linux/interrupt.h>
  11#include <linux/irq.h>
  12#include <linux/io.h>
  13#include <mach/hardware.h>
  14#include <mach/global_reg.h>
  15#include <asm/mach/time.h>
  16#include <linux/clockchips.h>
  17#include <linux/clocksource.h>
  18#include <linux/sched_clock.h>
  19
  20/*
  21 * Register definitions for the timers
  22 */
  23
  24#define TIMER1_BASE             GEMINI_TIMER_BASE
  25#define TIMER2_BASE             (GEMINI_TIMER_BASE + 0x10)
  26#define TIMER3_BASE             (GEMINI_TIMER_BASE + 0x20)
  27
  28#define TIMER_COUNT(BASE)       (IO_ADDRESS(BASE) + 0x00)
  29#define TIMER_LOAD(BASE)        (IO_ADDRESS(BASE) + 0x04)
  30#define TIMER_MATCH1(BASE)      (IO_ADDRESS(BASE) + 0x08)
  31#define TIMER_MATCH2(BASE)      (IO_ADDRESS(BASE) + 0x0C)
  32#define TIMER_CR                (IO_ADDRESS(GEMINI_TIMER_BASE) + 0x30)
  33#define TIMER_INTR_STATE        (IO_ADDRESS(GEMINI_TIMER_BASE) + 0x34)
  34#define TIMER_INTR_MASK         (IO_ADDRESS(GEMINI_TIMER_BASE) + 0x38)
  35
  36#define TIMER_1_CR_ENABLE       (1 << 0)
  37#define TIMER_1_CR_CLOCK        (1 << 1)
  38#define TIMER_1_CR_INT          (1 << 2)
  39#define TIMER_2_CR_ENABLE       (1 << 3)
  40#define TIMER_2_CR_CLOCK        (1 << 4)
  41#define TIMER_2_CR_INT          (1 << 5)
  42#define TIMER_3_CR_ENABLE       (1 << 6)
  43#define TIMER_3_CR_CLOCK        (1 << 7)
  44#define TIMER_3_CR_INT          (1 << 8)
  45#define TIMER_1_CR_UPDOWN       (1 << 9)
  46#define TIMER_2_CR_UPDOWN       (1 << 10)
  47#define TIMER_3_CR_UPDOWN       (1 << 11)
  48#define TIMER_DEFAULT_FLAGS     (TIMER_1_CR_UPDOWN | \
  49                                 TIMER_3_CR_ENABLE | \
  50                                 TIMER_3_CR_UPDOWN)
  51
  52#define TIMER_1_INT_MATCH1      (1 << 0)
  53#define TIMER_1_INT_MATCH2      (1 << 1)
  54#define TIMER_1_INT_OVERFLOW    (1 << 2)
  55#define TIMER_2_INT_MATCH1      (1 << 3)
  56#define TIMER_2_INT_MATCH2      (1 << 4)
  57#define TIMER_2_INT_OVERFLOW    (1 << 5)
  58#define TIMER_3_INT_MATCH1      (1 << 6)
  59#define TIMER_3_INT_MATCH2      (1 << 7)
  60#define TIMER_3_INT_OVERFLOW    (1 << 8)
  61#define TIMER_INT_ALL_MASK      0x1ff
  62
  63
  64static unsigned int tick_rate;
  65
  66static u64 notrace gemini_read_sched_clock(void)
  67{
  68        return readl(TIMER_COUNT(TIMER3_BASE));
  69}
  70
  71static int gemini_timer_set_next_event(unsigned long cycles,
  72                                       struct clock_event_device *evt)
  73{
  74        u32 cr;
  75
  76        /* Setup the match register */
  77        cr = readl(TIMER_COUNT(TIMER1_BASE));
  78        writel(cr + cycles, TIMER_MATCH1(TIMER1_BASE));
  79        if (readl(TIMER_COUNT(TIMER1_BASE)) - cr > cycles)
  80                return -ETIME;
  81
  82        return 0;
  83}
  84
  85static int gemini_timer_shutdown(struct clock_event_device *evt)
  86{
  87        u32 cr;
  88
  89        /*
  90         * Disable also for oneshot: the set_next() call will arm the timer
  91         * instead.
  92         */
  93        /* Stop timer and interrupt. */
  94        cr = readl(TIMER_CR);
  95        cr &= ~(TIMER_1_CR_ENABLE | TIMER_1_CR_INT);
  96        writel(cr, TIMER_CR);
  97
  98        /* Setup counter start from 0 */
  99        writel(0, TIMER_COUNT(TIMER1_BASE));
 100        writel(0, TIMER_LOAD(TIMER1_BASE));
 101
 102        /* enable interrupt */
 103        cr = readl(TIMER_INTR_MASK);
 104        cr &= ~(TIMER_1_INT_OVERFLOW | TIMER_1_INT_MATCH2);
 105        cr |= TIMER_1_INT_MATCH1;
 106        writel(cr, TIMER_INTR_MASK);
 107
 108        /* start the timer */
 109        cr = readl(TIMER_CR);
 110        cr |= TIMER_1_CR_ENABLE;
 111        writel(cr, TIMER_CR);
 112
 113        return 0;
 114}
 115
 116static int gemini_timer_set_periodic(struct clock_event_device *evt)
 117{
 118        u32 period = DIV_ROUND_CLOSEST(tick_rate, HZ);
 119        u32 cr;
 120
 121        /* Stop timer and interrupt */
 122        cr = readl(TIMER_CR);
 123        cr &= ~(TIMER_1_CR_ENABLE | TIMER_1_CR_INT);
 124        writel(cr, TIMER_CR);
 125
 126        /* Setup timer to fire at 1/HT intervals. */
 127        cr = 0xffffffff - (period - 1);
 128        writel(cr, TIMER_COUNT(TIMER1_BASE));
 129        writel(cr, TIMER_LOAD(TIMER1_BASE));
 130
 131        /* enable interrupt on overflow */
 132        cr = readl(TIMER_INTR_MASK);
 133        cr &= ~(TIMER_1_INT_MATCH1 | TIMER_1_INT_MATCH2);
 134        cr |= TIMER_1_INT_OVERFLOW;
 135        writel(cr, TIMER_INTR_MASK);
 136
 137        /* Start the timer */
 138        cr = readl(TIMER_CR);
 139        cr |= TIMER_1_CR_ENABLE;
 140        cr |= TIMER_1_CR_INT;
 141        writel(cr, TIMER_CR);
 142
 143        return 0;
 144}
 145
 146/* Use TIMER1 as clock event */
 147static struct clock_event_device gemini_clockevent = {
 148        .name                   = "TIMER1",
 149        /* Reasonably fast and accurate clock event */
 150        .rating                 = 300,
 151        .shift                  = 32,
 152        .features               = CLOCK_EVT_FEAT_PERIODIC |
 153                                  CLOCK_EVT_FEAT_ONESHOT,
 154        .set_next_event         = gemini_timer_set_next_event,
 155        .set_state_shutdown     = gemini_timer_shutdown,
 156        .set_state_periodic     = gemini_timer_set_periodic,
 157        .set_state_oneshot      = gemini_timer_shutdown,
 158        .tick_resume            = gemini_timer_shutdown,
 159};
 160
 161/*
 162 * IRQ handler for the timer
 163 */
 164static irqreturn_t gemini_timer_interrupt(int irq, void *dev_id)
 165{
 166        struct clock_event_device *evt = &gemini_clockevent;
 167
 168        evt->event_handler(evt);
 169        return IRQ_HANDLED;
 170}
 171
 172static struct irqaction gemini_timer_irq = {
 173        .name           = "Gemini Timer Tick",
 174        .flags          = IRQF_TIMER,
 175        .handler        = gemini_timer_interrupt,
 176};
 177
 178/*
 179 * Set up timer interrupt, and return the current time in seconds.
 180 */
 181void __init gemini_timer_init(void)
 182{
 183        u32 reg_v;
 184
 185        reg_v = readl(IO_ADDRESS(GEMINI_GLOBAL_BASE + GLOBAL_STATUS));
 186        tick_rate = REG_TO_AHB_SPEED(reg_v) * 1000000;
 187
 188        printk(KERN_INFO "Bus: %dMHz", tick_rate / 1000000);
 189
 190        tick_rate /= 6;         /* APB bus run AHB*(1/6) */
 191
 192        switch(reg_v & CPU_AHB_RATIO_MASK) {
 193        case CPU_AHB_1_1:
 194                printk(KERN_CONT "(1/1)\n");
 195                break;
 196        case CPU_AHB_3_2:
 197                printk(KERN_CONT "(3/2)\n");
 198                break;
 199        case CPU_AHB_24_13:
 200                printk(KERN_CONT "(24/13)\n");
 201                break;
 202        case CPU_AHB_2_1:
 203                printk(KERN_CONT "(2/1)\n");
 204                break;
 205        }
 206
 207        /*
 208         * Reset the interrupt mask and status
 209         */
 210        writel(TIMER_INT_ALL_MASK, TIMER_INTR_MASK);
 211        writel(0, TIMER_INTR_STATE);
 212        writel(TIMER_DEFAULT_FLAGS, TIMER_CR);
 213
 214        /*
 215         * Setup free-running clocksource timer (interrupts
 216         * disabled.)
 217         */
 218        writel(0, TIMER_COUNT(TIMER3_BASE));
 219        writel(0, TIMER_LOAD(TIMER3_BASE));
 220        writel(0, TIMER_MATCH1(TIMER3_BASE));
 221        writel(0, TIMER_MATCH2(TIMER3_BASE));
 222        clocksource_mmio_init(TIMER_COUNT(TIMER3_BASE),
 223                              "gemini_clocksource", tick_rate,
 224                              300, 32, clocksource_mmio_readl_up);
 225        sched_clock_register(gemini_read_sched_clock, 32, tick_rate);
 226
 227        /*
 228         * Setup clockevent timer (interrupt-driven.)
 229        */
 230        writel(0, TIMER_COUNT(TIMER1_BASE));
 231        writel(0, TIMER_LOAD(TIMER1_BASE));
 232        writel(0, TIMER_MATCH1(TIMER1_BASE));
 233        writel(0, TIMER_MATCH2(TIMER1_BASE));
 234        setup_irq(IRQ_TIMER1, &gemini_timer_irq);
 235        gemini_clockevent.cpumask = cpumask_of(0);
 236        clockevents_config_and_register(&gemini_clockevent, tick_rate,
 237                                        1, 0xffffffff);
 238
 239}
 240