summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/timer.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-omap2/timer.c')
-rw-r--r--arch/arm/mach-omap2/timer.c104
1 files changed, 103 insertions, 1 deletions
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index e2084facca59..a9c9b3dbc82c 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -42,6 +42,7 @@
#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>
@@ -72,6 +73,11 @@
#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;
@@ -263,6 +269,7 @@ static u32 notrace dmtimer_read_sched_clock(void)
return 0;
}
+#ifdef CONFIG_OMAP_32K_TIMER
/* Setup free-running counter for clocksource */
static int __init omap2_sync32k_clocksource_init(void)
{
@@ -302,6 +309,12 @@ static int __init omap2_sync32k_clocksource_init(void)
return ret;
}
+#else
+static inline int omap2_sync32k_clocksource_init(void)
+{
+ return -ENODEV;
+}
+#endif
static void __init omap2_gptimer_clocksource_init(int gptimer_id,
const char *fck_source)
@@ -342,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) \
@@ -403,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