#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:
{
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);
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 = {
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)
{
#endif
rk30_timer_init_clocksource();
rk30_timer_init_clockevent();
+#ifdef CONFIG_HAVE_SCHED_CLOCK
rk30_sched_clock_init();
+#endif
}
struct sys_timer rk30_timer = {