root/drivers/clocksource/timer-armada-370-xp.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. local_timer_ctrl_clrset
  2. armada_370_xp_read_sched_clock
  3. armada_370_xp_clkevt_next_event
  4. armada_370_xp_clkevt_shutdown
  5. armada_370_xp_clkevt_set_periodic
  6. armada_370_xp_timer_interrupt
  7. armada_370_xp_timer_starting_cpu
  8. armada_370_xp_timer_dying_cpu
  9. armada_370_xp_timer_suspend
  10. armada_370_xp_timer_resume
  11. armada_370_delay_timer_read
  12. armada_370_xp_timer_common_init
  13. armada_xp_timer_init
  14. armada_375_timer_init
  15. armada_370_timer_init

   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 #include <linux/syscore_ops.h>
  47 
  48 #include <asm/delay.h>
  49 
  50 /*
  51  * Timer block registers.
  52  */
  53 #define TIMER_CTRL_OFF          0x0000
  54 #define  TIMER0_EN               BIT(0)
  55 #define  TIMER0_RELOAD_EN        BIT(1)
  56 #define  TIMER0_25MHZ            BIT(11)
  57 #define  TIMER0_DIV(div)         ((div) << 19)
  58 #define  TIMER1_EN               BIT(2)
  59 #define  TIMER1_RELOAD_EN        BIT(3)
  60 #define  TIMER1_25MHZ            BIT(12)
  61 #define  TIMER1_DIV(div)         ((div) << 22)
  62 #define TIMER_EVENTS_STATUS     0x0004
  63 #define  TIMER0_CLR_MASK         (~0x1)
  64 #define  TIMER1_CLR_MASK         (~0x100)
  65 #define TIMER0_RELOAD_OFF       0x0010
  66 #define TIMER0_VAL_OFF          0x0014
  67 #define TIMER1_RELOAD_OFF       0x0018
  68 #define TIMER1_VAL_OFF          0x001c
  69 
  70 #define LCL_TIMER_EVENTS_STATUS 0x0028
  71 /* Global timers are connected to the coherency fabric clock, and the
  72    below divider reduces their incrementing frequency. */
  73 #define TIMER_DIVIDER_SHIFT     5
  74 #define TIMER_DIVIDER           (1 << TIMER_DIVIDER_SHIFT)
  75 
  76 /*
  77  * SoC-specific data.
  78  */
  79 static void __iomem *timer_base, *local_base;
  80 static unsigned int timer_clk;
  81 static bool timer25Mhz = true;
  82 static u32 enable_mask;
  83 
  84 /*
  85  * Number of timer ticks per jiffy.
  86  */
  87 static u32 ticks_per_jiffy;
  88 
  89 static struct clock_event_device __percpu *armada_370_xp_evt;
  90 
  91 static void local_timer_ctrl_clrset(u32 clr, u32 set)
  92 {
  93         writel((readl(local_base + TIMER_CTRL_OFF) & ~clr) | set,
  94                 local_base + TIMER_CTRL_OFF);
  95 }
  96 
  97 static u64 notrace armada_370_xp_read_sched_clock(void)
  98 {
  99         return ~readl(timer_base + TIMER0_VAL_OFF);
 100 }
 101 
 102 /*
 103  * Clockevent handling.
 104  */
 105 static int
 106 armada_370_xp_clkevt_next_event(unsigned long delta,
 107                                 struct clock_event_device *dev)
 108 {
 109         /*
 110          * Clear clockevent timer interrupt.
 111          */
 112         writel(TIMER0_CLR_MASK, local_base + LCL_TIMER_EVENTS_STATUS);
 113 
 114         /*
 115          * Setup new clockevent timer value.
 116          */
 117         writel(delta, local_base + TIMER0_VAL_OFF);
 118 
 119         /*
 120          * Enable the timer.
 121          */
 122         local_timer_ctrl_clrset(TIMER0_RELOAD_EN, enable_mask);
 123         return 0;
 124 }
 125 
 126 static int armada_370_xp_clkevt_shutdown(struct clock_event_device *evt)
 127 {
 128         /*
 129          * Disable timer.
 130          */
 131         local_timer_ctrl_clrset(TIMER0_EN, 0);
 132 
 133         /*
 134          * ACK pending timer interrupt.
 135          */
 136         writel(TIMER0_CLR_MASK, local_base + LCL_TIMER_EVENTS_STATUS);
 137         return 0;
 138 }
 139 
 140 static int armada_370_xp_clkevt_set_periodic(struct clock_event_device *evt)
 141 {
 142         /*
 143          * Setup timer to fire at 1/HZ intervals.
 144          */
 145         writel(ticks_per_jiffy - 1, local_base + TIMER0_RELOAD_OFF);
 146         writel(ticks_per_jiffy - 1, local_base + TIMER0_VAL_OFF);
 147 
 148         /*
 149          * Enable timer.
 150          */
 151         local_timer_ctrl_clrset(0, TIMER0_RELOAD_EN | enable_mask);
 152         return 0;
 153 }
 154 
 155 static int armada_370_xp_clkevt_irq;
 156 
 157 static irqreturn_t armada_370_xp_timer_interrupt(int irq, void *dev_id)
 158 {
 159         /*
 160          * ACK timer interrupt and call event handler.
 161          */
 162         struct clock_event_device *evt = dev_id;
 163 
 164         writel(TIMER0_CLR_MASK, local_base + LCL_TIMER_EVENTS_STATUS);
 165         evt->event_handler(evt);
 166 
 167         return IRQ_HANDLED;
 168 }
 169 
 170 /*
 171  * Setup the local clock events for a CPU.
 172  */
 173 static int armada_370_xp_timer_starting_cpu(unsigned int cpu)
 174 {
 175         struct clock_event_device *evt = per_cpu_ptr(armada_370_xp_evt, cpu);
 176         u32 clr = 0, set = 0;
 177 
 178         if (timer25Mhz)
 179                 set = TIMER0_25MHZ;
 180         else
 181                 clr = TIMER0_25MHZ;
 182         local_timer_ctrl_clrset(clr, set);
 183 
 184         evt->name               = "armada_370_xp_per_cpu_tick",
 185         evt->features           = CLOCK_EVT_FEAT_ONESHOT |
 186                                   CLOCK_EVT_FEAT_PERIODIC;
 187         evt->shift              = 32,
 188         evt->rating             = 300,
 189         evt->set_next_event     = armada_370_xp_clkevt_next_event,
 190         evt->set_state_shutdown = armada_370_xp_clkevt_shutdown;
 191         evt->set_state_periodic = armada_370_xp_clkevt_set_periodic;
 192         evt->set_state_oneshot  = armada_370_xp_clkevt_shutdown;
 193         evt->tick_resume        = armada_370_xp_clkevt_shutdown;
 194         evt->irq                = armada_370_xp_clkevt_irq;
 195         evt->cpumask            = cpumask_of(cpu);
 196 
 197         clockevents_config_and_register(evt, timer_clk, 1, 0xfffffffe);
 198         enable_percpu_irq(evt->irq, 0);
 199 
 200         return 0;
 201 }
 202 
 203 static int armada_370_xp_timer_dying_cpu(unsigned int cpu)
 204 {
 205         struct clock_event_device *evt = per_cpu_ptr(armada_370_xp_evt, cpu);
 206 
 207         evt->set_state_shutdown(evt);
 208         disable_percpu_irq(evt->irq);
 209         return 0;
 210 }
 211 
 212 static u32 timer0_ctrl_reg, timer0_local_ctrl_reg;
 213 
 214 static int armada_370_xp_timer_suspend(void)
 215 {
 216         timer0_ctrl_reg = readl(timer_base + TIMER_CTRL_OFF);
 217         timer0_local_ctrl_reg = readl(local_base + TIMER_CTRL_OFF);
 218         return 0;
 219 }
 220 
 221 static void armada_370_xp_timer_resume(void)
 222 {
 223         writel(0xffffffff, timer_base + TIMER0_VAL_OFF);
 224         writel(0xffffffff, timer_base + TIMER0_RELOAD_OFF);
 225         writel(timer0_ctrl_reg, timer_base + TIMER_CTRL_OFF);
 226         writel(timer0_local_ctrl_reg, local_base + TIMER_CTRL_OFF);
 227 }
 228 
 229 static struct syscore_ops armada_370_xp_timer_syscore_ops = {
 230         .suspend        = armada_370_xp_timer_suspend,
 231         .resume         = armada_370_xp_timer_resume,
 232 };
 233 
 234 static unsigned long armada_370_delay_timer_read(void)
 235 {
 236         return ~readl(timer_base + TIMER0_VAL_OFF);
 237 }
 238 
 239 static struct delay_timer armada_370_delay_timer = {
 240         .read_current_timer = armada_370_delay_timer_read,
 241 };
 242 
 243 static int __init armada_370_xp_timer_common_init(struct device_node *np)
 244 {
 245         u32 clr = 0, set = 0;
 246         int res;
 247 
 248         timer_base = of_iomap(np, 0);
 249         if (!timer_base) {
 250                 pr_err("Failed to iomap\n");
 251                 return -ENXIO;
 252         }
 253 
 254         local_base = of_iomap(np, 1);
 255         if (!local_base) {
 256                 pr_err("Failed to iomap\n");
 257                 return -ENXIO;
 258         }
 259 
 260         if (timer25Mhz) {
 261                 set = TIMER0_25MHZ;             
 262                 enable_mask = TIMER0_EN;
 263         } else {
 264                 clr = TIMER0_25MHZ;
 265                 enable_mask = TIMER0_EN | TIMER0_DIV(TIMER_DIVIDER_SHIFT);
 266         }
 267         atomic_io_modify(timer_base + TIMER_CTRL_OFF, clr | set, set);
 268         local_timer_ctrl_clrset(clr, set);
 269 
 270         /*
 271          * We use timer 0 as clocksource, and private(local) timer 0
 272          * for clockevents
 273          */
 274         armada_370_xp_clkevt_irq = irq_of_parse_and_map(np, 4);
 275 
 276         ticks_per_jiffy = (timer_clk + HZ / 2) / HZ;
 277 
 278         /*
 279          * Setup free-running clocksource timer (interrupts
 280          * disabled).
 281          */
 282         writel(0xffffffff, timer_base + TIMER0_VAL_OFF);
 283         writel(0xffffffff, timer_base + TIMER0_RELOAD_OFF);
 284 
 285         atomic_io_modify(timer_base + TIMER_CTRL_OFF,
 286                 TIMER0_RELOAD_EN | enable_mask,
 287                 TIMER0_RELOAD_EN | enable_mask);
 288 
 289         armada_370_delay_timer.freq = timer_clk;
 290         register_current_timer_delay(&armada_370_delay_timer);
 291 
 292         /*
 293          * Set scale and timer for sched_clock.
 294          */
 295         sched_clock_register(armada_370_xp_read_sched_clock, 32, timer_clk);
 296 
 297         res = clocksource_mmio_init(timer_base + TIMER0_VAL_OFF,
 298                                     "armada_370_xp_clocksource",
 299                                     timer_clk, 300, 32, clocksource_mmio_readl_down);
 300         if (res) {
 301                 pr_err("Failed to initialize clocksource mmio\n");
 302                 return res;
 303         }
 304 
 305         armada_370_xp_evt = alloc_percpu(struct clock_event_device);
 306         if (!armada_370_xp_evt)
 307                 return -ENOMEM;
 308 
 309         /*
 310          * Setup clockevent timer (interrupt-driven).
 311          */
 312         res = request_percpu_irq(armada_370_xp_clkevt_irq,
 313                                 armada_370_xp_timer_interrupt,
 314                                 "armada_370_xp_per_cpu_tick",
 315                                 armada_370_xp_evt);
 316         /* Immediately configure the timer on the boot CPU */
 317         if (res) {
 318                 pr_err("Failed to request percpu irq\n");
 319                 return res;
 320         }
 321 
 322         res = cpuhp_setup_state(CPUHP_AP_ARMADA_TIMER_STARTING,
 323                                 "clockevents/armada:starting",
 324                                 armada_370_xp_timer_starting_cpu,
 325                                 armada_370_xp_timer_dying_cpu);
 326         if (res) {
 327                 pr_err("Failed to setup hotplug state and timer\n");
 328                 return res;
 329         }
 330 
 331         register_syscore_ops(&armada_370_xp_timer_syscore_ops);
 332         
 333         return 0;
 334 }
 335 
 336 static int __init armada_xp_timer_init(struct device_node *np)
 337 {
 338         struct clk *clk = of_clk_get_by_name(np, "fixed");
 339         int ret;
 340 
 341         if (IS_ERR(clk)) {
 342                 pr_err("Failed to get clock\n");
 343                 return PTR_ERR(clk);
 344         }
 345 
 346         ret = clk_prepare_enable(clk);
 347         if (ret)
 348                 return ret;
 349 
 350         timer_clk = clk_get_rate(clk);
 351 
 352         return armada_370_xp_timer_common_init(np);
 353 }
 354 TIMER_OF_DECLARE(armada_xp, "marvell,armada-xp-timer",
 355                        armada_xp_timer_init);
 356 
 357 static int __init armada_375_timer_init(struct device_node *np)
 358 {
 359         struct clk *clk;
 360         int ret;
 361 
 362         clk = of_clk_get_by_name(np, "fixed");
 363         if (!IS_ERR(clk)) {
 364                 ret = clk_prepare_enable(clk);
 365                 if (ret)
 366                         return ret;
 367                 timer_clk = clk_get_rate(clk);
 368         } else {
 369 
 370                 /*
 371                  * This fallback is required in order to retain proper
 372                  * devicetree backwards compatibility.
 373                  */
 374                 clk = of_clk_get(np, 0);
 375 
 376                 /* Must have at least a clock */
 377                 if (IS_ERR(clk)) {
 378                         pr_err("Failed to get clock\n");
 379                         return PTR_ERR(clk);
 380                 }
 381 
 382                 ret = clk_prepare_enable(clk);
 383                 if (ret)
 384                         return ret;
 385 
 386                 timer_clk = clk_get_rate(clk) / TIMER_DIVIDER;
 387                 timer25Mhz = false;
 388         }
 389 
 390         return armada_370_xp_timer_common_init(np);
 391 }
 392 TIMER_OF_DECLARE(armada_375, "marvell,armada-375-timer",
 393                        armada_375_timer_init);
 394 
 395 static int __init armada_370_timer_init(struct device_node *np)
 396 {
 397         struct clk *clk;
 398         int ret;
 399 
 400         clk = of_clk_get(np, 0);
 401         if (IS_ERR(clk)) {
 402                 pr_err("Failed to get clock\n");
 403                 return PTR_ERR(clk);
 404         }
 405 
 406         ret = clk_prepare_enable(clk);
 407         if (ret)
 408                 return ret;
 409 
 410         timer_clk = clk_get_rate(clk) / TIMER_DIVIDER;
 411         timer25Mhz = false;
 412 
 413         return armada_370_xp_timer_common_init(np);
 414 }
 415 TIMER_OF_DECLARE(armada_370, "marvell,armada-370-timer",
 416                        armada_370_timer_init);

/* [<][>][^][v][top][bottom][index][help] */