1 /* 2 * arch/arm/plat-orion/time.c 3 * 4 * Marvell Orion SoC timer handling. 5 * 6 * This file is licensed under the terms of the GNU General Public 7 * License version 2. This program is licensed "as is" without any 8 * warranty of any kind, whether express or implied. 9 * 10 * Timer 0 is used as free-running clocksource, while timer 1 is 11 * used as clock_event_device. 12 */ 13 14 #include <linux/kernel.h> 15 #include <linux/timer.h> 16 #include <linux/clockchips.h> 17 #include <linux/interrupt.h> 18 #include <linux/irq.h> 19 #include <asm/sched_clock.h> 20 21 /* 22 * MBus bridge block registers. 23 */ 24 #define BRIDGE_CAUSE_OFF 0x0110 25 #define BRIDGE_MASK_OFF 0x0114 26 #define BRIDGE_INT_TIMER0 0x0002 27 #define BRIDGE_INT_TIMER1 0x0004 28 29 30 /* 31 * Timer block registers. 32 */ 33 #define TIMER_CTRL_OFF 0x0000 34 #define TIMER0_EN 0x0001 35 #define TIMER0_RELOAD_EN 0x0002 36 #define TIMER1_EN 0x0004 37 #define TIMER1_RELOAD_EN 0x0008 38 #define TIMER0_RELOAD_OFF 0x0010 39 #define TIMER0_VAL_OFF 0x0014 40 #define TIMER1_RELOAD_OFF 0x0018 41 #define TIMER1_VAL_OFF 0x001c 42 43 44 /* 45 * SoC-specific data. 46 */ 47 static void __iomem *bridge_base; 48 static u32 bridge_timer1_clr_mask; 49 static void __iomem *timer_base; 50 51 52 /* 53 * Number of timer ticks per jiffy. 54 */ 55 static u32 ticks_per_jiffy; 56 57 58 /* 59 * Orion's sched_clock implementation. It has a resolution of 60 * at least 7.5ns (133MHz TCLK). 61 */ 62 63 static u32 notrace orion_read_sched_clock(void) 64 { 65 return ~readl(timer_base + TIMER0_VAL_OFF); 66 } 67 68 /* 69 * Clockevent handling. 70 */ 71 static int 72 orion_clkevt_next_event(unsigned long delta, struct clock_event_device *dev) 73 { 74 unsigned long flags; 75 u32 u; 76 77 if (delta == 0) 78 return -ETIME; 79 80 local_irq_save(flags); 81 82 /* 83 * Clear and enable clockevent timer interrupt. 84 */ 85 writel(bridge_timer1_clr_mask, bridge_base + BRIDGE_CAUSE_OFF); 86 87 u = readl(bridge_base + BRIDGE_MASK_OFF); 88 u |= BRIDGE_INT_TIMER1; 89 writel(u, bridge_base + BRIDGE_MASK_OFF); 90 91 /* 92 * Setup new clockevent timer value. 93 */ 94 writel(delta, timer_base + TIMER1_VAL_OFF); 95 96 /* 97 * Enable the timer. 98 */ 99 u = readl(timer_base + TIMER_CTRL_OFF); 100 u = (u & ~TIMER1_RELOAD_EN) | TIMER1_EN; 101 writel(u, timer_base + TIMER_CTRL_OFF); 102 103 local_irq_restore(flags); 104 105 return 0; 106 } 107 108 static void 109 orion_clkevt_mode(enum clock_event_mode mode, struct clock_event_device *dev) 110 { 111 unsigned long flags; 112 u32 u; 113 114 local_irq_save(flags); 115 if (mode == CLOCK_EVT_MODE_PERIODIC) { 116 /* 117 * Setup timer to fire at 1/HZ intervals. 118 */ 119 writel(ticks_per_jiffy - 1, timer_base + TIMER1_RELOAD_OFF); 120 writel(ticks_per_jiffy - 1, timer_base + TIMER1_VAL_OFF); 121 122 /* 123 * Enable timer interrupt. 124 */ 125 u = readl(bridge_base + BRIDGE_MASK_OFF); 126 writel(u | BRIDGE_INT_TIMER1, bridge_base + BRIDGE_MASK_OFF); 127 128 /* 129 * Enable timer. 130 */ 131 u = readl(timer_base + TIMER_CTRL_OFF); 132 writel(u | TIMER1_EN | TIMER1_RELOAD_EN, 133 timer_base + TIMER_CTRL_OFF); 134 } else { 135 /* 136 * Disable timer. 137 */ 138 u = readl(timer_base + TIMER_CTRL_OFF); 139 writel(u & ~TIMER1_EN, timer_base + TIMER_CTRL_OFF); 140 141 /* 142 * Disable timer interrupt. 143 */ 144 u = readl(bridge_base + BRIDGE_MASK_OFF); 145 writel(u & ~BRIDGE_INT_TIMER1, bridge_base + BRIDGE_MASK_OFF); 146 147 /* 148 * ACK pending timer interrupt. 149 */ 150 writel(bridge_timer1_clr_mask, bridge_base + BRIDGE_CAUSE_OFF); 151 152 } 153 local_irq_restore(flags); 154 } 155 156 static struct clock_event_device orion_clkevt = { 157 .name = "orion_tick", 158 .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, 159 .shift = 32, 160 .rating = 300, 161 .set_next_event = orion_clkevt_next_event, 162 .set_mode = orion_clkevt_mode, 163 }; 164 165 static irqreturn_t orion_timer_interrupt(int irq, void *dev_id) 166 { 167 /* 168 * ACK timer interrupt and call event handler. 169 */ 170 writel(bridge_timer1_clr_mask, bridge_base + BRIDGE_CAUSE_OFF); 171 orion_clkevt.event_handler(&orion_clkevt); 172 173 return IRQ_HANDLED; 174 } 175 176 static struct irqaction orion_timer_irq = { 177 .name = "orion_tick", 178 .flags = IRQF_DISABLED | IRQF_TIMER, 179 .handler = orion_timer_interrupt 180 }; 181 182 void __init 183 orion_time_set_base(u32 _timer_base) 184 { 185 timer_base = (void __iomem *)_timer_base; 186 } 187 188 void __init 189 orion_time_init(u32 _bridge_base, u32 _bridge_timer1_clr_mask, 190 unsigned int irq, unsigned int tclk) 191 { 192 u32 u; 193 194 /* 195 * Set SoC-specific data. 196 */ 197 bridge_base = (void __iomem *)_bridge_base; 198 bridge_timer1_clr_mask = _bridge_timer1_clr_mask; 199 200 ticks_per_jiffy = (tclk + HZ/2) / HZ; 201 202 /* 203 * Set scale and timer for sched_clock. 204 */ 205 setup_sched_clock(orion_read_sched_clock, 32, tclk); 206 207 /* 208 * Setup free-running clocksource timer (interrupts 209 * disabled). 210 */ 211 writel(0xffffffff, timer_base + TIMER0_VAL_OFF); 212 writel(0xffffffff, timer_base + TIMER0_RELOAD_OFF); 213 u = readl(bridge_base + BRIDGE_MASK_OFF); 214 writel(u & ~BRIDGE_INT_TIMER0, bridge_base + BRIDGE_MASK_OFF); 215 u = readl(timer_base + TIMER_CTRL_OFF); 216 writel(u | TIMER0_EN | TIMER0_RELOAD_EN, timer_base + TIMER_CTRL_OFF); 217 clocksource_mmio_init(timer_base + TIMER0_VAL_OFF, "orion_clocksource", 218 tclk, 300, 32, clocksource_mmio_readl_down); 219 220 /* 221 * Setup clockevent timer (interrupt-driven). 222 */ 223 setup_irq(irq, &orion_timer_irq); 224 orion_clkevt.mult = div_sc(tclk, NSEC_PER_SEC, orion_clkevt.shift); 225 orion_clkevt.max_delta_ns = clockevent_delta2ns(0xfffffffe, &orion_clkevt); 226 orion_clkevt.min_delta_ns = clockevent_delta2ns(1, &orion_clkevt); 227 orion_clkevt.cpumask = cpumask_of(0); 228 clockevents_register_device(&orion_clkevt); 229 } 230