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        pr_debug("%s: changing mode to %s\n", __func__, state);
 135}
 136
 137static int mxs_shutdown(struct clock_event_device *evt)
 138{
 139        mxs_irq_clear("shutdown");
 140
 141        return 0;
 142}
 143
 144static int mxs_set_oneshot(struct clock_event_device *evt)
 145{
 146        if (clockevent_state_oneshot(evt))
 147                mxs_irq_clear("oneshot");
 148        timrot_irq_enable();
 149        return 0;
 150}
 151
 152static struct clock_event_device mxs_clockevent_device = {
 153        .name                   = "mxs_timrot",
 154        .features               = CLOCK_EVT_FEAT_ONESHOT,
 155        .set_state_shutdown     = mxs_shutdown,
 156        .set_state_oneshot      = mxs_set_oneshot,
 157        .tick_resume            = mxs_shutdown,
 158        .set_next_event         = timrotv2_set_next_event,
 159        .rating                 = 200,
 160};
 161
 162static int __init mxs_clockevent_init(struct clk *timer_clk)
 163{
 164        if (timrot_is_v1())
 165                mxs_clockevent_device.set_next_event = timrotv1_set_next_event;
 166        mxs_clockevent_device.cpumask = cpumask_of(0);
 167        clockevents_config_and_register(&mxs_clockevent_device,
 168                                        clk_get_rate(timer_clk),
 169                                        timrot_is_v1() ? 0xf : 0x2,
 170                                        timrot_is_v1() ? 0xfffe : 0xfffffffe);
 171
 172        return 0;
 173}
 174
 175static struct clocksource clocksource_mxs = {
 176        .name           = "mxs_timer",
 177        .rating         = 200,
 178        .read           = timrotv1_get_cycles,
 179        .mask           = CLOCKSOURCE_MASK(16),
 180        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 181};
 182
 183static u64 notrace mxs_read_sched_clock_v2(void)
 184{
 185        return ~readl_relaxed(mxs_timrot_base + HW_TIMROT_RUNNING_COUNTn(1));
 186}
 187
 188static int __init mxs_clocksource_init(struct clk *timer_clk)
 189{
 190        unsigned int c = clk_get_rate(timer_clk);
 191
 192        if (timrot_is_v1())
 193                clocksource_register_hz(&clocksource_mxs, c);
 194        else {
 195                clocksource_mmio_init(mxs_timrot_base + HW_TIMROT_RUNNING_COUNTn(1),
 196                        "mxs_timer", c, 200, 32, clocksource_mmio_readl_down);
 197                sched_clock_register(mxs_read_sched_clock_v2, 32, c);
 198        }
 199
 200        return 0;
 201}
 202
 203static int __init mxs_timer_init(struct device_node *np)
 204{
 205        struct clk *timer_clk;
 206        int irq, ret;
 207
 208        mxs_timrot_base = of_iomap(np, 0);
 209        WARN_ON(!mxs_timrot_base);
 210
 211        timer_clk = of_clk_get(np, 0);
 212        if (IS_ERR(timer_clk)) {
 213                pr_err("%s: failed to get clk\n", __func__);
 214                return PTR_ERR(timer_clk);
 215        }
 216
 217        ret = clk_prepare_enable(timer_clk);
 218        if (ret)
 219                return ret;
 220
 221        /*
 222         * Initialize timers to a known state
 223         */
 224        stmp_reset_block(mxs_timrot_base + HW_TIMROT_ROTCTRL);
 225
 226        /* get timrot version */
 227        timrot_major_version = __raw_readl(mxs_timrot_base +
 228                        (of_device_is_compatible(np, "fsl,imx23-timrot") ?
 229                                                MX23_TIMROT_VERSION_OFFSET :
 230                                                MX28_TIMROT_VERSION_OFFSET));
 231        timrot_major_version >>= BP_TIMROT_MAJOR_VERSION;
 232
 233        /* one for clock_event */
 234        __raw_writel((timrot_is_v1() ?
 235                        BV_TIMROTv1_TIMCTRLn_SELECT__32KHZ_XTAL :
 236                        BV_TIMROTv2_TIMCTRLn_SELECT__TICK_ALWAYS) |
 237                        BM_TIMROT_TIMCTRLn_UPDATE |
 238                        BM_TIMROT_TIMCTRLn_IRQ_EN,
 239                        mxs_timrot_base + HW_TIMROT_TIMCTRLn(0));
 240
 241        /* another for clocksource */
 242        __raw_writel((timrot_is_v1() ?
 243                        BV_TIMROTv1_TIMCTRLn_SELECT__32KHZ_XTAL :
 244                        BV_TIMROTv2_TIMCTRLn_SELECT__TICK_ALWAYS) |
 245                        BM_TIMROT_TIMCTRLn_RELOAD,
 246                        mxs_timrot_base + HW_TIMROT_TIMCTRLn(1));
 247
 248        /* set clocksource timer fixed count to the maximum */
 249        if (timrot_is_v1())
 250                __raw_writel(0xffff,
 251                        mxs_timrot_base + HW_TIMROT_TIMCOUNTn(1));
 252        else
 253                __raw_writel(0xffffffff,
 254                        mxs_timrot_base + HW_TIMROT_FIXED_COUNTn(1));
 255
 256        /* init and register the timer to the framework */
 257        ret = mxs_clocksource_init(timer_clk);
 258        if (ret)
 259                return ret;
 260
 261        ret = mxs_clockevent_init(timer_clk);
 262        if (ret)
 263                return ret;
 264
 265        /* Make irqs happen */
 266        irq = irq_of_parse_and_map(np, 0);
 267        if (irq <= 0)
 268                return -EINVAL;
 269
 270        return request_irq(irq, mxs_timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL,
 271                           "MXS Timer Tick", &mxs_clockevent_device);
 272}
 273TIMER_OF_DECLARE(mxs, "fsl,timrot", mxs_timer_init);
 274