linux/drivers/clocksource/timer-sp804.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 *  linux/drivers/clocksource/timer-sp.c
   4 *
   5 *  Copyright (C) 1999 - 2003 ARM Limited
   6 *  Copyright (C) 2000 Deep Blue Solutions Ltd
   7 */
   8
   9#define pr_fmt(fmt)    KBUILD_MODNAME ": " fmt
  10
  11#include <linux/clk.h>
  12#include <linux/clocksource.h>
  13#include <linux/clockchips.h>
  14#include <linux/err.h>
  15#include <linux/interrupt.h>
  16#include <linux/irq.h>
  17#include <linux/io.h>
  18#include <linux/of.h>
  19#include <linux/of_address.h>
  20#include <linux/of_clk.h>
  21#include <linux/of_irq.h>
  22#include <linux/sched_clock.h>
  23
  24#include "timer-sp.h"
  25
  26/* Hisilicon 64-bit timer(a variant of ARM SP804) */
  27#define HISI_TIMER_1_BASE       0x00
  28#define HISI_TIMER_2_BASE       0x40
  29#define HISI_TIMER_LOAD         0x00
  30#define HISI_TIMER_LOAD_H       0x04
  31#define HISI_TIMER_VALUE        0x08
  32#define HISI_TIMER_VALUE_H      0x0c
  33#define HISI_TIMER_CTRL         0x10
  34#define HISI_TIMER_INTCLR       0x14
  35#define HISI_TIMER_RIS          0x18
  36#define HISI_TIMER_MIS          0x1c
  37#define HISI_TIMER_BGLOAD       0x20
  38#define HISI_TIMER_BGLOAD_H     0x24
  39
  40static struct sp804_timer arm_sp804_timer __initdata = {
  41        .load           = TIMER_LOAD,
  42        .value          = TIMER_VALUE,
  43        .ctrl           = TIMER_CTRL,
  44        .intclr         = TIMER_INTCLR,
  45        .timer_base     = {TIMER_1_BASE, TIMER_2_BASE},
  46        .width          = 32,
  47};
  48
  49static struct sp804_timer hisi_sp804_timer __initdata = {
  50        .load           = HISI_TIMER_LOAD,
  51        .load_h         = HISI_TIMER_LOAD_H,
  52        .value          = HISI_TIMER_VALUE,
  53        .value_h        = HISI_TIMER_VALUE_H,
  54        .ctrl           = HISI_TIMER_CTRL,
  55        .intclr         = HISI_TIMER_INTCLR,
  56        .timer_base     = {HISI_TIMER_1_BASE, HISI_TIMER_2_BASE},
  57        .width          = 64,
  58};
  59
  60static struct sp804_clkevt sp804_clkevt[NR_TIMERS];
  61
  62static long __init sp804_get_clock_rate(struct clk *clk, const char *name)
  63{
  64        int err;
  65
  66        if (!clk)
  67                clk = clk_get_sys("sp804", name);
  68        if (IS_ERR(clk)) {
  69                pr_err("%s clock not found: %ld\n", name, PTR_ERR(clk));
  70                return PTR_ERR(clk);
  71        }
  72
  73        err = clk_prepare_enable(clk);
  74        if (err) {
  75                pr_err("clock failed to enable: %d\n", err);
  76                clk_put(clk);
  77                return err;
  78        }
  79
  80        return clk_get_rate(clk);
  81}
  82
  83static struct sp804_clkevt * __init sp804_clkevt_get(void __iomem *base)
  84{
  85        int i;
  86
  87        for (i = 0; i < NR_TIMERS; i++) {
  88                if (sp804_clkevt[i].base == base)
  89                        return &sp804_clkevt[i];
  90        }
  91
  92        /* It's impossible to reach here */
  93        WARN_ON(1);
  94
  95        return NULL;
  96}
  97
  98static struct sp804_clkevt *sched_clkevt;
  99
 100static u64 notrace sp804_read(void)
 101{
 102        return ~readl_relaxed(sched_clkevt->value);
 103}
 104
 105static int __init sp804_clocksource_and_sched_clock_init(void __iomem *base,
 106                                                         const char *name,
 107                                                         struct clk *clk,
 108                                                         int use_sched_clock)
 109{
 110        long rate;
 111        struct sp804_clkevt *clkevt;
 112
 113        rate = sp804_get_clock_rate(clk, name);
 114        if (rate < 0)
 115                return -EINVAL;
 116
 117        clkevt = sp804_clkevt_get(base);
 118
 119        writel(0, clkevt->ctrl);
 120        writel(0xffffffff, clkevt->load);
 121        writel(0xffffffff, clkevt->value);
 122        if (clkevt->width == 64) {
 123                writel(0xffffffff, clkevt->load_h);
 124                writel(0xffffffff, clkevt->value_h);
 125        }
 126        writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC,
 127                clkevt->ctrl);
 128
 129        clocksource_mmio_init(clkevt->value, name,
 130                rate, 200, 32, clocksource_mmio_readl_down);
 131
 132        if (use_sched_clock) {
 133                sched_clkevt = clkevt;
 134                sched_clock_register(sp804_read, 32, rate);
 135        }
 136
 137        return 0;
 138}
 139
 140
 141static struct sp804_clkevt *common_clkevt;
 142
 143/*
 144 * IRQ handler for the timer
 145 */
 146static irqreturn_t sp804_timer_interrupt(int irq, void *dev_id)
 147{
 148        struct clock_event_device *evt = dev_id;
 149
 150        /* clear the interrupt */
 151        writel(1, common_clkevt->intclr);
 152
 153        evt->event_handler(evt);
 154
 155        return IRQ_HANDLED;
 156}
 157
 158static inline void timer_shutdown(struct clock_event_device *evt)
 159{
 160        writel(0, common_clkevt->ctrl);
 161}
 162
 163static int sp804_shutdown(struct clock_event_device *evt)
 164{
 165        timer_shutdown(evt);
 166        return 0;
 167}
 168
 169static int sp804_set_periodic(struct clock_event_device *evt)
 170{
 171        unsigned long ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_IE |
 172                             TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
 173
 174        timer_shutdown(evt);
 175        writel(common_clkevt->reload, common_clkevt->load);
 176        writel(ctrl, common_clkevt->ctrl);
 177        return 0;
 178}
 179
 180static int sp804_set_next_event(unsigned long next,
 181        struct clock_event_device *evt)
 182{
 183        unsigned long ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_IE |
 184                             TIMER_CTRL_ONESHOT | TIMER_CTRL_ENABLE;
 185
 186        writel(next, common_clkevt->load);
 187        writel(ctrl, common_clkevt->ctrl);
 188
 189        return 0;
 190}
 191
 192static struct clock_event_device sp804_clockevent = {
 193        .features               = CLOCK_EVT_FEAT_PERIODIC |
 194                                  CLOCK_EVT_FEAT_ONESHOT |
 195                                  CLOCK_EVT_FEAT_DYNIRQ,
 196        .set_state_shutdown     = sp804_shutdown,
 197        .set_state_periodic     = sp804_set_periodic,
 198        .set_state_oneshot      = sp804_shutdown,
 199        .tick_resume            = sp804_shutdown,
 200        .set_next_event         = sp804_set_next_event,
 201        .rating                 = 300,
 202};
 203
 204static int __init sp804_clockevents_init(void __iomem *base, unsigned int irq,
 205                                         struct clk *clk, const char *name)
 206{
 207        struct clock_event_device *evt = &sp804_clockevent;
 208        long rate;
 209
 210        rate = sp804_get_clock_rate(clk, name);
 211        if (rate < 0)
 212                return -EINVAL;
 213
 214        common_clkevt = sp804_clkevt_get(base);
 215        common_clkevt->reload = DIV_ROUND_CLOSEST(rate, HZ);
 216        evt->name = name;
 217        evt->irq = irq;
 218        evt->cpumask = cpu_possible_mask;
 219
 220        writel(0, common_clkevt->ctrl);
 221
 222        if (request_irq(irq, sp804_timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL,
 223                        "timer", &sp804_clockevent))
 224                pr_err("request_irq() failed\n");
 225        clockevents_config_and_register(evt, rate, 0xf, 0xffffffff);
 226
 227        return 0;
 228}
 229
 230static void __init sp804_clkevt_init(struct sp804_timer *timer, void __iomem *base)
 231{
 232        int i;
 233
 234        for (i = 0; i < NR_TIMERS; i++) {
 235                void __iomem *timer_base;
 236                struct sp804_clkevt *clkevt;
 237
 238                timer_base = base + timer->timer_base[i];
 239                clkevt = &sp804_clkevt[i];
 240                clkevt->base    = timer_base;
 241                clkevt->load    = timer_base + timer->load;
 242                clkevt->load_h  = timer_base + timer->load_h;
 243                clkevt->value   = timer_base + timer->value;
 244                clkevt->value_h = timer_base + timer->value_h;
 245                clkevt->ctrl    = timer_base + timer->ctrl;
 246                clkevt->intclr  = timer_base + timer->intclr;
 247                clkevt->width   = timer->width;
 248        }
 249}
 250
 251static int __init sp804_of_init(struct device_node *np, struct sp804_timer *timer)
 252{
 253        static bool initialized = false;
 254        void __iomem *base;
 255        void __iomem *timer1_base;
 256        void __iomem *timer2_base;
 257        int irq, ret = -EINVAL;
 258        u32 irq_num = 0;
 259        struct clk *clk1, *clk2;
 260        const char *name = of_get_property(np, "compatible", NULL);
 261
 262        base = of_iomap(np, 0);
 263        if (!base)
 264                return -ENXIO;
 265
 266        timer1_base = base + timer->timer_base[0];
 267        timer2_base = base + timer->timer_base[1];
 268
 269        /* Ensure timers are disabled */
 270        writel(0, timer1_base + timer->ctrl);
 271        writel(0, timer2_base + timer->ctrl);
 272
 273        if (initialized || !of_device_is_available(np)) {
 274                ret = -EINVAL;
 275                goto err;
 276        }
 277
 278        clk1 = of_clk_get(np, 0);
 279        if (IS_ERR(clk1))
 280                clk1 = NULL;
 281
 282        /* Get the 2nd clock if the timer has 3 timer clocks */
 283        if (of_clk_get_parent_count(np) == 3) {
 284                clk2 = of_clk_get(np, 1);
 285                if (IS_ERR(clk2)) {
 286                        pr_err("%pOFn clock not found: %d\n", np,
 287                                (int)PTR_ERR(clk2));
 288                        clk2 = NULL;
 289                }
 290        } else
 291                clk2 = clk1;
 292
 293        irq = irq_of_parse_and_map(np, 0);
 294        if (irq <= 0)
 295                goto err;
 296
 297        sp804_clkevt_init(timer, base);
 298
 299        of_property_read_u32(np, "arm,sp804-has-irq", &irq_num);
 300        if (irq_num == 2) {
 301
 302                ret = sp804_clockevents_init(timer2_base, irq, clk2, name);
 303                if (ret)
 304                        goto err;
 305
 306                ret = sp804_clocksource_and_sched_clock_init(timer1_base,
 307                                                             name, clk1, 1);
 308                if (ret)
 309                        goto err;
 310        } else {
 311
 312                ret = sp804_clockevents_init(timer1_base, irq, clk1, name);
 313                if (ret)
 314                        goto err;
 315
 316                ret = sp804_clocksource_and_sched_clock_init(timer2_base,
 317                                                             name, clk2, 1);
 318                if (ret)
 319                        goto err;
 320        }
 321        initialized = true;
 322
 323        return 0;
 324err:
 325        iounmap(base);
 326        return ret;
 327}
 328
 329static int __init arm_sp804_of_init(struct device_node *np)
 330{
 331        return sp804_of_init(np, &arm_sp804_timer);
 332}
 333TIMER_OF_DECLARE(sp804, "arm,sp804", arm_sp804_of_init);
 334
 335static int __init hisi_sp804_of_init(struct device_node *np)
 336{
 337        return sp804_of_init(np, &hisi_sp804_timer);
 338}
 339TIMER_OF_DECLARE(hisi_sp804, "hisilicon,sp804", hisi_sp804_of_init);
 340
 341static int __init integrator_cp_of_init(struct device_node *np)
 342{
 343        static int init_count = 0;
 344        void __iomem *base;
 345        int irq, ret = -EINVAL;
 346        const char *name = of_get_property(np, "compatible", NULL);
 347        struct clk *clk;
 348
 349        base = of_iomap(np, 0);
 350        if (!base) {
 351                pr_err("Failed to iomap\n");
 352                return -ENXIO;
 353        }
 354
 355        clk = of_clk_get(np, 0);
 356        if (IS_ERR(clk)) {
 357                pr_err("Failed to get clock\n");
 358                return PTR_ERR(clk);
 359        }
 360
 361        /* Ensure timer is disabled */
 362        writel(0, base + arm_sp804_timer.ctrl);
 363
 364        if (init_count == 2 || !of_device_is_available(np))
 365                goto err;
 366
 367        sp804_clkevt_init(&arm_sp804_timer, base);
 368
 369        if (!init_count) {
 370                ret = sp804_clocksource_and_sched_clock_init(base,
 371                                                             name, clk, 0);
 372                if (ret)
 373                        goto err;
 374        } else {
 375                irq = irq_of_parse_and_map(np, 0);
 376                if (irq <= 0)
 377                        goto err;
 378
 379                ret = sp804_clockevents_init(base, irq, clk, name);
 380                if (ret)
 381                        goto err;
 382        }
 383
 384        init_count++;
 385        return 0;
 386err:
 387        iounmap(base);
 388        return ret;
 389}
 390TIMER_OF_DECLARE(intcp, "arm,integrator-cp-timer", integrator_cp_of_init);
 391