cpuidle:clk:Exynos4412: Enable support for clock down when WFI cpuidle state is entered
authorLukasz Majewski <l.majewski@samsung.com>
Thu, 10 Apr 2014 14:46:08 +0000 (16:46 +0200)
committerMarek Szyprowski <m.szyprowski@samsung.com>
Thu, 15 May 2014 05:28:30 +0000 (07:28 +0200)
This patch adds support for setting ARM cores' clock frequency down when
entering WFI/WFE based cpuidle state.

On the Trats2 device: performance governor, 1.4 GHz frequency, no extra
load, 4 cores enabled:
Without core clock down feature: 395 mA
With core clock down feature: 337 mA

Power consumption reduction around 15%

Change-Id: I7bae29b0332a97c7b18ffb79f4b0a5ff3d70b7ce
Signed-off-by: Lukasz Majewski <l.majewski@samsung.com>
arch/arm/mach-exynos/cpuidle.c
arch/arm/mach-exynos/include/mach/regs-clock.h

index df195ed..11c3db7 100644 (file)
@@ -167,7 +167,7 @@ static int exynos4_enter_lowpower(struct cpuidle_device *dev,
                return exynos4_enter_core0_aftr(dev, drv, new_index);
 }
 
-static void __init exynos5_core_down_clk(void)
+static void __init exynos_core_down_clk(void)
 {
        unsigned int tmp;
 
@@ -183,7 +183,15 @@ static void __init exynos5_core_down_clk(void)
              PWR_CTRL1_USE_CORE0_WFE    | \
              PWR_CTRL1_USE_CORE1_WFI    | \
              PWR_CTRL1_USE_CORE0_WFI;
-       __raw_writel(tmp, EXYNOS5_PWR_CTRL1);
+
+       if (soc_is_exynos4412())
+               tmp |= PWR_CTRL1_USE_CORE3_WFE | \
+                      PWR_CTRL1_USE_CORE2_WFE | \
+                      PWR_CTRL1_USE_CORE3_WFI | \
+                      PWR_CTRL1_USE_CORE2_WFI;
+
+       __raw_writel(tmp, soc_is_exynos5250() ? EXYNOS5_PWR_CTRL1
+                    : EXYNOS4_PWR_CTRL1);
 
        /*
         * Enable arm clock up (on exiting idle). Set arm divider
@@ -196,7 +204,9 @@ static void __init exynos5_core_down_clk(void)
              PWR_CTRL2_DUR_STANDBY1_VAL | \
              PWR_CTRL2_CORE2_UP_RATIO   | \
              PWR_CTRL2_CORE1_UP_RATIO;
-       __raw_writel(tmp, EXYNOS5_PWR_CTRL2);
+
+       __raw_writel(tmp, soc_is_exynos5250() ? EXYNOS5_PWR_CTRL2
+                    : EXYNOS4_PWR_CTRL2);
 }
 
 static int __init exynos4_init_cpuidle(void)
@@ -204,8 +214,8 @@ static int __init exynos4_init_cpuidle(void)
        int cpu_id, ret;
        struct cpuidle_device *device;
 
-       if (soc_is_exynos5250())
-               exynos5_core_down_clk();
+       if (soc_is_exynos4412() || soc_is_exynos5250())
+               exynos_core_down_clk();
 
        ret = cpuidle_register_driver(&exynos4_idle_driver);
        if (ret) {
index d36ad76..0cf9ad0 100644 (file)
 #define EXYNOS4_CLKGATE_IP_ISP0                        EXYNOS_CLKREG(0x18800)
 #define EXYNOS4_CLKGATE_IP_ISP1                        EXYNOS_CLKREG(0x18804)
 
+#define EXYNOS4_PWR_CTRL1                      EXYNOS_CLKREG(0x15020)
+#define EXYNOS4_PWR_CTRL2                      EXYNOS_CLKREG(0x15024)
+
 #define EXYNOS4_APLL_LOCKTIME                  (0x1C20)        /* 300us */
 
 #define EXYNOS4_APLLCON0_ENABLE_SHIFT          (31)
 #define PWR_CTRL1_CORE1_DOWN_RATIO             (7 << 16)
 #define PWR_CTRL1_DIV2_DOWN_EN                 (1 << 9)
 #define PWR_CTRL1_DIV1_DOWN_EN                 (1 << 8)
+#define PWR_CTRL1_USE_CORE3_WFE                        (1 << 7)
+#define PWR_CTRL1_USE_CORE2_WFE                        (1 << 6)
 #define PWR_CTRL1_USE_CORE1_WFE                        (1 << 5)
 #define PWR_CTRL1_USE_CORE0_WFE                        (1 << 4)
+#define PWR_CTRL1_USE_CORE3_WFI                        (1 << 3)
+#define PWR_CTRL1_USE_CORE2_WFI                        (1 << 2)
 #define PWR_CTRL1_USE_CORE1_WFI                        (1 << 1)
 #define PWR_CTRL1_USE_CORE0_WFI                        (1 << 0)