[PATCH v1] clk: samsung: exynos5420: Add support for power control registers

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



As per the Exynos5422 user manual, settings for the PWR_CTRL, PWR_CTRL2,
PWR_CTRL_KFC, and PWR_CNTL_KFC registers manage ARM clock down and up
configurations for idle and standby states.

The Exynos5422's dynamic clock frequency down feature enables automatic
clock down when all CPU cores are in Wait For Event (WFE) or
Wait For Interrupt (WFI) states, utilizing this feature in standby
configurations.

These modifications enhance the power management capabilities of the
Exynos542x by providing finer control over the ARM clock behavior in
various states.

Signed-off-by: Anand Moon <linux.amoon@xxxxxxxxx>
---
 drivers/clk/samsung/clk-exynos5420.c | 111 +++++++++++++++++++++++++++
 1 file changed, 111 insertions(+)

diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c
index a9df4e6db82fa..ce4c554eb59f1 100644
--- a/drivers/clk/samsung/clk-exynos5420.c
+++ b/drivers/clk/samsung/clk-exynos5420.c
@@ -8,6 +8,7 @@
  */
 
 #include <dt-bindings/clock/exynos5420.h>
+#include <linux/bitfield.h>
 #include <linux/slab.h>
 #include <linux/clk-provider.h>
 #include <linux/mod_devicetable.h>
@@ -29,6 +30,8 @@
 #define CLKOUT_CMU_CPU		0xa00
 #define SRC_MASK_CPERI		0x4300
 #define GATE_IP_G2D		0x8800
+#define PWR_CTRL		0x1020
+#define PWR_CTRL2		0x1024
 #define CPLL_LOCK		0x10020
 #define DPLL_LOCK		0x10030
 #define EPLL_LOCK		0x10040
@@ -139,10 +142,50 @@
 #define KPLL_CON0		0x28100
 #define SRC_KFC			0x28200
 #define DIV_KFC0		0x28500
+#define PWR_CTRL_KFC		0x29020
+#define PWR_CTRL2_KFC		0x29024
 
 /* NOTE: Must be equal to the last clock ID increased by one */
 #define CLKS_NR			(CLK_DOUT_PCLK_DREX1 + 1)
 
