linux/drivers/clocksource/timer-rda.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * RDA8810PL SoC timer driver
   4 *
   5 * Copyright RDA Microelectronics Company Limited
   6 * Copyright (c) 2017 Andreas F\xC3\xA4rber
   7 * Copyright (c) 2018 Manivannan Sadhasivam
   8 *
   9 * RDA8810PL has two independent timers: OSTIMER (56 bit) and HWTIMER (64 bit).
  10 * Each timer provides optional interrupt support. In this driver, OSTIMER is
  11 * used for clockevents and HWTIMER is used for clocksource.
  12 */
  13
  14#include <linux/init.h>
  15#include <linux/interrupt.h>
  16
  17#include "timer-of.h"
  18
  19#define RDA_OSTIMER_LOADVAL_L   0x000
  20#define RDA_OSTIMER_CTRL        0x004
  21#define RDA_HWTIMER_LOCKVAL_L   0x024
  22#define RDA_HWTIMER_LOCKVAL_H   0x028
  23#define RDA_TIMER_IRQ_MASK_SET  0x02c
  24#define RDA_TIMER_IRQ_MASK_CLR  0x030
  25#define RDA_TIMER_IRQ_CLR       0x034
  26
  27#define RDA_OSTIMER_CTRL_ENABLE         BIT(24)
  28#define RDA_OSTIMER_CTRL_REPEAT         BIT(28)
  29#define RDA_OSTIMER_CTRL_LOAD           BIT(30)
  30
  31#define RDA_TIMER_IRQ_MASK_OSTIMER      BIT(0)
  32
  33#define RDA_TIMER_IRQ_CLR_OSTIMER       BIT(0)
  34
  35static int rda_ostimer_start(void __iomem *base, bool periodic, u64 cycles)
  36{
  37        u32 ctrl, load_l;
  38
  39        load_l = (u32)cycles;
  40        ctrl = ((cycles >> 32) & 0xffffff);
  41        ctrl |= RDA_OSTIMER_CTRL_LOAD | RDA_OSTIMER_CTRL_ENABLE;
  42        if (periodic)
  43                ctrl |= RDA_OSTIMER_CTRL_REPEAT;
  44
  45        /* Enable ostimer interrupt first */
  46        writel_relaxed(RDA_TIMER_IRQ_MASK_OSTIMER,
  47                       base + RDA_TIMER_IRQ_MASK_SET);
  48
  49        /* Write low 32 bits first, high 24 bits are with ctrl */
  50        writel_relaxed(load_l, base + RDA_OSTIMER_LOADVAL_L);
  51        writel_relaxed(ctrl, base + RDA_OSTIMER_CTRL);
  52
  53        return 0;
  54}
  55
  56static int rda_ostimer_stop(void __iomem *base)
  57{
  58        /* Disable ostimer interrupt first */
  59        writel_relaxed(RDA_TIMER_IRQ_MASK_OSTIMER,
  60                       base + RDA_TIMER_IRQ_MASK_CLR);
  61
  62        writel_relaxed(0, base + RDA_OSTIMER_CTRL);
  63
  64        return 0;
  65}
  66
  67static int rda_ostimer_set_state_shutdown(struct clock_event_device *evt)
  68{
  69        struct timer_of *to = to_timer_of(evt);
  70
  71        rda_ostimer_stop(timer_of_base(to));
  72
  73        return 0;
  74}
  75
  76static int rda_ostimer_set_state_oneshot(struct clock_event_device *evt)
  77{
  78        struct timer_of *to = to_timer_of(evt);
  79
  80        rda_ostimer_stop(timer_of_base(to));
  81
  82        return 0;
  83}
  84
  85static int rda_ostimer_set_state_periodic(struct clock_event_device *evt)
  86{
  87        struct timer_of *to = to_timer_of(evt);
  88        unsigned long cycles_per_jiffy;
  89
  90        rda_ostimer_stop(timer_of_base(to));
  91
  92        cycles_per_jiffy = ((unsigned long long)NSEC_PER_SEC / HZ *
  93                             evt->mult) >> evt->shift;
  94        rda_ostimer_start(timer_of_base(to), true, cycles_per_jiffy);
  95
  96        return 0;
  97}
  98
  99static int rda_ostimer_tick_resume(struct clock_event_device *evt)
 100{
 101        return 0;
 102}
 103
 104static int rda_ostimer_set_next_event(unsigned long evt,
 105                                      struct clock_event_device *ev)
 106{
 107        struct timer_of *to = to_timer_of(ev);
 108
 109        rda_ostimer_start(timer_of_base(to), false, evt);
 110
 111        return 0;
 112}
 113
 114static irqreturn_t rda_ostimer_interrupt(int irq, void *dev_id)
 115{
 116        struct clock_event_device *evt = dev_id;
 117        struct timer_of *to = to_timer_of(evt);
 118
 119        /* clear timer int */
 120        writel_relaxed(RDA_TIMER_IRQ_CLR_OSTIMER,
 121                       timer_of_base(to) + RDA_TIMER_IRQ_CLR);
 122
 123        if (evt->event_handler)
 124                evt->event_handler(evt);
 125
 126        return IRQ_HANDLED;
 127}
 128
 129static struct timer_of rda_ostimer_of = {
 130        .flags = TIMER_OF_IRQ | TIMER_OF_BASE,
 131
 132        .clkevt = {
 133                .name = "rda-ostimer",
 134                .rating = 250,
 135                .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT |
 136                            CLOCK_EVT_FEAT_DYNIRQ,
 137                .set_state_shutdown = rda_ostimer_set_state_shutdown,
 138                .set_state_oneshot = rda_ostimer_set_state_oneshot,
 139                .set_state_periodic = rda_ostimer_set_state_periodic,
 140                .tick_resume = rda_ostimer_tick_resume,
 141                .set_next_event = rda_ostimer_set_next_event,
 142        },
 143
 144        .of_base = {
 145                .name = "rda-timer",
 146                .index = 0,
 147        },
 148
 149        .of_irq = {
 150                .name = "ostimer",
 151                .handler = rda_ostimer_interrupt,
 152                .flags = IRQF_TIMER,
 153        },
 154};
 155
 156static u64 rda_hwtimer_read(struct clocksource *cs)
 157{
 158        void __iomem *base = timer_of_base(&rda_ostimer_of);
 159        u32 lo, hi;
 160
 161        /* Always read low 32 bits first */
 162        do {
 163                lo = readl_relaxed(base + RDA_HWTIMER_LOCKVAL_L);
 164                hi = readl_relaxed(base + RDA_HWTIMER_LOCKVAL_H);
 165        } while (hi != readl_relaxed(base + RDA_HWTIMER_LOCKVAL_H));
 166
 167        return ((u64)hi << 32) | lo;
 168}
 169
 170static struct clocksource rda_hwtimer_clocksource = {
 171        .name           = "rda-timer",
 172        .rating         = 400,
 173        .read           = rda_hwtimer_read,
 174        .mask           = CLOCKSOURCE_MASK(64),
 175        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 176};
 177
 178static int __init rda_timer_init(struct device_node *np)
 179{
 180        unsigned long rate = 2000000;
 181        int ret;
 182
 183        ret = timer_of_init(np, &rda_ostimer_of);
 184        if (ret)
 185                return ret;
 186
 187        clocksource_register_hz(&rda_hwtimer_clocksource, rate);
 188
 189        clockevents_config_and_register(&rda_ostimer_of.clkevt, rate,
 190                                        0x2, UINT_MAX);
 191
 192        return 0;
 193}
 194
 195TIMER_OF_DECLARE(rda8810pl, "rda,8810pl-timer", rda_timer_init);
 196