From 92c638dd57ae43ecee56b4e397b8336e55fcaeec Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E9=BB=84=E6=B6=9B?= Date: Sat, 22 Oct 2011 10:00:54 +0800 Subject: [PATCH] rk29: timer: peripheral timer use pclk_periph 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 | 97 +++++++++++++++----------------------- 1 file changed, 39 insertions(+), 58 deletions(-) diff --git a/arch/arm/mach-rk29/timer.c b/arch/arm/mach-rk29/timer.c index a0d0596832c4..9bd94d105667 100644 --- a/arch/arm/mach-rk29/timer.c +++ b/arch/arm/mach-rk29/timer.c @@ -25,31 +25,40 @@ #include #include -#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 @@ -59,30 +68,6 @@ #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) -- 2.34.1