msm: mdss: dsi: ensure lanes are idle prior to ULPS entry
It is possible that the ULPS entry request can potentially overlap with the last DCS command that was sent out on the link. This is more likely if the DCS command was sent in LP mode. In such cases, the panel could see some issues in the LP transmission which may trigger an error when a BTA is done subsequently. To address this, ensure that the lanes are idle by checking that all active FIFOs are empty and the all active data lanes are in stop state. CRs-Fixed: 961817 Change-Id: Ia2575f06762f6bc847f64fb70e96a275712d9135 Signed-off-by: Aravind Venkateswaran <aravindh@codeaurora.org>
This commit is contained in:
parent
039af32693
commit
5bcd9e74b2
3 changed files with 91 additions and 0 deletions
|
@ -560,6 +560,7 @@ void mdss_dsi_clk_req(struct mdss_dsi_ctrl_pdata *ctrl,
|
|||
void mdss_dsi_controller_cfg(int enable,
|
||||
struct mdss_panel_data *pdata);
|
||||
void mdss_dsi_sw_reset(struct mdss_dsi_ctrl_pdata *ctrl_pdata, bool restore);
|
||||
int mdss_dsi_wait_for_lane_idle(struct mdss_dsi_ctrl_pdata *ctrl);
|
||||
|
||||
irqreturn_t mdss_dsi_isr(int irq, void *ptr);
|
||||
irqreturn_t hw_vsync_handler(int irq, void *data);
|
||||
|
|
|
@ -34,6 +34,9 @@
|
|||
#define DMA_TX_TIMEOUT 200
|
||||
#define DMA_TPG_FIFO_LEN 64
|
||||
|
||||
#define FIFO_STATUS 0x0C
|
||||
#define LANE_STATUS 0xA8
|
||||
|
||||
struct mdss_dsi_ctrl_pdata *ctrl_list[DSI_CTRL_MAX];
|
||||
|
||||
struct mdss_hw mdss_dsi0_hw = {
|
||||
|
@ -517,6 +520,73 @@ void mdss_dsi_sw_reset(struct mdss_dsi_ctrl_pdata *ctrl, bool restore)
|
|||
spin_unlock_irqrestore(&ctrl->mdp_lock, flag);
|
||||
}
|
||||
|
||||
/**
|
||||
* mdss_dsi_wait_for_lane_idle() - Wait for DSI lanes to be idle
|
||||
* @ctrl: pointer to DSI controller structure
|
||||
*
|
||||
* This function waits for all the active DSI lanes to be idle by polling all
|
||||
* the *FIFO_EMPTY bits and polling the lane status to ensure that all the lanes
|
||||
* are in stop state. This function assumes that the bus clocks required to
|
||||
* access the registers are already turned on.
|
||||
*/
|
||||
int mdss_dsi_wait_for_lane_idle(struct mdss_dsi_ctrl_pdata *ctrl)
|
||||
{
|
||||
int rc;
|
||||
u32 val;
|
||||
u32 fifo_empty_mask = 0;
|
||||
u32 stop_state_mask = 0;
|
||||
struct mipi_panel_info *mipi;
|
||||
u32 const sleep_us = 10;
|
||||
u32 const timeout_us = 100;
|
||||
|
||||
if (!ctrl) {
|
||||
pr_err("%s: invalid input\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mipi = &ctrl->panel_data.panel_info.mipi;
|
||||
|
||||
if (mipi->data_lane0) {
|
||||
stop_state_mask |= BIT(0);
|
||||
fifo_empty_mask |= (BIT(12) | BIT(16));
|
||||
}
|
||||
if (mipi->data_lane1) {
|
||||
stop_state_mask |= BIT(1);
|
||||
fifo_empty_mask |= BIT(20);
|
||||
}
|
||||
if (mipi->data_lane2) {
|
||||
stop_state_mask |= BIT(2);
|
||||
fifo_empty_mask |= BIT(24);
|
||||
}
|
||||
if (mipi->data_lane3) {
|
||||
stop_state_mask |= BIT(3);
|
||||
fifo_empty_mask |= BIT(28);
|
||||
}
|
||||
|
||||
pr_debug("%s: polling for fifo empty, mask=0x%08x\n", __func__,
|
||||
fifo_empty_mask);
|
||||
rc = readl_poll_timeout(ctrl->ctrl_base + FIFO_STATUS, val,
|
||||
(val & fifo_empty_mask), sleep_us, timeout_us);
|
||||
if (rc) {
|
||||
pr_err("%s: fifo not empty, FIFO_STATUS=0x%08x\n",
|
||||
__func__, val);
|
||||
goto error;
|
||||
}
|
||||
|
||||
pr_debug("%s: polling for lanes to be in stop state, mask=0x%08x\n",
|
||||
__func__, stop_state_mask);
|
||||
rc = readl_poll_timeout(ctrl->ctrl_base + LANE_STATUS, val,
|
||||
(val & stop_state_mask), sleep_us, timeout_us);
|
||||
if (rc) {
|
||||
pr_err("%s: lanes not in stop state, LANE_STATUS=0x%08x\n",
|
||||
__func__, val);
|
||||
goto error;
|
||||
}
|
||||
|
||||
error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void mdss_dsi_cfg_lane_ctrl(struct mdss_dsi_ctrl_pdata *ctrl,
|
||||
u32 bits, int set)
|
||||
{
|
||||
|
|
|
@ -1621,6 +1621,26 @@ static int mdss_dsi_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl,
|
|||
active_lanes, ctrl->mmss_clamp ? "enabled" : "disabled");
|
||||
|
||||
if (enable && !ctrl->ulps) {
|
||||
/*
|
||||
* Ensure that the lanes are idle prior to placing a ULPS entry
|
||||
* request. This is needed to ensure that there is no overlap
|
||||
* between any HS or LP commands being sent out on the lane and
|
||||
* a potential ULPS entry request.
|
||||
*
|
||||
* This check needs to be avoided when we are resuming from idle
|
||||
* power collapse and just restoring the controller state to
|
||||
* ULPS with the clamps still in place.
|
||||
*/
|
||||
if (!ctrl->mmss_clamp) {
|
||||
ret = mdss_dsi_wait_for_lane_idle(ctrl);
|
||||
if (ret) {
|
||||
pr_warn("%s: lanes not idle, skip ulps\n",
|
||||
__func__);
|
||||
ret = 0;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ULPS Entry Request.
|
||||
* Wait for a short duration to ensure that the lanes
|
||||
|
|
Loading…
Add table
Reference in a new issue