]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
ENGR00283186 imx6sl: Add support for power gating of display MIX
authorRobby Cai <R63905@freescale.com>
Thu, 14 Nov 2013 10:15:53 +0000 (18:15 +0800)
committerRobby Cai <R63905@freescale.com>
Mon, 18 Nov 2013 07:57:07 +0000 (15:57 +0800)
The display MIX can be power gated when EPDC, PXP and LCDIF are all inactive.
For safety, this feature is only supported when system enters suspend/standby
mode, in other words, this patch does not support run-time gating.

Signed-off-by: Robby Cai <R63905@freescale.com>
Signed-off-by: Robin Gong <b38343@freescale.com>
arch/arm/boot/dts/imx6sl.dtsi
arch/arm/mach-imx/gpc.c

index b751542f71c7bda79cf6be6ffd582020eed69147..605fefbc99d854926bc9c1c14c1e84398f460f7f 100644 (file)
                                reg = <0x020dc000 0x4000>;
                                interrupts = <0 89 0x04>;
                                clocks = <&clks IMX6SL_CLK_GPU2D_PODF>, <&clks IMX6SL_CLK_GPU2D_OVG>,
-                                       <&clks IMX6SL_CLK_IPG>;
-                               clock-names = "gpu2d_podf", "gpu2d_ovg", "ipg";
+                                       <&clks IMX6SL_CLK_IPG>, <&clks IMX6SL_CLK_LCDIF_AXI>,
+                                       <&clks IMX6SL_CLK_LCDIF_PIX>, <&clks IMX6SL_CLK_EPDC_AXI>,
+                                       <&clks IMX6SL_CLK_EPDC_PIX>, <&clks IMX6SL_CLK_PXP_AXI>;
+                               clock-names = "gpu2d_podf", "gpu2d_ovg", "ipg", "lcd_axi",
+                                               "lcd_pix", "epdc_axi", "epdc_pix", "pxp_axi";
                                pu-supply = <&reg_pu>;
                        };
 
index 2a3646b4d027d2b760ae41f398bb93c1c6bff817..97343277d1e8d9bdf9da00003bbe1e55a3b76a3f 100644 (file)
 #define GPC_PGC_GPU_PDN                0x260
 #define GPC_PGC_GPU_PUPSCR     0x264
 #define GPC_PGC_GPU_PDNSCR     0x268
+#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_PGC_GPU_SW_SHIFT           0
 #define GPC_PGC_GPU_SW_MASK            0x3f
 #define GPC_PGC_GPU_SW2ISO_SHIFT       8
@@ -51,6 +55,8 @@ static void __iomem *gpc_base;
 static u32 gpc_wake_irqs[IMR_NUM];
 static u32 gpc_saved_imrs[IMR_NUM];
 static struct clk *gpu3d_clk, *gpu3d_shader_clk, *gpu2d_clk, *gpu2d_axi_clk;
+static struct clk *lcd_axi_clk, *lcd_pix_clk, *epdc_axi_clk, *epdc_pix_clk;
+static struct clk *pxp_axi_clk;
 static struct clk *openvg_axi_clk, *vpu_clk, *ipg_clk;
 static struct device *gpc_dev;
 struct regulator *pu_reg;
@@ -65,11 +71,63 @@ static struct regulator_init_data pu_dummy_initdata = {
 };
 static int pu_dummy_enable;
 
+static void imx_disp_clk(bool enable)
+{
+       if (enable) {
+               clk_prepare_enable(lcd_axi_clk);
+               clk_prepare_enable(lcd_pix_clk);
+               clk_prepare_enable(epdc_axi_clk);
+               clk_prepare_enable(epdc_pix_clk);
+               clk_prepare_enable(pxp_axi_clk);
+       } else {
+               clk_disable_unprepare(lcd_axi_clk);
+               clk_disable_unprepare(lcd_pix_clk);
+               clk_disable_unprepare(epdc_axi_clk);
+               clk_disable_unprepare(epdc_pix_clk);
+               clk_disable_unprepare(pxp_axi_clk);
+       }
+}
+
+static void imx_gpc_dispmix_on(void)
+{
+       if (cpu_is_imx6sl()) {
+               imx_disp_clk(true);
+
+               writel_relaxed(0x0, gpc_base + GPC_PGC_DISP_PGCR_OFFSET);
+               writel_relaxed(0x20, gpc_base + GPC_CNTR);
+               while (readl_relaxed(gpc_base + GPC_CNTR) & 0x20)
+                       ;
+               writel_relaxed(0x1, gpc_base + GPC_PGC_DISP_SR_OFFSET);
+
+               imx_disp_clk(false);
+       }
+}
+
+static void imx_gpc_dispmix_off(void)
+{
+       if (cpu_is_imx6sl()) {
+               imx_disp_clk(true);
+
+               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, gpc_base + GPC_CNTR);
+               while (readl_relaxed(gpc_base + GPC_CNTR) & 0x10)
+                       ;
+
+               imx_disp_clk(false);
+       }
+}
+
 void imx_gpc_pre_suspend(bool arm_power_off)
 {
        void __iomem *reg_imr1 = gpc_base + GPC_IMR1;
        int i;
 
+       imx_gpc_dispmix_off();
+
        if (arm_power_off)
                /* Tell GPC to power off ARM core when suspend */
                writel_relaxed(0x1, gpc_base + GPC_PGC_CPU_PDN);
@@ -90,6 +148,8 @@ void imx_gpc_post_resume(void)
 
        for (i = 0; i < IMR_NUM; i++)
                writel_relaxed(gpc_saved_imrs[i], reg_imr1 + i * 4);
+
+       imx_gpc_dispmix_on();
 }
 
 static int imx_gpc_irq_set_wake(struct irq_data *d, unsigned int on)
@@ -420,8 +480,15 @@ static int imx_gpc_probe(struct platform_device *pdev)
                gpu2d_clk = devm_clk_get(gpc_dev, "gpu2d_podf");
                openvg_axi_clk = devm_clk_get(gpc_dev, "gpu2d_ovg");
                ipg_clk = devm_clk_get(gpc_dev, "ipg");
+               lcd_axi_clk = devm_clk_get(gpc_dev, "lcd_axi");
+               lcd_pix_clk = devm_clk_get(gpc_dev, "lcd_pix");
+               epdc_axi_clk = devm_clk_get(gpc_dev, "epdc_axi");
+               epdc_pix_clk = devm_clk_get(gpc_dev, "epdc_pix");
+               pxp_axi_clk = devm_clk_get(gpc_dev, "pxp_axi");
                if (IS_ERR(gpu2d_clk) || IS_ERR(openvg_axi_clk)
-                       || IS_ERR(ipg_clk)) {
+                       || IS_ERR(ipg_clk) || IS_ERR(lcd_axi_clk)
+                       || IS_ERR(lcd_pix_clk) || IS_ERR(epdc_axi_clk)
+                       || IS_ERR(epdc_pix_clk) || IS_ERR(pxp_axi_clk)) {
                        dev_err(gpc_dev, "failed to get clk!\n");
                        return -ENOENT;
                }