linux/drivers/clocksource/mxs_timer.c
<<
>>
Prefs
   1/*
   2 *  Copyright (C) 2000-2001 Deep Blue Solutions
   3 *  Copyright (C) 2002 Shane Nay (shane@minirl.com)
   4 *  Copyright (C) 2006-2007 Pavel Pisa (ppisa@pikron.com)
   5 *  Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de)
   6 *  Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved.
   7 *
   8 * This program is free software; you can redistribute it and/or
   9 * modify it under the terms of the GNU General Public License
  10 * as published by the Free Software Foundation; either version 2
  11 * of the License, or (at your option) any later version.
  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 * You should have received a copy of the GNU General Public License
  18 * along with this program; if not, write to the Free Software
  19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  20 * MA 02110-1301, USA.
  21 */
  22
  23#include <linux/err.h>
  24#include <linux/interrupt.h>
  25#include <linux/irq.h>
  26#include <linux/clockchips.h>
  27#include <linux/clk.h>
  28#include <linux/of.h>
  29#include <linux/of_address.h>
  30#include <linux/of_irq.h>
  31#include <linux/stmp_device.h>
  32
  33#include <asm/mach/time.h>
  34#include <asm/sched_clock.h>
  35
  36/*
  37 * There are 2 versions of the timrot on Freescale MXS-based SoCs.
  38 * The v1 on MX23 only gets 16 bits counter, while v2 on MX28
  39 * extends the counter to 32 bits.
  40 *
  41 * The implementation uses two timers, one for clock_event and
  42 * another for clocksource. MX28 uses timrot 0 and 1, while MX23
  43 * uses 0 and 2.
  44 */
  45
  46#define MX23_TIMROT_VERSION_OFFSET      0x0a0
  47#define MX28_TIMROT_VERSION_OFFSET      0x120
  48#define BP_TIMROT_MAJOR_VERSION         24
  49#define BV_TIMROT_VERSION_1             0x01
  50#define BV_TIMROT_VERSION_2             0x02
  51#define timrot_is_v1()  (timrot_major_version == BV_TIMROT_VERSION_1)
  52
  53/*
  54 * There are 4 registers for each timrotv2 instance, and 2 registers
  55 * for each timrotv1. So address step 0x40 in macros below strides
  56 * one instance of timrotv2 while two instances of timrotv1.
  57 *
  58 * As the result, HW_TIMROT_XXXn(1) defines the address of timrot1
  59 * on MX28 while timrot2 on MX23.
  60 */
  61/* common between v1 and v2 */
  62#define HW_TIMROT_ROTCTRL               0x00
  63#define HW_TIMROT_TIMCTRLn(n)           (0x20 + (n) * 0x40)
  64/* v1 only */
  65#define HW_TIMROT_TIMCOUNTn(n)          (0x30 + (n) * 0x40)
  66/* v2 only */
  67#define HW_TIMROT_RUNNING_COUNTn(n)     (0x30 + (n) * 0x40)
  68#define HW_TIMROT_FIXED_COUNTn(n)       (0x40 + (n) * 0x40)
  69
  70#define BM_TIMROT_TIMCTRLn_RELOAD       (1 << 6)
  71#define BM_TIMROT_TIMCTRLn_UPDATE       (1 << 7)
  72#define BM_TIMROT_TIMCTRLn_IRQ_EN       (1 << 14)
  73#define BM_TIMROT_TIMCTRLn_IRQ          (1 << 15)
  74#define BP_TIMROT_TIMCTRLn_SELECT       0
  75#define BV_TIMROTv1_TIMCTRLn_SELECT__32KHZ_XTAL         0x8
  76#define BV_TIMROTv2_TIMCTRLn_SELECT__32KHZ_XTAL         0xb
  77#define BV_TIMROTv2_TIMCTRLn_SELECT__TICK_ALWAYS        0xf
  78
  79static struct clock_event_device mxs_clockevent_device;
  80static enum clock_event_mode mxs_clockevent_mode = CLOCK_EVT_MODE_UNUSED;
  81
  82static void __iomem *mxs_timrot_base;
  83static u32 timrot_major_version;
  84
  85static inline void timrot_irq_disable(void)
  86{
  87        __raw_writel(BM_TIMROT_TIMCTRLn_IRQ_EN, mxs_timrot_base +
  88                     HW_TIMROT_TIMCTRLn(0) + STMP_OFFSET_REG_CLR);
  89}
  90
  91static inline void timrot_irq_enable(void)
  92{
  93        __raw_writel(BM_TIMROT_TIMCTRLn_IRQ_EN, mxs_timrot_base +
  94                     HW_TIMROT_TIMCTRLn(0) + STMP_OFFSET_REG_SET);
  95}
  96
  97static void timrot_irq_acknowledge(void)
  98{
  99        __raw_writel(BM_TIMROT_TIMCTRLn_IRQ, mxs_timrot_base +
 100                     HW_TIMROT_TIMCTRLn(0) + STMP_OFFSET_REG_CLR);
 101}
 102
 103static cycle_t timrotv1_get_cycles(struct clocksource *cs)
 104{
 105        return ~((__raw_readl(mxs_timrot_base + HW_TIMROT_TIMCOUNTn(1))
 106                        & 0xffff0000) >> 16);
 107}
 108
 109static int timrotv1_set_next_event(unsigned long evt,
 110                                        struct clock_event_device *dev)
 111{
 112        /* timrot decrements the count */
 113        __raw_writel(evt, mxs_timrot_base + HW_TIMROT_TIMCOUNTn(0));
 114
 115        return 0;
 116}
 117
 118static int timrotv2_set_next_event(unsigned long evt,
 119                                        struct clock_event_device *dev)
 120{
 121        /* timrot decrements the count */
 122        __raw_writel(evt, mxs_timrot_base + HW_TIMROT_FIXED_COUNTn(0));
 123
 124        return 0;
 125}
 126
 127static irqreturn_t mxs_timer_interrupt(int irq, void *dev_id)
 128{
 129        struct clock_event_device *evt = dev_id;
 130
 131        timrot_irq_acknowledge();
 132        evt->event_handler(evt);
 133
 134        return IRQ_HANDLED;
 135}
 136
 137static struct irqaction mxs_timer_irq = {
 138        .name           = "MXS Timer Tick",
 139        .dev_id         = &mxs_clockevent_device,
 140        .flags          = IRQF_TIMER | IRQF_IRQPOLL,
 141        .handler        = mxs_timer_interrupt,
 142};
 143
 144#ifdef DEBUG
 145static const char *clock_event_mode_label[] const = {
 146        [CLOCK_EVT_MODE_PERIODIC] = "CLOCK_EVT_MODE_PERIODIC",
 147        [CLOCK_EVT_MODE_ONESHOT]  = "CLOCK_EVT_MODE_ONESHOT",
 148        [CLOCK_EVT_MODE_SHUTDOWN] = "CLOCK_EVT_MODE_SHUTDOWN",
 149        [CLOCK_EVT_MODE_UNUSED]   = "CLOCK_EVT_MODE_UNUSED"
 150};
 151#endif /* DEBUG */
 152
 153static void mxs_set_mode(enum clock_event_mode mode,
 154                                struct clock_event_device *evt)
 155{
 156        /* Disable interrupt in timer module */
 157        timrot_irq_disable();
 158
 159        if (mode != mxs_clockevent_mode) {
 160                /* Set event time into the furthest future */
 161                if (timrot_is_v1())
 162                        __raw_writel(0xffff,
 163                                mxs_timrot_base + HW_TIMROT_TIMCOUNTn(1));
 164                else
 165                        __raw_writel(0xffffffff,
 166                                mxs_timrot_base + HW_TIMROT_FIXED_COUNTn(1));
 167
 168                /* Clear pending interrupt */
 169                timrot_irq_acknowledge();
 170        }
 171
 172#ifdef DEBUG
 173        pr_info("%s: changing mode from %s to %s\n", __func__,
 174                clock_event_mode_label[mxs_clockevent_mode],
 175                clock_event_mode_label[mode]);
 176#endif /* DEBUG */
 177
 178        /* Remember timer mode */
 179        mxs_clockevent_mode = mode;
 180
 181        switch (mode) {
 182        case CLOCK_EVT_MODE_PERIODIC:
 183                pr_err("%s: Periodic mode is not implemented\n", __func__);
 184                break;
 185        case CLOCK_EVT_MODE_ONESHOT:
 186                timrot_irq_enable();
 187                break;
 188        case CLOCK_EVT_MODE_SHUTDOWN:
 189        case CLOCK_EVT_MODE_UNUSED:
 190        case CLOCK_EVT_MODE_RESUME:
 191                /* Left event sources disabled, no more interrupts appear */
 192                break;
 193        }
 194}
 195
 196static struct clock_event_device mxs_clockevent_device = {
 197        .name           = "mxs_timrot",
 198        .features       = CLOCK_EVT_FEAT_ONESHOT,
 199        .set_mode       = mxs_set_mode,
 200        .set_next_event = timrotv2_set_next_event,
 201        .rating         = 200,
 202};
 203
 204static int __init mxs_clockevent_init(struct clk *timer_clk)
 205{
 206        if (timrot_is_v1())
 207                mxs_clockevent_device.set_next_event = timrotv1_set_next_event;
 208        mxs_clockevent_device.cpumask = cpumask_of(0);
 209        clockevents_config_and_register(&mxs_clockevent_device,
 210                                        clk_get_rate(timer_clk),
 211                                        timrot_is_v1() ? 0xf : 0x2,
 212                                        timrot_is_v1() ? 0xfffe : 0xfffffffe);
 213
 214        return 0;
 215}
 216
 217static struct clocksource clocksource_mxs = {
 218        .name           = "mxs_timer",
 219        .rating         = 200,
 220        .read           = timrotv1_get_cycles,
 221        .mask           = CLOCKSOURCE_MASK(16),
 222        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 223};
 224
 225static u32 notrace mxs_read_sched_clock_v2(void)
 226{
 227        return ~readl_relaxed(mxs_timrot_base + HW_TIMROT_RUNNING_COUNTn(1));
 228}
 229
 230static int __init mxs_clocksource_init(struct clk *timer_clk)
 231{
 232        unsigned int c = clk_get_rate(timer_clk);
 233
 234        if (timrot_is_v1())
 235                clocksource_register_hz(&clocksource_mxs, c);
 236        else {
 237                clocksource_mmio_init(mxs_timrot_base + HW_TIMROT_RUNNING_COUNTn(1),
 238                        "mxs_timer", c, 200, 32, clocksource_mmio_readl_down);
 239                setup_sched_clock(mxs_read_sched_clock_v2, 32, c);
 240        }
 241
 242        return 0;
 243}
 244
 245static void __init mxs_timer_init(struct device_node *np)
 246{
 247        struct clk *timer_clk;
 248        int irq;
 249
 250        mxs_timrot_base = of_iomap(np, 0);
 251        WARN_ON(!mxs_timrot_base);
 252
 253        timer_clk = of_clk_get(np, 0);
 254        if (IS_ERR(timer_clk)) {
 255                pr_err("%s: failed to get clk\n", __func__);
 256                return;
 257        }
 258
 259        clk_prepare_enable(timer_clk);
 260
 261        /*
 262         * Initialize timers to a known state
 263         */
 264        stmp_reset_block(mxs_timrot_base + HW_TIMROT_ROTCTRL);
 265
 266        /* get timrot version */
 267        timrot_major_version = __raw_readl(mxs_timrot_base +
 268                        (of_device_is_compatible(np, "fsl,imx23-timrot") ?
 269                                                MX23_TIMROT_VERSION_OFFSET :
 270                                                MX28_TIMROT_VERSION_OFFSET));
 271        timrot_major_version >>= BP_TIMROT_MAJOR_VERSION;
 272
 273        /* one for clock_event */
 274        __raw_writel((timrot_is_v1() ?
 275                        BV_TIMROTv1_TIMCTRLn_SELECT__32KHZ_XTAL :
 276                        BV_TIMROTv2_TIMCTRLn_SELECT__TICK_ALWAYS) |
 277                        BM_TIMROT_TIMCTRLn_UPDATE |
 278                        BM_TIMROT_TIMCTRLn_IRQ_EN,
 279                        mxs_timrot_base + HW_TIMROT_TIMCTRLn(0));
 280
 281        /* another for clocksource */
 282        __raw_writel((timrot_is_v1() ?
 283                        BV_TIMROTv1_TIMCTRLn_SELECT__32KHZ_XTAL :
 284                        BV_TIMROTv2_TIMCTRLn_SELECT__TICK_ALWAYS) |
 285                        BM_TIMROT_TIMCTRLn_RELOAD,
 286                        mxs_timrot_base + HW_TIMROT_TIMCTRLn(1));
 287
 288        /* set clocksource timer fixed count to the maximum */
 289        if (timrot_is_v1())
 290                __raw_writel(0xffff,
 291                        mxs_timrot_base + HW_TIMROT_TIMCOUNTn(1));
 292        else
 293                __raw_writel(0xffffffff,
 294                        mxs_timrot_base + HW_TIMROT_FIXED_COUNTn(1));
 295
 296        /* init and register the timer to the framework */
 297        mxs_clocksource_init(timer_clk);
 298        mxs_clockevent_init(timer_clk);
 299
 300        /* Make irqs happen */
 301        irq = irq_of_parse_and_map(np, 0);
 302        setup_irq(irq, &mxs_timer_irq);
 303}
 304CLOCKSOURCE_OF_DECLARE(mxs, "fsl,timrot", mxs_timer_init);
 305
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.