linux/drivers/clocksource/mxs_timer.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2//
   3//  Copyright (C) 2000-2001 Deep Blue Solutions
   4//  Copyright (C) 2002 Shane Nay (shane@minirl.com)
   5//  Copyright (C) 2006-2007 Pavel Pisa (ppisa@pikron.com)
   6//  Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de)
   7//  Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved.
   8
   9#include <linux/err.h>
  10#include <linux/interrupt.h>
  11#include <linux/irq.h>
  12#include <linux/clockchips.h>
  13#include <linux/clk.h>
  14#include <linux/of.h>
  15#include <linux/of_address.h>
  16#include <linux/of_irq.h>
  17#include <linux/stmp_device.h>
  18#include <linux/sched_clock.h>
  19
  20/*
  21 * There are 2 versions of the timrot on Freescale MXS-based SoCs.
  22 * The v1 on MX23 only gets 16 bits counter, while v2 on MX28
  23 * extends the counter to 32 bits.
  24 *
  25 * The implementation uses two timers, one for clock_event and
  26 * another for clocksource. MX28 uses timrot 0 and 1, while MX23
  27 * uses 0 and 2.
  28 */
  29
  30#define MX23_TIMROT_VERSION_OFFSET      0x0a0
  31#define MX28_TIMROT_VERSION_OFFSET      0x120
  32#define BP_TIMROT_MAJOR_VERSION         24
  33#define BV_TIMROT_VERSION_1             0x01
  34#define BV_TIMROT_VERSION_2             0x02
  35#define timrot_is_v1()  (timrot_major_version == BV_TIMROT_VERSION_1)
  36
  37/*
  38 * There are 4 registers for each timrotv2 instance, and 2 registers
  39 * for each timrotv1. So address step 0x40 in macros below strides
  40 * one instance of timrotv2 while two instances of timrotv1.
  41 *
  42 * As the result, HW_TIMROT_XXXn(1) defines the address of timrot1
  43 * on MX28 while timrot2 on MX23.
  44 */
  45/* common between v1 and v2 */
  46#define HW_TIMROT_ROTCTRL               0x00
  47#define HW_TIMROT_TIMCTRLn(n)           (0x20 + (n) * 0x40)
  48/* v1 only */
  49#define HW_TIMROT_TIMCOUNTn(n)          (0x30 + (n) * 0x40)
  50/* v2 only */
  51#define HW_TIMROT_RUNNING_COUNTn(n)     (0x30 + (n) * 0x40)
  52#define HW_TIMROT_FIXED_COUNTn(n)       (0x40 + (n) * 0x40)
  53
  54#define BM_TIMROT_TIMCTRLn_RELOAD       (1 << 6)
  55#define BM_TIMROT_TIMCTRLn_UPDATE       (1 << 7)
  56#define BM_TIMROT_TIMCTRLn_IRQ_EN       (1 << 14)
  57#define BM_TIMROT_TIMCTRLn_IRQ          (1 << 15)
  58#define BP_TIMROT_TIMCTRLn_SELECT       0
  59#define BV_TIMROTv1_TIMCTRLn_SELECT__32KHZ_XTAL         0x8
  60#define BV_TIMROTv2_TIMCTRLn_SELECT__32KHZ_XTAL         0xb
  61#define BV_TIMROTv2_TIMCTRLn_SELECT__TICK_ALWAYS        0xf
  62
  63static struct clock_event_device mxs_clockevent_device;
  64
  65static void __iomem *mxs_timrot_base;
  66static u32 timrot_major_version;
  67
  68static inline void timrot_irq_disable(void)
  69{
  70        __raw_writel(BM_TIMROT_TIMCTRLn_IRQ_EN, mxs_timrot_base +
  71                     HW_TIMROT_TIMCTRLn(0) + STMP_OFFSET_REG_CLR);
  72}
  73
  74static inline void timrot_irq_enable(void)
  75{
  76        __raw_writel(BM_TIMROT_TIMCTRLn_IRQ_EN, mxs_timrot_base +
  77                     HW_TIMROT_TIMCTRLn(0) + STMP_OFFSET_REG_SET);
  78}
  79
  80static void timrot_irq_acknowledge(void)
  81{
  82        __raw_writel(BM_TIMROT_TIMCTRLn_IRQ, mxs_timrot_base +
  83                     HW_TIMROT_TIMCTRLn(0) + STMP_OFFSET_REG_CLR);
  84}
  85
  86static u64 timrotv1_get_cycles(struct clocksource *cs)
  87{
  88        return ~((__raw_readl(mxs_timrot_base + HW_TIMROT_TIMCOUNTn(1))
  89                        & 0xffff0000) >> 16);
  90}
  91
  92static int timrotv1_set_next_event(unsigned long evt,
  93                                        struct clock_event_device *dev)
  94{
  95        /* timrot decrements the count */
  96        __raw_writel(evt, mxs_timrot_base + HW_TIMROT_TIMCOUNTn(0));
  97
  98        return 0;
  99}
 100
 101static int timrotv2_set_next_event(unsigned long evt,
 102                                        struct clock_event_device *dev)
 103{
 104        /* timrot decrements the count */
 105        __raw_writel(evt, mxs_timrot_base + HW_TIMROT_FIXED_COUNTn(0));
 106
 107        return 0;
 108}
 109
 110static irqreturn_t mxs_timer_interrupt(int irq, void *dev_id)
 111{
 112        struct clock_event_device *evt = dev_id;
 113
 114        timrot_irq_acknowledge();
 115        evt->event_handler(evt);
 116
 117        return IRQ_HANDLED;
 118}
 119
 120static void mxs_irq_clear(char *state)
 121{
 122        /* Disable interrupt in timer module */
 123        timrot_irq_disable();
 124
 125        /* Set event time into the furthest future */
 126        if (timrot_is_v1())
 127                __raw_writel(0xffff, mxs_timrot_base + HW_TIMROT_TIMCOUNTn(1));
 128        else
 129                __raw_writel(0xffffffff,
 130                             mxs_timrot_base + HW_TIMROT_FIXED_COUNTn(1));
 131
 132        /* Clear pending interrupt */
 133        timrot_irq_acknowledge();
 134
 135#ifdef DEBUG
 136        pr_info("%s: changing mode to %s\n", __func__, state)
 137#endif /* DEBUG */
 138}
 139
 140static int mxs_shutdown(struct clock_event_device *evt)
 141{
 142        mxs_irq_clear("shutdown");
 143
 144        return 0;
 145}
 146
 147static int mxs_set_oneshot(struct clock_event_device *evt)
 148{
 149        if (clockevent_state_oneshot(evt))
 150                mxs_irq_clear("oneshot");
 151        timrot_irq_enable();
 152        return 0;
 153}
 154
 155static struct clock_event_device mxs_clockevent_device = {
 156        .name                   = "mxs_timrot",
 157        .features               = CLOCK_EVT_FEAT_ONESHOT,
 158        .set_state_shutdown     = mxs_shutdown,
 159        .set_state_oneshot      = mxs_set_oneshot,
 160        .tick_resume            = mxs_shutdown,
 161        .set_next_event         = timrotv2_set_next_event,
 162        .rating                 = 200,
 163};
 164
 165static int __init mxs_clockevent_init(struct clk *timer_clk)
 166{
 167        if (timrot_is_v1())
 168                mxs_clockevent_device.set_next_event = timrotv1_set_next_event;
 169        mxs_clockevent_device.cpumask = cpumask_of(0);
 170        clockevents_config_and_register(&mxs_clockevent_device,
 171                                        clk_get_rate(timer_clk),
 172                                        timrot_is_v1() ? 0xf : 0x2,
 173                                        timrot_is_v1() ? 0xfffe : 0xfffffffe);
 174
 175        return 0;
 176}
 177
 178static struct clocksource clocksource_mxs = {
 179        .name           = "mxs_timer",
 180        .rating         = 200,
 181        .read           = timrotv1_get_cycles,
 182        .mask           = CLOCKSOURCE_MASK(16),
 183        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 184};
 185
 186static u64 notrace mxs_read_sched_clock_v2(void)
 187{
 188        return ~readl_relaxed(mxs_timrot_base + HW_TIMROT_RUNNING_COUNTn(1));
 189}
 190
 191static int __init mxs_clocksource_init(struct clk *timer_clk)
 192{
 193        unsigned int c = clk_get_rate(timer_clk);
 194
 195        if (timrot_is_v1())
 196                clocksource_register_hz(&clocksource_mxs, c);
 197        else {
 198                clocksource_mmio_init(mxs_timrot_base + HW_TIMROT_RUNNING_COUNTn(1),
 199                        "mxs_timer", c, 200, 32, clocksource_mmio_readl_down);
 200                sched_clock_register(mxs_read_sched_clock_v2, 32, c);
 201        }
 202
 203        return 0;
 204}
 205
 206static int __init mxs_timer_init(struct device_node *np)
 207{
 208        struct clk *timer_clk;
 209        int irq, ret;
 210
 211        mxs_timrot_base = of_iomap(np, 0);
 212        WARN_ON(!mxs_timrot_base);
 213
 214        timer_clk = of_clk_get(np, 0);
 215        if (IS_ERR(timer_clk)) {
 216                pr_err("%s: failed to get clk\n", __func__);
 217                return PTR_ERR(timer_clk);
 218        }
 219
 220        ret = clk_prepare_enable(timer_clk);
 221        if (ret)
 222                return ret;
 223
 224        /*
 225         * Initialize timers to a known state
 226         */
 227        stmp_reset_block(mxs_timrot_base + HW_TIMROT_ROTCTRL);
 228
 229        /* get timrot version */
 230        timrot_major_version = __raw_readl(mxs_timrot_base +
 231                        (of_device_is_compatible(np, "fsl,imx23-timrot") ?
 232                                                MX23_TIMROT_VERSION_OFFSET :
 233                                                MX28_TIMROT_VERSION_OFFSET));
 234        timrot_major_version >>= BP_TIMROT_MAJOR_VERSION;
 235
 236        /* one for clock_event */
 237        __raw_writel((timrot_is_v1() ?
 238                        BV_TIMROTv1_TIMCTRLn_SELECT__32KHZ_XTAL :
 239                        BV_TIMROTv2_TIMCTRLn_SELECT__TICK_ALWAYS) |
 240                        BM_TIMROT_TIMCTRLn_UPDATE |
 241                        BM_TIMROT_TIMCTRLn_IRQ_EN,
 242                        mxs_timrot_base + HW_TIMROT_TIMCTRLn(0));
 243
 244        /* another for clocksource */
 245        __raw_writel((timrot_is_v1() ?
 246                        BV_TIMROTv1_TIMCTRLn_SELECT__32KHZ_XTAL :
 247                        BV_TIMROTv2_TIMCTRLn_SELECT__TICK_ALWAYS) |
 248                        BM_TIMROT_TIMCTRLn_RELOAD,
 249                        mxs_timrot_base + HW_TIMROT_TIMCTRLn(1));
 250
 251        /* set clocksource timer fixed count to the maximum */
 252        if (timrot_is_v1())
 253                __raw_writel(0xffff,
 254                        mxs_timrot_base + HW_TIMROT_TIMCOUNTn(1));
 255        else
 256                __raw_writel(0xffffffff,
 257                        mxs_timrot_base + HW_TIMROT_FIXED_COUNTn(1));
 258
 259        /* init and register the timer to the framework */
 260        ret = mxs_clocksource_init(timer_clk);
 261        if (ret)
 262                return ret;
 263
 264        ret = mxs_clockevent_init(timer_clk);
 265        if (ret)
 266                return ret;
 267
 268        /* Make irqs happen */
 269        irq = irq_of_parse_and_map(np, 0);
 270        if (irq <= 0)
 271                return -EINVAL;
 272
 273        return request_irq(irq, mxs_timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL,
 274                           "MXS Timer Tick", &mxs_clockevent_device);
 275}
 276TIMER_OF_DECLARE(mxs, "fsl,timrot", mxs_timer_init);
 277