diff --git a/msm/dsi/dsi_ctrl.c b/msm/dsi/dsi_ctrl.c index fb20770728..8abff6e169 100644 --- a/msm/dsi/dsi_ctrl.c +++ b/msm/dsi/dsi_ctrl.c @@ -448,10 +448,8 @@ static void dsi_ctrl_post_cmd_transfer(struct dsi_ctrl *dsi_ctrl) if (rc) DSI_CTRL_ERR(dsi_ctrl, "failed to disable command engine\n"); - if (dsi_ctrl->pending_cmd_flags & DSI_CTRL_CMD_READ) - mask |= BIT(DSI_FIFO_UNDERFLOW); - - dsi_ctrl_mask_error_status_interrupts(dsi_ctrl, mask, false); + if (!(dsi_ctrl->pending_cmd_flags & DSI_CTRL_CMD_READ)) + dsi_ctrl_mask_error_status_interrupts(dsi_ctrl, mask, false); mutex_unlock(&dsi_ctrl->ctrl_lock); @@ -1909,16 +1907,18 @@ static int dsi_disable_ulps(struct dsi_ctrl *dsi_ctrl) return rc; } -static void dsi_ctrl_enable_error_interrupts(struct dsi_ctrl *dsi_ctrl) +void dsi_ctrl_toggle_error_interrupt_status(struct dsi_ctrl *dsi_ctrl, bool enable) { - if (dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE && - !dsi_ctrl->host_config.u.video_engine.bllp_lp11_en && - !dsi_ctrl->host_config.u.video_engine.eof_bllp_lp11_en) - dsi_ctrl->hw.ops.enable_error_interrupts(&dsi_ctrl->hw, - 0xFF00A0); - else - dsi_ctrl->hw.ops.enable_error_interrupts(&dsi_ctrl->hw, - 0xFF00E0); + if (!enable) { + dsi_ctrl->hw.ops.enable_error_interrupts(&dsi_ctrl->hw, 0); + } else { + if (dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE && + !dsi_ctrl->host_config.u.video_engine.bllp_lp11_en && + !dsi_ctrl->host_config.u.video_engine.eof_bllp_lp11_en) + dsi_ctrl->hw.ops.enable_error_interrupts(&dsi_ctrl->hw, 0xFF00A0); + else + dsi_ctrl->hw.ops.enable_error_interrupts(&dsi_ctrl->hw, 0xFF00E0); + } } static int dsi_ctrl_drv_state_init(struct dsi_ctrl *dsi_ctrl) @@ -2597,7 +2597,7 @@ int dsi_ctrl_setup(struct dsi_ctrl *dsi_ctrl) &dsi_ctrl->host_config.common_config); dsi_ctrl->hw.ops.enable_status_interrupts(&dsi_ctrl->hw, 0x0); - dsi_ctrl_enable_error_interrupts(dsi_ctrl); + dsi_ctrl_toggle_error_interrupt_status(dsi_ctrl, true); dsi_ctrl->hw.ops.ctrl_en(&dsi_ctrl->hw, true); @@ -3131,7 +3131,7 @@ int dsi_ctrl_host_init(struct dsi_ctrl *dsi_ctrl, bool skip_op) } dsi_ctrl->hw.ops.enable_status_interrupts(&dsi_ctrl->hw, 0x0); - dsi_ctrl_enable_error_interrupts(dsi_ctrl); + dsi_ctrl_toggle_error_interrupt_status(dsi_ctrl, true); DSI_CTRL_DEBUG(dsi_ctrl, "Host initialization complete, skip op: %d\n", skip_op); @@ -3417,10 +3417,8 @@ int dsi_ctrl_transfer_prepare(struct dsi_ctrl *dsi_ctrl, u32 flags) mutex_lock(&dsi_ctrl->ctrl_lock); - if (flags & DSI_CTRL_CMD_READ) - mask |= BIT(DSI_FIFO_UNDERFLOW); - - dsi_ctrl_mask_error_status_interrupts(dsi_ctrl, mask, true); + if (!(flags & DSI_CTRL_CMD_READ)) + dsi_ctrl_mask_error_status_interrupts(dsi_ctrl, mask, true); rc = dsi_ctrl_set_cmd_engine_state(dsi_ctrl, DSI_CTRL_ENGINE_ON, false); if (rc) { diff --git a/msm/dsi/dsi_ctrl.h b/msm/dsi/dsi_ctrl.h index f0ef3167bb..b1a5a90081 100644 --- a/msm/dsi/dsi_ctrl.h +++ b/msm/dsi/dsi_ctrl.h @@ -920,4 +920,8 @@ int dsi_ctrl_wait4dynamic_refresh_done(struct dsi_ctrl *ctrl); */ int dsi_ctrl_get_io_resources(struct msm_io_res *io_res); +/** + * dsi_ctrl_toggle_error_interrupt_status() - Toggles error interrupt status + */ +void dsi_ctrl_toggle_error_interrupt_status(struct dsi_ctrl *dsi_ctrl, bool enable); #endif /* _DSI_CTRL_H_ */ diff --git a/msm/dsi/dsi_ctrl_hw_cmn.c b/msm/dsi/dsi_ctrl_hw_cmn.c index 6534bff6c1..b4589ce770 100644 --- a/msm/dsi/dsi_ctrl_hw_cmn.c +++ b/msm/dsi/dsi_ctrl_hw_cmn.c @@ -1411,6 +1411,22 @@ void dsi_ctrl_hw_cmn_enable_error_interrupts(struct dsi_ctrl_hw *ctrl, { u32 int_ctrl = 0; u32 int_mask0 = 0x7FFF3BFF; + u32 dln0_phy_err = 0x11111; + u32 fifo_status = 0xCCCC0789; + u32 ack_error = 0x1193BFFF; + u32 timeout_status = 0x11111111; + u32 clk_status = 0x10000; + u32 dsi_status_error = 0x80000000; + u32 reg = 0; + + DSI_W32(ctrl, DSI_DLN0_PHY_ERR, dln0_phy_err); + DSI_W32(ctrl, DSI_FIFO_STATUS, fifo_status); + DSI_W32(ctrl, DSI_TIMEOUT_STATUS, timeout_status); + DSI_W32(ctrl, DSI_ACK_ERR_STATUS, ack_error); + reg = DSI_R32(ctrl, DSI_CLK_STATUS); + DSI_W32(ctrl, DSI_CLK_STATUS, reg | clk_status); + reg = DSI_R32(ctrl, DSI_STATUS); + DSI_W32(ctrl, DSI_STATUS, reg | dsi_status_error); int_ctrl = DSI_R32(ctrl, DSI_INT_CTRL); if (errors) diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index 16b22d48f3..fe9b9317cb 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -921,6 +921,19 @@ static int dsi_display_status_check_te(struct dsi_display *display, return rc; } +void dsi_display_toggle_error_interrupt_status(struct dsi_display * display, bool enable) +{ + int i = 0; + struct dsi_display_ctrl *ctrl; + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl) + continue; + dsi_ctrl_toggle_error_interrupt_status(ctrl->ctrl, enable); + } +} + int dsi_display_check_status(struct drm_connector *connector, void *display, bool te_check_override) { @@ -966,6 +979,11 @@ int dsi_display_check_status(struct drm_connector *connector, void *display, dsi_display_set_ctrl_esd_check_flag(dsi_display, true); + dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, DSI_ALL_CLKS, DSI_CLK_ON); + + /* Disable error interrupts while doing an ESD check */ + dsi_display_toggle_error_interrupt_status(dsi_display, false); + if (status_mode == ESD_MODE_REG_READ) { rc = dsi_display_status_reg_read(dsi_display); } else if (status_mode == ESD_MODE_SW_BTA) { @@ -990,7 +1008,11 @@ int dsi_display_check_status(struct drm_connector *connector, void *display, /* Handle Panel failures during display disable sequence */ if (rc <=0) atomic_set(&panel->esd_recovery_pending, 1); + else + /* Enable error interrupts post an ESD success */ + dsi_display_toggle_error_interrupt_status(dsi_display, true); + dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, DSI_ALL_CLKS, DSI_CLK_OFF); release_panel_lock: dsi_panel_release_panel_lock(panel); SDE_EVT32(SDE_EVTLOG_FUNC_EXIT, rc); @@ -1040,18 +1062,23 @@ static int dsi_display_cmd_rx(struct dsi_display *display, flags = DSI_CTRL_CMD_READ; + dsi_display_clk_ctrl(display->dsi_clk_handle, DSI_ALL_CLKS, DSI_CLK_ON); + dsi_display_toggle_error_interrupt_status(display, false); cmd->ctrl_flags = flags; dsi_display_set_cmd_tx_ctrl_flags(display, cmd); rc = dsi_ctrl_transfer_prepare(m_ctrl->ctrl, cmd->ctrl_flags); if (rc) { DSI_ERR("prepare for rx cmd transfer failed rc = %d\n", rc); - goto release_panel_lock; + goto enable_error_interrupts; } rc = dsi_ctrl_cmd_transfer(m_ctrl->ctrl, cmd); if (rc <= 0) DSI_ERR("rx cmd transfer failed rc = %d\n", rc); dsi_ctrl_transfer_unprepare(m_ctrl->ctrl, cmd->ctrl_flags); +enable_error_interrupts: + dsi_display_toggle_error_interrupt_status(display, true); + dsi_display_clk_ctrl(display->dsi_clk_handle, DSI_ALL_CLKS, DSI_CLK_OFF); release_panel_lock: dsi_panel_release_panel_lock(display->panel); return rc; @@ -3573,6 +3600,21 @@ static void dsi_display_ctrl_isr_configure(struct dsi_display *display, bool en) } } +static void dsi_display_cleanup_post_esd_failure(struct dsi_display *display) +{ + int i = 0; + struct dsi_display_ctrl *ctrl; + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl) + continue; + + dsi_phy_lane_reset(ctrl->phy); + dsi_ctrl_soft_reset(ctrl->ctrl); + } +} + int dsi_pre_clkoff_cb(void *priv, enum dsi_clk_type clk, enum dsi_lclk_type l_type, @@ -3584,6 +3626,14 @@ int dsi_pre_clkoff_cb(void *priv, if ((clk & DSI_LINK_CLK) && (new_state == DSI_CLK_OFF) && (l_type & DSI_LINK_LP_CLK)) { + + /* + * Clean up the DSI controller on a previous ESD failure. This requires a DSI + * controller soft reset. Also reset PHY lanes before resetting controller. + */ + if (atomic_read(&display->panel->esd_recovery_pending)) + dsi_display_cleanup_post_esd_failure(display); + /* * If continuous clock is enabled then disable it * before entering into ULPS Mode. @@ -3777,6 +3827,13 @@ int dsi_post_clkoff_cb(void *priv, return -EINVAL; } + /* Reset PHY to clear the PHY status once the HS clocks are turned off */ + if ((clk_type & DSI_LINK_CLK) && (curr_state == DSI_CLK_OFF) + && (l_type == DSI_LINK_HS_CLK)) { + if (atomic_read(&display->panel->esd_recovery_pending)) + dsi_display_phy_sw_reset(display); + } + if ((clk_type & DSI_CORE_CLK) && (curr_state == DSI_CLK_OFF)) { rc = dsi_display_phy_power_off(display);