rk29: clock: add display power domain clock support
author陈恒明 <chm@rockchip.com>
Tue, 22 Mar 2011 08:58:32 +0000 (16:58 +0800)
committer陈恒明 <chm@rockchip.com>
Tue, 22 Mar 2011 08:58:32 +0000 (16:58 +0800)
arch/arm/mach-rk29/clock.c
drivers/video/rk29_fb.c

index 2eb8d17cfc715081c00458f638e881c9d32515ec..512cff76351061ed277a035431c9a3d5bd253b78 100755 (executable)
@@ -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 ");
        }
 
index 5a029e655ebea014b604cb34ab1f0815bf611c24..020360dc11861cfedf8123d42045d1962b2c84c4 100755 (executable)
@@ -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;
        }