rk30: timer: try fix asynchronous read timer, return value may undefined
author黄涛 <huangtao@rock-chips.com>
Thu, 28 Jun 2012 03:17:55 +0000 (11:17 +0800)
committer黄涛 <huangtao@rock-chips.com>
Thu, 28 Jun 2012 03:20:41 +0000 (11:20 +0800)
arch/arm/mach-rk30/clock_data.c
arch/arm/mach-rk30/timer.c

index 1f24fcb58309ca84509485bd12d3c5bcdabc2bc0..3ef0cdfad4f2e1b0af575983a94fc7664a96f0e1 100644 (file)
@@ -3027,7 +3027,7 @@ static void __init rk30_init_enable_clocks(void)
 
        #endif
 
-               #if 1
+               #if 0
                clk_enable_nolock(&clk_timer0);
                clk_enable_nolock(&clk_pclk_timer0);
                
index 23ab6ef39a35e66df175cd4c7375f97025392fe0..87addf2b11b8379ba17e32ee2f8035c2263cc05f 100755 (executable)
@@ -70,28 +70,41 @@ static inline u32 timer_read(u32 n, u32 offset)
 #define IRQ_NR_TIMER_CLKSRC            IRQ_TIMER1
 #define TIMER_CLKSRC_NAME              "timer1"
 
+static inline u32 rk30_timer_read_current_value(u32 n)
+{
+       unsigned long flags;
+       u32 v[3];
+       int loop = 100;
+
+       do {
+               local_irq_save(flags);
+               v[0] = RK_TIMER_READVALUE(n);
+               v[1] = RK_TIMER_READVALUE(n);
+               v[2] = RK_TIMER_READVALUE(n);
+               local_irq_restore(flags);
+               if ((v[0] >= v[1]) && ((v[0] - v[1]) < 24)
+                && (v[1] >= v[2]) && ((v[1] - v[2]) < 24))
+                       break;
+       } while (loop--);
+
+       return v[1];
+}
+
 static int rk30_timer_set_next_event(unsigned long cycles, struct clock_event_device *evt)
 {
        do {
                RK_TIMER_DISABLE(TIMER_CLKEVT);
                RK_TIMER_SETCOUNT(TIMER_CLKEVT, cycles);
                RK_TIMER_ENABLE(TIMER_CLKEVT);
-       } while (RK_TIMER_READVALUE(TIMER_CLKEVT) > cycles);
+       } while (rk30_timer_read_current_value(TIMER_CLKEVT) > cycles);
        return 0;
 }
 
 static void rk30_timer_set_mode(enum clock_event_mode mode, struct clock_event_device *evt)
 {
-       u32 count;
-
        switch (mode) {
        case CLOCK_EVT_MODE_PERIODIC:
-               count = 24000000 / HZ - 1;
-               do {
-                       RK_TIMER_DISABLE(TIMER_CLKEVT);
-                       RK_TIMER_SETCOUNT(TIMER_CLKEVT, count);
-                       RK_TIMER_ENABLE(TIMER_CLKEVT);
-               } while (RK_TIMER_READVALUE(TIMER_CLKEVT) > count);
+               rk30_timer_set_next_event(24000000 / HZ - 1, evt);
                break;
        case CLOCK_EVT_MODE_RESUME:
        case CLOCK_EVT_MODE_ONESHOT:
@@ -136,7 +149,9 @@ static __init int rk30_timer_init_clockevent(void)
 {
        struct clock_event_device *ce = &rk30_timer_clockevent;
        struct clk *clk = clk_get(NULL, TIMER_CLKEVT_NAME);
+       struct clk *pclk = clk_get(NULL, "pclk_" TIMER_CLKEVT_NAME);
 
+       clk_enable(pclk);
        clk_enable(clk);
 
        RK_TIMER_DISABLE(TIMER_CLKEVT);
@@ -152,9 +167,15 @@ static __init int rk30_timer_init_clockevent(void)
 
 static cycle_t rk30_timer_read(struct clocksource *cs)
 {
-       return ~RK_TIMER_READVALUE(TIMER_CLKSRC);
+       return ~rk30_timer_read_current_value(TIMER_CLKSRC);
 }
 
+/*
+ * Constants generated by clocksource_hz2mult(24000000, 26).
+ * This gives a resolution of about 41ns and a wrap period of about 178s.
+ */
+#define MULT   2796202667u
+#define SHIFT  26
 #define MASK   (u32)~0
 
 static struct clocksource rk30_timer_clocksource = {
@@ -170,36 +191,41 @@ static void __init rk30_timer_init_clocksource(void)
        static char err[] __initdata = KERN_ERR "%s: can't register clocksource!\n";
        struct clocksource *cs = &rk30_timer_clocksource;
        struct clk *clk = clk_get(NULL, TIMER_CLKSRC_NAME);
+       struct clk *pclk = clk_get(NULL, "pclk_" TIMER_CLKSRC_NAME);
 
+       clk_enable(pclk);
        clk_enable(clk);
 
        RK_TIMER_DISABLE(TIMER_CLKSRC);
+       clk_disable(clk);
        RK_TIMER_SETCOUNT(TIMER_CLKSRC, 0xFFFFFFFF);
        RK_TIMER_ENABLE_FREE_RUNNING(TIMER_CLKSRC);
+       clk_enable(clk);
 
        if (clocksource_register_hz(cs, 24000000))
                printk(err, cs->name);
 }
 
+#ifdef CONFIG_HAVE_SCHED_CLOCK
 static DEFINE_CLOCK_DATA(cd);
 
 unsigned long long notrace sched_clock(void)
 {
-       u32 cyc = ~RK_TIMER_READVALUE(TIMER_CLKSRC);
-       const struct clocksource *cs = &rk30_timer_clocksource;
-       return cyc_to_fixed_sched_clock(&cd, cyc, MASK, cs->mult, cs->shift);
+       u32 cyc = ~rk30_timer_read_current_value(TIMER_CLKSRC);
+       return cyc_to_fixed_sched_clock(&cd, cyc, MASK, MULT, SHIFT);
 }
 
 static void notrace rk30_update_sched_clock(void)
 {
-       u32 cyc = ~RK_TIMER_READVALUE(TIMER_CLKSRC);
+       u32 cyc = ~rk30_timer_read_current_value(TIMER_CLKSRC);
        update_sched_clock(&cd, cyc, MASK);
 }
 
 static void __init rk30_sched_clock_init(void)
 {
-       init_sched_clock(&cd, rk30_update_sched_clock, 32, 24000000);
+       init_fixed_sched_clock(&cd, rk30_update_sched_clock, 32, 24000000, MULT, SHIFT);
 }
+#endif
 
 static void __init rk30_timer_init(void)
 {
@@ -208,7 +234,9 @@ static void __init rk30_timer_init(void)
 #endif
        rk30_timer_init_clocksource();
        rk30_timer_init_clockevent();
+#ifdef CONFIG_HAVE_SCHED_CLOCK
        rk30_sched_clock_init();
+#endif
 }
 
 struct sys_timer rk30_timer = {