diff options
Diffstat (limited to 'arch/microblaze/kernel/timer.c')
-rw-r--r-- | arch/microblaze/kernel/timer.c | 65 |
1 files changed, 46 insertions, 19 deletions
diff --git a/arch/microblaze/kernel/timer.c b/arch/microblaze/kernel/timer.c index ed61b2f17719..a5aa33db1df3 100644 --- a/arch/microblaze/kernel/timer.c +++ b/arch/microblaze/kernel/timer.c @@ -28,6 +28,7 @@ #include <asm/prom.h> #include <asm/irq.h> #include <asm/system.h> +#include <linux/cnt32_to_63.h> #ifdef CONFIG_SELFMOD_TIMER #include <asm/selfmod.h> @@ -37,6 +38,9 @@ static unsigned int timer_baseaddr; #define TIMER_BASE timer_baseaddr #endif +unsigned int freq_div_hz; +unsigned int timer_clock_freq; + #define TCSR0 (0x00) #define TLR0 (0x04) #define TCR0 (0x08) @@ -114,7 +118,7 @@ static void microblaze_timer_set_mode(enum clock_event_mode mode, switch (mode) { case CLOCK_EVT_MODE_PERIODIC: printk(KERN_INFO "%s: periodic\n", __func__); - microblaze_timer0_start_periodic(cpuinfo.freq_div_hz); + microblaze_timer0_start_periodic(freq_div_hz); break; case CLOCK_EVT_MODE_ONESHOT: printk(KERN_INFO "%s: oneshot\n", __func__); @@ -135,7 +139,7 @@ static void microblaze_timer_set_mode(enum clock_event_mode mode, static struct clock_event_device clockevent_microblaze_timer = { .name = "microblaze_clockevent", .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, - .shift = 24, + .shift = 8, .rating = 300, .set_next_event = microblaze_timer_set_next_event, .set_mode = microblaze_timer_set_mode, @@ -167,7 +171,7 @@ static struct irqaction timer_irqaction = { static __init void microblaze_clockevent_init(void) { clockevent_microblaze_timer.mult = - div_sc(cpuinfo.cpu_clock_freq, NSEC_PER_SEC, + div_sc(timer_clock_freq, NSEC_PER_SEC, clockevent_microblaze_timer.shift); clockevent_microblaze_timer.max_delta_ns = clockevent_delta2ns((u32)~0, &clockevent_microblaze_timer); @@ -195,12 +199,12 @@ static cycle_t microblaze_cc_read(const struct cyclecounter *cc) static struct cyclecounter microblaze_cc = { .read = microblaze_cc_read, .mask = CLOCKSOURCE_MASK(32), - .shift = 24, + .shift = 8, }; int __init init_microblaze_timecounter(void) { - microblaze_cc.mult = div_sc(cpuinfo.cpu_clock_freq, NSEC_PER_SEC, + microblaze_cc.mult = div_sc(timer_clock_freq, NSEC_PER_SEC, microblaze_cc.shift); timecounter_init(µblaze_tc, µblaze_cc, sched_clock()); @@ -213,14 +217,14 @@ static struct clocksource clocksource_microblaze = { .rating = 300, .read = microblaze_read, .mask = CLOCKSOURCE_MASK(32), - .shift = 24, /* I can shift it */ + .shift = 8, /* I can shift it */ .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; static int __init microblaze_clocksource_init(void) { clocksource_microblaze.mult = - clocksource_hz2mult(cpuinfo.cpu_clock_freq, + clocksource_hz2mult(timer_clock_freq, clocksource_microblaze.shift); if (clocksource_register(&clocksource_microblaze)) panic("failed to register clocksource"); @@ -235,11 +239,18 @@ static int __init microblaze_clocksource_init(void) return 0; } +/* + * We have to protect accesses before timer initialization + * and return 0 for sched_clock function below. + */ +static int timer_initialized; + void __init time_init(void) { u32 irq, i = 0; u32 timer_num = 1; struct device_node *timer = NULL; + const void *prop; #ifdef CONFIG_SELFMOD_TIMER unsigned int timer_baseaddr = 0; int arr_func[] = { @@ -251,12 +262,10 @@ void __init time_init(void) 0 }; #endif - char *timer_list[] = { - "xlnx,xps-timer-1.00.a", - "xlnx,opb-timer-1.00.b", - "xlnx,opb-timer-1.00.a", - NULL - }; + const char * const timer_list[] = { + "xlnx,xps-timer-1.00.a", + NULL + }; for (i = 0; timer_list[i] != NULL; i++) { timer = of_find_compatible_node(NULL, NULL, timer_list[i]); @@ -265,13 +274,13 @@ void __init time_init(void) } BUG_ON(!timer); - timer_baseaddr = *(int *) of_get_property(timer, "reg", NULL); + timer_baseaddr = be32_to_cpup(of_get_property(timer, "reg", NULL)); timer_baseaddr = (unsigned long) ioremap(timer_baseaddr, PAGE_SIZE); - irq = *(int *) of_get_property(timer, "interrupts", NULL); - timer_num = - *(int *) of_get_property(timer, "xlnx,one-timer-only", NULL); + irq = be32_to_cpup(of_get_property(timer, "interrupts", NULL)); + timer_num = be32_to_cpup(of_get_property(timer, + "xlnx,one-timer-only", NULL)); if (timer_num) { - printk(KERN_EMERG "Please enable two timers in HW\n"); + eprintk(KERN_EMERG "Please enable two timers in HW\n"); BUG(); } @@ -281,7 +290,14 @@ void __init time_init(void) printk(KERN_INFO "%s #0 at 0x%08x, irq=%d\n", timer_list[i], timer_baseaddr, irq); - cpuinfo.freq_div_hz = cpuinfo.cpu_clock_freq / HZ; + /* If there is clock-frequency property than use it */ + prop = of_get_property(timer, "clock-frequency", NULL); + if (prop) + timer_clock_freq = be32_to_cpup(prop); + else + timer_clock_freq = cpuinfo.cpu_clock_freq; + + freq_div_hz = timer_clock_freq / HZ; setup_irq(irq, &timer_irqaction); #ifdef CONFIG_HEART_BEAT @@ -289,4 +305,15 @@ void __init time_init(void) #endif microblaze_clocksource_init(); microblaze_clockevent_init(); + timer_initialized = 1; +} + +unsigned long long notrace sched_clock(void) +{ + if (timer_initialized) { + struct clocksource *cs = &clocksource_microblaze; + cycle_t cyc = cnt32_to_63(cs->read(NULL)); + return clocksource_cyc2ns(cyc, cs->mult, cs->shift); + } + return 0; } |