aboutsummaryrefslogtreecommitdiffstats
path: root/arch/cris/arch-v32
diff options
context:
space:
mode:
authorRabin Vincent <rabin@rab.in>2015-03-08 11:29:12 -0400
committerJesper Nilsson <jespern@axis.com>2015-03-25 06:03:40 -0400
commited9fd3ff0251783cb3943e71aac398b9064efae6 (patch)
tree37082935bde7a51e91e42ff8521e9ea89780f3b7 /arch/cris/arch-v32
parent16428f943d192390b4673612b1d3fb81772323d9 (diff)
CRISv32: use generic clockevents
Implement a oneshot-capable clockevents device so we get support for things like hrtimers and NOHZ. Signed-off-by: Rabin Vincent <rabin@rab.in> Signed-off-by: Jesper Nilsson <jespern@axis.com>
Diffstat (limited to 'arch/cris/arch-v32')
-rw-r--r--arch/cris/arch-v32/kernel/time.c145
1 files changed, 85 insertions, 60 deletions
diff --git a/arch/cris/arch-v32/kernel/time.c b/arch/cris/arch-v32/kernel/time.c
index aa2d94b7fb61..77e241d6fa3d 100644
--- a/arch/cris/arch-v32/kernel/time.c
+++ b/arch/cris/arch-v32/kernel/time.c
@@ -8,6 +8,7 @@
8#include <linux/timex.h> 8#include <linux/timex.h>
9#include <linux/time.h> 9#include <linux/time.h>
10#include <linux/clocksource.h> 10#include <linux/clocksource.h>
11#include <linux/clockchips.h>
11#include <linux/interrupt.h> 12#include <linux/interrupt.h>
12#include <linux/swap.h> 13#include <linux/swap.h>
13#include <linux/sched.h> 14#include <linux/sched.h>
@@ -36,6 +37,8 @@
36/* Number of 763 counts before watchdog bites */ 37/* Number of 763 counts before watchdog bites */
37#define ETRAX_WD_CNT ((2*ETRAX_WD_HZ)/HZ + 1) 38#define ETRAX_WD_CNT ((2*ETRAX_WD_HZ)/HZ + 1)
38 39
40#define CRISV32_TIMER_FREQ (100000000lu)
41
39/* Register the continuos readonly timer available in FS and ARTPEC-3. */ 42/* Register the continuos readonly timer available in FS and ARTPEC-3. */
40static cycle_t read_cont_rotime(struct clocksource *cs) 43static cycle_t read_cont_rotime(struct clocksource *cs)
41{ 44{
@@ -186,81 +189,99 @@ void handle_watchdog_bite(struct pt_regs *regs)
186#endif 189#endif
187} 190}
188 191
189/* 192extern void cris_profile_sample(struct pt_regs *regs);
190 * timer_interrupt() needs to keep up the real-time clock, 193static void __iomem *timer_base;
191 * as well as call the "xtime_update()" routine every clocktick.
192 */
193extern void cris_do_profile(struct pt_regs *regs);
194 194
195static inline irqreturn_t timer_interrupt(int irq, void *dev_id) 195static void crisv32_clkevt_mode(enum clock_event_mode mode,
196 struct clock_event_device *dev)
196{ 197{
197 struct pt_regs *regs = get_irq_regs(); 198 reg_timer_rw_tmr0_ctrl ctrl = {
198 int cpu = smp_processor_id(); 199 .op = regk_timer_hold,
199 reg_timer_r_masked_intr masked_intr; 200 .freq = regk_timer_f100,
200 reg_timer_rw_ack_intr ack_intr = { 0 }; 201 };
201
202 /* Check if the timer interrupt is for us (a tmr0 int) */
203 masked_intr = REG_RD(timer, timer_regs[cpu], r_masked_intr);
204 if (!masked_intr.tmr0)
205 return IRQ_NONE;
206 202
207 /* Acknowledge the timer irq. */ 203 REG_WR(timer, timer_base, rw_tmr0_ctrl, ctrl);
208 ack_intr.tmr0 = 1; 204}
209 REG_WR(timer, timer_regs[cpu], rw_ack_intr, ack_intr);
210 205
211 /* Reset watchdog otherwise it resets us! */ 206static int crisv32_clkevt_next_event(unsigned long evt,
212 reset_watchdog(); 207 struct clock_event_device *dev)
208{
209 reg_timer_rw_tmr0_ctrl ctrl = {
210 .op = regk_timer_ld,
211 .freq = regk_timer_f100,
212 };
213
214 REG_WR(timer, timer_base, rw_tmr0_div, evt);
215 REG_WR(timer, timer_base, rw_tmr0_ctrl, ctrl);
216
217 ctrl.op = regk_timer_run;
218 REG_WR(timer, timer_base, rw_tmr0_ctrl, ctrl);
219
220 return 0;
221}
213 222
214 /* Update statistics. */ 223static irqreturn_t crisv32_timer_interrupt(int irq, void *dev_id)
215 update_process_times(user_mode(regs)); 224{
225 struct clock_event_device *evt = dev_id;
226 reg_timer_rw_tmr0_ctrl ctrl = {
227 .op = regk_timer_hold,
228 .freq = regk_timer_f100,
229 };
230 reg_timer_rw_ack_intr ack = { .tmr0 = 1 };
231 reg_timer_r_masked_intr intr;
232
233 intr = REG_RD(timer, timer_base, r_masked_intr);
234 if (!intr.tmr0)
235 return IRQ_NONE;
236
237 REG_WR(timer, timer_base, rw_tmr0_ctrl, ctrl);
238 REG_WR(timer, timer_base, rw_ack_intr, ack);
216 239
217 cris_do_profile(regs); /* Save profiling information */ 240 reset_watchdog();
241#ifdef CONFIG_SYSTEM_PROFILER
242 cris_profile_sample(get_irq_regs());
243#endif
218 244
219 /* The master CPU is responsible for the time keeping. */ 245 evt->event_handler(evt);
220 if (cpu != 0)
221 return IRQ_HANDLED;
222 246
223 /* Call the real timer interrupt handler */
224 xtime_update(1);
225 return IRQ_HANDLED; 247 return IRQ_HANDLED;
226} 248}
227 249
250static struct clock_event_device crisv32_clockevent = {
251 .name = "crisv32-timer",
252 .rating = 300,
253 .features = CLOCK_EVT_FEAT_ONESHOT,
254 .set_mode = crisv32_clkevt_mode,
255 .set_next_event = crisv32_clkevt_next_event,
256};
257
228/* Timer is IRQF_SHARED so drivers can add stuff to the timer irq chain. */ 258/* Timer is IRQF_SHARED so drivers can add stuff to the timer irq chain. */
229static struct irqaction irq_timer = { 259static struct irqaction irq_timer = {
230 .handler = timer_interrupt, 260 .handler = crisv32_timer_interrupt,
231 .flags = IRQF_SHARED, 261 .flags = IRQF_TIMER | IRQF_SHARED,
232 .name = "timer" 262 .name = "crisv32-timer",
263 .dev_id = &crisv32_clockevent,
233}; 264};
234 265
235void __init cris_timer_init(void) 266static void __init crisv32_timer_init(void)
236{ 267{
237 int cpu = smp_processor_id();
238 reg_timer_rw_tmr0_ctrl tmr0_ctrl = { 0 };
239 reg_timer_rw_tmr0_div tmr0_div = TIMER0_DIV;
240 reg_timer_rw_intr_mask timer_intr_mask; 268 reg_timer_rw_intr_mask timer_intr_mask;
269 reg_timer_rw_tmr0_ctrl ctrl = {
270 .op = regk_timer_hold,
271 .freq = regk_timer_f100,
272 };
241 273
242 /* Setup the etrax timers. 274 REG_WR(timer, timer_base, rw_tmr0_ctrl, ctrl);
243 * Base frequency is 100MHz, divider 1000000 -> 100 HZ
244 * We use timer0, so timer1 is free.
245 * The trig timer is used by the fasttimer API if enabled.
246 */
247
248 tmr0_ctrl.op = regk_timer_ld;
249 tmr0_ctrl.freq = regk_timer_f100;
250 REG_WR(timer, timer_regs[cpu], rw_tmr0_div, tmr0_div);
251 REG_WR(timer, timer_regs[cpu], rw_tmr0_ctrl, tmr0_ctrl); /* Load */
252 tmr0_ctrl.op = regk_timer_run;
253 REG_WR(timer, timer_regs[cpu], rw_tmr0_ctrl, tmr0_ctrl); /* Start */
254 275
255 /* Enable the timer irq. */ 276 timer_intr_mask = REG_RD(timer, timer_base, rw_intr_mask);
256 timer_intr_mask = REG_RD(timer, timer_regs[cpu], rw_intr_mask);
257 timer_intr_mask.tmr0 = 1; 277 timer_intr_mask.tmr0 = 1;
258 REG_WR(timer, timer_regs[cpu], rw_intr_mask, timer_intr_mask); 278 REG_WR(timer, timer_base, rw_intr_mask, timer_intr_mask);
259} 279}
260 280
261void __init time_init(void) 281void __init time_init(void)
262{ 282{
263 reg_intr_vect_rw_mask intr_mask; 283 int irq;
284 int ret;
264 285
265 /* Probe for the RTC and read it if it exists. 286 /* Probe for the RTC and read it if it exists.
266 * Before the RTC can be probed the loops_per_usec variable needs 287 * Before the RTC can be probed the loops_per_usec variable needs
@@ -270,17 +291,21 @@ void __init time_init(void)
270 */ 291 */
271 loops_per_usec = 50; 292 loops_per_usec = 50;
272 293
273 /* Start CPU local timer. */ 294 irq = TIMER0_INTR_VECT;
274 cris_timer_init(); 295 timer_base = (void __iomem *) regi_timer0;
296
297 crisv32_timer_init();
298
299 crisv32_clockevent.cpumask = cpu_possible_mask;
300 crisv32_clockevent.irq = irq;
275 301
276 /* Enable the timer irq in global config. */ 302 ret = setup_irq(irq, &irq_timer);
277 intr_mask = REG_RD_VECT(intr_vect, regi_irq, rw_mask, 1); 303 if (ret)
278 intr_mask.timer0 = 1; 304 pr_warn("failed to setup irq %d\n", irq);
279 REG_WR_VECT(intr_vect, regi_irq, rw_mask, 1, intr_mask);
280 305
281 /* Now actually register the timer irq handler that calls 306 clockevents_config_and_register(&crisv32_clockevent,
282 * timer_interrupt(). */ 307 CRISV32_TIMER_FREQ,
283 setup_irq(TIMER0_INTR_VECT, &irq_timer); 308 2, 0xffffffff);
284 309
285 /* Enable watchdog if we should use one. */ 310 /* Enable watchdog if we should use one. */
286 311