msm_fb: Handle vsync interrupt properly on MDP 3.03 targets

Handle enabling/disabling the vsync interrupt and mdp clock
enabling/disabling in a better way on MDP 3.03 targets. This
will avoid target crashes due to unclocked register access.

CRs-fixed: 388751
Change-Id: I5c4a409772464ce7d06869374dcba5ad7e335955
Signed-off-by: Padmanabhan Komanduru <pkomandu@codeaurora.org>
Signed-off-by: Siddhartha Agrawal <agrawals@codeaurora.org>
This commit is contained in:
Padmanabhan Komanduru 2012-08-25 18:07:27 +05:30 committed by Stephen Boyd
parent f72ca836e3
commit a57b7f57a4
5 changed files with 66 additions and 46 deletions

View file

@ -1321,34 +1321,6 @@ static void send_vsync_work(struct work_struct *work)
kobject_uevent_env(&(vsync_cntrl.dev->kobj), KOBJ_CHANGE, envp); kobject_uevent_env(&(vsync_cntrl.dev->kobj), KOBJ_CHANGE, envp);
} }
void mdp3_vsync_irq_enable(int intr, int term)
{
unsigned long flag;
spin_lock_irqsave(&mdp_spin_lock, flag);
outp32(MDP_INTR_CLEAR, intr);
mdp_intr_mask |= intr;
outp32(MDP_INTR_ENABLE, mdp_intr_mask);
mdp_enable_irq(term);
spin_unlock_irqrestore(&mdp_spin_lock, flag);
}
void mdp3_vsync_irq_disable(int intr, int term)
{
unsigned long flag;
spin_lock_irqsave(&mdp_spin_lock, flag);
/* required to synchronize between frame update and vsync
* since both use the same LCDC_FRAME_START interrupt
*/
if (intr == LCDC_FRAME_START && dma2_data.waiting == FALSE) {
mdp_intr_mask &= ~intr;
outp32(MDP_INTR_ENABLE, mdp_intr_mask);
}
mdp_disable_irq(term);
spin_unlock_irqrestore(&mdp_spin_lock, flag);
}
#ifdef CONFIG_FB_MSM_MDP303 #ifdef CONFIG_FB_MSM_MDP303
/* vsync_isr_handler: Called from isr context*/ /* vsync_isr_handler: Called from isr context*/
static void vsync_isr_handler(void) static void vsync_isr_handler(void)
@ -1806,6 +1778,7 @@ irqreturn_t mdp_isr(int irq, void *ptr)
struct mdp_hist_mgmt *mgmt = NULL; struct mdp_hist_mgmt *mgmt = NULL;
char *base_addr; char *base_addr;
int i, ret; int i, ret;
int vsync_isr;
/* Ensure all the register write are complete */ /* Ensure all the register write are complete */
mb(); mb();
@ -1825,8 +1798,23 @@ irqreturn_t mdp_isr(int irq, void *ptr)
goto out; goto out;
/*Primary Vsync interrupt*/ /*Primary Vsync interrupt*/
if (mdp_interrupt & MDP_PRIM_RDPTR) if (mdp_interrupt & MDP_PRIM_RDPTR) {
vsync_isr_handler(); spin_lock_irqsave(&mdp_spin_lock, flag);
vsync_isr = vsync_cntrl.vsync_irq_enabled;
if (!vsync_isr) {
mdp_intr_mask &= ~MDP_PRIM_RDPTR;
outp32(MDP_INTR_ENABLE, mdp_intr_mask);
}
spin_unlock_irqrestore(&mdp_spin_lock, flag);
if (vsync_isr) {
vsync_isr_handler();
} else {
mdp_pipe_ctrl(MDP_CMD_BLOCK,
MDP_BLOCK_POWER_OFF, TRUE);
complete(&vsync_cntrl.vsync_wait);
}
}
/* DMA3 TV-Out Start */ /* DMA3 TV-Out Start */
if (mdp_interrupt & TV_OUT_DMA3_START) { if (mdp_interrupt & TV_OUT_DMA3_START) {
@ -1874,21 +1862,26 @@ irqreturn_t mdp_isr(int irq, void *ptr)
if (mdp_interrupt & LCDC_FRAME_START) { if (mdp_interrupt & LCDC_FRAME_START) {
dma = &dma2_data; dma = &dma2_data;
spin_lock_irqsave(&mdp_spin_lock, flag); spin_lock_irqsave(&mdp_spin_lock, flag);
vsync_isr = vsync_cntrl.vsync_irq_enabled;
/* let's disable LCDC interrupt */ /* let's disable LCDC interrupt */
if (dma->waiting) { if (dma->waiting) {
dma->waiting = FALSE; dma->waiting = FALSE;
complete(&dma->comp); complete(&dma->comp);
} }
if (vsync_cntrl.vsync_irq_enabled) if (!vsync_isr) {
vsync_isr_handler();
if (!vsync_cntrl.vsync_irq_enabled && !(dma->waiting)) {
mdp_intr_mask &= ~LCDC_FRAME_START; mdp_intr_mask &= ~LCDC_FRAME_START;
outp32(MDP_INTR_ENABLE, mdp_intr_mask); outp32(MDP_INTR_ENABLE, mdp_intr_mask);
} }
spin_unlock_irqrestore(&mdp_spin_lock, flag); spin_unlock_irqrestore(&mdp_spin_lock, flag);
if (vsync_isr) {
vsync_isr_handler();
} else {
mdp_pipe_ctrl(MDP_CMD_BLOCK,
MDP_BLOCK_POWER_OFF, TRUE);
complete(&vsync_cntrl.vsync_wait);
}
} }
/* DMA2 LCD-Out Complete */ /* DMA2 LCD-Out Complete */
@ -2019,6 +2012,7 @@ static void mdp_drv_init(void)
atomic_set(&mdp_block_power_cnt[i], 0); atomic_set(&mdp_block_power_cnt[i], 0);
} }
INIT_WORK(&(vsync_cntrl.vsync_work), send_vsync_work); INIT_WORK(&(vsync_cntrl.vsync_work), send_vsync_work);
init_completion(&vsync_cntrl.vsync_wait);
#ifdef MSM_FB_ENABLE_DBGFS #ifdef MSM_FB_ENABLE_DBGFS
{ {
struct dentry *root; struct dentry *root;

View file

@ -96,6 +96,7 @@ struct vsync {
struct device *dev; struct device *dev;
struct work_struct vsync_work; struct work_struct vsync_work;
int vsync_irq_enabled; int vsync_irq_enabled;
struct completion vsync_wait;
}; };
extern struct vsync vsync_cntrl; extern struct vsync vsync_cntrl;
@ -829,8 +830,6 @@ static inline int mdp_bus_scale_update_request(uint32_t index)
void mdp_dma_vsync_ctrl(int enable); void mdp_dma_vsync_ctrl(int enable);
void mdp_dma_video_vsync_ctrl(int enable); void mdp_dma_video_vsync_ctrl(int enable);
void mdp_dma_lcdc_vsync_ctrl(int enable); void mdp_dma_lcdc_vsync_ctrl(int enable);
void mdp3_vsync_irq_enable(int intr, int term);
void mdp3_vsync_irq_disable(int intr, int term);
#ifdef MDP_HW_VSYNC #ifdef MDP_HW_VSYNC
void vsync_clk_prepare_enable(void); void vsync_clk_prepare_enable(void);

View file

@ -514,18 +514,27 @@ void mdp_dma2_update(struct msm_fb_data_type *mfd)
void mdp_dma_vsync_ctrl(int enable) void mdp_dma_vsync_ctrl(int enable)
{ {
unsigned long flag;
if (vsync_cntrl.vsync_irq_enabled == enable) if (vsync_cntrl.vsync_irq_enabled == enable)
return; return;
spin_lock_irqsave(&mdp_spin_lock, flag);
vsync_cntrl.vsync_irq_enabled = enable; vsync_cntrl.vsync_irq_enabled = enable;
spin_unlock_irqrestore(&mdp_spin_lock, flag);
if (enable) { if (enable) {
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
MDP_OUTP(MDP_BASE + 0x021c, 0x10); /* read pointer */ MDP_OUTP(MDP_BASE + 0x021c, 0x10); /* read pointer */
mdp3_vsync_irq_enable(MDP_PRIM_RDPTR, MDP_VSYNC_TERM); spin_lock_irqsave(&mdp_spin_lock, flag);
outp32(MDP_INTR_CLEAR, MDP_PRIM_RDPTR);
mdp_intr_mask |= MDP_PRIM_RDPTR;
outp32(MDP_INTR_ENABLE, mdp_intr_mask);
mdp_enable_irq(MDP_VSYNC_TERM);
spin_unlock_irqrestore(&mdp_spin_lock, flag);
} else { } else {
mdp3_vsync_irq_disable(MDP_PRIM_RDPTR, MDP_VSYNC_TERM); INIT_COMPLETION(vsync_cntrl.vsync_wait);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); wait_for_completion(&vsync_cntrl.vsync_wait);
mdp_disable_irq(MDP_VSYNC_TERM);
} }
} }

