MLK-10117-1: gpc: add dispmix power save feature
authorSandor Yu <R01008@freescale.com>
Tue, 20 Jan 2015 08:00:37 +0000 (16:00 +0800)
committerNitin Garg <nitin.garg@nxp.com>
Mon, 19 Mar 2018 19:48:40 +0000 (14:48 -0500)
Add dispmix power save feature to generic power domain.

Signed-off-by: Sandor Yu <R01008@freescale.com>
Signed-off-by: Robin Gong <b38343@freescale.com>
(cherry picked from commit 2794e34cfb03b40e0e0f63f1f5eda347e137a41f)

arch/arm/mach-imx/gpc.c

index f027228..cc9088e 100644 (file)
 #define GPC_PGC_CPU_PDNSCR     0x2a8
 #define GPC_PGC_SW2ISO_SHIFT   0x8
 #define GPC_PGC_SW_SHIFT       0x0
+#define GPC_PGC_DISP_PGCR_OFFSET       0x240
+#define GPC_PGC_DISP_PUPSCR_OFFSET     0x244
+#define GPC_PGC_DISP_PDNSCR_OFFSET     0x248
+#define GPC_PGC_DISP_SR_OFFSET         0x24c
 #define GPC_M4_LPSR            0x2c
 #define GPC_M4_LPSR_M4_SLEEPING_SHIFT  4
 #define GPC_M4_LPSR_M4_SLEEPING_MASK   0x1
@@ -59,7 +63,7 @@
 #define GPU_VPU_PUP_REQ                BIT(1)
 #define GPU_VPU_PDN_REQ                BIT(0)
 
-#define GPC_CLK_MAX            6
+#define GPC_CLK_MAX            10
 
 struct pu_domain {
        struct generic_pm_domain base;
@@ -68,6 +72,12 @@ struct pu_domain {
        int num_clks;
 };
 
+struct disp_domain {
+       struct generic_pm_domain base;
+       struct clk *clk[GPC_CLK_MAX];
+       int num_clks;
+};
+
 static void __iomem *gpc_base;
 static u32 gpc_wake_irqs[IMR_NUM];
 static u32 gpc_saved_imrs[IMR_NUM];
@@ -585,6 +595,62 @@ static int imx6q_pm_pu_power_on(struct generic_pm_domain *genpd)
        return 0;
 }
 
+static int imx_pm_dispmix_on(struct generic_pm_domain *genpd)
+{
+       struct disp_domain *disp = container_of(genpd, struct disp_domain, base);
+       u32 val = readl_relaxed(gpc_base + GPC_CNTR);
+       int i;
+
+       if ((cpu_is_imx6sl() &&
+               imx_get_soc_revision() >= IMX_CHIP_REVISION_1_2) || cpu_is_imx6sx()) {
+
+               /* Enable reset clocks for all devices in the disp domain */
+               for (i = 0; i < disp->num_clks; i++)
+                       clk_prepare_enable(disp->clk[i]);
+
+               writel_relaxed(0x0, gpc_base + GPC_PGC_DISP_PGCR_OFFSET);
+               writel_relaxed(0x20 | val, gpc_base + GPC_CNTR);
+               while (readl_relaxed(gpc_base + GPC_CNTR) & 0x20)
+                       ;
+
+               writel_relaxed(0x1, gpc_base + GPC_PGC_DISP_SR_OFFSET);
+
+               /* Disable reset clocks for all devices in the disp domain */
+               for (i = 0; i < disp->num_clks; i++)
+                       clk_disable_unprepare(disp->clk[i]);
+       }
+       return 0;
+}
+
+static int imx_pm_dispmix_off(struct generic_pm_domain *genpd)
+{
+       struct disp_domain *disp = container_of(genpd, struct disp_domain, base);
+       u32 val = readl_relaxed(gpc_base + GPC_CNTR);
+       int i;
+
+       if ((cpu_is_imx6sl() &&
+               imx_get_soc_revision() >= IMX_CHIP_REVISION_1_2) || cpu_is_imx6sx()) {
+
+               /* Enable reset clocks for all devices in the disp domain */
+               for (i = 0; i < disp->num_clks; i++)
+                       clk_prepare_enable(disp->clk[i]);
+
+               writel_relaxed(0xFFFFFFFF,
+                               gpc_base + GPC_PGC_DISP_PUPSCR_OFFSET);
+               writel_relaxed(0xFFFFFFFF,
+                               gpc_base + GPC_PGC_DISP_PDNSCR_OFFSET);
+               writel_relaxed(0x1, gpc_base + GPC_PGC_DISP_PGCR_OFFSET);
+               writel_relaxed(0x10 | val, gpc_base + GPC_CNTR);
+               while (readl_relaxed(gpc_base + GPC_CNTR) & 0x10)
+                       ;
+
+               /* Disable reset clocks for all devices in the disp domain */
+               for (i = 0; i < disp->num_clks; i++)
+                       clk_disable_unprepare(disp->clk[i]);
+       }
+       return 0;
+}
+
 static struct generic_pm_domain imx6q_arm_domain = {
        .name = "ARM",
 };
