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 <linux/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 .rating = 300, 160 .set_next_event = orion_clkevt_next_event, 161 .set_mode = orion_clkevt_mode, 162 }; 163 164 static irqreturn_t orion_timer_interrupt(int irq, void *dev_id) 165 { 166 /* 167 * ACK timer interrupt and call event handler. 168 */ 169 writel(bridge_timer1_clr_mask, bridge_base + BRIDGE_CAUSE_OFF); 170 orion_clkevt.event_handler(&orion_clkevt); 171 172 return IRQ_HANDLED; 173 } 174 175 static struct irqaction orion_timer_irq = { 176 .name = "orion_tick", 177 .flags = IRQF_DISABLED | IRQF_TIMER, 178 .handler = orion_timer_interrupt 179 }; 180 181 void __init 182 orion_time_set_base(void __iomem *_timer_base) 183 { 184 timer_base = _timer_base; 185 } 186 187 void __init 188 orion_time_init(void __iomem *_bridge_base, u32 _bridge_timer1_clr_mask, 189 unsigned int irq, unsigned int tclk) 190 { 191 u32 u; 192 193 /* 194 * Set SoC-specific data. 195 */ 196 bridge_base = _bridge_base; 197 bridge_timer1_clr_mask = _bridge_timer1_clr_mask; 198 199 ticks_per_jiffy = (tclk + HZ/2) / HZ; 200 201 /* 202 * Set scale and timer for sched_clock. 203 */ 204 setup_sched_clock(orion_read_sched_clock, 32, tclk); 205 206 /* 207 * Setup free-running clocksource timer (interrupts 208 * disabled). 209 */ 210 writel(0xffffffff, timer_base + TIMER0_VAL_OFF); 211 writel(0xffffffff, timer_base + TIMER0_RELOAD_OFF); 212 u = readl(bridge_base + BRIDGE_MASK_OFF); 213 writel(u & ~BRIDGE_INT_TIMER0, bridge_base + BRIDGE_MASK_OFF); 214 u = readl(timer_base + TIMER_CTRL_OFF); 215 writel(u | TIMER0_EN | TIMER0_RELOAD_EN, timer_base + TIMER_CTRL_OFF); 216 clocksource_mmio_init(timer_base + TIMER0_VAL_OFF, "orion_clocksource", 217 tclk, 300, 32, clocksource_mmio_readl_down); 218 219 /* 220 * Setup clockevent timer (interrupt-driven). 221 */ 222 setup_irq(irq, &orion_timer_irq); 223 orion_clkevt.cpumask = cpumask_of(0); 224 clockevents_config_and_register(&orion_clkevt, tclk, 1, 0xfffffffe); 225 } 226