View file

@ -249,17 +249,26 @@ int mdp_dsi_video_off(struct platform_device *pdev)
void mdp_dma_video_vsync_ctrl(int enable) void mdp_dma_video_vsync_ctrl(int enable)
{ {
unsigned long flag;
if (vsync_cntrl.vsync_irq_enabled == enable) if (vsync_cntrl.vsync_irq_enabled == enable)
return; return;
spin_lock_irqsave(&mdp_spin_lock, flag);
vsync_cntrl.vsync_irq_enabled = enable; vsync_cntrl.vsync_irq_enabled = enable;
spin_unlock_irqrestore(&mdp_spin_lock, flag);
if (enable) { if (enable) {
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
mdp3_vsync_irq_enable(LCDC_FRAME_START, MDP_VSYNC_TERM); spin_lock_irqsave(&mdp_spin_lock, flag);
outp32(MDP_INTR_CLEAR, LCDC_FRAME_START);
mdp_intr_mask |= LCDC_FRAME_START;
outp32(MDP_INTR_ENABLE, mdp_intr_mask);
mdp_enable_irq(MDP_VSYNC_TERM);
spin_unlock_irqrestore(&mdp_spin_lock, flag);
} else { } else {
mdp3_vsync_irq_disable(LCDC_FRAME_START, MDP_VSYNC_TERM); INIT_COMPLETION(vsync_cntrl.vsync_wait);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); wait_for_completion(&vsync_cntrl.vsync_wait);
mdp_disable_irq(MDP_VSYNC_TERM);
} }
} }

