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
 178static struct irqaction timer_irq = {
 179        .name           = "timer",
 180        .flags          = IRQF_TIMER | IRQF_IRQPOLL,
 181        .handler        = timer_interrupt,
 182        .dev_id         = &ckevt,
 183};
 184
 185void __init mmp_timer_init(int irq, unsigned long rate)
 186{
 187        timer_config();
 188
 189        sched_clock_register(mmp_read_sched_clock, 32, rate);
 190
 191        ckevt.cpumask = cpumask_of(0);
 192
 193        setup_irq(irq, &timer_irq);
 194
 195        clocksource_register_hz(&cksrc, rate);
 196        clockevents_config_and_register(&ckevt, rate, MIN_DELTA, MAX_DELTA);
 197}
 198
 199static int __init mmp_dt_init_timer(struct device_node *np)
 200{
 201        struct clk *clk;
 202        int irq, ret;
 203        unsigned long rate;
 204
 205        clk = of_clk_get(np, 0);
 206        if (!IS_ERR(clk)) {
 207                ret = clk_prepare_enable(clk);
 208                if (ret)
 209                        return ret;
 210                rate = clk_get_rate(clk);
 211        } else if (cpu_is_pj4()) {
 212                rate = 6500000;
 213        } else {
 214                rate = 3250000;
 215        }
 216
 217        irq = irq_of_parse_and_map(np, 0);
 218        if (!irq)
 219                return -EINVAL;
 220
 221        mmp_timer_base = of_iomap(np, 0);
 222        if (!mmp_timer_base)
 223                return -ENOMEM;
 224
 225        mmp_timer_init(irq, rate);
 226        return 0;
 227}
 228
 229TIMER_OF_DECLARE(mmp_timer, "mrvl,mmp-timer", mmp_dt_init_timer);
 230