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