summaryrefslogtreecommitdiff
path: root/drivers/clocksource
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@linaro.org>2017-06-11 23:26:17 +0200
committerDaniel Lezcano <daniel.lezcano@linaro.org>2017-06-14 12:02:33 +0200
commit385c98fcc1fb58c3e10157be2203eb37595dac7b (patch)
treececb7dc61cc843b667e7d23e0309300f9315f0ab /drivers/clocksource
parentdc11bae78529526605c5c45c369c9512fd012093 (diff)
clocksource/drivers/fttmr010: Implement delay timer
This timer is often used on the ARM architecture, so as with so many siblings, we can implement delay timers, removing the need for the system to calibrate jiffys at boot, and potentially handling CPU frequency scaling on targets. We cannot just protect the Kconfig with a "depends on ARM" because it is already known that different architectures are using Faraday IP blocks, so it is better to make things open-ended and use Result on boot dmesg: Switching to timer-based delay loop, resolution 40n Calibrating delay loop (skipped), value calculated using timer frequency.. 50.00 BogoMIPS (lpj=250000) This is accurately the timer frequency, 250MHz on the APB bus. Cc: Andrew Jeffery <andrew@aj.id.au> Cc: Joel Stanley <joel@jms.id.au> Cc: Jonas Jensen <jonas.jensen@gmail.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Tested-by: Jonas Jensen <jonas.jensen@gmail.com> Tested-by: Andrew Jeffery <andrew@aj.id.au> Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Diffstat (limited to 'drivers/clocksource')
-rw-r--r--drivers/clocksource/timer-fttmr010.c35
1 files changed, 34 insertions, 1 deletions
diff --git a/drivers/clocksource/timer-fttmr010.c b/drivers/clocksource/timer-fttmr010.c
index b56d7bdfcba1..009370460f23 100644
--- a/drivers/clocksource/timer-fttmr010.c
+++ b/drivers/clocksource/timer-fttmr010.c
@@ -17,6 +17,7 @@
#include <linux/clk.h>
#include <linux/slab.h>
#include <linux/bitops.h>
+#include <linux/delay.h>
/*
* Register definitions for the timers
@@ -81,9 +82,15 @@ struct fttmr010 {
bool count_down;
u32 t1_enable_val;
struct clock_event_device clkevt;
+#ifdef CONFIG_ARM
+ struct delay_timer delay_timer;
+#endif
};
-/* A local singleton used by sched_clock, which is stateless */
+/*
+ * A local singleton used by sched_clock and delay timer reads, which are
+ * fast and stateless
+ */
static struct fttmr010 *local_fttmr;
static inline struct fttmr010 *to_fttmr010(struct clock_event_device *evt)
@@ -101,6 +108,20 @@ static u64 notrace fttmr010_read_sched_clock_down(void)
return ~readl(local_fttmr->base + TIMER2_COUNT);
}
+#ifdef CONFIG_ARM
+
+static unsigned long fttmr010_read_current_timer_up(void)
+{
+ return readl(local_fttmr->base + TIMER2_COUNT);
+}
+
+static unsigned long fttmr010_read_current_timer_down(void)
+{
+ return ~readl(local_fttmr->base + TIMER2_COUNT);
+}
+
+#endif
+
static int fttmr010_timer_set_next_event(unsigned long cycles,
struct clock_event_device *evt)
{
@@ -347,6 +368,18 @@ static int __init fttmr010_common_init(struct device_node *np, bool is_aspeed)
fttmr010->tick_rate,
1, 0xffffffff);
+#ifdef CONFIG_ARM
+ /* Also use this timer for delays */
+ if (fttmr010->count_down)
+ fttmr010->delay_timer.read_current_timer =
+ fttmr010_read_current_timer_down;
+ else
+ fttmr010->delay_timer.read_current_timer =
+ fttmr010_read_current_timer_up;
+ fttmr010->delay_timer.freq = fttmr010->tick_rate;
+ register_current_timer_delay(&fttmr010->delay_timer);
+#endif
+
return 0;
out_unmap: