From 60488c1a79485da875a14a1ebafb4e11978224d0 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E9=99=88=E6=81=92=E6=98=8E?= Date: Tue, 22 Mar 2011 16:58:32 +0800 Subject: [PATCH] rk29: clock: add display power domain clock support --- arch/arm/mach-rk29/clock.c | 106 +++++++++++++++++++++++++++++++++++-- drivers/video/rk29_fb.c | 20 +++++-- 2 files changed, 118 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-rk29/clock.c b/arch/arm/mach-rk29/clock.c index 2eb8d17cfc71..512cff763510 100755 --- a/arch/arm/mach-rk29/clock.c +++ b/arch/arm/mach-rk29/clock.c @@ -37,6 +37,7 @@ /* bit 0 is free */ #define RATE_FIXED (1 << 1) /* Fixed clock rate */ #define CONFIG_PARTICIPANT (1 << 10) /* Fundamental clock */ +#define IS_PD (1 << 2) /* Power Domain */ #define cru_readl(offset) readl(RK29_CRU_BASE + offset) #define cru_writel(v, offset) writel(v, RK29_CRU_BASE + offset) @@ -201,7 +202,7 @@ static int gate_mode(struct clk *clk, int on) v = cru_readl(reg); if (on) - v &= ~(1 << idx); // clear bit + v &= ~(1 << idx); // clear bit else v |= (1 << idx); // set bit @@ -1697,6 +1698,101 @@ GATE_CLK(hclk_mmc0, hclk_periph, HCLK_MMC0); GATE_CLK(hclk_mmc1, hclk_periph, HCLK_MMC1); GATE_CLK(hclk_emmc, hclk_periph, HCLK_EMMC); + +static int pd_vcodec_mode(struct clk *clk, int on) +{ + if (on) { + u32 gate, gate2; + + gate = cru_clkgate3_con_mirror; + gate |= (1 << CLK_GATE_ACLK_DDR_VEPU % 32); + gate &= ~((1 << CLK_GATE_ACLK_VEPU % 32) + | (1 << CLK_GATE_HCLK_VEPU % 32) + | (1 << CLK_GATE_HCLK_CPU_VCODEC % 32)); + cru_writel(gate, CRU_CLKGATE3_CON); + + pmu_set_power_domain(PD_VCODEC, true); + + udelay(10); + + cru_writel(cru_clkgate3_con_mirror, CRU_CLKGATE3_CON); + } else { + pmu_set_power_domain(PD_VCODEC, false); + } + + return 0; +} + +static struct clk pd_vcodec = { + .name = "pd_vcodec", + .flags = IS_PD, + .mode = pd_vcodec_mode, +}; + +static int pd_display_mode(struct clk *clk, int on) +{ + if (on) { + u32 gate, gate2; + + gate = cru_clkgate3_con_mirror; + gate |= (1 << CLK_GATE_ACLK_DDR_LCDC % 32); + gate &= ~((1 << CLK_GATE_HCLK_CPU_DISPLAY % 32) + | (1 << CLK_GATE_HCLK_DISP_MATRIX % 32) + | (1 << CLK_GATE_ACLK_DISP_MATRIX % 32) + | (1 << CLK_GATE_DCLK_EBOOK % 32) + | (1 << CLK_GATE_HCLK_EBOOK % 32) + | (1 << CLK_GATE_HCLK_IPP % 32) + | (1 << CLK_GATE_ACLK_IPP % 32) + | (1 << CLK_GATE_DCLK_LCDC % 32) + | (1 << CLK_GATE_HCLK_LCDC % 32) + | (1 << CLK_GATE_ACLK_LCDC % 32)); + cru_writel(gate, CRU_CLKGATE3_CON); + + gate2 = cru_readl(CRU_CLKGATE2_CON); + gate = gate2; + gate &= ~((1 << CLK_GATE_VIP_OUT % 32) + | (1 << CLK_GATE_VIP_SLAVE % 32) + | (1 << CLK_GATE_VIP_MATRIX % 32) + | (1 << CLK_GATE_VIP_BUS % 32)); + cru_writel(gate, CRU_CLKGATE2_CON); + + pmu_set_power_domain(PD_DISPLAY, true); + + udelay(10); + + cru_writel(gate2, CRU_CLKGATE2_CON); + cru_writel(cru_clkgate3_con_mirror, CRU_CLKGATE3_CON); + } else { + pmu_set_power_domain(PD_DISPLAY, false); + } + + return 0; +} + +static struct clk pd_display = { + .name = "pd_display", + .flags = IS_PD, + .mode = pd_display_mode, +}; + +static int pd_gpu_mode(struct clk *clk, int on) +{ + if (on) { + pmu_set_power_domain(PD_GPU, true); + } else { + pmu_set_power_domain(PD_GPU, false); + } + + return 0; +} + +static struct clk pd_gpu = { + .name = "pd_gpu", + .flags = IS_PD, + .mode = pd_gpu_mode, +}; + + #define CLK(dev, con, ck) \ { \ .dev_id = dev, \ @@ -1874,6 +1970,10 @@ static struct clk_lookup clks[] = { CLK1(hclk_gpu), CLK1(hclk_cpu_vcodec), CLK1(hclk_cpu_display), + + CLK(NULL, "pd_vcodec", &pd_vcodec), + CLK(NULL, "pd_display", &pd_display), + CLK(NULL, "pd_gpu", &pd_gpu), }; static LIST_HEAD(clocks); @@ -2283,7 +2383,7 @@ static int __init clk_disable_unused(void) struct clk *ck; list_for_each_entry(ck, &clocks, node) { - if (ck->usecount > 0 || ck->mode == NULL) + if (ck->usecount > 0 || ck->mode == NULL || (ck->flags & IS_PD)) continue; LOCK(); @@ -2358,7 +2458,7 @@ static void dump_clock(struct seq_file *s, struct clk *clk, int deep) v = cru_clkgate3_con_mirror & (1 << idx); else v = cru_readl(reg) & (1 << idx); - + seq_printf(s, "%s ", v ? "off" : "on "); } diff --git a/drivers/video/rk29_fb.c b/drivers/video/rk29_fb.c index 5a029e655ebe..020360dc1186 100755 --- a/drivers/video/rk29_fb.c +++ b/drivers/video/rk29_fb.c @@ -195,6 +195,7 @@ struct rk29fb_inf { struct clk *aclk_ddr_lcdc; //DDR LCDC AXI clock disable. struct clk *aclk_disp_matrix; //DISPLAY matrix AXI clock disable. struct clk *hclk_cpu_display; //CPU DISPLAY AHB bus clock disable. + struct clk *pd_display; // display power domain unsigned long dclk_rate; /* lcdc reg base address and backup reg */ @@ -455,7 +456,12 @@ int init_lcdc(struct fb_info *info) inf->aclk_ddr_lcdc = clk_get(NULL, "aclk_ddr_lcdc"); inf->aclk_disp_matrix = clk_get(NULL, "aclk_disp_matrix"); inf->hclk_cpu_display = clk_get(NULL, "hclk_cpu_display"); - if ((IS_ERR(inf->clk)) || (IS_ERR(inf->aclk_ddr_lcdc)) || (IS_ERR(inf->aclk_disp_matrix)) ||(IS_ERR(inf->hclk_cpu_display))) + inf->pd_display = clk_get(NULL, "pd_display"); + if ((IS_ERR(inf->clk)) || + (IS_ERR(inf->aclk_ddr_lcdc)) || + (IS_ERR(inf->aclk_disp_matrix)) || + (IS_ERR(inf->hclk_cpu_display)) || + (IS_ERR(inf->pd_display))) { printk(KERN_ERR "failed to get lcdc_hclk source\n"); return PTR_ERR(inf->clk); @@ -463,7 +469,8 @@ int init_lcdc(struct fb_info *info) clk_enable(inf->aclk_disp_matrix); clk_enable(inf->hclk_cpu_display); clk_enable(inf->clk); - pmu_set_power_domain(PD_DISPLAY, 1); + clk_enable(inf->pd_display); + //pmu_set_power_domain(PD_DISPLAY, 1); clk_enable(inf->aclk_ddr_lcdc); // set AHB access rule and disable all windows @@ -2175,7 +2182,8 @@ static int rk29fb_suspend(struct platform_device *pdev, pm_message_t mesg) if(inf->clk){ clk_disable(inf->aclk); } - pmu_set_power_domain(PD_DISPLAY, 0); + clk_disable(inf->pd_display); + //pmu_set_power_domain(PD_DISPLAY, 0); inf->in_suspend = 1; } return 0; @@ -2200,7 +2208,8 @@ static int rk29fb_resume(struct platform_device *pdev) clk_enable(inf->aclk_disp_matrix); clk_enable(inf->hclk_cpu_display); clk_enable(inf->clk); - pmu_set_power_domain(PD_DISPLAY, 1); + clk_enable(inf->pd_display); + //pmu_set_power_domain(PD_DISPLAY, 1); clk_enable(inf->aclk_ddr_lcdc); if (inf->dclk){ @@ -2662,7 +2671,8 @@ static void rk29fb_shutdown(struct platform_device *pdev) if(inf->clk){ clk_disable(inf->aclk); } - pmu_set_power_domain(PD_DISPLAY, 0); + clk_disable(inf->pd_display); + //pmu_set_power_domain(PD_DISPLAY, 0); inf->in_suspend = 1; } -- 2.34.1