diff options
Diffstat (limited to 'arch/microblaze/kernel/timer.c')
-rw-r--r-- | arch/microblaze/kernel/timer.c | 186 |
1 files changed, 76 insertions, 110 deletions
diff --git a/arch/microblaze/kernel/timer.c b/arch/microblaze/kernel/timer.c index aec5020a6e31..e4b3f33ef34c 100644 --- a/arch/microblaze/kernel/timer.c +++ b/arch/microblaze/kernel/timer.c @@ -1,5 +1,6 @@ /* - * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu> + * Copyright (C) 2007-2013 Michal Simek <monstr@monstr.eu> + * Copyright (C) 2012-2013 Xilinx, Inc. * Copyright (C) 2007-2009 PetaLogix * Copyright (C) 2006 Atmark Techno, Inc. * @@ -8,34 +9,16 @@ * for more details. */ -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/param.h> #include <linux/interrupt.h> -#include <linux/profile.h> -#include <linux/irq.h> #include <linux/delay.h> #include <linux/sched.h> -#include <linux/spinlock.h> -#include <linux/err.h> #include <linux/clk.h> -#include <linux/clocksource.h> #include <linux/clockchips.h> -#include <linux/io.h> -#include <linux/bug.h> +#include <linux/of_address.h> #include <asm/cpuinfo.h> -#include <asm/setup.h> -#include <asm/prom.h> -#include <asm/irq.h> #include <linux/cnt32_to_63.h> -#ifdef CONFIG_SELFMOD_TIMER -#include <asm/selfmod.h> -#define TIMER_BASE BARRIER_BASE_ADDR -#else -static unsigned int timer_baseaddr; -#define TIMER_BASE timer_baseaddr -#endif +static void __iomem *timer_baseaddr; static unsigned int freq_div_hz; static unsigned int timer_clock_freq; @@ -59,19 +42,21 @@ static unsigned int timer_clock_freq; #define TCSR_PWMA (1<<9) #define TCSR_ENALL (1<<10) -static inline void microblaze_timer0_stop(void) +static inline void xilinx_timer0_stop(void) { - out_be32(TIMER_BASE + TCSR0, in_be32(TIMER_BASE + TCSR0) & ~TCSR_ENT); + out_be32(timer_baseaddr + TCSR0, + in_be32(timer_baseaddr + TCSR0) & ~TCSR_ENT); } -static inline void microblaze_timer0_start_periodic(unsigned long load_val) +static inline void xilinx_timer0_start_periodic(unsigned long load_val) { if (!load_val) load_val = 1; - out_be32(TIMER_BASE + TLR0, load_val); /* loading value to timer reg */ + /* loading value to timer reg */ + out_be32(timer_baseaddr + TLR0, load_val); /* load the initial value */ - out_be32(TIMER_BASE + TCSR0, TCSR_LOAD); + out_be32(timer_baseaddr + TCSR0, TCSR_LOAD); /* see timer data sheet for detail * !ENALL - don't enable 'em all @@ -86,38 +71,39 @@ static inline void microblaze_timer0_start_periodic(unsigned long load_val) * UDT - set the timer as down counter * !MDT0 - generate mode */ - out_be32(TIMER_BASE + TCSR0, + out_be32(timer_baseaddr + TCSR0, TCSR_TINT|TCSR_ENIT|TCSR_ENT|TCSR_ARHT|TCSR_UDT); } -static inline void microblaze_timer0_start_oneshot(unsigned long load_val) +static inline void xilinx_timer0_start_oneshot(unsigned long load_val) { if (!load_val) load_val = 1; - out_be32(TIMER_BASE + TLR0, load_val); /* loading value to timer reg */ + /* loading value to timer reg */ + out_be32(timer_baseaddr + TLR0, load_val); /* load the initial value */ - out_be32(TIMER_BASE + TCSR0, TCSR_LOAD); + out_be32(timer_baseaddr + TCSR0, TCSR_LOAD); - out_be32(TIMER_BASE + TCSR0, + out_be32(timer_baseaddr + TCSR0, TCSR_TINT|TCSR_ENIT|TCSR_ENT|TCSR_ARHT|TCSR_UDT); } -static int microblaze_timer_set_next_event(unsigned long delta, +static int xilinx_timer_set_next_event(unsigned long delta, struct clock_event_device *dev) { pr_debug("%s: next event, delta %x\n", __func__, (u32)delta); - microblaze_timer0_start_oneshot(delta); + xilinx_timer0_start_oneshot(delta); return 0; } -static void microblaze_timer_set_mode(enum clock_event_mode mode, +static void xilinx_timer_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) { switch (mode) { case CLOCK_EVT_MODE_PERIODIC: pr_info("%s: periodic\n", __func__); - microblaze_timer0_start_periodic(freq_div_hz); + xilinx_timer0_start_periodic(freq_div_hz); break; case CLOCK_EVT_MODE_ONESHOT: pr_info("%s: oneshot\n", __func__); @@ -127,7 +113,7 @@ static void microblaze_timer_set_mode(enum clock_event_mode mode, break; case CLOCK_EVT_MODE_SHUTDOWN: pr_info("%s: shutdown\n", __func__); - microblaze_timer0_stop(); + xilinx_timer0_stop(); break; case CLOCK_EVT_MODE_RESUME: pr_info("%s: resume\n", __func__); @@ -135,23 +121,23 @@ static void microblaze_timer_set_mode(enum clock_event_mode mode, } } -static struct clock_event_device clockevent_microblaze_timer = { - .name = "microblaze_clockevent", +static struct clock_event_device clockevent_xilinx_timer = { + .name = "xilinx_clockevent", .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, .shift = 8, .rating = 300, - .set_next_event = microblaze_timer_set_next_event, - .set_mode = microblaze_timer_set_mode, + .set_next_event = xilinx_timer_set_next_event, + .set_mode = xilinx_timer_set_mode, }; static inline void timer_ack(void) { - out_be32(TIMER_BASE + TCSR0, in_be32(TIMER_BASE + TCSR0)); + out_be32(timer_baseaddr + TCSR0, in_be32(timer_baseaddr + TCSR0)); } static irqreturn_t timer_interrupt(int irq, void *dev_id) { - struct clock_event_device *evt = &clockevent_microblaze_timer; + struct clock_event_device *evt = &clockevent_xilinx_timer; #ifdef CONFIG_HEART_BEAT heartbeat(); #endif @@ -164,73 +150,74 @@ static struct irqaction timer_irqaction = { .handler = timer_interrupt, .flags = IRQF_DISABLED | IRQF_TIMER, .name = "timer", - .dev_id = &clockevent_microblaze_timer, + .dev_id = &clockevent_xilinx_timer, }; -static __init void microblaze_clockevent_init(void) +static __init void xilinx_clockevent_init(void) { - clockevent_microblaze_timer.mult = + clockevent_xilinx_timer.mult = 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); - clockevent_microblaze_timer.min_delta_ns = - clockevent_delta2ns(1, &clockevent_microblaze_timer); - clockevent_microblaze_timer.cpumask = cpumask_of(0); - clockevents_register_device(&clockevent_microblaze_timer); + clockevent_xilinx_timer.shift); + clockevent_xilinx_timer.max_delta_ns = + clockevent_delta2ns((u32)~0, &clockevent_xilinx_timer); + clockevent_xilinx_timer.min_delta_ns = + clockevent_delta2ns(1, &clockevent_xilinx_timer); + clockevent_xilinx_timer.cpumask = cpumask_of(0); + clockevents_register_device(&clockevent_xilinx_timer); } -static cycle_t microblaze_read(struct clocksource *cs) +static cycle_t xilinx_read(struct clocksource *cs) { /* reading actual value of timer 1 */ - return (cycle_t) (in_be32(TIMER_BASE + TCR1)); + return (cycle_t) (in_be32(timer_baseaddr + TCR1)); } -static struct timecounter microblaze_tc = { +static struct timecounter xilinx_tc = { .cc = NULL, }; -static cycle_t microblaze_cc_read(const struct cyclecounter *cc) +static cycle_t xilinx_cc_read(const struct cyclecounter *cc) { - return microblaze_read(NULL); + return xilinx_read(NULL); } -static struct cyclecounter microblaze_cc = { - .read = microblaze_cc_read, +static struct cyclecounter xilinx_cc = { + .read = xilinx_cc_read, .mask = CLOCKSOURCE_MASK(32), .shift = 8, }; -static int __init init_microblaze_timecounter(void) +static int __init init_xilinx_timecounter(void) { - microblaze_cc.mult = div_sc(timer_clock_freq, NSEC_PER_SEC, - microblaze_cc.shift); + xilinx_cc.mult = div_sc(timer_clock_freq, NSEC_PER_SEC, + xilinx_cc.shift); - timecounter_init(µblaze_tc, µblaze_cc, sched_clock()); + timecounter_init(&xilinx_tc, &xilinx_cc, sched_clock()); return 0; } static struct clocksource clocksource_microblaze = { - .name = "microblaze_clocksource", + .name = "xilinx_clocksource", .rating = 300, - .read = microblaze_read, + .read = xilinx_read, .mask = CLOCKSOURCE_MASK(32), .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; -static int __init microblaze_clocksource_init(void) +static int __init xilinx_clocksource_init(void) { if (clocksource_register_hz(&clocksource_microblaze, timer_clock_freq)) panic("failed to register clocksource"); /* stop timer1 */ - out_be32(TIMER_BASE + TCSR1, in_be32(TIMER_BASE + TCSR1) & ~TCSR_ENT); + out_be32(timer_baseaddr + TCSR1, + in_be32(timer_baseaddr + TCSR1) & ~TCSR_ENT); /* start timer1 - up counting without interrupt */ - out_be32(TIMER_BASE + TCSR1, TCSR_TINT|TCSR_ENT|TCSR_ARHT); + out_be32(timer_baseaddr + TCSR1, TCSR_TINT|TCSR_ENT|TCSR_ARHT); /* register timecounter - for ftrace support */ - init_microblaze_timecounter(); + init_xilinx_timecounter(); return 0; } @@ -240,55 +227,31 @@ static int __init microblaze_clocksource_init(void) */ static int timer_initialized; -void __init time_init(void) +static void __init xilinx_timer_init(struct device_node *timer) { u32 irq; u32 timer_num = 1; - struct device_node *timer = NULL; - const void *prop; -#ifdef CONFIG_SELFMOD_TIMER - unsigned int timer_baseaddr = 0; - int arr_func[] = { - (int)µblaze_read, - (int)&timer_interrupt, - (int)µblaze_clocksource_init, - (int)µblaze_timer_set_mode, - (int)µblaze_timer_set_next_event, - 0 - }; -#endif - prop = of_get_property(of_chosen, "system-timer", NULL); - if (prop) - timer = of_find_node_by_phandle(be32_to_cpup(prop)); - else - pr_info("No chosen timer found, using default\n"); - - if (!timer) - timer = of_find_compatible_node(NULL, NULL, - "xlnx,xps-timer-1.00.a"); - BUG_ON(!timer); - - timer_baseaddr = be32_to_cpup(of_get_property(timer, "reg", NULL)); - timer_baseaddr = (unsigned long) ioremap(timer_baseaddr, PAGE_SIZE); + int ret; + + timer_baseaddr = of_iomap(timer, 0); + if (!timer_baseaddr) { + pr_err("ERROR: invalid timer base address\n"); + BUG(); + } + irq = irq_of_parse_and_map(timer, 0); - timer_num = be32_to_cpup(of_get_property(timer, - "xlnx,one-timer-only", NULL)); + + of_property_read_u32(timer, "xlnx,one-timer-only", &timer_num); if (timer_num) { - pr_emerg("Please enable two timers in HW\n"); + pr_emerg("Please enable two timers in HW\n"); BUG(); } -#ifdef CONFIG_SELFMOD_TIMER - selfmod_function((int *) arr_func, timer_baseaddr); -#endif - pr_info("%s #0 at 0x%08x, irq=%d\n", - timer->name, timer_baseaddr, irq); + pr_info("%s: irq=%d\n", timer->full_name, irq); /* 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 + ret = of_property_read_u32(timer, "clock-frequency", &timer_clock_freq); + if (ret < 0) timer_clock_freq = cpuinfo.cpu_clock_freq; freq_div_hz = timer_clock_freq / HZ; @@ -297,8 +260,8 @@ void __init time_init(void) #ifdef CONFIG_HEART_BEAT setup_heartbeat(); #endif - microblaze_clocksource_init(); - microblaze_clockevent_init(); + xilinx_clocksource_init(); + xilinx_clockevent_init(); timer_initialized = 1; } @@ -312,3 +275,6 @@ unsigned long long notrace sched_clock(void) } return 0; } + +CLOCKSOURCE_OF_DECLARE(xilinx_timer, "xlnx,xps-timer-1.00.a", + xilinx_timer_init); |