The current framebuffer driver oopses when used as a console (kernel parameter: console=tty ). Here is a patch that makes it work - at the cost of performance. Signed-off-by: Bradley Smith <brad@xxxxxxxxxxxxxxxx> (cherry picked from commit 28d06a6366c851c6e0c5b954353bf82cb641d4e7) --- drivers/video/msm/Kconfig | 4 ++++ drivers/video/msm/mdp.c | 20 ++++++++++++++++++++ drivers/video/msm/mdp.h | 3 +++ drivers/video/msm/mdp_dma.c | 15 +++++++++++++++ drivers/video/msm/mdp_dma_s.c | 28 ++++++++++++++++++++++++++++ drivers/video/msm/msm_fb.c | 2 ++ drivers/video/msm/msm_fb.h | 14 ++++++++++++++ 7 files changed, 86 insertions(+), 0 deletions(-) diff --git a/drivers/video/msm/Kconfig b/drivers/video/msm/Kconfig index e887a2d..cff8435 100644 --- a/drivers/video/msm/Kconfig +++ b/drivers/video/msm/Kconfig @@ -14,3 +14,7 @@ config FB_MSM_LCDC depends on FB_MSM && MSM_MDP31 default y +config MSM_FB_TTY_WORKAROUND + bool "Workaround TTY kernel OOPS at the cost of performance" + depends on FB_MSM + default n diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c index e56dd81..8bc2b13 100644 --- a/drivers/video/msm/mdp.c +++ b/drivers/video/msm/mdp.c @@ -118,6 +118,10 @@ static int mdp_suspend(struct platform_device *pdev, pm_message_t state); struct timeval mdp_dma2_timeval; struct timeval mdp_ppp_timeval; +#ifdef CONFIG_MSM_FB_TTY_WORKAROUND +LIST_HEAD(msm_fb_dma_task_list); +#endif + #ifdef CONFIG_HAS_EARLYSUSPEND static struct early_suspend early_suspend; #endif @@ -634,10 +638,26 @@ irqreturn_t mdp_isr(int irq, void *ptr) /* DMA2 LCD-Out Complete */ if (mdp_interrupt & MDP_DMA_S_DONE) { dma = &dma_s_data; +#ifdef CONFIG_MSM_FB_TTY_WORKAROUND + if(!list_empty(&msm_fb_dma_task_list)) { + struct msm_fb_dma_task *tsk = list_first_entry( + &msm_fb_dma_task_list, struct msm_fb_dma_task, list); + dma->busy = TRUE; + mdp_dma_s_update_lcd(tsk->mfd, &tsk->ibuf); + list_del(&tsk->list); + kfree(tsk); + } + else { + mdp_disable_irq(MDP_DMA_S_TERM); + mdp_disable_irq(MDP_DMA_E_TERM); + dma->busy = FALSE; + } +#else dma->busy = FALSE; mdp_pipe_ctrl(MDP_DMA_S_BLOCK, MDP_BLOCK_POWER_OFF, TRUE); complete(&dma->comp); +#endif } /* DMA_E LCD-Out Complete */ if (mdp_interrupt & MDP_DMA_E_DONE) { diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h index d60ccae..f3d064b 100644 --- a/drivers/video/msm/mdp.h +++ b/drivers/video/msm/mdp.h @@ -680,4 +680,7 @@ int mdp_debugfs_init(void); #endif void mdp_dma_s_update(struct msm_fb_data_type *mfd); +#ifdef CONFIG_MSM_FB_TTY_WORKAROUND +void mdp_dma_s_update_lcd(struct msm_fb_data_type *mfd, MDPIBUF *iBuf); +#endif #endif /* MDP_H */ diff --git a/drivers/video/msm/mdp_dma.c b/drivers/video/msm/mdp_dma.c index dc8d58d..f62c7e3 100644 --- a/drivers/video/msm/mdp_dma.c +++ b/drivers/video/msm/mdp_dma.c @@ -433,7 +433,9 @@ void mdp_dma2_update(struct msm_fb_data_type *mfd) down(&mfd->dma->mutex); if ((mfd) && (!mfd->dma->busy) && (mfd->panel_power_on)) { down(&mfd->sem); +#if !defined(CONFIG_MSM_FB_TTY_WORKAROUND) mfd->ibuf_flushed = TRUE; +#endif mdp_dma2_update_lcd(mfd); mdp_enable_irq(MDP_DMA2_TERM); @@ -448,11 +450,13 @@ void mdp_dma2_update(struct msm_fb_data_type *mfd) wait_for_completion_killable(&mfd->dma->comp); mdp_disable_irq(MDP_DMA2_TERM); +#if !defined(CONFIG_MSM_FB_TTY_WORKAROUND) /* signal if pan function is waiting for the update completion */ if (mfd->pan_waiting) { mfd->pan_waiting = FALSE; complete(&mfd->pan_comp); } +#endif } up(&mfd->dma->mutex); } @@ -484,6 +488,12 @@ void mdp_set_dma_pan_info(struct fb_info *info, struct mdp_dirty_region *dirty, iBuf->vsync_enable = sync; +#ifdef CONFIG_MSM_FB_TTY_WORKAROUND + iBuf->dma_x = 0; + iBuf->dma_y = 0; + iBuf->dma_w = info->var.xres; + iBuf->dma_h = info->var.yres; +#else if (dirty) { /* * ToDo: dirty region check inside var.xoffset+xres @@ -500,6 +510,7 @@ void mdp_set_dma_pan_info(struct fb_info *info, struct mdp_dirty_region *dirty, iBuf->dma_h = info->var.yres; } mfd->ibuf_flushed = FALSE; +#endif up(&mfd->sem); } @@ -510,6 +521,9 @@ void mdp_dma_pan_update(struct fb_info *info) iBuf = &mfd->ibuf; +#ifdef CONFIG_MSM_FB_TTY_WORKAROUND + mfd->dma_fnc(mfd); +#else if (mfd->sw_currently_refreshing) { /* we need to wait for the pending update */ mfd->pan_waiting = TRUE; @@ -521,6 +535,7 @@ void mdp_dma_pan_update(struct fb_info *info) wait_for_completion_killable(&mfd->pan_comp); } else mfd->dma_fnc(mfd); +#endif } void mdp_refresh_screen(unsigned long data) diff --git a/drivers/video/msm/mdp_dma_s.c b/drivers/video/msm/mdp_dma_s.c index ee39504..c9b67d5 100644 --- a/drivers/video/msm/mdp_dma_s.c +++ b/drivers/video/msm/mdp_dma_s.c @@ -37,9 +37,14 @@ #include "mdp.h" #include "msm_fb.h" +#ifdef CONFIG_MSM_FB_TTY_WORKAROUND +void mdp_dma_s_update_lcd(struct msm_fb_data_type *mfd, MDPIBUF *iBuf) +{ +#else static void mdp_dma_s_update_lcd(struct msm_fb_data_type *mfd) { MDPIBUF *iBuf = &mfd->ibuf; +#endif int mddi_dest = FALSE; uint32 outBpp = iBuf->bpp; uint32 dma_s_cfg_reg; @@ -141,6 +146,28 @@ static void mdp_dma_s_update_lcd(struct msm_fb_data_type *mfd) void mdp_dma_s_update(struct msm_fb_data_type *mfd) { down(&mfd->dma->mutex); +#ifdef CONFIG_MSM_FB_TTY_WORKAROUND + if(mfd && mfd->panel_power_on) { + if (!mfd->dma->busy) { + down(&mfd->sem); + mdp_enable_irq(MDP_DMA_S_TERM); + if (mfd->panel_info.type == MDDI_PANEL) + mdp_enable_irq(MDP_DMA_S_TERM); + else + mdp_enable_irq(MDP_DMA_E_TERM); + mfd->dma->busy = TRUE; + mdp_dma_s_update_lcd(mfd, &mfd->ibuf); + up(&mfd->sem); + } + else { + struct msm_fb_dma_task *tsk = kzalloc(sizeof( + struct msm_fb_dma_task), GFP_ATOMIC); + tsk->mfd = mfd; + tsk->ibuf = mfd->ibuf; + list_add_tail(&tsk->list, &msm_fb_dma_task_list); + } + } +#else if ((mfd) && (!mfd->dma->busy) && (mfd->panel_power_on)) { down(&mfd->sem); mdp_enable_irq(MDP_DMA_S_TERM); @@ -167,5 +194,6 @@ void mdp_dma_s_update(struct msm_fb_data_type *mfd) complete(&mfd->pan_comp); } } +#endif up(&mfd->dma->mutex); } diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c index 14b1860..d355813 100644 --- a/drivers/video/msm/msm_fb.c +++ b/drivers/video/msm/msm_fb.c @@ -1025,8 +1025,10 @@ static int msm_fb_register(struct msm_fb_data_type *mfd) mfd->sw_refreshing_enable = TRUE; mfd->panel_power_on = FALSE; +#if !defined(CONFIG_MSM_FB_TTY_WORKAROUND) mfd->pan_waiting = FALSE; init_completion(&mfd->pan_comp); +#endif init_completion(&mfd->refresher_comp); init_MUTEX(&mfd->sem); diff --git a/drivers/video/msm/msm_fb.h b/drivers/video/msm/msm_fb.h index 2395cb2..2e1e38a 100644 --- a/drivers/video/msm/msm_fb.h +++ b/drivers/video/msm/msm_fb.h @@ -63,6 +63,10 @@ #define MFD_KEY 0x11161126 #define MSM_FB_MAX_DEV_LIST 32 +#ifdef CONFIG_MSM_FB_TTY_WORKAROUND +extern struct list_head msm_fb_dma_task_list; +#endif + struct disp_info_type_suspend { boolean op_enable; boolean sw_refreshing_enable; @@ -91,12 +95,16 @@ struct msm_fb_data_type { #endif MDPIBUF ibuf; +#if !defined(CONFIG_MSM_FB_TTY_WORKAROUND) boolean ibuf_flushed; +#endif struct timer_list refresh_timer; struct completion refresher_comp; +#if !defined(CONFIG_MSM_FB_TTY_WORKAROUND) boolean pan_waiting; struct completion pan_comp; +#endif /* vsync */ boolean use_mdp_vsync; @@ -167,6 +175,12 @@ struct msm_fb_data_type { struct pm_qos_request_list *pm_qos_req; }; +struct msm_fb_dma_task { + struct msm_fb_data_type* mfd; + MDPIBUF ibuf; + struct list_head list; +}; + struct dentry *msm_fb_get_debugfs_root(void); void msm_fb_debugfs_file_create(struct dentry *root, const char *name, u32 *var); -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html