From 58ebc4a9edccc7a7accf00398aaeafb8da1cc146 Mon Sep 17 00:00:00 2001 From: yxj Date: Sat, 14 Jul 2012 15:12:34 +0800 Subject: [PATCH] turn of lcdc power domain and clk in earyl suspend --- drivers/video/rockchip/chips/rk30_lcdc.c | 157 ++++++++++++++++------- drivers/video/rockchip/chips/rk30_lcdc.h | 5 +- drivers/video/rockchip/rk_fb.c | 9 +- 3 files changed, 121 insertions(+), 50 deletions(-) diff --git a/drivers/video/rockchip/chips/rk30_lcdc.c b/drivers/video/rockchip/chips/rk30_lcdc.c index bfec242709c1..87d2ab494b61 100644 --- a/drivers/video/rockchip/chips/rk30_lcdc.c +++ b/drivers/video/rockchip/chips/rk30_lcdc.c @@ -47,12 +47,14 @@ static int init_rk30_lcdc(struct rk_lcdc_device_driver *dev_drv) struct rk30_lcdc_device *lcdc_dev = container_of(dev_drv,struct rk30_lcdc_device,driver); if(lcdc_dev->id == 0) //lcdc0 { + lcdc_dev->pd = clk_get(NULL,"pd_lcdc0"); lcdc_dev->hclk = clk_get(NULL,"hclk_lcdc0"); lcdc_dev->aclk = clk_get(NULL,"aclk_lcdc0"); lcdc_dev->dclk = clk_get(NULL,"dclk_lcdc0"); } else if(lcdc_dev->id == 1) { + lcdc_dev->pd = clk_get(NULL,"pd_lcdc1"); lcdc_dev->hclk = clk_get(NULL,"hclk_lcdc1"); lcdc_dev->aclk = clk_get(NULL,"aclk_lcdc1"); lcdc_dev->dclk = clk_get(NULL,"dclk_lcdc1"); @@ -62,10 +64,11 @@ static int init_rk30_lcdc(struct rk_lcdc_device_driver *dev_drv) printk(KERN_ERR "invalid lcdc device!\n"); return -EINVAL; } - if ((IS_ERR(lcdc_dev->aclk)) ||(IS_ERR(lcdc_dev->dclk)) || (IS_ERR(lcdc_dev->hclk))) + if (IS_ERR(lcdc_dev->pd) || (IS_ERR(lcdc_dev->aclk)) ||(IS_ERR(lcdc_dev->dclk)) || (IS_ERR(lcdc_dev->hclk))) { printk(KERN_ERR "failed to get lcdc%d clk source\n",lcdc_dev->id); } + clk_enable(lcdc_dev->pd); clk_enable(lcdc_dev->hclk); //enable aclk and hclk for register config clk_enable(lcdc_dev->aclk); lcdc_dev->clk_on = 1; @@ -79,19 +82,30 @@ static int init_rk30_lcdc(struct rk_lcdc_device_driver *dev_drv) LcdMskReg(lcdc_dev,INT_STATUS,m_FRM_START_INT_CLEAR | m_BUS_ERR_INT_CLEAR | m_LINE_FLAG_INT_EN | m_FRM_START_INT_EN | m_HOR_START_INT_EN,v_FRM_START_INT_CLEAR(1) | v_BUS_ERR_INT_CLEAR(0) | v_LINE_FLAG_INT_EN(0) | v_FRM_START_INT_EN(0) | v_HOR_START_INT_EN(0)); //enable frame start interrupt for sync - LcdWrReg(lcdc_dev, REG_CFG_DONE, 0x01); // write any value to REG_CFG_DONE let config become effective + LCDC_REG_CFG_DONE(); // write any value to REG_CFG_DONE let config become effective return 0; } static int rk30_lcdc_deinit(struct rk30_lcdc_device *lcdc_dev) { - LcdSetBit(lcdc_dev,SYS_CTRL0,m_LCDC_STANDBY); - clk_disable(lcdc_dev->aclk); - clk_disable(lcdc_dev->dclk); - clk_disable(lcdc_dev->hclk); - clk_put(lcdc_dev->aclk); - clk_put(lcdc_dev->dclk); - clk_put(lcdc_dev->hclk); + spin_lock(&lcdc_dev->reg_lock); + if(likely(lcdc_dev->clk_on)) + { + lcdc_dev->clk_on = 0; + LcdMskReg(lcdc_dev, INT_STATUS, m_FRM_START_INT_CLEAR, v_FRM_START_INT_CLEAR(1)); + LcdMskReg(lcdc_dev, INT_STATUS, m_HOR_START_INT_EN | m_FRM_START_INT_EN | + m_LINE_FLAG_INT_EN | m_BUS_ERR_INT_EN,v_HOR_START_INT_EN(0) | v_FRM_START_INT_EN(0) | + v_LINE_FLAG_INT_EN(0) | v_BUS_ERR_INT_EN(0)); //disable all lcdc interrupt + LcdSetBit(lcdc_dev,SYS_CTRL0,m_LCDC_STANDBY); + LCDC_REG_CFG_DONE(); + spin_unlock(&lcdc_dev->reg_lock); + } + else //clk already disabled + { + spin_unlock(&lcdc_dev->reg_lock); + return 0; + } + mdelay(1); return 0; } @@ -195,7 +209,7 @@ static int rk30_load_screen(struct rk_lcdc_device_driver *dev_drv, bool initscre LcdWrReg(lcdc_dev, DSP_VACT_ST_END, v_VAEP(screen->vsync_len + screen->upper_margin+y_res)| v_VASP(screen->vsync_len + screen->upper_margin)); // let above to take effect - LcdWrReg(lcdc_dev, REG_CFG_DONE, 0x01); + LCDC_REG_CFG_DONE(); } spin_unlock(&lcdc_dev->reg_lock); @@ -238,9 +252,26 @@ static int win0_open(struct rk30_lcdc_device *lcdc_dev,bool open) spin_lock(&lcdc_dev->reg_lock); if(likely(lcdc_dev->clk_on)) { - LcdMskReg(lcdc_dev, SYS_CTRL1, m_W0_EN, v_W0_EN(open)); - LcdWrReg(lcdc_dev, REG_CFG_DONE, 0x01); + if(open) + { + if(!lcdc_dev->atv_layer_cnt) + { + LcdMskReg(lcdc_dev, SYS_CTRL0,m_LCDC_STANDBY,v_LCDC_STANDBY(0)); + } + lcdc_dev->atv_layer_cnt++; + } + else + { + lcdc_dev->atv_layer_cnt--; + } lcdc_dev->driver.layer_par[0]->state = open; + + LcdMskReg(lcdc_dev, SYS_CTRL1, m_W0_EN, v_W0_EN(open)); + if(!lcdc_dev->atv_layer_cnt) //if no layer used,disable lcdc + { + LcdMskReg(lcdc_dev, SYS_CTRL0,m_LCDC_STANDBY,v_LCDC_STANDBY(1)); + } + LCDC_REG_CFG_DONE(); } spin_unlock(&lcdc_dev->reg_lock); printk(KERN_INFO "lcdc%d win0 %s\n",lcdc_dev->id,open?"open":"closed"); @@ -251,9 +282,28 @@ static int win1_open(struct rk30_lcdc_device *lcdc_dev,bool open) spin_lock(&lcdc_dev->reg_lock); if(likely(lcdc_dev->clk_on)) { - LcdMskReg(lcdc_dev, SYS_CTRL1, m_W1_EN, v_W1_EN(open)); - LcdWrReg(lcdc_dev, REG_CFG_DONE, 0x01); + if(open) + { + if(!lcdc_dev->atv_layer_cnt) + { + printk("lcdc%d wakeup from stanby\n",lcdc_dev->id); + LcdMskReg(lcdc_dev, SYS_CTRL0,m_LCDC_STANDBY,v_LCDC_STANDBY(0)); + } + lcdc_dev->atv_layer_cnt++; + } + else + { + lcdc_dev->atv_layer_cnt--; + } lcdc_dev->driver.layer_par[1]->state = open; + + LcdMskReg(lcdc_dev, SYS_CTRL1, m_W1_EN, v_W1_EN(open)); + if(!lcdc_dev->atv_layer_cnt) //if no layer used,disable lcdc + { + printk(KERN_INFO "no layer of lcdc%d is used,go to standby!",lcdc_dev->id); + LcdMskReg(lcdc_dev, SYS_CTRL0,m_LCDC_STANDBY,v_LCDC_STANDBY(1)); + } + LCDC_REG_CFG_DONE(); } spin_unlock(&lcdc_dev->reg_lock); printk(KERN_INFO "lcdc%d win1 %s\n",lcdc_dev->id,open?"open":"closed"); @@ -282,7 +332,7 @@ static int rk30_lcdc_blank(struct rk_lcdc_device_driver*lcdc_drv,int layer_id,in LcdMskReg(lcdc_dev,DSP_CTRL1,m_BLANK_MODE ,v_BLANK_MODE(1)); break; } - LcdWrReg(lcdc_dev, REG_CFG_DONE, 0x01); + LCDC_REG_CFG_DONE(); } spin_unlock(&lcdc_dev->reg_lock); @@ -302,7 +352,7 @@ static int win0_display(struct rk30_lcdc_device *lcdc_dev,struct layer_par *par { LcdWrReg(lcdc_dev, WIN0_YRGB_MST0, y_addr); LcdWrReg(lcdc_dev, WIN0_CBR_MST0, uv_addr); - LcdWrReg(lcdc_dev, REG_CFG_DONE, 0x01); + LCDC_REG_CFG_DONE(); } spin_unlock(&lcdc_dev->reg_lock); @@ -323,7 +373,7 @@ static int win1_display(struct rk30_lcdc_device *lcdc_dev,struct layer_par *par { LcdWrReg(lcdc_dev, WIN1_YRGB_MST, y_addr); LcdWrReg(lcdc_dev, WIN1_CBR_MST, uv_addr); - LcdWrReg(lcdc_dev, REG_CFG_DONE, 0x01); + LCDC_REG_CFG_DONE(); } spin_unlock(&lcdc_dev->reg_lock); @@ -403,7 +453,7 @@ static int win0_set_par(struct rk30_lcdc_device *lcdc_dev,rk_screen *screen, break; } - LcdWrReg(lcdc_dev, REG_CFG_DONE, 0x01); + LCDC_REG_CFG_DONE(); } spin_unlock(&lcdc_dev->reg_lock); @@ -484,7 +534,7 @@ static int win1_set_par(struct rk30_lcdc_device *lcdc_dev,rk_screen *screen, break; } - LcdWrReg(lcdc_dev, REG_CFG_DONE, 0x01); + LCDC_REG_CFG_DONE(); } spin_unlock(&lcdc_dev->reg_lock); return 0; @@ -556,23 +606,20 @@ int rk30_lcdc_pan_display(struct rk_lcdc_device_driver * dev_drv,int layer_id) dev_drv->first_frame = 0; LcdMskReg(lcdc_dev,INT_STATUS,m_FRM_START_INT_CLEAR |m_FRM_START_INT_EN , v_FRM_START_INT_CLEAR(1) | v_FRM_START_INT_EN(1)); - LcdWrReg(lcdc_dev, REG_CFG_DONE, 0x01); // write any value to REG_CFG_DONE let config become effective + LCDC_REG_CFG_DONE(); // write any value to REG_CFG_DONE let config become effective } spin_lock_irqsave(&dev_drv->cpl_lock,flags); init_completion(&dev_drv->frame_done); spin_unlock_irqrestore(&dev_drv->cpl_lock,flags); - timeout = wait_for_completion_interruptible_timeout(&dev_drv->frame_done,msecs_to_jiffies(dev_drv->screen->ft+5)); - if(!timeout) + timeout = wait_for_completion_timeout(&dev_drv->frame_done,msecs_to_jiffies(dev_drv->screen->ft+5)); + if(!timeout&&(!dev_drv->frame_done.done)) { printk(KERN_ERR "wait for new frame start time out!\n"); return -ETIMEDOUT; } - else if(timeout < 0) - { - return timeout; - } + return 0; } @@ -638,6 +685,7 @@ static int rk30_lcdc_ovl_mgr(struct rk_lcdc_device_driver *dev_drv,int swap,bool { LcdMskReg(lcdc_dev,DSP_CTRL0,m_W0W1_POSITION_SWAP,v_W0W1_POSITION_SWAP(swap)); LcdWrReg(lcdc_dev, REG_CFG_DONE, 0x01); + LCDC_REG_CFG_DONE(); ovl = swap; } else //get overlay @@ -700,11 +748,27 @@ int rk30_lcdc_early_suspend(struct rk_lcdc_device_driver *dev_drv) struct rk30_lcdc_device *lcdc_dev = container_of(dev_drv,struct rk30_lcdc_device,driver); spin_lock(&lcdc_dev->reg_lock); - lcdc_dev->clk_on = 0; - LcdMskReg(lcdc_dev, SYS_CTRL0,m_LCDC_STANDBY,v_LCDC_STANDBY(1)); - LcdWrReg(lcdc_dev, REG_CFG_DONE, 0x01); - spin_unlock(&lcdc_dev->reg_lock); + if(likely(lcdc_dev->clk_on)) + { + lcdc_dev->clk_on = 0; + LcdMskReg(lcdc_dev, INT_STATUS, m_FRM_START_INT_CLEAR, v_FRM_START_INT_CLEAR(1)); + LcdMskReg(lcdc_dev, SYS_CTRL0,m_LCDC_STANDBY,v_LCDC_STANDBY(1)); + LCDC_REG_CFG_DONE(); + spin_unlock(&lcdc_dev->reg_lock); + } + else //clk already disabled + { + spin_unlock(&lcdc_dev->reg_lock); + return 0; + } + + mdelay(1); + clk_disable(lcdc_dev->dclk); + clk_disable(lcdc_dev->hclk); + clk_disable(lcdc_dev->aclk); + clk_disable(lcdc_dev->pd); + return 0; } @@ -713,9 +777,21 @@ int rk30_lcdc_early_resume(struct rk_lcdc_device_driver *dev_drv) { struct rk30_lcdc_device *lcdc_dev = container_of(dev_drv,struct rk30_lcdc_device,driver); + if(!lcdc_dev->clk_on) + { + clk_enable(lcdc_dev->pd); + clk_enable(lcdc_dev->hclk); + clk_enable(lcdc_dev->dclk); + clk_enable(lcdc_dev->aclk); + } + memcpy((u8*)lcdc_dev->preg, (u8*)&lcdc_dev->regbak, 0xc4); //resume reg + spin_lock(&lcdc_dev->reg_lock); - LcdMskReg(lcdc_dev, SYS_CTRL0,m_LCDC_STANDBY,v_LCDC_STANDBY(0)); - LcdWrReg(lcdc_dev, REG_CFG_DONE, 0x01); + if(lcdc_dev->atv_layer_cnt) + { + LcdMskReg(lcdc_dev, SYS_CTRL0,m_LCDC_STANDBY,v_LCDC_STANDBY(0)); + LCDC_REG_CFG_DONE(); + } lcdc_dev->clk_on = 1; spin_unlock(&lcdc_dev->reg_lock); @@ -724,8 +800,11 @@ int rk30_lcdc_early_resume(struct rk_lcdc_device_driver *dev_drv) static irqreturn_t rk30_lcdc_isr(int irq, void *dev_id) { struct rk30_lcdc_device *lcdc_dev = (struct rk30_lcdc_device *)dev_id; + LcdMskReg(lcdc_dev, INT_STATUS, m_FRM_START_INT_CLEAR, v_FRM_START_INT_CLEAR(1)); + LCDC_REG_CFG_DONE(); //LcdMskReg(lcdc_dev, INT_STATUS, m_LINE_FLAG_INT_CLEAR, v_LINE_FLAG_INT_CLEAR(1)); + spin_lock(&(lcdc_dev->driver.cpl_lock)); complete(&(lcdc_dev->driver.frame_done)); spin_unlock(&(lcdc_dev->driver.cpl_lock)); @@ -766,25 +845,11 @@ static struct rk_lcdc_device_driver lcdc_driver = { #ifdef CONFIG_PM static int rk30_lcdc_suspend(struct platform_device *pdev, pm_message_t state) { - struct rk30_lcdc_device *lcdc_dev = platform_get_drvdata(pdev); - - - clk_disable(lcdc_dev->dclk); - clk_disable(lcdc_dev->hclk); - clk_disable(lcdc_dev->aclk); - return 0; } static int rk30_lcdc_resume(struct platform_device *pdev) { - struct rk30_lcdc_device *lcdc_dev = platform_get_drvdata(pdev); - - clk_enable(lcdc_dev->hclk); - clk_enable(lcdc_dev->dclk); - clk_enable(lcdc_dev->aclk); - memcpy((u8*)lcdc_dev->preg, (u8*)&lcdc_dev->regbak, 0xc4); //resume reg - return 0; } diff --git a/drivers/video/rockchip/chips/rk30_lcdc.h b/drivers/video/rockchip/chips/rk30_lcdc.h index 813fc10a7649..b986c3fc330f 100644 --- a/drivers/video/rockchip/chips/rk30_lcdc.h +++ b/drivers/video/rockchip/chips/rk30_lcdc.h @@ -10,6 +10,7 @@ #define LcdClrBit(inf, addr, msk) inf->preg->addr=((inf->regbak.addr) &= ~(msk)) #define LcdSetRegBit(inf, addr, msk) inf->preg->addr=((inf->preg->addr) |= (msk)) #define LcdMskReg(inf, addr, msk, val) (inf->regbak.addr)&=~(msk); inf->preg->addr=(inf->regbak.addr|=(val)) +#define LCDC_REG_CFG_DONE() LcdWrReg(lcdc_dev, REG_CFG_DONE, 0x01); dsb() /******************************************************************** ** ½á¹¹¶¨Òå * @@ -483,9 +484,11 @@ struct rk30_lcdc_device{ u32 len; // physical map length of lcdc register spinlock_t reg_lock; //one time only one process allowed to config the register bool clk_on; //if aclk or hclk is closed ,acess to register is not allowed + u8 atv_layer_cnt; //active layer counter,when atv_layer_cnt = 0,disable lcdc unsigned int irq; - + + struct clk *pd; //lcdc power domain struct clk *hclk; //lcdc AHP clk struct clk *dclk; //lcdc dclk struct clk *aclk; //lcdc share memory frequency diff --git a/drivers/video/rockchip/rk_fb.c b/drivers/video/rockchip/rk_fb.c index 5a42aa8735c3..9ec9cd885821 100644 --- a/drivers/video/rockchip/rk_fb.c +++ b/drivers/video/rockchip/rk_fb.c @@ -637,7 +637,10 @@ int rk_fb_switch_screen(rk_screen *screen ,int enable ,int lcdc_id) layer_id = get_fb_layer_id(&info->fix); if(!enable) { - dev_drv->open(dev_drv,layer_id,enable); //disable the layer which attached to this fb + if(dev_drv->layer_par[layer_id]->state) + { + dev_drv->open(dev_drv,layer_id,enable); //disable the layer which attached to this fb + } return 0; } @@ -662,8 +665,8 @@ int rk_fb_switch_screen(rk_screen *screen ,int enable ,int lcdc_id) #endif hdmi_var->grayscale &= 0xff; hdmi_var->grayscale |= (dev_drv->screen->x_res<<8) + (dev_drv->screen->y_res<<20); - ret = dev_drv->load_screen(dev_drv,1); ret = info->fbops->fb_open(info,1); + ret = dev_drv->load_screen(dev_drv,1); ret = info->fbops->fb_set_par(info); #if defined(CONFIG_DUAL_DISP_IN_KERNEL) if(likely(inf->num_lcdc == 2)) @@ -888,7 +891,7 @@ int rk_fb_register(struct rk_lcdc_device_driver *dev_drv, if(NULL==fb_inf->lcdc_dev_drv[i]) { fb_inf->lcdc_dev_drv[i] = dev_drv; - fb_inf->lcdc_dev_drv[i]->id = i; + fb_inf->lcdc_dev_drv[i]->id = id; fb_inf->num_lcdc++; break; } -- 2.34.1