summaryrefslogtreecommitdiff
path: root/drivers/video/fbdev
diff options
context:
space:
mode:
authorPadmanabhan Komanduru <pkomandu@codeaurora.org>2015-03-31 18:34:16 +0530
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-23 20:44:19 -0700
commit1fae88febd6504b2a6a6701182663cc41df22bfa (patch)
tree3641259e21252f464674fef7ff3aa997c863effd /drivers/video/fbdev
parent44d78c021c2f457d7096c002bcef3cce295f7bb0 (diff)
msm: mdss: add support for handling LP_RX_TIMEOUT error
During ESD attack, sometimes the panel DDIC might not respond to the ESD read command. This causes the data lane0 to get stuck in reverse transmission causing DSI HS FIFO overflow errors continuously in forward transmission. Enable the error interrupt generation for LP_RX_TIMEOUT to handle this. Reset the DSI controller and force DSI lanes to LP-11 to recover from this situation. Crs-Fixed: 863383 Change-Id: Iee7d5e0c85fb77b9c8f899e569e37b54a100f67a Signed-off-by: Padmanabhan Komanduru <pkomandu@codeaurora.org> Signed-off-by: Sandeep Panda <spanda@codeaurora.org> Signed-off-by: Siddhartha Agrawal <agrawals@codeaurora.org> Signed-off-by: Vinu Deokaran <vinud@codeaurora.org>
Diffstat (limited to 'drivers/video/fbdev')
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.h2
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi_host.c42
2 files changed, 33 insertions, 11 deletions
diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h
index a9367763baba..b73776e2b040 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.h
+++ b/drivers/video/fbdev/msm/mdss_dsi.h
@@ -195,6 +195,7 @@ enum dsi_pm_type {
#define DSI_DATA_LANES_STOP_STATE 0xF
#define DSI_CLK_LANE_STOP_STATE BIT(4)
+#define DSI_DATA_LANES_ENABLED 0xF0
/* offsets for dynamic refresh */
#define DSI_DYNAMIC_REFRESH_CTRL 0x200
@@ -333,6 +334,7 @@ struct panel_horizontal_idle {
#define DSI_EV_MDP_FIFO_UNDERFLOW 0x0002
#define DSI_EV_DSI_FIFO_EMPTY 0x0004
#define DSI_EV_DLNx_FIFO_OVERFLOW 0x0008
+#define DSI_EV_LP_RX_TIMEOUT 0x0010
#define DSI_EV_STOP_HS_CLK_LANE 0x40000000
#define DSI_EV_MDP_BUSY_RELEASE 0x80000000
diff --git a/drivers/video/fbdev/msm/mdss_dsi_host.c b/drivers/video/fbdev/msm/mdss_dsi_host.c
index 839fd3056e28..c0541c7c22ae 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_host.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_host.c
@@ -389,7 +389,7 @@ void mdss_dsi_host_init(struct mdss_panel_data *pdata)
/* allow only ack-err-status to generate interrupt */
/* DSI_ERR_INT_MASK0 */
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x010c, 0x03f03fe0);
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x010c, 0x03f03fc0);
intr_ctrl |= DSI_INTR_ERROR_MASK;
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0110,
@@ -632,9 +632,9 @@ static void mdss_dsi_cmd_stop_hs_clk_lane(struct mdss_dsi_ctrl_pdata *ctrl)
mdss_dsi_stop_hs_clk_lane(ctrl);
}
-static void mdss_dsi_ctl_phy_reset(struct mdss_dsi_ctrl_pdata *ctrl)
+static void mdss_dsi_ctl_phy_reset(struct mdss_dsi_ctrl_pdata *ctrl, u32 event)
{
- u32 data0, data1;
+ u32 data0, data1, mask = 0, data_lane_en = 0;
struct mdss_dsi_ctrl_pdata *ctrl0, *ctrl1;
u32 ln0, ln1, ln_ctrl0, ln_ctrl1, i;
/*
@@ -644,6 +644,14 @@ static void mdss_dsi_ctl_phy_reset(struct mdss_dsi_ctrl_pdata *ctrl)
u32 loop = 10, u_dly = 200;
pr_debug("%s: MDSS DSI CTRL and PHY reset. ctrl-num = %d\n",
__func__, ctrl->ndx);
+ if (event == DSI_EV_DLNx_FIFO_OVERFLOW) {
+ mask = BIT(20); /* clock lane only for overflow recovery */
+ } else if (event == DSI_EV_LP_RX_TIMEOUT) {
+ data_lane_en = (MIPI_INP(ctrl->ctrl_base + 0x0004) &
+ DSI_DATA_LANES_ENABLED) >> 4;
+ /* clock and data lanes for LP_RX_TO recovery */
+ mask = BIT(20) | (data_lane_en << 16);
+ }
if (mdss_dsi_is_hw_config_split(ctrl->shared_data)) {
pr_debug("%s: Split display enabled\n", __func__);
@@ -700,8 +708,8 @@ static void mdss_dsi_ctl_phy_reset(struct mdss_dsi_ctrl_pdata *ctrl)
__func__, ln0, ln1);
ln_ctrl0 = MIPI_INP(ctrl0->ctrl_base + 0x00ac);
ln_ctrl1 = MIPI_INP(ctrl1->ctrl_base + 0x00ac);
- MIPI_OUTP(ctrl0->ctrl_base + 0x0ac, ln_ctrl0 | BIT(20));
- MIPI_OUTP(ctrl1->ctrl_base + 0x0ac, ln_ctrl1 | BIT(20));
+ MIPI_OUTP(ctrl0->ctrl_base + 0x0ac, ln_ctrl0 | mask);
+ MIPI_OUTP(ctrl1->ctrl_base + 0x0ac, ln_ctrl1 | mask);
ln_ctrl0 = MIPI_INP(ctrl0->ctrl_base + 0x00ac);
ln_ctrl1 = MIPI_INP(ctrl1->ctrl_base + 0x00ac);
for (i = 0; i < loop; i++) {
@@ -722,8 +730,8 @@ static void mdss_dsi_ctl_phy_reset(struct mdss_dsi_ctrl_pdata *ctrl)
}
pr_debug("%s: lane ctrl, ctrl0 = 0x%x, ctrl1 = 0x%x\n",
__func__, ln0, ln1);
- MIPI_OUTP(ctrl0->ctrl_base + 0x0ac, ln_ctrl0 & ~BIT(20));
- MIPI_OUTP(ctrl1->ctrl_base + 0x0ac, ln_ctrl1 & ~BIT(20));
+ MIPI_OUTP(ctrl0->ctrl_base + 0x0ac, ln_ctrl0 & ~mask);
+ MIPI_OUTP(ctrl1->ctrl_base + 0x0ac, ln_ctrl1 & ~mask);
/* Enable Video mode for DSI controller */
MIPI_OUTP(ctrl0->ctrl_base + 0x004, data0);
@@ -775,7 +783,7 @@ static void mdss_dsi_ctl_phy_reset(struct mdss_dsi_ctrl_pdata *ctrl)
pr_debug("%s: lane status, ctrl = 0x%x\n",
__func__, ln0);
ln_ctrl0 = MIPI_INP(ctrl->ctrl_base + 0x00ac);
- MIPI_OUTP(ctrl->ctrl_base + 0x0ac, ln_ctrl0 | BIT(20));
+ MIPI_OUTP(ctrl->ctrl_base + 0x0ac, ln_ctrl0 | mask);
ln_ctrl0 = MIPI_INP(ctrl->ctrl_base + 0x00ac);
for (i = 0; i < loop; i++) {
ln0 = MIPI_INP(ctrl->ctrl_base + 0x00a8);
@@ -793,7 +801,7 @@ static void mdss_dsi_ctl_phy_reset(struct mdss_dsi_ctrl_pdata *ctrl)
}
pr_debug("%s: lane status = 0x%x\n",
__func__, ln0);
- MIPI_OUTP(ctrl->ctrl_base + 0x0ac, ln_ctrl0 & ~BIT(20));
+ MIPI_OUTP(ctrl->ctrl_base + 0x0ac, ln_ctrl0 & ~mask);
/* Enable Video mode for DSI controller */
MIPI_OUTP(ctrl->ctrl_base + 0x004, data0);
@@ -2326,7 +2334,8 @@ static int dsi_event_thread(void *data)
mdss_dsi_clk_ctrl(ctrl, ctrl->dsi_clk_handle,
MDSS_DSI_ALL_CLKS,
MDSS_DSI_CLK_ON);
- mdss_dsi_ctl_phy_reset(ctrl);
+ mdss_dsi_ctl_phy_reset(ctrl,
+ DSI_EV_DLNx_FIFO_OVERFLOW);
mdss_dsi_err_intr_ctrl(ctrl,
DSI_INTR_ERROR_MASK, 1);
mdss_dsi_clk_ctrl(ctrl, ctrl->dsi_clk_handle,
@@ -2340,7 +2349,8 @@ static int dsi_event_thread(void *data)
mdss_dsi_clk_ctrl(ctrl, ctrl->dsi_clk_handle,
MDSS_DSI_ALL_CLKS,
MDSS_DSI_CLK_ON);
- mdss_dsi_ctl_phy_reset(ctrl);
+ mdss_dsi_ctl_phy_reset(ctrl,
+ DSI_EV_DLNx_FIFO_OVERFLOW);
mdss_dsi_err_intr_ctrl(ctrl,
DSI_INTR_ERROR_MASK, 1);
mdss_dsi_clk_ctrl(ctrl, ctrl->dsi_clk_handle,
@@ -2369,6 +2379,14 @@ static int dsi_event_thread(void *data)
if (todo & DSI_EV_STOP_HS_CLK_LANE)
mdss_dsi_stop_hs_clk_lane(ctrl);
+
+ if (todo & DSI_EV_LP_RX_TIMEOUT) {
+ mdss_dsi_clk_ctrl(ctrl, ctrl->dsi_clk_handle,
+ MDSS_DSI_ALL_CLKS, MDSS_DSI_CLK_ON);
+ mdss_dsi_ctl_phy_reset(ctrl, DSI_EV_LP_RX_TIMEOUT);
+ mdss_dsi_clk_ctrl(ctrl, ctrl->dsi_clk_handle,
+ MDSS_DSI_ALL_CLKS, MDSS_DSI_CLK_OFF);
+ }
}
return 0;
@@ -2412,6 +2430,8 @@ void mdss_dsi_timeout_status(struct mdss_dsi_ctrl_pdata *ctrl)
if (status & 0x0111) {
MIPI_OUTP(base + 0x00c0, status);
+ if (status & 0x0010)
+ dsi_send_events(ctrl, DSI_EV_LP_RX_TIMEOUT, 0);
pr_err("%s: status=%x\n", __func__, status);
}
}