linux/drivers/clocksource/dw_apb_timer.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2009 Intel Corporation
   3 * Author: Jacob Pan (jacob.jun.pan@intel.com)
   4 *
   5 * Shared with ARM platforms, Jamie Iles, Picochip 2011
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 *
  11 * Support for the Synopsys DesignWare APB Timers.
  12 */
  13#include <linux/dw_apb_timer.h>
  14#include <linux/delay.h>
  15#include <linux/kernel.h>
  16#include <linux/interrupt.h>
  17#include <linux/irq.h>
  18#include <linux/io.h>
  19#include <linux/slab.h>
  20
  21#define APBT_MIN_PERIOD                 4
  22#define APBT_MIN_DELTA_USEC             200
  23
  24#define APBTMR_N_LOAD_COUNT             0x00
  25#define APBTMR_N_CURRENT_VALUE          0x04
  26#define APBTMR_N_CONTROL                0x08
  27#define APBTMR_N_EOI                    0x0c
  28#define APBTMR_N_INT_STATUS             0x10
  29
  30#define APBTMRS_INT_STATUS              0xa0
  31#define APBTMRS_EOI                     0xa4
  32#define APBTMRS_RAW_INT_STATUS          0xa8
  33#define APBTMRS_COMP_VERSION            0xac
  34
  35#define APBTMR_CONTROL_ENABLE           (1 << 0)
  36/* 1: periodic, 0:free running. */
  37#define APBTMR_CONTROL_MODE_PERIODIC    (1 << 1)
  38#define APBTMR_CONTROL_INT              (1 << 2)
  39
  40static inline struct dw_apb_clock_event_device *
  41ced_to_dw_apb_ced(struct clock_event_device *evt)
  42{
  43        return container_of(evt, struct dw_apb_clock_event_device, ced);
  44}
  45
  46static inline struct dw_apb_clocksource *
  47clocksource_to_dw_apb_clocksource(struct clocksource *cs)
  48{
  49        return container_of(cs, struct dw_apb_clocksource, cs);
  50}
  51
  52static unsigned long apbt_readl(struct dw_apb_timer *timer, unsigned long offs)
  53{
  54        return readl(timer->base + offs);
  55}
  56
  57static void apbt_writel(struct dw_apb_timer *timer, unsigned long val,
  58                 unsigned long offs)
  59{
  60        writel(val, timer->base + offs);
  61}
  62
  63static void apbt_disable_int(struct dw_apb_timer *timer)
  64{
  65        unsigned long ctrl = apbt_readl(timer, APBTMR_N_CONTROL);
  66
  67        ctrl |= APBTMR_CONTROL_INT;
  68        apbt_writel(timer, ctrl, APBTMR_N_CONTROL);
  69}
  70
  71/**
  72 * dw_apb_clockevent_pause() - stop the clock_event_device from running
  73 *
  74 * @dw_ced:     The APB clock to stop generating events.
  75 */
  76void dw_apb_clockevent_pause(struct dw_apb_clock_event_device *dw_ced)
  77{
  78        disable_irq(dw_ced->timer.irq);
  79        apbt_disable_int(&dw_ced->timer);
  80}
  81
  82static void apbt_eoi(struct dw_apb_timer *timer)
  83{
  84        apbt_readl(timer, APBTMR_N_EOI);
  85}
  86
  87static irqreturn_t dw_apb_clockevent_irq(int irq, void *data)
  88{
  89        struct clock_event_device *evt = data;
  90        struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt);
  91
  92        if (!evt->event_handler) {
  93                pr_info("Spurious APBT timer interrupt %d", irq);
  94                return IRQ_NONE;
  95        }
  96
  97        if (dw_ced->eoi)
  98                dw_ced->eoi(&dw_ced->timer);
  99
 100        evt->event_handler(evt);
 101        return IRQ_HANDLED;
 102}
 103
 104static void apbt_enable_int(struct dw_apb_timer *timer)
 105{
 106        unsigned long ctrl = apbt_readl(timer, APBTMR_N_CONTROL);
 107        /* clear pending intr */
 108        apbt_readl(timer, APBTMR_N_EOI);
 109        ctrl &= ~APBTMR_CONTROL_INT;
 110        apbt_writel(timer, ctrl, APBTMR_N_CONTROL);
 111}
 112
 113static void apbt_set_mode(enum clock_event_mode mode,
 114                          struct clock_event_device *evt)
 115{
 116        unsigned long ctrl;
 117        unsigned long period;
 118        struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt);
 119
 120        pr_debug("%s CPU %d mode=%d\n", __func__, first_cpu(*evt->cpumask),
 121                 mode);
 122
 123        switch (mode) {
 124        case CLOCK_EVT_MODE_PERIODIC:
 125                period = DIV_ROUND_UP(dw_ced->timer.freq, HZ);
 126                ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL);
 127                ctrl |= APBTMR_CONTROL_MODE_PERIODIC;
 128                apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL);
 129                /*
 130                 * DW APB p. 46, have to disable timer before load counter,
 131                 * may cause sync problem.
 132                 */
 133                ctrl &= ~APBTMR_CONTROL_ENABLE;
 134                apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL);
 135                udelay(1);
 136                pr_debug("Setting clock period %lu for HZ %d\n", period, HZ);
 137                apbt_writel(&dw_ced->timer, period, APBTMR_N_LOAD_COUNT);
 138                ctrl |= APBTMR_CONTROL_ENABLE;
 139                apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL);
 140                break;
 141
 142        case CLOCK_EVT_MODE_ONESHOT:
 143                ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL);
 144                /*
 145                 * set free running mode, this mode will let timer reload max
 146                 * timeout which will give time (3min on 25MHz clock) to rearm
 147                 * the next event, therefore emulate the one-shot mode.
 148                 */
 149                ctrl &= ~APBTMR_CONTROL_ENABLE;
 150                ctrl &= ~APBTMR_CONTROL_MODE_PERIODIC;
 151
 152                apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL);
 153                /* write again to set free running mode */
 154                apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL);
 155
 156                /*
 157                 * DW APB p. 46, load counter with all 1s before starting free
 158                 * running mode.
 159                 */
 160                apbt_writel(&dw_ced->timer, ~0, APBTMR_N_LOAD_COUNT);
 161                ctrl &= ~APBTMR_CONTROL_INT;
 162                ctrl |= APBTMR_CONTROL_ENABLE;
 163                apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL);
 164                break;
 165
 166        case CLOCK_EVT_MODE_UNUSED:
 167        case CLOCK_EVT_MODE_SHUTDOWN:
 168                ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL);
 169                ctrl &= ~APBTMR_CONTROL_ENABLE;
 170                apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL);
 171                break;
 172
 173        case CLOCK_EVT_MODE_RESUME:
 174                apbt_enable_int(&dw_ced->timer);
 175                break;
 176        }
 177}
 178
 179static int apbt_next_event(unsigned long delta,
 180                           struct clock_event_device *evt)
 181{
 182        unsigned long ctrl;
 183        struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt);
 184
 185        /* Disable timer */
 186        ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL);
 187        ctrl &= ~APBTMR_CONTROL_ENABLE;
 188        apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL);
 189        /* write new count */
 190        apbt_writel(&dw_ced->timer, delta, APBTMR_N_LOAD_COUNT);
 191        ctrl |= APBTMR_CONTROL_ENABLE;
 192        apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL);
 193
 194        return 0;
 195}
 196
 197/**
 198 * dw_apb_clockevent_init() - use an APB timer as a clock_event_device
 199 *
 200 * @cpu:        The CPU the events will be targeted at.
 201 * @name:       The name used for the timer and the IRQ for it.
 202 * @rating:     The rating to give the timer.
 203 * @base:       I/O base for the timer registers.
 204 * @irq:        The interrupt number to use for the timer.
 205 * @freq:       The frequency that the timer counts at.
 206 *
 207 * This creates a clock_event_device for using with the generic clock layer
 208 * but does not start and register it.  This should be done with
 209 * dw_apb_clockevent_register() as the next step.  If this is the first time
 210 * it has been called for a timer then the IRQ will be requested, if not it
 211 * just be enabled to allow CPU hotplug to avoid repeatedly requesting and
 212 * releasing the IRQ.
 213 */
 214struct dw_apb_clock_event_device *
 215dw_apb_clockevent_init(int cpu, const char *name, unsigned rating,
 216                       void __iomem *base, int irq, unsigned long freq)
 217{
 218        struct dw_apb_clock_event_device *dw_ced =
 219                kzalloc(sizeof(*dw_ced), GFP_KERNEL);
 220        int err;
 221
 222        if (!dw_ced)
 223                return NULL;
 224
 225        dw_ced->timer.base = base;
 226        dw_ced->timer.irq = irq;
 227        dw_ced->timer.freq = freq;
 228
 229        clockevents_calc_mult_shift(&dw_ced->ced, freq, APBT_MIN_PERIOD);
 230        dw_ced->ced.max_delta_ns = clockevent_delta2ns(0x7fffffff,
 231                                                       &dw_ced->ced);
 232        dw_ced->ced.min_delta_ns = clockevent_delta2ns(5000, &dw_ced->ced);
 233        dw_ced->ced.cpumask = cpumask_of(cpu);
 234        dw_ced->ced.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
 235        dw_ced->ced.set_mode = apbt_set_mode;
 236        dw_ced->ced.set_next_event = apbt_next_event;
 237        dw_ced->ced.irq = dw_ced->timer.irq;
 238        dw_ced->ced.rating = rating;
 239        dw_ced->ced.name = name;
 240
 241        dw_ced->irqaction.name          = dw_ced->ced.name;
 242        dw_ced->irqaction.handler       = dw_apb_clockevent_irq;
 243        dw_ced->irqaction.dev_id        = &dw_ced->ced;
 244        dw_ced->irqaction.irq           = irq;
 245        dw_ced->irqaction.flags         = IRQF_TIMER | IRQF_IRQPOLL |
 246                                          IRQF_NOBALANCING |
 247                                          IRQF_DISABLED;
 248
 249        dw_ced->eoi = apbt_eoi;
 250        err = setup_irq(irq, &dw_ced->irqaction);
 251        if (err) {
 252                pr_err("failed to request timer irq\n");
 253                kfree(dw_ced);
 254                dw_ced = NULL;
 255        }
 256
 257        return dw_ced;
 258}
 259
 260/**
 261 * dw_apb_clockevent_resume() - resume a clock that has been paused.
 262 *
 263 * @dw_ced:     The APB clock to resume.
 264 */
 265void dw_apb_clockevent_resume(struct dw_apb_clock_event_device *dw_ced)
 266{
 267        enable_irq(dw_ced->timer.irq);
 268}
 269
 270/**
 271 * dw_apb_clockevent_stop() - stop the clock_event_device and release the IRQ.
 272 *
 273 * @dw_ced:     The APB clock to stop generating the events.
 274 */
 275void dw_apb_clockevent_stop(struct dw_apb_clock_event_device *dw_ced)
 276{
 277        free_irq(dw_ced->timer.irq, &dw_ced->ced);
 278}
 279
 280/**
 281 * dw_apb_clockevent_register() - register the clock with the generic layer
 282 *
 283 * @dw_ced:     The APB clock to register as a clock_event_device.
 284 */
 285void dw_apb_clockevent_register(struct dw_apb_clock_event_device *dw_ced)
 286{
 287        apbt_writel(&dw_ced->timer, 0, APBTMR_N_CONTROL);
 288        clockevents_register_device(&dw_ced->ced);
 289        apbt_enable_int(&dw_ced->timer);
 290}
 291
 292/**
 293 * dw_apb_clocksource_start() - start the clocksource counting.
 294 *
 295 * @dw_cs:      The clocksource to start.
 296 *
 297 * This is used to start the clocksource before registration and can be used
 298 * to enable calibration of timers.
 299 */
 300void dw_apb_clocksource_start(struct dw_apb_clocksource *dw_cs)
 301{
 302        /*
 303         * start count down from 0xffff_ffff. this is done by toggling the
 304         * enable bit then load initial load count to ~0.
 305         */
 306        unsigned long ctrl = apbt_readl(&dw_cs->timer, APBTMR_N_CONTROL);
 307
 308        ctrl &= ~APBTMR_CONTROL_ENABLE;
 309        apbt_writel(&dw_cs->timer, ctrl, APBTMR_N_CONTROL);
 310        apbt_writel(&dw_cs->timer, ~0, APBTMR_N_LOAD_COUNT);
 311        /* enable, mask interrupt */
 312        ctrl &= ~APBTMR_CONTROL_MODE_PERIODIC;
 313        ctrl |= (APBTMR_CONTROL_ENABLE | APBTMR_CONTROL_INT);
 314        apbt_writel(&dw_cs->timer, ctrl, APBTMR_N_CONTROL);
 315        /* read it once to get cached counter value initialized */
 316        dw_apb_clocksource_read(dw_cs);
 317}
 318
 319static cycle_t __apbt_read_clocksource(struct clocksource *cs)
 320{
 321        unsigned long current_count;
 322        struct dw_apb_clocksource *dw_cs =
 323                clocksource_to_dw_apb_clocksource(cs);
 324
 325        current_count = apbt_readl(&dw_cs->timer, APBTMR_N_CURRENT_VALUE);
 326
 327        return (cycle_t)~current_count;
 328}
 329
 330static void apbt_restart_clocksource(struct clocksource *cs)
 331{
 332        struct dw_apb_clocksource *dw_cs =
 333                clocksource_to_dw_apb_clocksource(cs);
 334
 335        dw_apb_clocksource_start(dw_cs);
 336}
 337
 338/**
 339 * dw_apb_clocksource_init() - use an APB timer as a clocksource.
 340 *
 341 * @rating:     The rating to give the clocksource.
 342 * @name:       The name for the clocksource.
 343 * @base:       The I/O base for the timer registers.
 344 * @freq:       The frequency that the timer counts at.
 345 *
 346 * This creates a clocksource using an APB timer but does not yet register it
 347 * with the clocksource system.  This should be done with
 348 * dw_apb_clocksource_register() as the next step.
 349 */
 350struct dw_apb_clocksource *
 351dw_apb_clocksource_init(unsigned rating, const char *name, void __iomem *base,
 352                        unsigned long freq)
 353{
 354        struct dw_apb_clocksource *dw_cs = kzalloc(sizeof(*dw_cs), GFP_KERNEL);
 355
 356        if (!dw_cs)
 357                return NULL;
 358
 359        dw_cs->timer.base = base;
 360        dw_cs->timer.freq = freq;
 361        dw_cs->cs.name = name;
 362        dw_cs->cs.rating = rating;
 363        dw_cs->cs.read = __apbt_read_clocksource;
 364        dw_cs->cs.mask = CLOCKSOURCE_MASK(32);
 365        dw_cs->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS;
 366        dw_cs->cs.resume = apbt_restart_clocksource;
 367
 368        return dw_cs;
 369}
 370
 371/**
 372 * dw_apb_clocksource_register() - register the APB clocksource.
 373 *
 374 * @dw_cs:      The clocksource to register.
 375 */
 376void dw_apb_clocksource_register(struct dw_apb_clocksource *dw_cs)
 377{
 378        clocksource_register_hz(&dw_cs->cs, dw_cs->timer.freq);
 379}
 380
 381/**
 382 * dw_apb_clocksource_read() - read the current value of a clocksource.
 383 *
 384 * @dw_cs:      The clocksource to read.
 385 */
 386cycle_t dw_apb_clocksource_read(struct dw_apb_clocksource *dw_cs)
 387{
 388        return (cycle_t)~apbt_readl(&dw_cs->timer, APBTMR_N_CURRENT_VALUE);
 389}
 390
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.