rk29: timer: peripheral timer use pclk_periph
author黄涛 <huangtao@rock-chips.com>
Sat, 22 Oct 2011 02:00:54 +0000 (10:00 +0800)
committer黄涛 <huangtao@rock-chips.com>
Sat, 22 Oct 2011 02:10:32 +0000 (10:10 +0800)
We never change pclk_periph when use timer, so it is safe use pclk_periph
as parent clock.
We see some bug when use xin24m. For example rk29_timer_set_next_event will
loop 1s+ on ramos w15 machines.

arch/arm/mach-rk29/timer.c

index a0d0596832c47cce6d39bc29e2a097b54f9f8637..9bd94d105667e8f5b0bc476ff0a338347ee87dc9 100644 (file)
 #include <asm/mach/time.h>
 #include <mach/rk29_iomap.h>
 
-#define TIMER_LOAD_COUNT       0x0000
-#define TIMER_CUR_VALUE                0x0004
-#define TIMER_CONTROL_REG      0x0008
-#define TIMER_EOI              0x000C
-#define TIMER_INT_STATUS       0x0010
+#define TIMER_LOAD_COUNT               0x0000
+#define TIMER_CUR_VALUE                        0x0004
+#define TIMER_CONTROL_REG              0x0008
+#define TIMER_EOI                      0x000C
+#define TIMER_INT_STATUS               0x0010
 
 #define TIMER_DISABLE                  6
 #define TIMER_ENABLE                   3
 #define TIMER_ENABLE_FREE_RUNNING      5
 
-#define timer_writel(v, addr)          do { writel(v, addr); readl(addr); } while (0)
+static inline void timer_write(u32 n, u32 v, u32 offset)
+{
+       u32 addr = RK29_TIMER2_BASE + 0x4000 * (n - 2) + offset;
+       writel(v, addr);
+       dsb();
+}
 
-#if 1  /* by default, use periph sync timer */
+static inline u32 timer_read(u32 n, u32 offset)
+{
+       u32 addr = RK29_TIMER2_BASE + 0x4000 * (n - 2) + offset;
+       return readl(addr);
+}
 
-#define RK_TIMER_ENABLE(n)             timer_writel(TIMER_ENABLE, RK29_TIMER2_BASE + 0x4000 * (n - 2) + TIMER_CONTROL_REG)
-#define RK_TIMER_ENABLE_FREE_RUNNING(n)        timer_writel(TIMER_ENABLE_FREE_RUNNING, RK29_TIMER2_BASE + 0x4000 * (n - 2) + TIMER_CONTROL_REG)
-#define RK_TIMER_DISABLE(n)            timer_writel(TIMER_DISABLE, RK29_TIMER2_BASE + 0x4000 * (n - 2) + TIMER_CONTROL_REG)
+#define RK_TIMER_ENABLE(n)             timer_write(n, TIMER_ENABLE, TIMER_CONTROL_REG)
+#define RK_TIMER_ENABLE_FREE_RUNNING(n)        timer_write(n, TIMER_ENABLE_FREE_RUNNING, TIMER_CONTROL_REG)
+#define RK_TIMER_DISABLE(n)            timer_write(n, TIMER_DISABLE, TIMER_CONTROL_REG)
 
-#define RK_TIMER_SETCOUNT(n, count)    timer_writel(count, RK29_TIMER2_BASE + 0x4000 * (n - 2) + TIMER_LOAD_COUNT)
-#define RK_TIMER_GETCOUNT(n)           readl(RK29_TIMER2_BASE + 0x4000 * (n - 2) + TIMER_LOAD_COUNT)
+#define RK_TIMER_SETCOUNT(n, count)    timer_write(n, count, TIMER_LOAD_COUNT)
+#define RK_TIMER_GETCOUNT(n)           timer_read(n, TIMER_LOAD_COUNT)
 
