From 468ab95fb57f1b72da838aa46346635a48a94af4 Mon Sep 17 00:00:00 2001
From: Doug Anderson <dianders@chromium.org>
Date: Fri, 16 May 2014 14:12:13 -0700
Subject: [PATCH] clocksource: mct: Don't clear the mct
On exynos5 SoCs, the mct and the arch timers appear to share the same
root timer. ...so clearing the mct actually ends up clearing up the
arch timer and that confuses the heck out of the arch timer code.
Let's allow the arch timer and mct driver to coexist by just not ever
clearing the timer. Just in case someone cares, we'll still pretend
that we cleared it by keeping track of our own offset.
BUG=chrome-os-partner:13805
TEST=Arch timer no longers goes all screwy
Change-Id: I2c4bd3cb0fede67c36a2734b2972763f079f2872
Signed-off-by: Doug Anderson <dianders@chromium.org>
---
drivers/clocksource/exynos_mct.c | 42 +++++++++++++++++++++++-----------------
1 file changed, 24 insertions(+), 18 deletions(-)
@@ -93,6 +93,7 @@ static unsigned long clk_rate;
static unsigned int mct_int_type;
static int mct_irqs[MCT_NR_IRQS];
static int nr_mct_irqs;
+static cycle_t exynos_mct_offset;
static const char *irq_names[MCT_NR_LOCAL_IRQS] = {
"mct_tick0_irq",
@@ -176,24 +177,13 @@ static void exynos4_mct_write(unsigned int value, unsigned long offset)
}
/* Clocksource handling */
-static void exynos4_mct_frc_start(u32 hi, u32 lo)
-{
- u32 reg;
-
- exynos4_mct_write(lo, EXYNOS4_MCT_G_CNT_L);
- exynos4_mct_write(hi, EXYNOS4_MCT_G_CNT_U);
-
- reg = __raw_readl(reg_base + EXYNOS4_MCT_G_TCON);
- reg |= MCT_G_TCON_START;
- exynos4_mct_write(reg, EXYNOS4_MCT_G_TCON);
-}
-
static notrace u32 exynos4_read_sched_clock(void)
{
- return __raw_readl(reg_base + EXYNOS4_MCT_G_CNT_L);
+ return __raw_readl(reg_base + EXYNOS4_MCT_G_CNT_L) -
+ (exynos_mct_offset & 0xffffffff);
}
-static cycle_t exynos4_frc_read(struct clocksource *cs)
+static cycle_t _exynos4_frc_read(void)
{
u32 lo, hi;
static u32 __suspend_volatile_bss hi2;
@@ -207,9 +197,25 @@ static cycle_t exynos4_frc_read(struct clocksource *cs)
return ((cycle_t)hi << 32) | lo;
}
+static cycle_t exynos4_frc_read(struct clocksource *cs)
+{
+ return _exynos4_frc_read() - exynos_mct_offset;
+}
+
+static void exynos4_mct_frc_start(void)
+{
+ u32 reg;
+
+ exynos_mct_offset = _exynos4_frc_read();
+
+ reg = __raw_readl(reg_base + EXYNOS4_MCT_G_TCON);
+ reg |= MCT_G_TCON_START;
+ exynos4_mct_write(reg, EXYNOS4_MCT_G_TCON);
+}
+
static void exynos4_frc_resume(void)
{
- exynos4_mct_frc_start(0, 0);
+ exynos4_mct_frc_start();
}
struct clocksource mct_frc = {
@@ -226,12 +232,12 @@ struct syscore_ops mct_frc_core = {
static void __init exynos4_clocksource_init(void)
{
- u64 initial_time = exynos4_frc_read(&mct_frc);
+ u64 initial_time = _exynos4_frc_read();
do_div(initial_time, (clk_rate / 1000000));
printk(KERN_INFO "Initial usec timer %llu\n", initial_time);
- exynos4_mct_frc_start(0, 0);
+ exynos4_mct_frc_start();
if (clocksource_register_hz(&mct_frc, clk_rate))
panic("%s: can't register clocksource\n", mct_frc.name);
@@ -267,7 +273,7 @@ static void exynos4_mct_comp0_start(enum clock_event_mode mode,
exynos4_mct_write(cycles, EXYNOS4_MCT_G_COMP0_ADD_INCR);
}
- comp_cycle = exynos4_frc_read(&mct_frc) + cycles;
+ comp_cycle = _exynos4_frc_read() + cycles;
exynos4_mct_write((u32)comp_cycle, EXYNOS4_MCT_G_COMP0_L);
exynos4_mct_write((u32)(comp_cycle >> 32), EXYNOS4_MCT_G_COMP0_U);
--
1.9.1.423.g4596e3a