linux/arch/arm/mach-mmp/time.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * linux/arch/arm/mach-mmp/time.c
   4 *
   5 *   Support for clocksource and clockevents
   6 *
   7 * Copyright (C) 2008 Marvell International Ltd.
   8 * All rights reserved.
   9 *
  10 *   2008-04-11: Jason Chagas <Jason.chagas@marvell.com>
  11 *   2008-10-08: Bin Yang <bin.yang@marvell.com>
  12 *
  13 * The timers module actually includes three timers, each timer with up to
  14 * three match comparators. Timer #0 is used here in free-running mode as
  15 * the clock source, and match comparator #1 used as clock event device.
  16 */
  17
  18#include <linux/init.h>
  19#include <linux/kernel.h>
  20#include <linux/interrupt.h>
  21#include <linux/clockchips.h>
  22#include <linux/clk.h>
  23
  24#include <linux/io.h>
  25#include <linux/irq.h>
  26#include <linux/of.h>
  27#include <linux/of_address.h>
  28#include <linux/of_irq.h>
  29#include <linux/sched_clock.h>
  30#include <asm/mach/time.h>
  31
  32#include "addr-map.h"
  33#include "regs-timers.h"
  34#include "regs-apbc.h"
  35#include "irqs.h"
  36#include <linux/soc/mmp/cputype.h>
  37#include "clock.h"
  38
  39#define TIMERS_VIRT_BASE        TIMERS1_VIRT_BASE
  40
  41#define MAX_DELTA               (0xfffffffe)
  42#define MIN_DELTA               (16)
  43
  44static void __iomem *mmp_timer_base = TIMERS_VIRT_BASE;
  45
  46/*
  47 * FIXME: the timer needs some delay to stablize the counter capture
  48 */
  49static inline uint32_t timer_read(void)
  50{
  51        int delay = 100;
  52
  53        __raw_writel(1, mmp_timer_base + TMR_CVWR(1));
  54
  55        while (delay--)
  56                cpu_relax();
  57
  58        return __raw_readl(mmp_timer_base + TMR_CVWR(1));
  59}
  60
  61static u64 notrace mmp_read_sched_clock(void)
  62{
  63        return timer_read();
  64}
  65
  66static irqreturn_t timer_interrupt(int irq, void *dev_id)
  67{
  68        struct clock_event_device *c = dev_id;
  69
  70        /*
  71         * Clear pending interrupt status.
  72         */
  73        __raw_writel(0x01, mmp_timer_base + TMR_ICR(0));
  74
  75        /*
  76         * Disable timer 0.
  77         */
  78        __raw_writel(0x02, mmp_timer_base + TMR_CER);
  79
  80        c->event_handler(c);
  81
  82        return IRQ_HANDLED;
  83}
  84
  85static int timer_set_next_event(unsigned long delta,
  86                                struct clock_event_device *dev)
  87{
  88        unsigned long flags;
  89
  90        local_irq_save(flags);
  91
  92        /*
  93         * Disable timer 0.
  94         */
  95        __raw_writel(0x02, mmp_timer_base + TMR_CER);
  96
  97        /*
  98         * Clear and enable timer match 0 interrupt.
  99         */
 100        __raw_writel(0x01, mmp_timer_base + TMR_ICR(0));
 101        __raw_writel(0x01, mmp_timer_base + TMR_IER(0));
 102
 103        /*
 104         * Setup new clockevent timer value.
 105         */
 106        __raw_writel(delta - 1, mmp_timer_base + TMR_TN_MM(0, 0));
 107
 108        /*
 109         * Enable timer 0.
 110         */
 111        __raw_writel(0x03, mmp_timer_base + TMR_CER);
 112
 113        local_irq_restore(flags);
 114
 115        return 0;
 116}
 117
 118static int timer_set_shutdown(struct clock_event_device *evt)
 119{
 120        unsigned long flags;
 121
 122        local_irq_save(flags);
 123        /* disable the matching interrupt */
 124        __raw_writel(0x00, mmp_timer_base + TMR_IER(0));
 125        local_irq_restore(flags);
 126
 127        return 0;
 128}
 129
 130static struct clock_event_device ckevt = {
 131        .name                   = "clockevent",
 132        .features               = CLOCK_EVT_FEAT_ONESHOT,
 133        .rating                 = 200,
 134        .set_next_event         = timer_set_next_event,
 135        .set_state_shutdown     = timer_set_shutdown,
 136        .set_state_oneshot      = timer_set_shutdown,
 137};
 138
 139static u64 clksrc_read(struct clocksource *cs)
 140{
 141        return timer_read();
 142}
 143
 144static struct clocksource cksrc = {
 145        .name           = "clocksource",
 146        .rating         = 200,
 147        .read           = clksrc_read,
 148        .mask           = CLOCKSOURCE_MASK(32),
 149        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 150};
 151
 152static void __init timer_config(void)
 153{
 154        uint32_t ccr = __raw_readl(mmp_timer_base + TMR_CCR);
 155
 156        __raw_writel(0x0, mmp_timer_base + TMR_CER); /* disable */
 157
 158        ccr &= (cpu_is_mmp2() || cpu_is_mmp3()) ?
 159                (TMR_CCR_CS_0(0) | TMR_CCR_CS_1(0)) :
 160                (TMR_CCR_CS_0(3) | TMR_CCR_CS_1(3));
 161        __raw_writel(ccr, mmp_timer_base + TMR_CCR);
 162
 163        /* set timer 0 to periodic mode, and timer 1 to free-running mode */
 164        __raw_writel(0x2, mmp_timer_base + TMR_CMR);
 165
 166        __raw_writel(0x1, mmp_timer_base + TMR_PLCR(0)); /* periodic */
 167        __raw_writel(0x7, mmp_timer_base + TMR_ICR(0));  /* clear status */
 168        __raw_writel(0x0, mmp_timer_base + TMR_IER(0));
 169
 170        __raw_writel(0x0, mmp_timer_base + TMR_PLCR(1)); /* free-running */
 171        __raw_writel(0x7, mmp_timer_base + TMR_ICR(1));  /* clear status */
 172        __raw_writel(0x0, mmp_timer_base + TMR_IER(1));
 173
 174        /* enable timer 1 counter */
 175        __raw_writel(0x2, mmp_timer_base + TMR_CER);
 176}
 177
 178void __init mmp_timer_init(int irq, unsigned long rate)
 179{
 180        timer_config();
 181
 182        sched_clock_register(mmp_read_sched_clock, 32, rate);
 183
 184        ckevt.cpumask = cpumask_of(0);
 185
 186        if (request_irq(irq, timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL,
 187                        "timer", &ckevt))
 188                pr_err("Failed to request irq %d (timer)\n", irq);
 189
 190        clocksource_register_hz(&cksrc, rate);
 191        clockevents_config_and_register(&ckevt, rate, MIN_DELTA, MAX_DELTA);
 192}
 193
 194static int __init mmp_dt_init_timer(struct device_node *np)
 195{
 196        struct clk *clk;
 197        int irq, ret;
 198        unsigned long rate;
 199
 200        clk = of_clk_get(np, 0);
 201        if (!IS_ERR(clk)) {
 202                ret = clk_prepare_enable(clk);
 203                if (ret)
 204                        return ret;
 205                rate = clk_get_rate(clk);
 206        } else if (cpu_is_pj4()) {
 207                rate = 6500000;
 208        } else {
 209                rate = 3250000;
 210        }
 211
 212        irq = irq_of_parse_and_map(np, 0);
 213        if (!irq)
 214                return -EINVAL;
 215
 216        mmp_timer_base = of_iomap(np, 0);
 217        if (!mmp_timer_base)
 218                return -ENOMEM;
 219
 220        mmp_timer_init(irq, rate);
 221        return 0;
 222}
 223
 224TIMER_OF_DECLARE(mmp_timer, "mrvl,mmp-timer", mmp_dt_init_timer);
 225