+/* Below definitions are used for PWR_CTRL settings */
+#define PWR_CTRL_ARM2_RATIO_MASK       GENMASK(30, 28)
+#define PWR_CTRL_ARM_RATIO_MASK        GENMASK(18, 16)
+#define PWR_CTRL_DIVARM2_DOWN_ENB      BIT(9)
+#define PWR_CTRL_DIVARM_DOWN_ENB       BIT(8)
+#define PWR_CTRL_USE_STANDBYWFE_ARM_CORE3  BIT(7)
+#define PWR_CTRL_USE_STANDBYWFE_ARM_CORE2  BIT(6)
+#define PWR_CTRL_USE_STANDBYWFE_ARM_CORE1  BIT(5)
+#define PWR_CTRL_USE_STANDBYWFE_ARM_CORE0  BIT(4)
+#define PWR_CTRL_USE_STANDBYWFI_ARM_CORE3  BIT(3)
+#define PWR_CTRL_USE_STANDBYWFI_ARM_CORE2  BIT(2)
+#define PWR_CTRL_USE_STANDBYWFI_ARM_CORE1  BIT(1)
+#define PWR_CTRL_USE_STANDBYWFI_ARM_CORE0  BIT(0)
+
+#define PWR_CTRL2_DIVARM2_UP_ENB       BIT(25)
+#define PWR_CTRL2_DIVARM_UP_ENB        BIT(24)
+#define PWR_CTRL2_DUR_STANDBY2_MASK    GENMASK(23, 16)
+#define PWR_CTRL2_DUR_STANDBY1_MASK    GENMASK(15, 8)
+#define PWR_CTRL2_UP_ARM2_RATIO_MASK   GENMASK(6, 4)
+#define PWR_CTRL2_UP_ARM_RATIO_MASK    GENMASK(2, 0)
+
+/* Below definitions are used for PWR_CTRL_KFC settings */
+#define PWR_CTRL_KFC_RATIO_MASK       GENMASK(21, 16)
+#define PWR_CTRL_KFC_DIVKFC_DOWN_ENB       BIT(8)
+#define PWR_CTRL_KFC_USE_STANDBYWFE_ARM_CORE3  BIT(7)
+#define PWR_CTRL_KFC_USE_STANDBYWFE_ARM_CORE2  BIT(6)
+#define PWR_CTRL_KFC_USE_STANDBYWFE_ARM_CORE1  BIT(5)
+#define PWR_CTRL_KFC_USE_STANDBYWFE_ARM_CORE0  BIT(4)
+#define PWR_CTRL_KFC_USE_STANDBYWFI_ARM_CORE3  BIT(3)
+#define PWR_CTRL_KFC_USE_STANDBYWFI_ARM_CORE2  BIT(2)
+#define PWR_CTRL_KFC_USE_STANDBYWFI_ARM_CORE1  BIT(1)
+#define PWR_CTRL_KFC_USE_STANDBYWFI_ARM_CORE0  BIT(0)
+
+#define PWR_CTRL2_KFC_DIVKFC_UP_ENB        BIT(24)
+#define PWR_CTRL2_KFC_DUR_STANDBY2_MASK    GENMASK(23, 16)
+#define PWR_CTRL2_KFC_DUR_STANDBY1_MASK    GENMASK(15, 8)
+#define PWR_CTRL2_KFC_UP_ARM_RATIO_MASK    GENMASK(5, 0)
+
 /* Exynos5x SoC type */
 enum exynos5x_soc {
 	EXYNOS5420,
@@ -1574,6 +1617,72 @@ static const struct of_device_id ext_clk_match[] __initconst = {
 	{ },
 };
 
+static void __init exynos5420_core_down_clock(void)
+{
+	unsigned int tmp;
+
+	/*
+	 * Enable arm clock down (in idle) and set arm divider
+	 * ratios in WFI/WFE state.
+	 */
+	tmp = (FIELD_PREP(PWR_CTRL_ARM2_RATIO_MASK, 7) |
+		FIELD_PREP(PWR_CTRL_ARM_RATIO_MASK, 7) |
+		PWR_CTRL_DIVARM_DOWN_ENB |
+		PWR_CTRL_DIVARM2_DOWN_ENB |
+		PWR_CTRL_USE_STANDBYWFE_ARM_CORE3 |
+		PWR_CTRL_USE_STANDBYWFE_ARM_CORE2 |
+		PWR_CTRL_USE_STANDBYWFE_ARM_CORE1 |
+		PWR_CTRL_USE_STANDBYWFE_ARM_CORE0 |
+		PWR_CTRL_USE_STANDBYWFI_ARM_CORE3 |
+		PWR_CTRL_USE_STANDBYWFI_ARM_CORE2 |
+		PWR_CTRL_USE_STANDBYWFI_ARM_CORE1 |
+		PWR_CTRL_USE_STANDBYWFI_ARM_CORE0);
+
+	writel_relaxed(tmp, reg_base + PWR_CTRL);
+
+	/*
+	 * Enable arm clock up (on exiting idle). Set arm divider
+	 * ratios when not in idle along with the standby duration
+	 * ratios.
+	 */
+	tmp = (PWR_CTRL2_DIVARM2_UP_ENB | PWR_CTRL2_DIVARM_UP_ENB |
+		FIELD_PREP(PWR_CTRL2_DUR_STANDBY2_MASK, 3) |
+		FIELD_PREP(PWR_CTRL2_DUR_STANDBY1_MASK, 3) |
+		FIELD_PREP(PWR_CTRL2_UP_ARM2_RATIO_MASK, 3) |
+		FIELD_PREP(PWR_CTRL2_UP_ARM_RATIO_MASK, 2));
+
+	writel_relaxed(tmp, reg_base + PWR_CTRL2);
+
+	/*
+	 * Enable arm clock down (in idle) and set kfc divider
+	 * ratios in WFI/WFE state.
+	 */
+	tmp = (FIELD_PREP(PWR_CTRL_KFC_RATIO_MASK, 7) |
+		PWR_CTRL_KFC_DIVKFC_DOWN_ENB |
+		PWR_CTRL_KFC_USE_STANDBYWFE_ARM_CORE3 |
+		PWR_CTRL_KFC_USE_STANDBYWFE_ARM_CORE2 |
+		PWR_CTRL_KFC_USE_STANDBYWFE_ARM_CORE1 |
+		PWR_CTRL_KFC_USE_STANDBYWFE_ARM_CORE0 |
+		PWR_CTRL_KFC_USE_STANDBYWFI_ARM_CORE3 |
+		PWR_CTRL_KFC_USE_STANDBYWFI_ARM_CORE2 |
+		PWR_CTRL_KFC_USE_STANDBYWFI_ARM_CORE1 |
+		PWR_CTRL_KFC_USE_STANDBYWFI_ARM_CORE0);
+
+	writel_relaxed(tmp, reg_base + PWR_CTRL_KFC);
+
+	/*
+	 * Enable arm clock up (on exiting idle). Set kfc divider
+	 * ratios when not in idle along with the standby duration
+	 * ratios.
+	 */
+	tmp = (PWR_CTRL2_KFC_DIVKFC_UP_ENB |
+		FIELD_PREP(PWR_CTRL2_KFC_DUR_STANDBY2_MASK, 3) |
+		FIELD_PREP(PWR_CTRL2_KFC_DUR_STANDBY1_MASK, 3) |
+		FIELD_PREP(PWR_CTRL2_KFC_UP_ARM_RATIO_MASK, 2));
+
+	writel_relaxed(tmp, reg_base + PWR_CTRL2_KFC);
+}
+
 /* register exynos5420 clocks */
 static void __init exynos5x_clk_init(struct device_node *np,
 		enum exynos5x_soc soc)
@@ -1649,6 +1758,8 @@ static void __init exynos5x_clk_init(struct device_node *np,
 				ARRAY_SIZE(exynos5800_cpu_clks));
 	}
 
+	exynos5420_core_down_clock();
+
 	samsung_clk_extended_sleep_init(reg_base,
 		exynos5x_clk_regs, ARRAY_SIZE(exynos5x_clk_regs),
 		exynos5420_set_clksrc, ARRAY_SIZE(exynos5420_set_clksrc));

base-commit: cf6fc5eefc5bbbbff92a085039ff74cdbd065c29
-- 
2.50.1





[Index of Archives]     [Linux SoC Development]     [Linux Rockchip Development]     [Linux for Synopsys ARC Processors]    
  • [Linux on Unisoc (RDA Micro) SoCs]     [Linux Actions SoC]     [Linux USB Development]     [Video for Linux]     [Linux Audio Users]     [Linux SCSI]     [Yosemite News]

  •   Powered by Linux