]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge remote-tracking branch 'tip/timers/core' into fordlezcano/3.13/sched-clock64...
authorJohn Stultz <john.stultz@linaro.org>
Thu, 26 Sep 2013 19:05:54 +0000 (12:05 -0700)
committerJohn Stultz <john.stultz@linaro.org>
Thu, 26 Sep 2013 19:05:54 +0000 (12:05 -0700)
Update to tip/timers/core and resolve minor conflict.

Conflicts:
drivers/clocksource/samsung_pwm_timer.c

Signed-off-by: John Stultz <john.stultz@linaro.org>
1  2 
drivers/clocksource/nomadik-mtu.c
drivers/clocksource/samsung_pwm_timer.c
drivers/clocksource/time-armada-370-xp.c

index 2242cd3d618d95414cd181cc644999c71cadb4a7,1b74bea12385a20acd695f2d422665be1dfd90f3..ed7b73b508e096bb06a3e87a1843aa813f835430
@@@ -76,7 -76,7 +76,7 @@@ static struct delay_timer mtu_delay_tim
   * local implementation which uses the clocksource to get some
   * better resolution when scheduling the kernel.
   */
 -static u32 notrace nomadik_read_sched_clock(void)
 +static u64 notrace nomadik_read_sched_clock(void)
  {
        if (unlikely(!mtu_base))
                return 0;
@@@ -165,7 -165,8 +165,8 @@@ static void nmdk_clkevt_resume(struct c
  
  static struct clock_event_device nmdk_clkevt = {
        .name           = "mtu_1",
-       .features       = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
+       .features       = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC |
+                         CLOCK_EVT_FEAT_DYNIRQ,
        .rating         = 200,
        .set_mode       = nmdk_clkevt_mode,
        .set_next_event = nmdk_clkevt_next,
@@@ -230,7 -231,7 +231,7 @@@ static void __init __nmdk_timer_init(vo
                       "mtu_0");
  
  #ifdef CONFIG_CLKSRC_NOMADIK_MTU_SCHED_CLOCK
 -      setup_sched_clock(nomadik_read_sched_clock, 32, rate);
 +      sched_clock_register(nomadik_read_sched_clock, 32, rate);
  #endif
  
        /* Timer 1 is used for events, register irq and clockevents */
index 09e8bc7bc92f8a94c64ad6de53756dc77bdf4d0f,ab29476ee5f9e21dd85de872a45df747dec4a0e4..85082e8d305298ac41b085df4bdb493aca95c682
  #define TCFG1_SHIFT(x)                        ((x) * 4)
  #define TCFG1_MUX_MASK                        0xf
  
+ /*
+  * Each channel occupies 4 bits in TCON register, but there is a gap of 4
+  * bits (one channel) after channel 0, so channels have different numbering
+  * when accessing TCON register.
+  *
+  * In addition, the location of autoreload bit for channel 4 (TCON channel 5)
+  * in its set of bits is 2 as opposed to 3 for other channels.
+  */
  #define TCON_START(chan)              (1 << (4 * (chan) + 0))
  #define TCON_MANUALUPDATE(chan)               (1 << (4 * (chan) + 1))
  #define TCON_INVERT(chan)             (1 << (4 * (chan) + 2))
- #define TCON_AUTORELOAD(chan)         (1 << (4 * (chan) + 3))
+ #define _TCON_AUTORELOAD(chan)                (1 << (4 * (chan) + 3))
+ #define _TCON_AUTORELOAD4(chan)               (1 << (4 * (chan) + 2))
+ #define TCON_AUTORELOAD(chan)         \
+       ((chan < 5) ? _TCON_AUTORELOAD(chan) : _TCON_AUTORELOAD4(chan))
  
  DEFINE_SPINLOCK(samsung_pwm_lock);
  EXPORT_SYMBOL(samsung_pwm_lock);
  
  struct samsung_pwm_clocksource {
        void __iomem *base;
+       void __iomem *source_reg;
        unsigned int irq[SAMSUNG_PWM_NUM];
        struct samsung_pwm_variant variant;
  
@@@ -195,17 -207,6 +207,6 @@@ static int samsung_set_next_event(unsig
        return 0;
  }
  
- static void samsung_timer_resume(void)
- {
-       /* event timer restart */
-       samsung_time_setup(pwm.event_id, pwm.clock_count_per_tick - 1);
-       samsung_time_start(pwm.event_id, true);
-       /* source timer restart */
-       samsung_time_setup(pwm.source_id, pwm.tcnt_max);
-       samsung_time_start(pwm.source_id, true);
- }
  static void samsung_set_mode(enum clock_event_mode mode,
                                struct clock_event_device *evt)
  {
  
        case CLOCK_EVT_MODE_UNUSED:
        case CLOCK_EVT_MODE_SHUTDOWN:
-               break;
        case CLOCK_EVT_MODE_RESUME:
-               samsung_timer_resume();
                break;
        }
  }
  
+ static void samsung_clockevent_resume(struct clock_event_device *cev)
+ {
+       samsung_timer_set_prescale(pwm.event_id, pwm.tscaler_div);
+       samsung_timer_set_divisor(pwm.event_id, pwm.tdiv);
+       if (pwm.variant.has_tint_cstat) {
+               u32 mask = (1 << pwm.event_id);
+               writel(mask | (mask << 5), pwm.base + REG_TINT_CSTAT);
+       }
+ }
  static struct clock_event_device time_event_device = {
        .name           = "samsung_event_timer",
        .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
        .rating         = 200,
        .set_next_event = samsung_set_next_event,
        .set_mode       = samsung_set_mode,
+       .resume         = samsung_clockevent_resume,
  };
  
  static irqreturn_t samsung_clock_event_isr(int irq, void *dev_id)
@@@ -286,23 -296,34 +296,34 @@@ static void __init samsung_clockevent_i
        }
  }
  
- static void __iomem *samsung_timer_reg(void)
+ static void samsung_clocksource_suspend(struct clocksource *cs)
  {
-       switch (pwm.source_id) {
-       case 0:
-       case 1:
-       case 2:
-       case 3:
-               return pwm.base + pwm.source_id * 0x0c + 0x14;
-       case 4:
-               return pwm.base + 0x40;
-       default:
-               BUG();
-       }
+       samsung_time_stop(pwm.source_id);
  }
  
+ static void samsung_clocksource_resume(struct clocksource *cs)
+ {
+       samsung_timer_set_prescale(pwm.source_id, pwm.tscaler_div);
+       samsung_timer_set_divisor(pwm.source_id, pwm.tdiv);
+       samsung_time_setup(pwm.source_id, pwm.tcnt_max);
+       samsung_time_start(pwm.source_id, true);
+ }
+ static cycle_t samsung_clocksource_read(struct clocksource *c)
+ {
+       return ~readl_relaxed(pwm.source_reg);
+ }
+ static struct clocksource samsung_clocksource = {
+       .name           = "samsung_clocksource_timer",
+       .rating         = 250,
+       .read           = samsung_clocksource_read,
+       .suspend        = samsung_clocksource_suspend,
+       .resume         = samsung_clocksource_resume,
+       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
+ };
  /*
   * Override the global weak sched_clock symbol with this
   * local implementation which uses the clocksource to get some
   * this wraps around for now, since it is just a relative time
   * stamp. (Inspired by U300 implementation.)
   */
 -static u32 notrace samsung_read_sched_clock(void)
 +static u64 notrace samsung_read_sched_clock(void)
  {
-       void __iomem *reg = samsung_timer_reg();
-       if (!reg)
-               return 0;
-       return ~__raw_readl(reg);
+       return samsung_clocksource_read(NULL);
  }
  
  static void __init samsung_clocksource_init(void)
  {
-       void __iomem *reg = samsung_timer_reg();
        unsigned long pclk;
        unsigned long clock_rate;
        int ret;
        samsung_time_setup(pwm.source_id, pwm.tcnt_max);
        samsung_time_start(pwm.source_id, true);
  
 -      setup_sched_clock(samsung_read_sched_clock,
+       if (pwm.source_id == 4)
+               pwm.source_reg = pwm.base + 0x40;
+       else
+               pwm.source_reg = pwm.base + pwm.source_id * 0x0c + 0x14;
 +      sched_clock_register(samsung_read_sched_clock,
                                                pwm.variant.bits, clock_rate);
  
-       ret = clocksource_mmio_init(reg, "samsung_clocksource_timer",
-                                       clock_rate, 250, pwm.variant.bits,
-                                       clocksource_mmio_readl_down);
+       samsung_clocksource.mask = CLOCKSOURCE_MASK(pwm.variant.bits);
+       ret = clocksource_register_hz(&samsung_clocksource, clock_rate);
        if (ret)
                panic("samsung_clocksource_timer: can't register clocksource\n");
  }
  
  static void __init samsung_timer_resources(void)
  {
-       pwm.timerclk = clk_get(NULL, "timers");
-       if (IS_ERR(pwm.timerclk))
-               panic("failed to get timers clock for timer");
        clk_prepare_enable(pwm.timerclk);
  
        pwm.tcnt_max = (1UL << pwm.variant.bits) - 1;
@@@ -397,6 -412,10 +412,10 @@@ void __init samsung_pwm_clocksource_ini
        memcpy(&pwm.variant, variant, sizeof(pwm.variant));
        memcpy(pwm.irq, irqs, SAMSUNG_PWM_NUM * sizeof(*irqs));
  
+       pwm.timerclk = clk_get(NULL, "timers");
+       if (IS_ERR(pwm.timerclk))
+               panic("failed to get timers clock for timer");
        _samsung_pwm_clocksource_init();
  }
  
  static void __init samsung_pwm_alloc(struct device_node *np,
                                     const struct samsung_pwm_variant *variant)
  {
-       struct resource res;
        struct property *prop;
        const __be32 *cur;
        u32 val;
                pwm.variant.output_mask |= 1 << val;
        }
  
-       of_address_to_resource(np, 0, &res);
-       if (!request_mem_region(res.start,
-                               resource_size(&res), "samsung-pwm")) {
-               pr_err("%s: failed to request IO mem region\n", __func__);
-               return;
-       }
-       pwm.base = ioremap(res.start, resource_size(&res));
+       pwm.base = of_iomap(np, 0);
        if (!pwm.base) {
                pr_err("%s: failed to map PWM registers\n", __func__);
-               release_mem_region(res.start, resource_size(&res));
                return;
        }
  
+       pwm.timerclk = of_clk_get_by_name(np, "timers");
+       if (IS_ERR(pwm.timerclk))
+               panic("failed to get timers clock for timer");
        _samsung_pwm_clocksource_init();
  }
  
index 2bec8dca74b646afb796bb7636f4a390d69b01f7,0198504ef6b02388c8847bc4897eca4e58328479..d8e47e5027858faf9f99c0b3ad99883bd7bc9cc2
   *
   * Timer 0 is used as free-running clocksource, while timer 1 is
   * used as clock_event_device.
+  *
+  * ---
+  * Clocksource driver for Armada 370 and Armada XP SoC.
+  * This driver implements one compatible string for each SoC, given
+  * each has its own characteristics:
+  *
+  *   * Armada 370 has no 25 MHz fixed timer.
+  *
+  *   * Armada XP cannot work properly without such 25 MHz fixed timer as
+  *     doing otherwise leads to using a clocksource whose frequency varies
+  *     when doing cpufreq frequency changes.
+  *
+  * See Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt
   */
  
  #include <linux/init.h>
  #include <linux/platform_device.h>
  #include <linux/kernel.h>
  #include <linux/clk.h>
+ #include <linux/cpu.h>
  #include <linux/timer.h>
  #include <linux/clockchips.h>
  #include <linux/interrupt.h>
  #include <linux/irq.h>
  #include <linux/module.h>
  #include <linux/sched_clock.h>
- #include <asm/localtimer.h>
  #include <linux/percpu.h>
  /*
   * Timer block registers.
   */
  #define TIMER_CTRL_OFF                0x0000
- #define  TIMER0_EN             0x0001
- #define  TIMER0_RELOAD_EN      0x0002
- #define  TIMER0_25MHZ            0x0800
+ #define  TIMER0_EN             BIT(0)
+ #define  TIMER0_RELOAD_EN      BIT(1)
+ #define  TIMER0_25MHZ            BIT(11)
  #define  TIMER0_DIV(div)         ((div) << 19)
- #define  TIMER1_EN             0x0004
- #define  TIMER1_RELOAD_EN      0x0008
- #define  TIMER1_25MHZ            0x1000
+ #define  TIMER1_EN             BIT(2)
+ #define  TIMER1_RELOAD_EN      BIT(3)
+ #define  TIMER1_25MHZ            BIT(12)
  #define  TIMER1_DIV(div)         ((div) << 22)
  #define TIMER_EVENTS_STATUS   0x0004
  #define  TIMER0_CLR_MASK         (~0x1)
@@@ -69,9 -82,21 +82,21 @@@ static bool timer25Mhz = true
   */
  static u32 ticks_per_jiffy;
  
- static struct clock_event_device __percpu **percpu_armada_370_xp_evt;
+ static struct clock_event_device __percpu *armada_370_xp_evt;
+ static void timer_ctrl_clrset(u32 clr, u32 set)
+ {
+       writel((readl(timer_base + TIMER_CTRL_OFF) & ~clr) | set,
+               timer_base + TIMER_CTRL_OFF);
+ }
+ static void local_timer_ctrl_clrset(u32 clr, u32 set)
+ {
+       writel((readl(local_base + TIMER_CTRL_OFF) & ~clr) | set,
+               local_base + TIMER_CTRL_OFF);
+ }
  
 -static u32 notrace armada_370_xp_read_sched_clock(void)
 +static u64 notrace armada_370_xp_read_sched_clock(void)
  {
        return ~readl(timer_base + TIMER0_VAL_OFF);
  }
@@@ -83,7 -108,6 +108,6 @@@ static in
  armada_370_xp_clkevt_next_event(unsigned long delta,
                                struct clock_event_device *dev)
  {
-       u32 u;
        /*
         * Clear clockevent timer interrupt.
         */
        /*
         * Enable the timer.
         */
-       u = readl(local_base + TIMER_CTRL_OFF);
-       u = ((u & ~TIMER0_RELOAD_EN) | TIMER0_EN |
-            TIMER0_DIV(TIMER_DIVIDER_SHIFT));
-       writel(u, local_base + TIMER_CTRL_OFF);
+       local_timer_ctrl_clrset(TIMER0_RELOAD_EN,
+                               TIMER0_EN | TIMER0_DIV(TIMER_DIVIDER_SHIFT));
        return 0;
  }
  
@@@ -109,8 -130,6 +130,6 @@@ static voi
  armada_370_xp_clkevt_mode(enum clock_event_mode mode,
                          struct clock_event_device *dev)
  {
-       u32 u;
        if (mode == CLOCK_EVT_MODE_PERIODIC) {
  
                /*
                /*
                 * Enable timer.
                 */
-               u = readl(local_base + TIMER_CTRL_OFF);
-               writel((u | TIMER0_EN | TIMER0_RELOAD_EN |
-                       TIMER0_DIV(TIMER_DIVIDER_SHIFT)),
-                       local_base + TIMER_CTRL_OFF);
+               local_timer_ctrl_clrset(0, TIMER0_RELOAD_EN |
+                                          TIMER0_EN |
+                                          TIMER0_DIV(TIMER_DIVIDER_SHIFT));
        } else {
                /*
                 * Disable timer.
                 */
-               u = readl(local_base + TIMER_CTRL_OFF);
-               writel(u & ~TIMER0_EN, local_base + TIMER_CTRL_OFF);
+               local_timer_ctrl_clrset(TIMER0_EN, 0);
  
                /*
                 * ACK pending timer interrupt.
        }
  }
  
- static struct clock_event_device armada_370_xp_clkevt = {
-       .name           = "armada_370_xp_per_cpu_tick",
-       .features       = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
-       .shift          = 32,
-       .rating         = 300,
-       .set_next_event = armada_370_xp_clkevt_next_event,
-       .set_mode       = armada_370_xp_clkevt_mode,
- };
+ static int armada_370_xp_clkevt_irq;
  
  static irqreturn_t armada_370_xp_timer_interrupt(int irq, void *dev_id)
  {
        /*
         * ACK timer interrupt and call event handler.
         */
-       struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
+       struct clock_event_device *evt = dev_id;
  
        writel(TIMER0_CLR_MASK, local_base + LCL_TIMER_EVENTS_STATUS);
        evt->event_handler(evt);
  /*
   * Setup the local clock events for a CPU.
   */
- static int __cpuinit armada_370_xp_timer_setup(struct clock_event_device *evt)
+ static int armada_370_xp_timer_setup(struct clock_event_device *evt)
  {
-       u32 u;
+       u32 clr = 0, set = 0;
        int cpu = smp_processor_id();
  
-       /* Use existing clock_event for cpu 0 */
-       if (!smp_processor_id())
-               return 0;
-       u = readl(local_base + TIMER_CTRL_OFF);
        if (timer25Mhz)
-               writel(u | TIMER0_25MHZ, local_base + TIMER_CTRL_OFF);
+               set = TIMER0_25MHZ;
        else
-               writel(u & ~TIMER0_25MHZ, local_base + TIMER_CTRL_OFF);
-       evt->name               = armada_370_xp_clkevt.name;
-       evt->irq                = armada_370_xp_clkevt.irq;
-       evt->features           = armada_370_xp_clkevt.features;
-       evt->shift              = armada_370_xp_clkevt.shift;
-       evt->rating             = armada_370_xp_clkevt.rating,
+               clr = TIMER0_25MHZ;
+       local_timer_ctrl_clrset(clr, set);
+       evt->name               = "armada_370_xp_per_cpu_tick",
+       evt->features           = CLOCK_EVT_FEAT_ONESHOT |
+                                 CLOCK_EVT_FEAT_PERIODIC;
+       evt->shift              = 32,
+       evt->rating             = 300,
        evt->set_next_event     = armada_370_xp_clkevt_next_event,
        evt->set_mode           = armada_370_xp_clkevt_mode,
+       evt->irq                = armada_370_xp_clkevt_irq;
        evt->cpumask            = cpumask_of(cpu);
  
-       *__this_cpu_ptr(percpu_armada_370_xp_evt) = evt;
        clockevents_config_and_register(evt, timer_clk, 1, 0xfffffffe);
        enable_percpu_irq(evt->irq, 0);
  
        return 0;
  }
  
- static void  armada_370_xp_timer_stop(struct clock_event_device *evt)
+ static void armada_370_xp_timer_stop(struct clock_event_device *evt)
  {
        evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
        disable_percpu_irq(evt->irq);
  }
  
- static struct local_timer_ops armada_370_xp_local_timer_ops __cpuinitdata = {
-       .setup  = armada_370_xp_timer_setup,
-       .stop   =  armada_370_xp_timer_stop,
+ static int armada_370_xp_timer_cpu_notify(struct notifier_block *self,
+                                          unsigned long action, void *hcpu)
+ {
+       /*
+        * Grab cpu pointer in each case to avoid spurious
+        * preemptible warnings
+        */
+       switch (action & ~CPU_TASKS_FROZEN) {
+       case CPU_STARTING:
+               armada_370_xp_timer_setup(this_cpu_ptr(armada_370_xp_evt));
+               break;
+       case CPU_DYING:
+               armada_370_xp_timer_stop(this_cpu_ptr(armada_370_xp_evt));
+               break;
+       }
+       return NOTIFY_OK;
+ }
+ static struct notifier_block armada_370_xp_timer_cpu_nb = {
+       .notifier_call = armada_370_xp_timer_cpu_notify,
  };
  
void __init armada_370_xp_timer_init(void)
static void __init armada_370_xp_timer_common_init(struct device_node *np)
  {
-       u32 u;
-       struct device_node *np;
+       u32 clr = 0, set = 0;
        int res;
  
-       np = of_find_compatible_node(NULL, NULL, "marvell,armada-370-xp-timer");
        timer_base = of_iomap(np, 0);
        WARN_ON(!timer_base);
        local_base = of_iomap(np, 1);
  
-       if (of_find_property(np, "marvell,timer-25Mhz", NULL)) {
-               /* The fixed 25MHz timer is available so let's use it */
-               u = readl(local_base + TIMER_CTRL_OFF);
-               writel(u | TIMER0_25MHZ,
-                      local_base + TIMER_CTRL_OFF);
-               u = readl(timer_base + TIMER_CTRL_OFF);
-               writel(u | TIMER0_25MHZ,
-                      timer_base + TIMER_CTRL_OFF);
-               timer_clk = 25000000;
-       } else {
-               unsigned long rate = 0;
-               struct clk *clk = of_clk_get(np, 0);
-               WARN_ON(IS_ERR(clk));
-               rate =  clk_get_rate(clk);
-               u = readl(local_base + TIMER_CTRL_OFF);
-               writel(u & ~(TIMER0_25MHZ),
-                      local_base + TIMER_CTRL_OFF);
-               u = readl(timer_base + TIMER_CTRL_OFF);
-               writel(u & ~(TIMER0_25MHZ),
-                      timer_base + TIMER_CTRL_OFF);
-               timer_clk = rate / TIMER_DIVIDER;
-               timer25Mhz = false;
-       }
+       if (timer25Mhz)
+               set = TIMER0_25MHZ;             
+       else
+               clr = TIMER0_25MHZ;
+       timer_ctrl_clrset(clr, set);
+       local_timer_ctrl_clrset(clr, set);
  
        /*
         * We use timer 0 as clocksource, and private(local) timer 0
         * for clockevents
         */
-       armada_370_xp_clkevt.irq = irq_of_parse_and_map(np, 4);
+       armada_370_xp_clkevt_irq = irq_of_parse_and_map(np, 4);
  
        ticks_per_jiffy = (timer_clk + HZ / 2) / HZ;
  
        /*
         * Set scale and timer for sched_clock.
         */
 -      setup_sched_clock(armada_370_xp_read_sched_clock, 32, timer_clk);
 +      sched_clock_register(armada_370_xp_read_sched_clock, 32, timer_clk);
  
        /*
         * Setup free-running clocksource timer (interrupts
        writel(0xffffffff, timer_base + TIMER0_VAL_OFF);
        writel(0xffffffff, timer_base + TIMER0_RELOAD_OFF);
  
-       u = readl(timer_base + TIMER_CTRL_OFF);
-       writel((u | TIMER0_EN | TIMER0_RELOAD_EN |
-               TIMER0_DIV(TIMER_DIVIDER_SHIFT)), timer_base + TIMER_CTRL_OFF);
+       timer_ctrl_clrset(0, TIMER0_EN | TIMER0_RELOAD_EN |
+                            TIMER0_DIV(TIMER_DIVIDER_SHIFT));
  
        clocksource_mmio_init(timer_base + TIMER0_VAL_OFF,
                              "armada_370_xp_clocksource",
                              timer_clk, 300, 32, clocksource_mmio_readl_down);
  
-       /* Register the clockevent on the private timer of CPU 0 */
-       armada_370_xp_clkevt.cpumask = cpumask_of(0);
-       clockevents_config_and_register(&armada_370_xp_clkevt,
-                                       timer_clk, 1, 0xfffffffe);
+       register_cpu_notifier(&armada_370_xp_timer_cpu_nb);
  
-       percpu_armada_370_xp_evt = alloc_percpu(struct clock_event_device *);
+       armada_370_xp_evt = alloc_percpu(struct clock_event_device);
  
  
        /*
         * Setup clockevent timer (interrupt-driven).
         */
-       *__this_cpu_ptr(percpu_armada_370_xp_evt) = &armada_370_xp_clkevt;
-       res = request_percpu_irq(armada_370_xp_clkevt.irq,
+       res = request_percpu_irq(armada_370_xp_clkevt_irq,
                                armada_370_xp_timer_interrupt,
-                               armada_370_xp_clkevt.name,
-                               percpu_armada_370_xp_evt);
-       if (!res) {
-               enable_percpu_irq(armada_370_xp_clkevt.irq, 0);
- #ifdef CONFIG_LOCAL_TIMERS
-               local_timer_register(&armada_370_xp_local_timer_ops);
- #endif
-       }
+                               "armada_370_xp_per_cpu_tick",
+                               armada_370_xp_evt);
+       /* Immediately configure the timer on the boot CPU */
+       if (!res)
+               armada_370_xp_timer_setup(this_cpu_ptr(armada_370_xp_evt));
+ }
+ static void __init armada_xp_timer_init(struct device_node *np)
+ {
+       struct clk *clk = of_clk_get_by_name(np, "fixed");
+       /* The 25Mhz fixed clock is mandatory, and must always be available */
+       BUG_ON(IS_ERR(clk));
+       timer_clk = clk_get_rate(clk);
+       armada_370_xp_timer_common_init(np);
+ }
+ CLOCKSOURCE_OF_DECLARE(armada_xp, "marvell,armada-xp-timer",
+                      armada_xp_timer_init);
+ static void __init armada_370_timer_init(struct device_node *np)
+ {
+       struct clk *clk = of_clk_get(np, 0);
+       BUG_ON(IS_ERR(clk));
+       timer_clk = clk_get_rate(clk) / TIMER_DIVIDER;
+       timer25Mhz = false;
+       armada_370_xp_timer_common_init(np);
  }
+ CLOCKSOURCE_OF_DECLARE(armada_370, "marvell,armada-370-timer",
+                      armada_370_timer_init);