linux/drivers/clocksource/timer-pxa.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * arch/arm/mach-pxa/time.c
   4 *
   5 * PXA clocksource, clockevents, and OST interrupt handlers.
   6 * Copyright (c) 2007 by Bill Gatliff <bgat@billgatliff.com>.
   7 *
   8 * Derived from Nicolas Pitre's PXA timer handler Copyright (c) 2001
   9 * by MontaVista Software, Inc.  (Nico, your code rocks!)
  10 */
  11
  12#include <linux/kernel.h>
  13#include <linux/init.h>
  14#include <linux/interrupt.h>
  15#include <linux/clk.h>
  16#include <linux/clockchips.h>
  17#include <linux/of_address.h>
  18#include <linux/of_irq.h>
  19#include <linux/sched/clock.h>
  20#include <linux/sched_clock.h>
  21
  22#include <clocksource/pxa.h>
  23
  24#include <asm/div64.h>
  25
  26#define OSMR0           0x00    /* OS Timer 0 Match Register */
  27#define OSMR1           0x04    /* OS Timer 1 Match Register */
  28#define OSMR2           0x08    /* OS Timer 2 Match Register */
  29#define OSMR3           0x0C    /* OS Timer 3 Match Register */
  30
  31#define OSCR            0x10    /* OS Timer Counter Register */
  32#define OSSR            0x14    /* OS Timer Status Register */
  33#define OWER            0x18    /* OS Timer Watchdog Enable Register */
  34#define OIER            0x1C    /* OS Timer Interrupt Enable Register */
  35
  36#define OSSR_M3         (1 << 3)        /* Match status channel 3 */
  37#define OSSR_M2         (1 << 2)        /* Match status channel 2 */
  38#define OSSR_M1         (1 << 1)        /* Match status channel 1 */
  39#define OSSR_M0         (1 << 0)        /* Match status channel 0 */
  40
  41#define OIER_E0         (1 << 0)        /* Interrupt enable channel 0 */
  42
  43/*
  44 * This is PXA's sched_clock implementation. This has a resolution
  45 * of at least 308 ns and a maximum value of 208 days.
  46 *
  47 * The return value is guaranteed to be monotonic in that range as
  48 * long as there is always less than 582 seconds between successive
  49 * calls to sched_clock() which should always be the case in practice.
  50 */
  51
  52#define timer_readl(reg) readl_relaxed(timer_base + (reg))
  53#define timer_writel(val, reg) writel_relaxed((val), timer_base + (reg))
  54
  55static void __iomem *timer_base;
  56
  57static u64 notrace pxa_read_sched_clock(void)
  58{
  59        return timer_readl(OSCR);
  60}
  61
  62
  63#define MIN_OSCR_DELTA 16
  64
  65static irqreturn_t
  66pxa_ost0_interrupt(int irq, void *dev_id)
  67{
  68        struct clock_event_device *c = dev_id;
  69
  70        /* Disarm the compare/match, signal the event. */
  71        timer_writel(timer_readl(OIER) & ~OIER_E0, OIER);
  72        timer_writel(OSSR_M0, OSSR);
  73        c->event_handler(c);
  74
  75        return IRQ_HANDLED;
  76}
  77
  78static int
  79pxa_osmr0_set_next_event(unsigned long delta, struct clock_event_device *dev)
  80{
  81        unsigned long next, oscr;
  82
  83        timer_writel(timer_readl(OIER) | OIER_E0, OIER);
  84        next = timer_readl(OSCR) + delta;
  85        timer_writel(next, OSMR0);
  86        oscr = timer_readl(OSCR);
  87
  88        return (signed)(next - oscr) <= MIN_OSCR_DELTA ? -ETIME : 0;
  89}
  90
  91static int pxa_osmr0_shutdown(struct clock_event_device *evt)
  92{
  93        /* initializing, released, or preparing for suspend */
  94        timer_writel(timer_readl(OIER) & ~OIER_E0, OIER);
  95        timer_writel(OSSR_M0, OSSR);
  96        return 0;
  97}
  98
  99#ifdef CONFIG_PM
 100static unsigned long osmr[4], oier, oscr;
 101
 102static void pxa_timer_suspend(struct clock_event_device *cedev)
 103{
 104        osmr[0] = timer_readl(OSMR0);
 105        osmr[1] = timer_readl(OSMR1);
 106        osmr[2] = timer_readl(OSMR2);
 107        osmr[3] = timer_readl(OSMR3);
 108        oier = timer_readl(OIER);
 109        oscr = timer_readl(OSCR);
 110}
 111
 112static void pxa_timer_resume(struct clock_event_device *cedev)
 113{
 114        /*
 115         * Ensure that we have at least MIN_OSCR_DELTA between match
 116         * register 0 and the OSCR, to guarantee that we will receive
 117         * the one-shot timer interrupt.  We adjust OSMR0 in preference
 118         * to OSCR to guarantee that OSCR is monotonically incrementing.
 119         */
 120        if (osmr[0] - oscr < MIN_OSCR_DELTA)
 121                osmr[0] += MIN_OSCR_DELTA;
 122
 123        timer_writel(osmr[0], OSMR0);
 124        timer_writel(osmr[1], OSMR1);
 125        timer_writel(osmr[2], OSMR2);
 126        timer_writel(osmr[3], OSMR3);
 127        timer_writel(oier, OIER);
 128        timer_writel(oscr, OSCR);
 129}
 130#else
 131#define pxa_timer_suspend NULL
 132#define pxa_timer_resume NULL
 133#endif
 134
 135static struct clock_event_device ckevt_pxa_osmr0 = {
 136        .name                   = "osmr0",
 137        .features               = CLOCK_EVT_FEAT_ONESHOT,
 138        .rating                 = 200,
 139        .set_next_event         = pxa_osmr0_set_next_event,
 140        .set_state_shutdown     = pxa_osmr0_shutdown,
 141        .set_state_oneshot      = pxa_osmr0_shutdown,
 142        .suspend                = pxa_timer_suspend,
 143        .resume                 = pxa_timer_resume,
 144};
 145
 146static int __init pxa_timer_common_init(int irq, unsigned long clock_tick_rate)
 147{
 148        int ret;
 149
 150        timer_writel(0, OIER);
 151        timer_writel(OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3, OSSR);
 152
 153        sched_clock_register(pxa_read_sched_clock, 32, clock_tick_rate);
 154
 155        ckevt_pxa_osmr0.cpumask = cpumask_of(0);
 156
 157        ret = request_irq(irq, pxa_ost0_interrupt, IRQF_TIMER | IRQF_IRQPOLL,
 158                          "ost0", &ckevt_pxa_osmr0);
 159        if (ret) {
 160                pr_err("Failed to setup irq\n");
 161                return ret;
 162        }
 163
 164        ret = clocksource_mmio_init(timer_base + OSCR, "oscr0", clock_tick_rate, 200,
 165                                    32, clocksource_mmio_readl_up);
 166        if (ret) {
 167                pr_err("Failed to init clocksource\n");
 168                return ret;
 169        }
 170
 171        clockevents_config_and_register(&ckevt_pxa_osmr0, clock_tick_rate,
 172                                        MIN_OSCR_DELTA * 2, 0x7fffffff);
 173
 174        return 0;
 175}
 176
 177static int __init pxa_timer_dt_init(struct device_node *np)
 178{
 179        struct clk *clk;
 180        int irq, ret;
 181
 182        /* timer registers are shared with watchdog timer */
 183        timer_base = of_iomap(np, 0);
 184        if (!timer_base) {
 185                pr_err("%pOFn: unable to map resource\n", np);
 186                return -ENXIO;
 187        }
 188
 189        clk = of_clk_get(np, 0);
 190        if (IS_ERR(clk)) {
 191                pr_crit("%pOFn: unable to get clk\n", np);
 192                return PTR_ERR(clk);
 193        }
 194
 195        ret = clk_prepare_enable(clk);
 196        if (ret) {
 197                pr_crit("Failed to prepare clock\n");
 198                return ret;
 199        }
 200
 201        /* we are only interested in OS-timer0 irq */
 202        irq = irq_of_parse_and_map(np, 0);
 203        if (irq <= 0) {
 204                pr_crit("%pOFn: unable to parse OS-timer0 irq\n", np);
 205                return -EINVAL;
 206        }
 207
 208        return pxa_timer_common_init(irq, clk_get_rate(clk));
 209}
 210TIMER_OF_DECLARE(pxa_timer, "marvell,pxa-timer", pxa_timer_dt_init);
 211
 212/*
 213 * Legacy timer init for non device-tree boards.
 214 */
 215void __init pxa_timer_nodt_init(int irq, void __iomem *base)
 216{
 217        struct clk *clk;
 218
 219        timer_base = base;
 220        clk = clk_get(NULL, "OSTIMER0");
 221        if (clk && !IS_ERR(clk)) {
 222                clk_prepare_enable(clk);
 223                pxa_timer_common_init(irq, clk_get_rate(clk));
 224        } else {
 225                pr_crit("%s: unable to get clk\n", __func__);
 226        }
 227}
 228