#include <linux/platform_device.h>
#include <asm/localtimer.h>
+#include <asm/sched_clock.h>
#define TIMER_NAME "rk_timer"
dsb();
}
-static inline u64 rk_timer_read_current_value(void __iomem *base)
+static inline u32 rk_timer_read_current_value(void __iomem *base)
{
- /*
- * 1. Read the upper 32-bit timer counter register
- * 2. Read the lower 32-bit timer counter register
- * 3. Read the upper 32-bit timer counter register again. If the value is different to the 32-bit
- * upper value read previously, go back to step 2. Otherwise the 64-bit timer counter value
- * is correct.
- */
- u32 upper, lower;
-
- do {
- upper = readl_relaxed(base + TIMER_CURRENT_VALUE1);
- lower = readl_relaxed(base + TIMER_CURRENT_VALUE0);
- } while (upper != readl_relaxed(base + TIMER_CURRENT_VALUE1));
-
- return ((u64) upper << 32) + lower;
+ return readl_relaxed(base + TIMER_CURRENT_VALUE0);
}
struct rk_timer {
return ~rk_timer_read_current_value(timer.cs_base);
}
+/*
+ * 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 rk_timer_clocksource = {
.name = TIMER_NAME,
.rating = 200,
.read = rk_timer_read,
- .mask = CLOCKSOURCE_MASK(64),
+ .mask = CLOCKSOURCE_MASK(32),
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
printk(err, cs->name);
}
+static DEFINE_CLOCK_DATA(cd);
+
+unsigned long long notrace sched_clock(void)
+{
+ cycle_t cyc;
+
+ if (!timer.cs_base)
+ return 0;
+
+ cyc = ~rk_timer_read_current_value(timer.cs_base);
+ return cyc_to_fixed_sched_clock(&cd, cyc, MASK, MULT, SHIFT);
+}
+
+static void notrace rk_timer_update_sched_clock(void)
+{
+ u32 cyc = ~rk_timer_read_current_value(timer.cs_base);
+ update_sched_clock(&cd, cyc, MASK);
+}
+
+static void __init rk_timer_init_sched_clock(void)
+{
+ init_fixed_sched_clock(&cd, rk_timer_update_sched_clock, 32, 24000000, MULT, SHIFT);
+}
+
#ifndef CONFIG_LOCAL_TIMERS
static struct clock_event_device rk_timer_clockevent;
#endif
rk_timer_clockevent.rating = 200;
rk_timer_init_clockevent(&rk_timer_clockevent, 0);
#endif
+ rk_timer_init_sched_clock();
- printk("rk_timer: version 1.1\n");
+ printk("rk_timer: version 1.2\n");
return 0;
}
return 0;
}
#endif
-
-/*
- * Scheduler clock - returns current time in nanosec units.
- */
-unsigned long long notrace sched_clock(void)
-{
- const struct clocksource *cs = &rk_timer_clocksource;
- cycle_t cyc;
-
- if (!timer.cs_base)
- return 0;
-
- cyc = ~rk_timer_read_current_value(timer.cs_base);
- return clocksource_cyc2ns(cyc, cs->mult, cs->shift);
-}