View file

@ -330,17 +330,26 @@ int mdp_lcdc_off(struct platform_device *pdev)
void mdp_dma_lcdc_vsync_ctrl(int enable) void mdp_dma_lcdc_vsync_ctrl(int enable)
{ {
unsigned long flag;
if (vsync_cntrl.vsync_irq_enabled == enable) if (vsync_cntrl.vsync_irq_enabled == enable)
return; return;
spin_lock_irqsave(&mdp_spin_lock, flag);
vsync_cntrl.vsync_irq_enabled = enable; vsync_cntrl.vsync_irq_enabled = enable;
spin_unlock_irqrestore(&mdp_spin_lock, flag);
if (enable) { if (enable) {
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
mdp3_vsync_irq_enable(LCDC_FRAME_START, MDP_VSYNC_TERM); spin_lock_irqsave(&mdp_spin_lock, flag);
outp32(MDP_INTR_CLEAR, LCDC_FRAME_START);
mdp_intr_mask |= LCDC_FRAME_START;
outp32(MDP_INTR_ENABLE, mdp_intr_mask);
mdp_enable_irq(MDP_VSYNC_TERM);
spin_unlock_irqrestore(&mdp_spin_lock, flag);
} else { } else {
mdp3_vsync_irq_disable(LCDC_FRAME_START, MDP_VSYNC_TERM); INIT_COMPLETION(vsync_cntrl.vsync_wait);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); wait_for_completion(&vsync_cntrl.vsync_wait);
mdp_disable_irq(MDP_VSYNC_TERM);
} }
} }