turn of lcdc power domain and clk in earyl suspend

This commit is contained in:
yxj
2012-07-14 15:12:34 +08:00
parent 1690f2c243
commit 58ebc4a9ed
3 changed files with 121 additions and 50 deletions

View File

@@ -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;
}

View File

@@ -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()
/********************************************************************
** <20><EFBFBD><E1B9B9><EFBFBD><EFBFBD> *
@@ -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

View File

@@ -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;
}