summaryrefslogtreecommitdiffstats
path: root/arch/sparc/kernel/leon_kernel.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc/kernel/leon_kernel.c')
-rw-r--r--arch/sparc/kernel/leon_kernel.c49
1 files changed, 45 insertions, 4 deletions
diff --git a/arch/sparc/kernel/leon_kernel.c b/arch/sparc/kernel/leon_kernel.c
index a94122bc0c7..722650ab83d 100644
--- a/arch/sparc/kernel/leon_kernel.c
+++ b/arch/sparc/kernel/leon_kernel.c
@@ -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);