linux/arch/arm/mach-zynq/timer.c
<<
>>
Prefs
   1/*
   2 * This file contains driver for the Xilinx PS Timer Counter IP.
   3 *
   4 *  Copyright (C) 2011 Xilinx
   5 *
   6 * based on arch/mips/kernel/time.c timer driver
   7 *
   8 * This software is licensed under the terms of the GNU General Public
   9 * License version 2, as published by the Free Software Foundation, and
  10 * may be copied, distributed, and modified under those terms.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16 */
  17
  18#include <linux/kernel.h>
  19#include <linux/init.h>
  20#include <linux/interrupt.h>
  21#include <linux/irq.h>
  22#include <linux/types.h>
  23#include <linux/clocksource.h>
  24#include <linux/clockchips.h>
  25#include <linux/io.h>
  26
  27#include <asm/mach/time.h>
  28#include <mach/zynq_soc.h>
  29#include "common.h"
  30
  31#define IRQ_TIMERCOUNTER0       42
  32
  33/*
  34 * This driver configures the 2 16-bit count-up timers as follows:
  35 *
  36 * T1: Timer 1, clocksource for generic timekeeping
  37 * T2: Timer 2, clockevent source for hrtimers
  38 * T3: Timer 3, <unused>
  39 *
  40 * The input frequency to the timer module for emulation is 2.5MHz which is
  41 * common to all the timer channels (T1, T2, and T3). With a pre-scaler of 32,
  42 * the timers are clocked at 78.125KHz (12.8 us resolution).
  43 *
  44 * The input frequency to the timer module in silicon will be 200MHz. With the
  45 * pre-scaler of 32, the timers are clocked at 6.25MHz (160ns resolution).
  46 */
  47#define XTTCPSS_CLOCKSOURCE     0       /* Timer 1 as a generic timekeeping */
  48#define XTTCPSS_CLOCKEVENT      1       /* Timer 2 as a clock event */
  49
  50#define XTTCPSS_TIMER_BASE              TTC0_BASE
  51#define XTTCPCC_EVENT_TIMER_IRQ         (IRQ_TIMERCOUNTER0 + 1)
  52/*
  53 * Timer Register Offset Definitions of Timer 1, Increment base address by 4
  54 * and use same offsets for Timer 2
  55 */
  56#define XTTCPSS_CLK_CNTRL_OFFSET        0x00 /* Clock Control Reg, RW */
  57#define XTTCPSS_CNT_CNTRL_OFFSET        0x0C /* Counter Control Reg, RW */
  58#define XTTCPSS_COUNT_VAL_OFFSET        0x18 /* Counter Value Reg, RO */
  59#define XTTCPSS_INTR_VAL_OFFSET         0x24 /* Interval Count Reg, RW */
  60#define XTTCPSS_MATCH_1_OFFSET          0x30 /* Match 1 Value Reg, RW */
  61#define XTTCPSS_MATCH_2_OFFSET          0x3C /* Match 2 Value Reg, RW */
  62#define XTTCPSS_MATCH_3_OFFSET          0x48 /* Match 3 Value Reg, RW */
  63#define XTTCPSS_ISR_OFFSET              0x54 /* Interrupt Status Reg, RO */
  64#define XTTCPSS_IER_OFFSET              0x60 /* Interrupt Enable Reg, RW */
  65
  66#define XTTCPSS_CNT_CNTRL_DISABLE_MASK  0x1
  67
  68/* Setup the timers to use pre-scaling */
  69
  70#define TIMER_RATE (PERIPHERAL_CLOCK_RATE / 32)
  71
  72/**
  73 * struct xttcpss_timer - This definition defines local timer structure
  74 *
  75 * @base_addr:  Base address of timer
  76 **/
  77struct xttcpss_timer {
  78        void __iomem *base_addr;
  79};
  80
  81static struct xttcpss_timer timers[2];
  82static struct clock_event_device xttcpss_clockevent;
  83
  84/**
  85 * xttcpss_set_interval - Set the timer interval value
  86 *
  87 * @timer:      Pointer to the timer instance
  88 * @cycles:     Timer interval ticks
  89 **/
  90static void xttcpss_set_interval(struct xttcpss_timer *timer,
  91                                        unsigned long cycles)
  92{
  93        u32 ctrl_reg;
  94
  95        /* Disable the counter, set the counter value  and re-enable counter */
  96        ctrl_reg = __raw_readl(timer->base_addr + XTTCPSS_CNT_CNTRL_OFFSET);
  97        ctrl_reg |= XTTCPSS_CNT_CNTRL_DISABLE_MASK;
  98        __raw_writel(ctrl_reg, timer->base_addr + XTTCPSS_CNT_CNTRL_OFFSET);
  99
 100        __raw_writel(cycles, timer->base_addr + XTTCPSS_INTR_VAL_OFFSET);
 101
 102        /* Reset the counter (0x10) so that it starts from 0, one-shot
 103           mode makes this needed for timing to be right. */
 104        ctrl_reg |= 0x10;
 105        ctrl_reg &= ~XTTCPSS_CNT_CNTRL_DISABLE_MASK;
 106        __raw_writel(ctrl_reg, timer->base_addr + XTTCPSS_CNT_CNTRL_OFFSET);
 107}
 108
 109/**
 110 * xttcpss_clock_event_interrupt - Clock event timer interrupt handler
 111 *
 112 * @irq:        IRQ number of the Timer
 113 * @dev_id:     void pointer to the xttcpss_timer instance
 114 *
 115 * returns: Always IRQ_HANDLED - success
 116 **/
 117static irqreturn_t xttcpss_clock_event_interrupt(int irq, void *dev_id)
 118{
 119        struct clock_event_device *evt = &xttcpss_clockevent;
 120        struct xttcpss_timer *timer = dev_id;
 121
 122        /* Acknowledge the interrupt and call event handler */
 123        __raw_writel(__raw_readl(timer->base_addr + XTTCPSS_ISR_OFFSET),
 124                        timer->base_addr + XTTCPSS_ISR_OFFSET);
 125
 126        evt->event_handler(evt);
 127
 128        return IRQ_HANDLED;
 129}
 130
 131static struct irqaction event_timer_irq = {
 132        .name   = "xttcpss clockevent",
 133        .flags  = IRQF_DISABLED | IRQF_TIMER,
 134        .handler = xttcpss_clock_event_interrupt,
 135};
 136
 137/**
 138 * xttcpss_timer_hardware_init - Initialize the timer hardware
 139 *
 140 * Initialize the hardware to start the clock source, get the clock
 141 * event timer ready to use, and hook up the interrupt.
 142 **/
 143static void __init xttcpss_timer_hardware_init(void)
 144{
 145        /* Setup the clock source counter to be an incrementing counter
 146         * with no interrupt and it rolls over at 0xFFFF. Pre-scale
 147           it by 32 also. Let it start running now.
 148         */
 149        timers[XTTCPSS_CLOCKSOURCE].base_addr = XTTCPSS_TIMER_BASE;
 150
 151        __raw_writel(0x0, timers[XTTCPSS_CLOCKSOURCE].base_addr +
 152                                XTTCPSS_IER_OFFSET);
 153        __raw_writel(0x9, timers[XTTCPSS_CLOCKSOURCE].base_addr +
 154                                XTTCPSS_CLK_CNTRL_OFFSET);
 155        __raw_writel(0x10, timers[XTTCPSS_CLOCKSOURCE].base_addr +
 156                                XTTCPSS_CNT_CNTRL_OFFSET);
 157
 158        /* Setup the clock event timer to be an interval timer which
 159         * is prescaled by 32 using the interval interrupt. Leave it
 160         * disabled for now.
 161         */
 162
 163        timers[XTTCPSS_CLOCKEVENT].base_addr = XTTCPSS_TIMER_BASE + 4;
 164
 165        __raw_writel(0x23, timers[XTTCPSS_CLOCKEVENT].base_addr +
 166                        XTTCPSS_CNT_CNTRL_OFFSET);
 167        __raw_writel(0x9, timers[XTTCPSS_CLOCKEVENT].base_addr +
 168                        XTTCPSS_CLK_CNTRL_OFFSET);
 169        __raw_writel(0x1, timers[XTTCPSS_CLOCKEVENT].base_addr +
 170                        XTTCPSS_IER_OFFSET);
 171
 172        /* Setup IRQ the clock event timer */
 173        event_timer_irq.dev_id = &timers[XTTCPSS_CLOCKEVENT];
 174        setup_irq(XTTCPCC_EVENT_TIMER_IRQ, &event_timer_irq);
 175}
 176
 177/**
 178 * __raw_readl_cycles - Reads the timer counter register
 179 *
 180 * returns: Current timer counter register value
 181 **/
 182static cycle_t __raw_readl_cycles(struct clocksource *cs)
 183{
 184        struct xttcpss_timer *timer = &timers[XTTCPSS_CLOCKSOURCE];
 185
 186        return (cycle_t)__raw_readl(timer->base_addr +
 187                                XTTCPSS_COUNT_VAL_OFFSET);
 188}
 189
 190
 191/*
 192 * Instantiate and initialize the clock source structure
 193 */
 194static struct clocksource clocksource_xttcpss = {
 195        .name           = "xttcpss_timer1",
 196        .rating         = 200,                  /* Reasonable clock source */
 197        .read           = __raw_readl_cycles,
 198        .mask           = CLOCKSOURCE_MASK(16),
 199        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 200};
 201
 202
 203/**
 204 * xttcpss_set_next_event - Sets the time interval for next event
 205 *
 206 * @cycles:     Timer interval ticks
 207 * @evt:        Address of clock event instance
 208 *
 209 * returns: Always 0 - success
 210 **/
 211static int xttcpss_set_next_event(unsigned long cycles,
 212                                        struct clock_event_device *evt)
 213{
 214        struct xttcpss_timer *timer = &timers[XTTCPSS_CLOCKEVENT];
 215
 216        xttcpss_set_interval(timer, cycles);
 217        return 0;
 218}
 219
 220/**
 221 * xttcpss_set_mode - Sets the mode of timer
 222 *
 223 * @mode:       Mode to be set
 224 * @evt:        Address of clock event instance
 225 **/
 226static void xttcpss_set_mode(enum clock_event_mode mode,
 227                                        struct clock_event_device *evt)
 228{
 229        struct xttcpss_timer *timer = &timers[XTTCPSS_CLOCKEVENT];
 230        u32 ctrl_reg;
 231
 232        switch (mode) {
 233        case CLOCK_EVT_MODE_PERIODIC:
 234                xttcpss_set_interval(timer, TIMER_RATE / HZ);
 235                break;
 236        case CLOCK_EVT_MODE_ONESHOT:
 237        case CLOCK_EVT_MODE_UNUSED:
 238        case CLOCK_EVT_MODE_SHUTDOWN:
 239                ctrl_reg = __raw_readl(timer->base_addr +
 240                                        XTTCPSS_CNT_CNTRL_OFFSET);
 241                ctrl_reg |= XTTCPSS_CNT_CNTRL_DISABLE_MASK;
 242                __raw_writel(ctrl_reg,
 243                                timer->base_addr + XTTCPSS_CNT_CNTRL_OFFSET);
 244                break;
 245        case CLOCK_EVT_MODE_RESUME:
 246                ctrl_reg = __raw_readl(timer->base_addr +
 247                                        XTTCPSS_CNT_CNTRL_OFFSET);
 248                ctrl_reg &= ~XTTCPSS_CNT_CNTRL_DISABLE_MASK;
 249                __raw_writel(ctrl_reg,
 250                                timer->base_addr + XTTCPSS_CNT_CNTRL_OFFSET);
 251                break;
 252        }
 253}
 254
 255/*
 256 * Instantiate and initialize the clock event structure
 257 */
 258static struct clock_event_device xttcpss_clockevent = {
 259        .name           = "xttcpss_timer2",
 260        .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
 261        .set_next_event = xttcpss_set_next_event,
 262        .set_mode       = xttcpss_set_mode,
 263        .rating         = 200,
 264};
 265
 266/**
 267 * xttcpss_timer_init - Initialize the timer
 268 *
 269 * Initializes the timer hardware and register the clock source and clock event
 270 * timers with Linux kernal timer framework
 271 **/
 272static void __init xttcpss_timer_init(void)
 273{
 274        xttcpss_timer_hardware_init();
 275        clocksource_register_hz(&clocksource_xttcpss, TIMER_RATE);
 276
 277        /* Calculate the parameters to allow the clockevent to operate using
 278           integer math
 279        */
 280        clockevents_calc_mult_shift(&xttcpss_clockevent, TIMER_RATE, 4);
 281
 282        xttcpss_clockevent.max_delta_ns =
 283                clockevent_delta2ns(0xfffe, &xttcpss_clockevent);
 284        xttcpss_clockevent.min_delta_ns =
 285                clockevent_delta2ns(1, &xttcpss_clockevent);
 286
 287        /* Indicate that clock event is on 1st CPU as SMP boot needs it */
 288
 289        xttcpss_clockevent.cpumask = cpumask_of(0);
 290        clockevents_register_device(&xttcpss_clockevent);
 291}
 292
 293/*
 294 * Instantiate and initialize the system timer structure
 295 */
 296struct sys_timer xttcpss_sys_timer = {
 297        .init           = xttcpss_timer_init,
 298};
 299