linux/drivers/clocksource/time-armada-370-xp.c
<<
>>
Prefs
   1/*
   2 * Marvell Armada 370/XP SoC timer handling.
   3 *
   4 * Copyright (C) 2012 Marvell
   5 *
   6 * Lior Amsalem <alior@marvell.com>
   7 * Gregory CLEMENT <gregory.clement@free-electrons.com>
   8 * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
   9 *
  10 * This file is licensed under the terms of the GNU General Public
  11 * License version 2.  This program is licensed "as is" without any
  12 * warranty of any kind, whether express or implied.
  13 *
  14 * Timer 0 is used as free-running clocksource, while timer 1 is
  15 * used as clock_event_device.
  16 *
  17 * ---
  18 * Clocksource driver for Armada 370 and Armada XP SoC.
  19 * This driver implements one compatible string for each SoC, given
  20 * each has its own characteristics:
  21 *
  22 *   * Armada 370 has no 25 MHz fixed timer.
  23 *
  24 *   * Armada XP cannot work properly without such 25 MHz fixed timer as
  25 *     doing otherwise leads to using a clocksource whose frequency varies
  26 *     when doing cpufreq frequency changes.
  27 *
  28 * See Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt
  29 */
  30
  31#include <linux/init.h>
  32#include <linux/platform_device.h>
  33#include <linux/kernel.h>
  34#include <linux/clk.h>
  35#include <linux/cpu.h>
  36#include <linux/timer.h>
  37#include <linux/clockchips.h>
  38#include <linux/interrupt.h>
  39#include <linux/of.h>
  40#include <linux/of_irq.h>
  41#include <linux/of_address.h>
  42#include <linux/irq.h>
  43#include <linux/module.h>
  44#include <linux/sched_clock.h>
  45#include <linux/percpu.h>
  46
  47/*
  48 * Timer block registers.
  49 */
  50#define TIMER_CTRL_OFF          0x0000
  51#define  TIMER0_EN               BIT(0)
  52#define  TIMER0_RELOAD_EN        BIT(1)
  53#define  TIMER0_25MHZ            BIT(11)
  54#define  TIMER0_DIV(div)         ((div) << 19)
  55#define  TIMER1_EN               BIT(2)
  56#define  TIMER1_RELOAD_EN        BIT(3)
  57#define  TIMER1_25MHZ            BIT(12)
  58#define  TIMER1_DIV(div)         ((div) << 22)
  59#define TIMER_EVENTS_STATUS     0x0004
  60#define  TIMER0_CLR_MASK         (~0x1)
  61#define  TIMER1_CLR_MASK         (~0x100)
  62#define TIMER0_RELOAD_OFF       0x0010
  63#define TIMER0_VAL_OFF          0x0014
  64#define TIMER1_RELOAD_OFF       0x0018
  65#define TIMER1_VAL_OFF          0x001c
  66
  67#define LCL_TIMER_EVENTS_STATUS 0x0028
  68/* Global timers are connected to the coherency fabric clock, and the
  69   below divider reduces their incrementing frequency. */
  70#define TIMER_DIVIDER_SHIFT     5
  71#define TIMER_DIVIDER           (1 << TIMER_DIVIDER_SHIFT)
  72
  73/*
  74 * SoC-specific data.
  75 */
  76static void __iomem *timer_base, *local_base;
  77static unsigned int timer_clk;
  78static bool timer25Mhz = true;
  79
  80/*
  81 * Number of timer ticks per jiffy.
  82 */
  83static u32 ticks_per_jiffy;
  84
  85static struct clock_event_device __percpu *armada_370_xp_evt;
  86
  87static void timer_ctrl_clrset(u32 clr, u32 set)
  88{
  89        writel((readl(timer_base + TIMER_CTRL_OFF) & ~clr) | set,
  90                timer_base + TIMER_CTRL_OFF);
  91}
  92
  93static void local_timer_ctrl_clrset(u32 clr, u32 set)
  94{
  95        writel((readl(local_base + TIMER_CTRL_OFF) & ~clr) | set,
  96                local_base + TIMER_CTRL_OFF);
  97}
  98
  99static u32 notrace armada_370_xp_read_sched_clock(void)
 100{
 101        return ~readl(timer_base + TIMER0_VAL_OFF);
 102}
 103
 104/*
 105 * Clockevent handling.
 106 */
 107static int
 108armada_370_xp_clkevt_next_event(unsigned long delta,
 109                                struct clock_event_device *dev)
 110{
 111        /*
 112         * Clear clockevent timer interrupt.
 113         */
 114        writel(TIMER0_CLR_MASK, local_base + LCL_TIMER_EVENTS_STATUS);
 115
 116        /*
 117         * Setup new clockevent timer value.
 118         */
 119        writel(delta, local_base + TIMER0_VAL_OFF);
 120
 121        /*
 122         * Enable the timer.
 123         */
 124        local_timer_ctrl_clrset(TIMER0_RELOAD_EN,
 125                                TIMER0_EN | TIMER0_DIV(TIMER_DIVIDER_SHIFT));
 126        return 0;
 127}
 128
 129static void
 130armada_370_xp_clkevt_mode(enum clock_event_mode mode,
 131                          struct clock_event_device *dev)
 132{
 133        if (mode == CLOCK_EVT_MODE_PERIODIC) {
 134
 135                /*
 136                 * Setup timer to fire at 1/HZ intervals.
 137                 */
 138                writel(ticks_per_jiffy - 1, local_base + TIMER0_RELOAD_OFF);
 139                writel(ticks_per_jiffy - 1, local_base + TIMER0_VAL_OFF);
 140
 141                /*
 142                 * Enable timer.
 143                 */
 144                local_timer_ctrl_clrset(0, TIMER0_RELOAD_EN |
 145                                           TIMER0_EN |
 146                                           TIMER0_DIV(TIMER_DIVIDER_SHIFT));
 147        } else {
 148                /*
 149                 * Disable timer.
 150                 */
 151                local_timer_ctrl_clrset(TIMER0_EN, 0);
 152
 153                /*
 154                 * ACK pending timer interrupt.
 155                 */
 156                writel(TIMER0_CLR_MASK, local_base + LCL_TIMER_EVENTS_STATUS);
 157        }
 158}
 159
 160static int armada_370_xp_clkevt_irq;
 161
 162static irqreturn_t armada_370_xp_timer_interrupt(int irq, void *dev_id)
 163{
 164        /*
 165         * ACK timer interrupt and call event handler.
 166         */
 167        struct clock_event_device *evt = dev_id;
 168
 169        writel(TIMER0_CLR_MASK, local_base + LCL_TIMER_EVENTS_STATUS);
 170        evt->event_handler(evt);
 171
 172        return IRQ_HANDLED;
 173}
 174
 175/*
 176 * Setup the local clock events for a CPU.
 177 */
 178static int armada_370_xp_timer_setup(struct clock_event_device *evt)
 179{
 180        u32 clr = 0, set = 0;
 181        int cpu = smp_processor_id();
 182
 183        if (timer25Mhz)
 184                set = TIMER0_25MHZ;
 185        else
 186                clr = TIMER0_25MHZ;
 187        local_timer_ctrl_clrset(clr, set);
 188
 189        evt->name               = "armada_370_xp_per_cpu_tick",
 190        evt->features           = CLOCK_EVT_FEAT_ONESHOT |
 191                                  CLOCK_EVT_FEAT_PERIODIC;
 192        evt->shift              = 32,
 193        evt->rating             = 300,
 194        evt->set_next_event     = armada_370_xp_clkevt_next_event,
 195        evt->set_mode           = armada_370_xp_clkevt_mode,
 196        evt->irq                = armada_370_xp_clkevt_irq;
 197        evt->cpumask            = cpumask_of(cpu);
 198
 199        clockevents_config_and_register(evt, timer_clk, 1, 0xfffffffe);
 200        enable_percpu_irq(evt->irq, 0);
 201
 202        return 0;
 203}
 204
 205static void armada_370_xp_timer_stop(struct clock_event_device *evt)
 206{
 207        evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
 208        disable_percpu_irq(evt->irq);
 209}
 210
 211static int armada_370_xp_timer_cpu_notify(struct notifier_block *self,
 212                                           unsigned long action, void *hcpu)
 213{
 214        /*
 215         * Grab cpu pointer in each case to avoid spurious
 216         * preemptible warnings
 217         */
 218        switch (action & ~CPU_TASKS_FROZEN) {
 219        case CPU_STARTING:
 220                armada_370_xp_timer_setup(this_cpu_ptr(armada_370_xp_evt));
 221                break;
 222        case CPU_DYING:
 223                armada_370_xp_timer_stop(this_cpu_ptr(armada_370_xp_evt));
 224                break;
 225        }
 226
 227        return NOTIFY_OK;
 228}
 229
 230static struct notifier_block armada_370_xp_timer_cpu_nb = {
 231        .notifier_call = armada_370_xp_timer_cpu_notify,
 232};
 233
 234static void __init armada_370_xp_timer_common_init(struct device_node *np)
 235{
 236        u32 clr = 0, set = 0;
 237        int res;
 238
 239        timer_base = of_iomap(np, 0);
 240        WARN_ON(!timer_base);
 241        local_base = of_iomap(np, 1);
 242
 243        if (timer25Mhz)
 244                set = TIMER0_25MHZ;             
 245        else
 246                clr = TIMER0_25MHZ;
 247        timer_ctrl_clrset(clr, set);
 248        local_timer_ctrl_clrset(clr, set);
 249
 250        /*
 251         * We use timer 0 as clocksource, and private(local) timer 0
 252         * for clockevents
 253         */
 254        armada_370_xp_clkevt_irq = irq_of_parse_and_map(np, 4);
 255
 256        ticks_per_jiffy = (timer_clk + HZ / 2) / HZ;
 257
 258        /*
 259         * Set scale and timer for sched_clock.
 260         */
 261        setup_sched_clock(armada_370_xp_read_sched_clock, 32, timer_clk);
 262
 263        /*
 264         * Setup free-running clocksource timer (interrupts
 265         * disabled).
 266         */
 267        writel(0xffffffff, timer_base + TIMER0_VAL_OFF);
 268        writel(0xffffffff, timer_base + TIMER0_RELOAD_OFF);
 269
 270        timer_ctrl_clrset(0, TIMER0_EN | TIMER0_RELOAD_EN |
 271                             TIMER0_DIV(TIMER_DIVIDER_SHIFT));
 272
 273        clocksource_mmio_init(timer_base + TIMER0_VAL_OFF,
 274                              "armada_370_xp_clocksource",
 275                              timer_clk, 300, 32, clocksource_mmio_readl_down);
 276
 277        register_cpu_notifier(&armada_370_xp_timer_cpu_nb);
 278
 279        armada_370_xp_evt = alloc_percpu(struct clock_event_device);
 280
 281
 282        /*
 283         * Setup clockevent timer (interrupt-driven).
 284         */
 285        res = request_percpu_irq(armada_370_xp_clkevt_irq,
 286                                armada_370_xp_timer_interrupt,
 287                                "armada_370_xp_per_cpu_tick",
 288                                armada_370_xp_evt);
 289        /* Immediately configure the timer on the boot CPU */
 290        if (!res)
 291                armada_370_xp_timer_setup(this_cpu_ptr(armada_370_xp_evt));
 292}
 293
 294static void __init armada_xp_timer_init(struct device_node *np)
 295{
 296        struct clk *clk = of_clk_get_by_name(np, "fixed");
 297
 298        /* The 25Mhz fixed clock is mandatory, and must always be available */
 299        BUG_ON(IS_ERR(clk));
 300        timer_clk = clk_get_rate(clk);
 301
 302        armada_370_xp_timer_common_init(np);
 303}
 304CLOCKSOURCE_OF_DECLARE(armada_xp, "marvell,armada-xp-timer",
 305                       armada_xp_timer_init);
 306
 307static void __init armada_370_timer_init(struct device_node *np)
 308{
 309        struct clk *clk = of_clk_get(np, 0);
 310
 311        BUG_ON(IS_ERR(clk));
 312        timer_clk = clk_get_rate(clk) / TIMER_DIVIDER;
 313        timer25Mhz = false;
 314
 315        armada_370_xp_timer_common_init(np);
 316}
 317CLOCKSOURCE_OF_DECLARE(armada_370, "marvell,armada-370-timer",
 318                       armada_370_timer_init);
 319
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.