]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - arch/arm/mach-omap2/timer.c
Merge tag 'dt' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
[karo-tx-linux.git] / arch / arm / mach-omap2 / timer.c
index 5214d5bfba27a9b23d5450a614690415c456adf2..8847d6eb23131b7df5e32c94fea1b8a4018f15fa 100644 (file)
 #include <linux/clocksource.h>
 #include <linux/clockchips.h>
 #include <linux/slab.h>
+#include <linux/of.h>
 
 #include <asm/mach/time.h>
 #include <asm/smp_twd.h>
 #include <asm/sched_clock.h>
 
+#include <asm/arch_timer.h>
 #include <plat/omap_hwmod.h>
 #include <plat/omap_device.h>
 #include <plat/dmtimer.h>
 #define OMAP3_SECURE_TIMER     1
 #endif
 
+#define REALTIME_COUNTER_BASE                          0x48243200
+#define INCREMENTER_NUMERATOR_OFFSET                   0x10
+#define INCREMENTER_DENUMERATOR_RELOAD_OFFSET          0x14
+#define NUMERATOR_DENUMERATOR_MASK                     0xfffff000
+
 /* Clockevent code */
 
 static struct omap_dm_timer clkev;
@@ -348,6 +355,84 @@ static void __init omap2_clocksource_init(int gptimer_id,
                omap2_gptimer_clocksource_init(gptimer_id, fck_source);
 }
 
+#ifdef CONFIG_SOC_HAS_REALTIME_COUNTER
+/*
+ * The realtime counter also called master counter, is a free-running
+ * counter, which is related to real time. It produces the count used
+ * by the CPU local timer peripherals in the MPU cluster. The timer counts
+ * at a rate of 6.144 MHz. Because the device operates on different clocks
+ * in different power modes, the master counter shifts operation between
+ * clocks, adjusting the increment per clock in hardware accordingly to
+ * maintain a constant count rate.
+ */
+static void __init realtime_counter_init(void)
+{
+       void __iomem *base;
+       static struct clk *sys_clk;
+       unsigned long rate;
+       unsigned int reg, num, den;
+
+       base = ioremap(REALTIME_COUNTER_BASE, SZ_32);
+       if (!base) {
+               pr_err("%s: ioremap failed\n", __func__);
+               return;
+       }
+       sys_clk = clk_get(NULL, "sys_clkin_ck");
+       if (!sys_clk) {
+               pr_err("%s: failed to get system clock handle\n", __func__);
+               iounmap(base);
+               return;
+       }
+
+       rate = clk_get_rate(sys_clk);
+       /* Numerator/denumerator values refer TRM Realtime Counter section */
+       switch (rate) {
+       case 1200000:
+               num = 64;
+               den = 125;
+               break;
+       case 1300000:
+               num = 768;
+               den = 1625;
+               break;
+       case 19200000:
+               num = 8;
+               den = 25;
+               break;
+       case 2600000:
+               num = 384;
+               den = 1625;
+               break;
+       case 2700000:
+               num = 256;
+               den = 1125;
+               break;
+       case 38400000:
+       default:
+               /* Program it for 38.4 MHz */
+               num = 4;
+               den = 25;
+               break;
+       }
+
+       /* Program numerator and denumerator registers */
+       reg = __raw_readl(base + INCREMENTER_NUMERATOR_OFFSET) &
+                       NUMERATOR_DENUMERATOR_MASK;
+       reg |= num;
+       __raw_writel(reg, base + INCREMENTER_NUMERATOR_OFFSET);
+
+       reg = __raw_readl(base + INCREMENTER_NUMERATOR_OFFSET) &
+                       NUMERATOR_DENUMERATOR_MASK;
+       reg |= den;
+       __raw_writel(reg, base + INCREMENTER_DENUMERATOR_RELOAD_OFFSET);
+
+       iounmap(base);
+}
+#else
+static inline void __init realtime_counter_init(void)
+{}
+#endif
+
 #define OMAP_SYS_TIMER_INIT(name, clkev_nr, clkev_src,                 \
                                clksrc_nr, clksrc_src)                  \
 static void __init omap##name##_timer_init(void)                       \
@@ -394,6 +479,11 @@ static void __init omap4_timer_init(void)
        if (omap_rev() != OMAP4430_REV_ES1_0) {
                int err;
 
+               if (of_have_populated_dt()) {
+                       twd_local_timer_of_register();
+                       return;
+               }
+
                err = twd_local_timer_register(&twd_local_timer);
                if (err)
                        pr_err("twd_local_timer_register failed %d\n", err);
@@ -404,7 +494,18 @@ OMAP_SYS_TIMER(4)
 #endif
 
 #ifdef CONFIG_SOC_OMAP5
-OMAP_SYS_TIMER_INIT(5, 1, OMAP4_CLKEV_SOURCE, 2, OMAP4_MPU_SOURCE)
+static void __init omap5_timer_init(void)
+{
+       int err;
+
+       omap2_gp_clockevent_init(1, OMAP4_CLKEV_SOURCE);
+       omap2_clocksource_init(2, OMAP4_MPU_SOURCE);
+       realtime_counter_init();
+
+       err = arch_timer_of_register();
+       if (err)
+               pr_err("%s: arch_timer_register failed %d\n", __func__, err);
+}
 OMAP_SYS_TIMER(5)
 #endif