]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
clocksource/drivers/sprd: Enable register for timer counter from 32 bit to 64 bit
authorEnlin Mu <enlin.mu@unisoc.com>
Thu, 6 Nov 2025 02:18:30 +0000 (10:18 +0800)
committerDaniel Lezcano <daniel.lezcano@linaro.org>
Wed, 26 Nov 2025 10:24:26 +0000 (11:24 +0100)
Using 32 bit for suspend compensation, the max compensation time is 36
hours(working clock is 32k).In some IOT devices, the suspend time may
be long, even exceeding 36 hours. Therefore, a 64 bit timer counter
is needed for counting.

Signed-off-by: Enlin Mu <enlin.mu@unisoc.com>
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Link: https://patch.msgid.link/20251106021830.34846-1-enlin.mu@linux.dev
drivers/clocksource/timer-sprd.c

index 430cb99d8d79b4894c1c219821d6fbdb37bf6e24..2c07dd2af760eef0e49121d722ac7b8e7c14c618 100644 (file)
@@ -30,6 +30,7 @@
 #define TIMER_VALUE_SHDW_HI    0x1c
 
 #define TIMER_VALUE_LO_MASK    GENMASK(31, 0)
+#define TIMER_VALUE_HI_MASK    GENMASK(31, 0)
 
 static void sprd_timer_enable(void __iomem *base, u32 flag)
 {
@@ -162,15 +163,26 @@ static struct timer_of suspend_to = {
 
 static u64 sprd_suspend_timer_read(struct clocksource *cs)
 {
-       return ~(u64)readl_relaxed(timer_of_base(&suspend_to) +
-                                  TIMER_VALUE_SHDW_LO) & cs->mask;
+       u32 lo, hi;
+
+       do {
+               hi = readl_relaxed(timer_of_base(&suspend_to) +
+                                  TIMER_VALUE_SHDW_HI);
+               lo = readl_relaxed(timer_of_base(&suspend_to) +
+                                  TIMER_VALUE_SHDW_LO);
+       } while (hi != readl_relaxed(timer_of_base(&suspend_to) + TIMER_VALUE_SHDW_HI));
+
+       return ~(((u64)hi << 32) | lo);
 }
 
 static int sprd_suspend_timer_enable(struct clocksource *cs)
 {
-       sprd_timer_update_counter(timer_of_base(&suspend_to),
-                                 TIMER_VALUE_LO_MASK);
-       sprd_timer_enable(timer_of_base(&suspend_to), TIMER_CTL_PERIOD_MODE);
+       writel_relaxed(TIMER_VALUE_LO_MASK,
+                      timer_of_base(&suspend_to) + TIMER_LOAD_LO);
+       writel_relaxed(TIMER_VALUE_HI_MASK,
+                      timer_of_base(&suspend_to) + TIMER_LOAD_HI);
+       sprd_timer_enable(timer_of_base(&suspend_to),
+                         TIMER_CTL_PERIOD_MODE|TIMER_CTL_64BIT_WIDTH);
 
        return 0;
 }
@@ -186,7 +198,7 @@ static struct clocksource suspend_clocksource = {
        .read   = sprd_suspend_timer_read,
        .enable = sprd_suspend_timer_enable,
        .disable = sprd_suspend_timer_disable,
-       .mask   = CLOCKSOURCE_MASK(32),
+       .mask   = CLOCKSOURCE_MASK(64),
        .flags  = CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_SUSPEND_NONSTOP,
 };