]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - arch/sparc/kernel/leon_kernel.c
sparc32: generic clockevent support
[karo-tx-linux.git] / arch / sparc / kernel / leon_kernel.c
index a94122bc0c7bb4674a2cea8c39601c6e6aad64f4..722650ab83dac678afd670559bfc6f40a0d653aa 100644 (file)
@@ -10,6 +10,8 @@
 #include <linux/of_platform.h>
 #include <linux/interrupt.h>
 #include <linux/of_device.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
 
 #include <asm/oplib.h>
 #include <asm/timer.h>
@@ -250,7 +252,38 @@ void leon_update_virq_handling(unsigned int virq,
        irq_set_chip_data(virq, (void *)mask);
 }
 
-void __init leon_init_timers(irq_handler_t counter_fn)
+static u32 leon_cycles_offset(void)
+{
+       u32 rld, val, off;
+       rld = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].rld);
+       val = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].val);
+       off = rld - val;
+       return rld - val;
+}
+
+#ifdef CONFIG_SMP
+
+/* smp clockevent irq */
+irqreturn_t leon_percpu_timer_ce_interrupt(int irq, void *unused)
+{
+       struct clock_event_device *ce;
+       int cpu = smp_processor_id();
+
+       leon_clear_profile_irq(cpu);
+
+       ce = &per_cpu(sparc32_clockevent, cpu);
+
+       irq_enter();
+       if (ce->event_handler)
+               ce->event_handler(ce);
+       irq_exit();
+
+       return IRQ_HANDLED;
+}
+
+#endif /* CONFIG_SMP */
+
+void __init leon_init_timers(void)
 {
        int irq, eirq;
        struct device_node *rootnp, *np, *nnp;
@@ -260,6 +293,14 @@ void __init leon_init_timers(irq_handler_t counter_fn)
        int ampopts;
        int err;
 
+       sparc_config.get_cycles_offset = leon_cycles_offset;
+       sparc_config.cs_period = 1000000 / HZ;
+       sparc_config.features |= FEAT_L10_CLOCKSOURCE;
+
+#ifndef CONFIG_SMP
+       sparc_config.features |= FEAT_L10_CLOCKEVENT;
+#endif
+
        leondebug_irq_disable = 0;
        leon_debug_irqout = 0;
        master_l10_counter = (unsigned int *)&dummy_master_l10_counter;
@@ -369,7 +410,7 @@ void __init leon_init_timers(irq_handler_t counter_fn)
                leon_eirq_setup(eirq);
 
        irq = _leon_build_device_irq(NULL, leon3_gptimer_irq+leon3_gptimer_idx);
-       err = request_irq(irq, counter_fn, IRQF_TIMER, "timer", NULL);
+       err = request_irq(irq, timer_interrupt, IRQF_TIMER, "timer", NULL);
        if (err) {
                printk(KERN_ERR "unable to attach timer IRQ%d\n", irq);
                prom_halt();
@@ -401,7 +442,7 @@ void __init leon_init_timers(irq_handler_t counter_fn)
        /* Install per-cpu IRQ handler for broadcasted ticker */
        irq = leon_build_device_irq(leon3_ticker_irq, handle_percpu_irq,
                                    "per-cpu", 0);
-       err = request_irq(irq, leon_percpu_timer_interrupt,
+       err = request_irq(irq, leon_percpu_timer_ce_interrupt,
                          IRQF_PERCPU | IRQF_TIMER, "ticker",
                          NULL);
        if (err) {
@@ -428,7 +469,6 @@ void leon_clear_clock_irq(void)
 
 void leon_load_profile_irq(int cpu, unsigned int limit)
 {
-       BUG();
 }
 
 void __init leon_trans_init(struct device_node *dp)
@@ -496,6 +536,7 @@ void __init leon_init_IRQ(void)
 {
        sparc_config.init_timers      = leon_init_timers;
        sparc_config.build_device_irq = _leon_build_device_irq;
+       sparc_config.clock_rate = 1000000;
 
        BTFIXUPSET_CALL(clear_clock_irq, leon_clear_clock_irq,
                        BTFIXUPCALL_NORM);