From 59defd1dbf4eb1c3fac3383d417c325a505e5eb7 Mon Sep 17 00:00:00 2001 From: Dhaval Patel Date: Thu, 5 Sep 2013 18:37:32 -0700 Subject: msm: mdss: Add BTA status check API in DSI controller Add Bus-Turn-Around (BTA) status check API in DSI controller to check if it is alive or not. Subscriber of this API should send relevant notification to user space for correct action. Update fb driver and cmd interface to support the BTA failure scenario. Change-Id: Ic78379b31a48278282182fdba6ba7b2e6f9c26d5 Signed-off-by: Dhaval Patel --- drivers/video/fbdev/msm/mdss_dsi.c | 1 + drivers/video/fbdev/msm/mdss_dsi.h | 6 ++++ drivers/video/fbdev/msm/mdss_dsi_host.c | 53 +++++++++++++++++++++++++++-- drivers/video/fbdev/msm/mdss_fb.c | 4 ++- drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c | 17 ++++++++- drivers/video/fbdev/msm/mdss_panel.h | 2 ++ 6 files changed, 79 insertions(+), 4 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c index 23aa047d1c6d..a9942fd0ba5d 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.c +++ b/drivers/video/fbdev/msm/mdss_dsi.c @@ -1307,6 +1307,7 @@ int dsi_panel_device_register(struct device_node *pan_node, } ctrl_pdata->panel_data.event_handler = mdss_dsi_event_handler; + ctrl_pdata->check_status = mdss_dsi_bta_status_check; if (ctrl_pdata->bklt_ctrl == BL_PWM) mdss_dsi_panel_pwm_cfg(ctrl_pdata); diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h index 54e4d49569ff..681190381774 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.h +++ b/drivers/video/fbdev/msm/mdss_dsi.h @@ -118,6 +118,8 @@ enum dsi_ctrl_op_mode { #define DSI_INTR_ERROR_MASK BIT(25) #define DSI_INTR_ERROR BIT(24) +#define DSI_INTR_BTA_DONE_MASK BIT(21) +#define DSI_INTR_BTA_DONE BIT(20) #define DSI_INTR_VIDEO_DONE_MASK BIT(17) #define DSI_INTR_VIDEO_DONE BIT(16) #define DSI_INTR_CMD_MDP_DONE_MASK BIT(9) @@ -133,6 +135,7 @@ enum dsi_ctrl_op_mode { #define DSI_VIDEO_TERM BIT(16) #define DSI_MDP_TERM BIT(8) +#define DSI_BTA_TERM BIT(1) #define DSI_CMD_TERM BIT(0) extern struct device dsi_dev; @@ -315,6 +318,7 @@ struct mdss_dsi_ctrl_pdata { int (*on) (struct mdss_panel_data *pdata); int (*off) (struct mdss_panel_data *pdata); int (*partial_update_fnc) (struct mdss_panel_data *pdata); + int (*check_status) (struct mdss_dsi_ctrl_pdata *pdata); struct mdss_panel_data panel_data; unsigned char *ctrl_base; int reg_size; @@ -362,6 +366,7 @@ struct mdss_dsi_ctrl_pdata { struct completion dma_comp; struct completion mdp_comp; struct completion video_comp; + struct completion bta_comp; spinlock_t irq_lock; spinlock_t mdp_lock; int mdp_busy; @@ -430,6 +435,7 @@ int mdss_dsi_cmdlist_put(struct mdss_dsi_ctrl_pdata *ctrl, struct dcs_cmd_req *cmdreq); struct dcs_cmd_req *mdss_dsi_cmdlist_get(struct mdss_dsi_ctrl_pdata *ctrl); void mdss_dsi_cmdlist_kickoff(int intf); +int mdss_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl); int mdss_dsi_panel_init(struct device_node *node, struct mdss_dsi_ctrl_pdata *ctrl_pdata, diff --git a/drivers/video/fbdev/msm/mdss_dsi_host.c b/drivers/video/fbdev/msm/mdss_dsi_host.c index 77dd4c44d299..058695c49705 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_host.c +++ b/drivers/video/fbdev/msm/mdss_dsi_host.c @@ -49,6 +49,8 @@ struct mdss_hw mdss_dsi1_hw = { #define DSI_EVENT_Q_MAX 4 +#define DSI_BTA_EVENT_TIMEOUT (HZ / 10) + /* event */ struct dsi_event_q { struct mdss_dsi_ctrl_pdata *ctrl; @@ -98,6 +100,7 @@ void mdss_dsi_ctrl_init(struct mdss_dsi_ctrl_pdata *ctrl) init_completion(&ctrl->dma_comp); init_completion(&ctrl->mdp_comp); init_completion(&ctrl->video_comp); + init_completion(&ctrl->bta_comp); spin_lock_init(&ctrl->irq_lock); spin_lock_init(&ctrl->mdp_lock); mutex_init(&ctrl->mutex); @@ -1107,14 +1110,14 @@ void mdss_dsi_op_mode_config(int mode, if (mode == DSI_VIDEO_MODE) { dsi_ctrl |= 0x03; - intr_ctrl = DSI_INTR_CMD_DMA_DONE_MASK; + intr_ctrl = DSI_INTR_CMD_DMA_DONE_MASK | DSI_INTR_BTA_DONE_MASK; } else { /* command mode */ dsi_ctrl |= 0x05; if (pdata->panel_info.type == MIPI_VIDEO_PANEL) dsi_ctrl |= 0x02; intr_ctrl = DSI_INTR_CMD_DMA_DONE_MASK | DSI_INTR_ERROR_MASK | - DSI_INTR_CMD_MDP_DONE_MASK; + DSI_INTR_CMD_MDP_DONE_MASK | DSI_INTR_BTA_DONE_MASK; } if (ctrl_pdata->shared_pdata.broadcast_enable) @@ -1160,6 +1163,45 @@ void mdss_dsi_cmd_bta_sw_trigger(struct mdss_panel_data *pdata) pr_debug("%s: BTA done, status = %d\n", __func__, status); } +int mdss_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl_pdata) +{ + int ret = 0; + unsigned long flag; + + if (ctrl_pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + + /* + * This should not return error otherwise + * BTA status thread will treat it as dead panel scenario + * and request for blank/unblank + */ + return 0; + } + + pr_debug("%s: Checking BTA status\n", __func__); + + mdss_dsi_clk_ctrl(ctrl_pdata, 1); + spin_lock_irqsave(&ctrl_pdata->mdp_lock, flag); + INIT_COMPLETION(ctrl_pdata->bta_comp); + mdss_dsi_enable_irq(ctrl_pdata, DSI_BTA_TERM); + spin_unlock_irqrestore(&ctrl_pdata->mdp_lock, flag); + MIPI_OUTP(ctrl_pdata->ctrl_base + 0x098, 0x01); /* trigger */ + wmb(); + + ret = wait_for_completion_killable_timeout(&ctrl_pdata->bta_comp, + DSI_BTA_EVENT_TIMEOUT); + if (ret <= 0) { + mdss_dsi_disable_irq(ctrl_pdata, DSI_BTA_TERM); + pr_err("%s: DSI BTA error: %i\n", __func__, ret); + } + + mdss_dsi_clk_ctrl(ctrl_pdata, 0); + pr_debug("%s: BTA done with ret: %d\n", __func__, ret); + + return ret; +} + static char set_tear_on[2] = {0x35, 0x00}; static struct dsi_cmd_desc dsi_tear_on_cmd = { {DTYPE_DCS_WRITE1, 1, 0, 0, 0, sizeof(set_tear_on)}, set_tear_on}; @@ -2079,5 +2121,12 @@ irqreturn_t mdss_dsi_isr(int irq, void *ptr) spin_unlock(&ctrl->mdp_lock); } + if (isr & DSI_INTR_BTA_DONE) { + spin_lock(&ctrl->mdp_lock); + mdss_dsi_disable_irq_nosync(ctrl, DSI_BTA_TERM); + complete(&ctrl->bta_comp); + spin_unlock(&ctrl->mdp_lock); + } + return IRQ_HANDLED; } diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c index f6c5074e87ec..2a3519e8f3df 100644 --- a/drivers/video/fbdev/msm/mdss_fb.c +++ b/drivers/video/fbdev/msm/mdss_fb.c @@ -709,8 +709,10 @@ static int mdss_fb_blank_sub(int blank_mode, struct fb_info *info, case FB_BLANK_UNBLANK: if (!mfd->panel_power_on && mfd->mdp.on_fnc) { ret = mfd->mdp.on_fnc(mfd); - if (ret == 0) + if (ret == 0) { mfd->panel_power_on = true; + mfd->panel_info->panel_dead = false; + } mutex_lock(&mfd->update.lock); mfd->update.type = NOTIFY_TYPE_UPDATE; mutex_unlock(&mfd->update.lock); diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c index 496206996638..c490862df453 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c @@ -509,6 +509,7 @@ int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg) int mdss_mdp_cmd_stop(struct mdss_mdp_ctl *ctl) { struct mdss_mdp_cmd_ctx *ctx; + struct mdss_panel_info *pinfo; unsigned long flags; struct mdss_mdp_vsync_handler *tmp, *handle; int need_wait = 0; @@ -532,9 +533,23 @@ int mdss_mdp_cmd_stop(struct mdss_mdp_ctl *ctl) if (need_wait) if (wait_for_completion_timeout(&ctx->stop_comp, STOP_TIMEOUT) - <= 0) + <= 0) { WARN(1, "stop cmd time out\n"); + if (IS_ERR_OR_NULL(ctl->panel_data)) { + pr_err("no panel data\n"); + } else { + pinfo = &ctl->panel_data->panel_info; + + if (pinfo->panel_dead) { + mdss_mdp_irq_disable + (MDSS_MDP_IRQ_PING_PONG_RD_PTR, + ctx->pp_num); + ctx->rdptr_enabled = 0; + } + } + } + if (cancel_work_sync(&ctx->clk_work)) pr_debug("no pending clk work\n"); diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h index 82411153bb86..30408f837979 100644 --- a/drivers/video/fbdev/msm/mdss_panel.h +++ b/drivers/video/fbdev/msm/mdss_panel.h @@ -314,6 +314,8 @@ struct mdss_panel_info { struct ion_handle *splash_ihdl; u32 panel_power_on; + uint32_t panel_dead; + struct mdss_mdp_pp_tear_check te; struct lcd_panel_info lcdc; -- cgit v1.2.3