-#define RK_TIMER_READVALUE(n)          readl(RK29_TIMER2_BASE + 0x4000 * (n - 2) + TIMER_CUR_VALUE)
-#define RK_TIMER_INT_CLEAR(n)          readl(RK29_TIMER2_BASE + 0x4000 * (n - 2) + TIMER_EOI)
+#define RK_TIMER_READVALUE(n)          timer_read(n, TIMER_CUR_VALUE)
+#define RK_TIMER_INT_CLEAR(n)          timer_read(n, TIMER_EOI)
 
-#define RK_TIMER_INT_STATUS(n)         readl(RK29_TIMER2_BASE + 0x4000 * (n - 2) + TIMER_INT_STATUS)
+#define RK_TIMER_INT_STATUS(n)         timer_read(n, TIMER_INT_STATUS)
 
 #define TIMER_CLKEVT                   2       /* timer2 */
 #define IRQ_NR_TIMER_CLKEVT            IRQ_TIMER2
 #define IRQ_NR_TIMER_CLKSRC            IRQ_TIMER3
 #define TIMER_CLKSRC_NAME              "timer3"
 
-#else
-
-#define RK_TIMER_ENABLE(n)             timer_writel(TIMER_ENABLE, RK29_TIMER0_BASE + 0x2000 * n + TIMER_CONTROL_REG)
-#define RK_TIMER_ENABLE_FREE_RUNNING(n)        timer_writel(TIMER_ENABLE_FREE_RUNNING, RK29_TIMER0_BASE + 0x2000 * n + TIMER_CONTROL_REG)
-#define RK_TIMER_DISABLE(n)            timer_writel(TIMER_DISABLE, RK29_TIMER0_BASE + 0x2000 * n + TIMER_CONTROL_REG)
-
-#define RK_TIMER_SETCOUNT(n, count)    timer_writel(count, RK29_TIMER0_BASE + 0x2000 * n + TIMER_LOAD_COUNT)
-#define RK_TIMER_GETCOUNT(n)           readl(RK29_TIMER0_BASE + 0x2000 * n + TIMER_LOAD_COUNT)
-
-#define RK_TIMER_READVALUE(n)          readl(RK29_TIMER0_BASE + 0x2000 * n + TIMER_CUR_VALUE)
-#define RK_TIMER_INT_CLEAR(n)          readl(RK29_TIMER0_BASE + 0x2000 * n + TIMER_EOI)
-
-#define RK_TIMER_INT_STATUS(n)         readl(RK29_TIMER0_BASE + 0x2000 * n + TIMER_INT_STATUS)
-
-#define TIMER_CLKEVT                   0       /* timer0 */
-#define IRQ_NR_TIMER_CLKEVT            IRQ_TIMER0
-#define TIMER_CLKEVT_NAME              "timer0"
-
-#define TIMER_CLKSRC                   1       /* timer1 */
-#define IRQ_NR_TIMER_CLKSRC            IRQ_TIMER1
-#define TIMER_CLKSRC_NAME              "timer1"
-
-#endif
-
 static int rk29_timer_set_next_event(unsigned long cycles, struct clock_event_device *evt)
 {
        do {
@@ -95,13 +80,16 @@ static int rk29_timer_set_next_event(unsigned long cycles, struct clock_event_de
 
 static void rk29_timer_set_mode(enum clock_event_mode mode, struct clock_event_device *evt)
 {
+       u32 count;
+
        switch (mode) {
        case CLOCK_EVT_MODE_PERIODIC:
+               count = clk_get_rate(clk_get(NULL, TIMER_CLKEVT_NAME)) / HZ - 1;
                do {
                        RK_TIMER_DISABLE(TIMER_CLKEVT);
-                       RK_TIMER_SETCOUNT(TIMER_CLKEVT, 24000000/HZ - 1);
+                       RK_TIMER_SETCOUNT(TIMER_CLKEVT, count);
                        RK_TIMER_ENABLE(TIMER_CLKEVT);
-               } while (RK_TIMER_READVALUE(TIMER_CLKEVT) > (24000000/HZ - 1));
+               } while (RK_TIMER_READVALUE(TIMER_CLKEVT) > count);
                break;
        case CLOCK_EVT_MODE_RESUME:
        case CLOCK_EVT_MODE_ONESHOT:
@@ -116,7 +104,6 @@ static void rk29_timer_set_mode(enum clock_event_mode mode, struct clock_event_d
 static struct clock_event_device rk29_timer_clockevent = {
        .name           = TIMER_CLKEVT_NAME,
        .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
-       .shift          = 32,
        .rating         = 200,
        .set_next_event = rk29_timer_set_next_event,
        .set_mode       = rk29_timer_set_mode,
@@ -147,16 +134,16 @@ static __init int rk29_timer_init_clockevent(void)
 {
        struct clock_event_device *ce = &rk29_timer_clockevent;
        struct clk *clk = clk_get(NULL, TIMER_CLKEVT_NAME);
-       struct clk *xin24m = clk_get(NULL, "xin24m");
+       struct clk *pclk_periph = clk_get(NULL, "pclk_periph");
 
-       clk_set_parent(clk, xin24m);
+       clk_set_parent(clk, pclk_periph);
        clk_enable(clk);
 
        RK_TIMER_DISABLE(TIMER_CLKEVT);
 
        setup_irq(rk29_timer_clockevent_irq.irq, &rk29_timer_clockevent_irq);
 
-       ce->mult = div_sc(24000000, NSEC_PER_SEC, ce->shift);
+       clockevents_calc_mult_shift(ce, clk_get_rate(clk), 4);
        ce->max_delta_ns = clockevent_delta2ns(0xFFFFFFFFUL, ce);
        ce->min_delta_ns = clockevent_delta2ns(1, ce) + 1;
 
@@ -172,12 +159,6 @@ static cycle_t rk29_timer_read(struct clocksource *cs)
        return ~RK_TIMER_READVALUE(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 rk29_timer_clocksource = {
@@ -185,7 +166,6 @@ static struct clocksource rk29_timer_clocksource = {
        .rating         = 200,
        .read           = rk29_timer_read,
        .mask           = CLOCKSOURCE_MASK(32),
-       .shift          = SHIFT,
        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
@@ -194,16 +174,16 @@ static void __init rk29_timer_init_clocksource(void)
        static char err[] __initdata = KERN_ERR "%s: can't register clocksource!\n";
        struct clocksource *cs = &rk29_timer_clocksource;
        struct clk *clk = clk_get(NULL, TIMER_CLKSRC_NAME);
-       struct clk *xin24m = clk_get(NULL, "xin24m");
+       struct clk *pclk_periph = clk_get(NULL, "pclk_periph");
 
-       clk_set_parent(clk, xin24m);
+       clk_set_parent(clk, pclk_periph);
        clk_enable(clk);
 
        RK_TIMER_DISABLE(TIMER_CLKSRC);
        RK_TIMER_SETCOUNT(TIMER_CLKSRC, 0xFFFFFFFF);
        RK_TIMER_ENABLE_FREE_RUNNING(TIMER_CLKSRC);
 
-       cs->mult = MULT;
+       clocksource_calc_mult_shift(cs, clk_get_rate(clk), 60);
        if (clocksource_register(cs))
                printk(err, cs->name);
 }
@@ -213,7 +193,8 @@ static DEFINE_CLOCK_DATA(cd);
 unsigned long long notrace sched_clock(void)
 {
        u32 cyc = ~RK_TIMER_READVALUE(TIMER_CLKSRC);
-       return cyc_to_fixed_sched_clock(&cd, cyc, MASK, MULT, SHIFT);
+       const struct clocksource *cs = &rk29_timer_clocksource;
+       return cyc_to_fixed_sched_clock(&cd, cyc, MASK, cs->mult, cs->shift);
 }
 
 static void notrace rk29_update_sched_clock(void)
@@ -224,8 +205,8 @@ static void notrace rk29_update_sched_clock(void)
 
 static void __init rk29_sched_clock_init(void)
 {
-       init_fixed_sched_clock(&cd, rk29_update_sched_clock,
-                              32, 24000000, MULT, SHIFT);
+       init_sched_clock(&cd, rk29_update_sched_clock, 32,
+                        clk_get_rate(clk_get(NULL, TIMER_CLKSRC_NAME)));
 }
 
 static void __init rk29_timer_init(void)