diff options
author | Robby Cai <R63905@freescale.com> | 2013-11-14 05:15:53 -0500 |
---|---|---|
committer | Nitin Garg <nitin.garg@freescale.com> | 2014-04-16 09:47:14 -0400 |
commit | 8dfdc91887fc4ff52181875ef44a425cf2e8959e (patch) | |
tree | 7f59b85ecd9ba8f36328da30f88238c8474aea0a | |
parent | 8c1d1a071947fec0819881cf5ce91b53614ad763 (diff) |
ENGR00283186 imx6sl: Add support for power gating of display MIX
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>
-rw-r--r-- | arch/arm/boot/dts/imx6sl.dtsi | 7 | ||||
-rw-r--r-- | arch/arm/mach-imx/gpc.c | 69 |
2 files changed, 73 insertions, 3 deletions
diff --git a/arch/arm/boot/dts/imx6sl.dtsi b/arch/arm/boot/dts/imx6sl.dtsi index b751542f71c7..605fefbc99d8 100644 --- a/arch/arm/boot/dts/imx6sl.dtsi +++ b/arch/arm/boot/dts/imx6sl.dtsi | |||
@@ -601,8 +601,11 @@ | |||
601 | reg = <0x020dc000 0x4000>; | 601 | reg = <0x020dc000 0x4000>; |
602 | interrupts = <0 89 0x04>; | 602 | interrupts = <0 89 0x04>; |
603 | clocks = <&clks IMX6SL_CLK_GPU2D_PODF>, <&clks IMX6SL_CLK_GPU2D_OVG>, | 603 | clocks = <&clks IMX6SL_CLK_GPU2D_PODF>, <&clks IMX6SL_CLK_GPU2D_OVG>, |
604 | <&clks IMX6SL_CLK_IPG>; | 604 | <&clks IMX6SL_CLK_IPG>, <&clks IMX6SL_CLK_LCDIF_AXI>, |
605 | clock-names = "gpu2d_podf", "gpu2d_ovg", "ipg"; | 605 | <&clks IMX6SL_CLK_LCDIF_PIX>, <&clks IMX6SL_CLK_EPDC_AXI>, |
606 | <&clks IMX6SL_CLK_EPDC_PIX>, <&clks IMX6SL_CLK_PXP_AXI>; | ||
607 | clock-names = "gpu2d_podf", "gpu2d_ovg", "ipg", "lcd_axi", | ||
608 | "lcd_pix", "epdc_axi", "epdc_pix", "pxp_axi"; | ||
606 | pu-supply = <®_pu>; | 609 | pu-supply = <®_pu>; |
607 | }; | 610 | }; |
608 | 611 | ||
diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c index 2a3646b4d027..97343277d1e8 100644 --- a/arch/arm/mach-imx/gpc.c +++ b/arch/arm/mach-imx/gpc.c | |||
@@ -31,6 +31,10 @@ | |||
31 | #define GPC_PGC_GPU_PDN 0x260 | 31 | #define GPC_PGC_GPU_PDN 0x260 |
32 | #define GPC_PGC_GPU_PUPSCR 0x264 | 32 | #define GPC_PGC_GPU_PUPSCR 0x264 |
33 | #define GPC_PGC_GPU_PDNSCR 0x268 | 33 | #define GPC_PGC_GPU_PDNSCR 0x268 |
34 | #define GPC_PGC_DISP_PGCR_OFFSET 0x240 | ||
35 | #define GPC_PGC_DISP_PUPSCR_OFFSET 0x244 | ||
36 | #define GPC_PGC_DISP_PDNSCR_OFFSET 0x248 | ||
37 | #define GPC_PGC_DISP_SR_OFFSET 0x24c | ||
34 | #define GPC_PGC_GPU_SW_SHIFT 0 | 38 | #define GPC_PGC_GPU_SW_SHIFT 0 |
35 | #define GPC_PGC_GPU_SW_MASK 0x3f | 39 | #define GPC_PGC_GPU_SW_MASK 0x3f |
36 | #define GPC_PGC_GPU_SW2ISO_SHIFT 8 | 40 | #define GPC_PGC_GPU_SW2ISO_SHIFT 8 |
@@ -51,6 +55,8 @@ static void __iomem *gpc_base; | |||
51 | static u32 gpc_wake_irqs[IMR_NUM]; | 55 | static u32 gpc_wake_irqs[IMR_NUM]; |
52 | static u32 gpc_saved_imrs[IMR_NUM]; | 56 | static u32 gpc_saved_imrs[IMR_NUM]; |
53 | static struct clk *gpu3d_clk, *gpu3d_shader_clk, *gpu2d_clk, *gpu2d_axi_clk; | 57 | static struct clk *gpu3d_clk, *gpu3d_shader_clk, *gpu2d_clk, *gpu2d_axi_clk; |
58 | static struct clk *lcd_axi_clk, *lcd_pix_clk, *epdc_axi_clk, *epdc_pix_clk; | ||
59 | static struct clk *pxp_axi_clk; | ||
54 | static struct clk *openvg_axi_clk, *vpu_clk, *ipg_clk; | 60 | static struct clk *openvg_axi_clk, *vpu_clk, *ipg_clk; |
55 | static struct device *gpc_dev; | 61 | static struct device *gpc_dev; |
56 | struct regulator *pu_reg; | 62 | struct regulator *pu_reg; |
@@ -65,11 +71,63 @@ static struct regulator_init_data pu_dummy_initdata = { | |||
65 | }; | 71 | }; |
66 | static int pu_dummy_enable; | 72 | static int pu_dummy_enable; |
67 | 73 | ||
74 | static void imx_disp_clk(bool enable) | ||
75 | { | ||
76 | if (enable) { | ||
77 | clk_prepare_enable(lcd_axi_clk); | ||
78 | clk_prepare_enable(lcd_pix_clk); | ||
79 | clk_prepare_enable(epdc_axi_clk); | ||
80 | clk_prepare_enable(epdc_pix_clk); | ||
81 | clk_prepare_enable(pxp_axi_clk); | ||
82 | } else { | ||
83 | clk_disable_unprepare(lcd_axi_clk); | ||
84 | clk_disable_unprepare(lcd_pix_clk); | ||
85 | clk_disable_unprepare(epdc_axi_clk); | ||
86 | clk_disable_unprepare(epdc_pix_clk); | ||
87 | clk_disable_unprepare(pxp_axi_clk); | ||
88 | } | ||
89 | } | ||
90 | |||
91 | static void imx_gpc_dispmix_on(void) | ||
92 | { | ||
93 | if (cpu_is_imx6sl()) { | ||
94 | imx_disp_clk(true); | ||
95 | |||
96 | writel_relaxed(0x0, gpc_base + GPC_PGC_DISP_PGCR_OFFSET); | ||
97 | writel_relaxed(0x20, gpc_base + GPC_CNTR); | ||
98 | while (readl_relaxed(gpc_base + GPC_CNTR) & 0x20) | ||
99 | ; | ||
100 | writel_relaxed(0x1, gpc_base + GPC_PGC_DISP_SR_OFFSET); | ||
101 | |||
102 | imx_disp_clk(false); | ||
103 | } | ||
104 | } | ||
105 | |||
106 | static void imx_gpc_dispmix_off(void) | ||
107 | { | ||
108 | if (cpu_is_imx6sl()) { | ||
109 | imx_disp_clk(true); | ||
110 | |||
111 | writel_relaxed(0xFFFFFFFF, | ||
112 | gpc_base + GPC_PGC_DISP_PUPSCR_OFFSET); | ||
113 | writel_relaxed(0xFFFFFFFF, | ||
114 | gpc_base + GPC_PGC_DISP_PDNSCR_OFFSET); | ||
115 | writel_relaxed(0x1, gpc_base + GPC_PGC_DISP_PGCR_OFFSET); | ||
116 | writel_relaxed(0x10, gpc_base + GPC_CNTR); | ||
117 | while (readl_relaxed(gpc_base + GPC_CNTR) & 0x10) | ||
118 | ; | ||
119 | |||
120 | imx_disp_clk(false); | ||
121 | } | ||
122 | } | ||
123 | |||
68 | void imx_gpc_pre_suspend(bool arm_power_off) | 124 | void imx_gpc_pre_suspend(bool arm_power_off) |
69 | { | 125 | { |
70 | void __iomem *reg_imr1 = gpc_base + GPC_IMR1; | 126 | void __iomem *reg_imr1 = gpc_base + GPC_IMR1; |
71 | int i; | 127 | int i; |
72 | 128 | ||
129 | imx_gpc_dispmix_off(); | ||
130 | |||
73 | if (arm_power_off) | 131 | if (arm_power_off) |
74 | /* Tell GPC to power off ARM core when suspend */ | 132 | /* Tell GPC to power off ARM core when suspend */ |
75 | writel_relaxed(0x1, gpc_base + GPC_PGC_CPU_PDN); | 133 | writel_relaxed(0x1, gpc_base + GPC_PGC_CPU_PDN); |
@@ -90,6 +148,8 @@ void imx_gpc_post_resume(void) | |||
90 | 148 | ||
91 | for (i = 0; i < IMR_NUM; i++) | 149 | for (i = 0; i < IMR_NUM; i++) |
92 | writel_relaxed(gpc_saved_imrs[i], reg_imr1 + i * 4); | 150 | writel_relaxed(gpc_saved_imrs[i], reg_imr1 + i * 4); |
151 | |||
152 | imx_gpc_dispmix_on(); | ||
93 | } | 153 | } |
94 | 154 | ||
95 | static int imx_gpc_irq_set_wake(struct irq_data *d, unsigned int on) | 155 | 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) | |||
420 | gpu2d_clk = devm_clk_get(gpc_dev, "gpu2d_podf"); | 480 | gpu2d_clk = devm_clk_get(gpc_dev, "gpu2d_podf"); |
421 | openvg_axi_clk = devm_clk_get(gpc_dev, "gpu2d_ovg"); | 481 | openvg_axi_clk = devm_clk_get(gpc_dev, "gpu2d_ovg"); |
422 | ipg_clk = devm_clk_get(gpc_dev, "ipg"); | 482 | ipg_clk = devm_clk_get(gpc_dev, "ipg"); |
483 | lcd_axi_clk = devm_clk_get(gpc_dev, "lcd_axi"); | ||
484 | lcd_pix_clk = devm_clk_get(gpc_dev, "lcd_pix"); | ||
485 | epdc_axi_clk = devm_clk_get(gpc_dev, "epdc_axi"); | ||
486 | epdc_pix_clk = devm_clk_get(gpc_dev, "epdc_pix"); | ||
487 | pxp_axi_clk = devm_clk_get(gpc_dev, "pxp_axi"); | ||
423 | if (IS_ERR(gpu2d_clk) || IS_ERR(openvg_axi_clk) | 488 | if (IS_ERR(gpu2d_clk) || IS_ERR(openvg_axi_clk) |
424 | || IS_ERR(ipg_clk)) { | 489 | || IS_ERR(ipg_clk) || IS_ERR(lcd_axi_clk) |
490 | || IS_ERR(lcd_pix_clk) || IS_ERR(epdc_axi_clk) | ||
491 | || IS_ERR(epdc_pix_clk) || IS_ERR(pxp_axi_clk)) { | ||
425 | dev_err(gpc_dev, "failed to get clk!\n"); | 492 | dev_err(gpc_dev, "failed to get clk!\n"); |
426 | return -ENOENT; | 493 | return -ENOENT; |
427 | } | 494 | } |