linux/drivers/clocksource/renesas-ostm.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Renesas Timer Support - OSTM
   4 *
   5 * Copyright (C) 2017 Renesas Electronics America, Inc.
   6 * Copyright (C) 2017 Chris Brandt
   7 */
   8
   9#include <linux/clk.h>
  10#include <linux/clockchips.h>
  11#include <linux/interrupt.h>
  12#include <linux/sched_clock.h>
  13#include <linux/slab.h>
  14
  15#include "timer-of.h"
  16
  17/*
  18 * The OSTM contains independent channels.
  19 * The first OSTM channel probed will be set up as a free running
  20 * clocksource. Additionally we will use this clocksource for the system
  21 * schedule timer sched_clock().
  22 *
  23 * The second (or more) channel probed will be set up as an interrupt
  24 * driven clock event.
  25 */
  26
  27static void __iomem *system_clock;      /* For sched_clock() */
  28
  29/* OSTM REGISTERS */
  30#define OSTM_CMP                0x000   /* RW,32 */
  31#define OSTM_CNT                0x004   /* R,32 */
  32#define OSTM_TE                 0x010   /* R,8 */
  33#define OSTM_TS                 0x014   /* W,8 */
  34#define OSTM_TT                 0x018   /* W,8 */
  35#define OSTM_CTL                0x020   /* RW,8 */
  36
  37#define TE                      0x01
  38#define TS                      0x01
  39#define TT                      0x01
  40#define CTL_PERIODIC            0x00
  41#define CTL_ONESHOT             0x02
  42#define CTL_FREERUN             0x02
  43
  44static void ostm_timer_stop(struct timer_of *to)
  45{
  46        if (readb(timer_of_base(to) + OSTM_TE) & TE) {
  47                writeb(TT, timer_of_base(to) + OSTM_TT);
  48
  49                /*
  50                 * Read back the register simply to confirm the write operation
  51                 * has completed since I/O writes can sometimes get queued by
  52                 * the bus architecture.
  53                 */
  54                while (readb(timer_of_base(to) + OSTM_TE) & TE)
  55                        ;
  56        }
  57}
  58
  59static int __init ostm_init_clksrc(struct timer_of *to)
  60{
  61        ostm_timer_stop(to);
  62
  63        writel(0, timer_of_base(to) + OSTM_CMP);
  64        writeb(CTL_FREERUN, timer_of_base(to) + OSTM_CTL);
  65        writeb(TS, timer_of_base(to) + OSTM_TS);
  66
  67        return clocksource_mmio_init(timer_of_base(to) + OSTM_CNT,
  68                                     to->np->full_name, timer_of_rate(to), 300,
  69                                     32, clocksource_mmio_readl_up);
  70}
  71
  72static u64 notrace ostm_read_sched_clock(void)
  73{
  74        return readl(system_clock);
  75}
  76
  77static void __init ostm_init_sched_clock(struct timer_of *to)
  78{
  79        system_clock = timer_of_base(to) + OSTM_CNT;
  80        sched_clock_register(ostm_read_sched_clock, 32, timer_of_rate(to));
  81}
  82
  83static int ostm_clock_event_next(unsigned long delta,
  84                                 struct clock_event_device *ced)
  85{
  86        struct timer_of *to = to_timer_of(ced);
  87
  88        ostm_timer_stop(to);
  89
  90        writel(delta, timer_of_base(to) + OSTM_CMP);
  91        writeb(CTL_ONESHOT, timer_of_base(to) + OSTM_CTL);
  92        writeb(TS, timer_of_base(to) + OSTM_TS);
  93
  94        return 0;
  95}
  96
  97static int ostm_shutdown(struct clock_event_device *ced)
  98{
  99        struct timer_of *to = to_timer_of(ced);
 100
 101        ostm_timer_stop(to);
 102
 103        return 0;
 104}
 105static int ostm_set_periodic(struct clock_event_device *ced)
 106{
 107        struct timer_of *to = to_timer_of(ced);
 108
 109        if (clockevent_state_oneshot(ced) || clockevent_state_periodic(ced))
 110                ostm_timer_stop(to);
 111
 112        writel(timer_of_period(to) - 1, timer_of_base(to) + OSTM_CMP);
 113        writeb(CTL_PERIODIC, timer_of_base(to) + OSTM_CTL);
 114        writeb(TS, timer_of_base(to) + OSTM_TS);
 115
 116        return 0;
 117}
 118
 119static int ostm_set_oneshot(struct clock_event_device *ced)
 120{
 121        struct timer_of *to = to_timer_of(ced);
 122
 123        ostm_timer_stop(to);
 124
 125        return 0;
 126}
 127
 128static irqreturn_t ostm_timer_interrupt(int irq, void *dev_id)
 129{
 130        struct clock_event_device *ced = dev_id;
 131
 132        if (clockevent_state_oneshot(ced))
 133                ostm_timer_stop(to_timer_of(ced));
 134
 135        /* notify clockevent layer */
 136        if (ced->event_handler)
 137                ced->event_handler(ced);
 138
 139        return IRQ_HANDLED;
 140}
 141
 142static int __init ostm_init_clkevt(struct timer_of *to)
 143{
 144        struct clock_event_device *ced = &to->clkevt;
 145
 146        ced->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC;
 147        ced->set_state_shutdown = ostm_shutdown;
 148        ced->set_state_periodic = ostm_set_periodic;
 149        ced->set_state_oneshot = ostm_set_oneshot;
 150        ced->set_next_event = ostm_clock_event_next;
 151        ced->shift = 32;
 152        ced->rating = 300;
 153        ced->cpumask = cpumask_of(0);
 154        clockevents_config_and_register(ced, timer_of_rate(to), 0xf,
 155                                        0xffffffff);
 156
 157        return 0;
 158}
 159
 160static int __init ostm_init(struct device_node *np)
 161{
 162        struct timer_of *to;
 163        int ret;
 164
 165        to = kzalloc(sizeof(*to), GFP_KERNEL);
 166        if (!to)
 167                return -ENOMEM;
 168
 169        to->flags = TIMER_OF_BASE | TIMER_OF_CLOCK;
 170        if (system_clock) {
 171                /*
 172                 * clock sources don't use interrupts, clock events do
 173                 */
 174                to->flags |= TIMER_OF_IRQ;
 175                to->of_irq.flags = IRQF_TIMER | IRQF_IRQPOLL;
 176                to->of_irq.handler = ostm_timer_interrupt;
 177        }
 178
 179        ret = timer_of_init(np, to);
 180        if (ret)
 181                goto err_free;
 182
 183        /*
 184         * First probed device will be used as system clocksource. Any
 185         * additional devices will be used as clock events.
 186         */
 187        if (!system_clock) {
 188                ret = ostm_init_clksrc(to);
 189                if (ret)
 190                        goto err_cleanup;
 191
 192                ostm_init_sched_clock(to);
 193                pr_info("%pOF: used for clocksource\n", np);
 194        } else {
 195                ret = ostm_init_clkevt(to);
 196                if (ret)
 197                        goto err_cleanup;
 198
 199                pr_info("%pOF: used for clock events\n", np);
 200        }
 201
 202        return 0;
 203
 204err_cleanup:
 205        timer_of_cleanup(to);
 206err_free:
 207        kfree(to);
 208        return ret;
 209}
 210
 211TIMER_OF_DECLARE(ostm, "renesas,ostm", ostm_init);
 212