@@ -604,14 +670,18 @@ static struct pu_domain imx6q_pu_domain = {
        },
 };
 
-static struct generic_pm_domain imx6sl_display_domain = {
-       .name = "DISPLAY",
+static struct disp_domain imx6s_display_domain = {
+       .base = {
+               .name = "DISPLAY",
+               .power_off = imx_pm_dispmix_off,
+               .power_on = imx_pm_dispmix_on,
+       },
 };
 
 static struct generic_pm_domain *imx_gpc_domains[] = {
        &imx6q_arm_domain,
        &imx6q_pu_domain.base,
-       &imx6sl_display_domain,
+       &imx6s_display_domain.base,
 };
 
 static struct genpd_onecell_data imx_gpc_onecell_data = {
@@ -622,30 +692,55 @@ static struct genpd_onecell_data imx_gpc_onecell_data = {
 static int imx_gpc_genpd_init(struct device *dev, struct regulator *pu_reg)
 {
        struct clk *clk;
-       int i, ret;
+       bool is_off;
+       int pu_clks, disp_clks;
+       int i = 0, k = 0, ret;
 
        imx6q_pu_domain.reg = pu_reg;
 
-       for (i = 0; ; i++) {
+       if ((cpu_is_imx6sl() &&
+            imx_get_soc_revision() >= IMX_CHIP_REVISION_1_2)) {
+               pu_clks = 2 ;
+               disp_clks = 6;
+       } else if (cpu_is_imx6sx()) {
+               pu_clks = 1;
+               disp_clks = 7;
+       } else {
+               pu_clks = GPC_CLK_MAX;
+               disp_clks = 0;
+       }
+
+       /* Get pu domain clks */
+       for (i = 0; i < pu_clks ; i++) {
                clk = of_clk_get(dev->of_node, i);
                if (IS_ERR(clk))
                        break;
-               if (i >= GPC_CLK_MAX) {
-                       dev_err(dev, "more than %d clocks\n", GPC_CLK_MAX);
-                       goto clk_err;
-               }
                imx6q_pu_domain.clk[i] = clk;
        }
        imx6q_pu_domain.num_clks = i;
 
-       /* Enable power always in case bootloader disabled it. */
-       imx6q_pm_pu_power_on(&imx6q_pu_domain.base);
-
-       if (!IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS))
-               return 0;
+       /* Get disp domain clks */
+       for (k = 0, i = pu_clks; i < pu_clks + disp_clks ; i++, k++) {
+               clk = of_clk_get(dev->of_node, i);
+               if (IS_ERR(clk))
+                       break;
+               imx6s_display_domain.clk[k] = clk;
+       }
+       imx6s_display_domain.num_clks = k;
+
+       is_off = IS_ENABLED(CONFIG_PM);
+       if (is_off) {
+               _imx6q_pm_pu_power_off(&imx6q_pu_domain.base);
+       } else {
+               /*
+                * Enable power if compiled without CONFIG_PM in case the
+                * bootloader disabled it.
+                */
+               imx6q_pm_pu_power_on(&imx6q_pu_domain.base);
+       }
 
        for (i = 0; i < ARRAY_SIZE(imx_gpc_domains); i++)
-               pm_genpd_init(imx_gpc_domains[i], NULL, false);
+               pm_genpd_init(imx_gpc_domains[i], NULL, is_off);
 
        ret =  of_genpd_add_provider_onecell(dev->of_node,
                                             &imx_gpc_onecell_data);
@@ -656,10 +751,6 @@ static int imx_gpc_genpd_init(struct device *dev, struct regulator *pu_reg)
 
 power_off:
        imx6q_pm_pu_power_off(&imx6q_pu_domain.base);
-clk_err:
-       while (i--)
-               clk_put(imx6q_pu_domain.clk[i]);
-       imx6q_pu_domain.reg = NULL;
        return -EINVAL;
 }