diff --git a/msm/dsi/dsi_ctrl.c b/msm/dsi/dsi_ctrl.c index bc7c0ef0..81eeaca1 100644 --- a/msm/dsi/dsi_ctrl.c +++ b/msm/dsi/dsi_ctrl.c @@ -18,6 +18,7 @@ #include "dsi_clk.h" #include "dsi_pwr.h" #include "dsi_catalog.h" +#include "dsi_panel.h" #include "sde_dbg.h" @@ -1268,9 +1269,9 @@ static void dsi_kickoff_msg_tx(struct dsi_ctrl *dsi_ctrl, } } -static u32 dsi_ctrl_validate_msg_flags(struct dsi_ctrl *dsi_ctrl, +static void dsi_ctrl_validate_msg_flags(struct dsi_ctrl *dsi_ctrl, const struct mipi_dsi_msg *msg, - u32 flags) + u32 *flags) { /* * ASYNC command wait mode is not supported for @@ -1280,20 +1281,20 @@ static u32 dsi_ctrl_validate_msg_flags(struct dsi_ctrl *dsi_ctrl, * - whenever an explicit wait time is specificed for the command * since the wait time cannot be guaranteed in async mode * - video mode panels + * If async override is set, skip async flag reset */ - if ((flags & DSI_CTRL_CMD_FIFO_STORE) || - flags & DSI_CTRL_CMD_READ || - flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE || + if (((*flags & DSI_CTRL_CMD_FIFO_STORE) || + *flags & DSI_CTRL_CMD_READ || + *flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE || msg->wait_ms || - (dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE)) - flags &= ~DSI_CTRL_CMD_ASYNC_WAIT; - - return flags; + (dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE)) && + !(msg->flags & MIPI_DSI_MSG_ASYNC_OVERRIDE)) + *flags &= ~DSI_CTRL_CMD_ASYNC_WAIT; } static int dsi_message_tx(struct dsi_ctrl *dsi_ctrl, const struct mipi_dsi_msg *msg, - u32 flags) + u32 *flags) { int rc = 0; struct mipi_dsi_packet packet; @@ -1305,10 +1306,10 @@ static int dsi_message_tx(struct dsi_ctrl *dsi_ctrl, u8 *cmdbuf; /* Select the tx mode to transfer the command */ - dsi_message_setup_tx_mode(dsi_ctrl, msg->tx_len, &flags); + dsi_message_setup_tx_mode(dsi_ctrl, msg->tx_len, flags); /* Validate the mode before sending the command */ - rc = dsi_message_validate_tx_mode(dsi_ctrl, msg->tx_len, &flags); + rc = dsi_message_validate_tx_mode(dsi_ctrl, msg->tx_len, flags); if (rc) { DSI_CTRL_ERR(dsi_ctrl, "Cmd tx validation failed, cannot transfer cmd\n"); @@ -1316,16 +1317,16 @@ static int dsi_message_tx(struct dsi_ctrl *dsi_ctrl, goto error; } - flags = dsi_ctrl_validate_msg_flags(dsi_ctrl, msg, flags); + dsi_ctrl_validate_msg_flags(dsi_ctrl, msg, flags); if (dsi_ctrl->dma_wait_queued) dsi_ctrl_flush_cmd_dma_queue(dsi_ctrl); - if (flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE) { + if (*flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE) { cmd_mem.offset = dsi_ctrl->cmd_buffer_iova; - cmd_mem.en_broadcast = (flags & DSI_CTRL_CMD_BROADCAST) ? + cmd_mem.en_broadcast = (*flags & DSI_CTRL_CMD_BROADCAST) ? true : false; - cmd_mem.is_master = (flags & DSI_CTRL_CMD_BROADCAST_MASTER) ? + cmd_mem.is_master = (*flags & DSI_CTRL_CMD_BROADCAST_MASTER) ? true : false; cmd_mem.use_lpm = (msg->flags & MIPI_DSI_MSG_USE_LPM) ? true : false; @@ -1360,12 +1361,12 @@ static int dsi_message_tx(struct dsi_ctrl *dsi_ctrl, if ((msg->flags & MIPI_DSI_MSG_LASTCOMMAND)) buffer[3] |= BIT(7);//set the last cmd bit in header. - if (flags & DSI_CTRL_CMD_FETCH_MEMORY) { + if (*flags & DSI_CTRL_CMD_FETCH_MEMORY) { /* Embedded mode config is selected */ cmd_mem.offset = dsi_ctrl->cmd_buffer_iova; - cmd_mem.en_broadcast = (flags & DSI_CTRL_CMD_BROADCAST) ? + cmd_mem.en_broadcast = (*flags & DSI_CTRL_CMD_BROADCAST) ? true : false; - cmd_mem.is_master = (flags & DSI_CTRL_CMD_BROADCAST_MASTER) ? + cmd_mem.is_master = (*flags & DSI_CTRL_CMD_BROADCAST_MASTER) ? true : false; cmd_mem.use_lpm = (msg->flags & MIPI_DSI_MSG_USE_LPM) ? true : false; @@ -1385,19 +1386,19 @@ static int dsi_message_tx(struct dsi_ctrl *dsi_ctrl, dsi_ctrl->cmd_len = 0; } - } else if (flags & DSI_CTRL_CMD_FIFO_STORE) { + } else if (*flags & DSI_CTRL_CMD_FIFO_STORE) { cmd.command = (u32 *)buffer; cmd.size = length; - cmd.en_broadcast = (flags & DSI_CTRL_CMD_BROADCAST) ? + cmd.en_broadcast = (*flags & DSI_CTRL_CMD_BROADCAST) ? true : false; - cmd.is_master = (flags & DSI_CTRL_CMD_BROADCAST_MASTER) ? + cmd.is_master = (*flags & DSI_CTRL_CMD_BROADCAST_MASTER) ? true : false; cmd.use_lpm = (msg->flags & MIPI_DSI_MSG_USE_LPM) ? true : false; } kickoff: - dsi_kickoff_msg_tx(dsi_ctrl, msg, &cmd, &cmd_mem, flags); + dsi_kickoff_msg_tx(dsi_ctrl, msg, &cmd, &cmd_mem, *flags); error: if (buffer) devm_kfree(&dsi_ctrl->pdev->dev, buffer); @@ -1425,7 +1426,7 @@ static int dsi_set_max_return_size(struct dsi_ctrl *dsi_ctrl, dflags &= ~BIT(3); msg.flags = dflags; - rc = dsi_message_tx(dsi_ctrl, &msg, flags); + rc = dsi_message_tx(dsi_ctrl, &msg, &flags); if (rc) DSI_CTRL_ERR(dsi_ctrl, "failed to send max return size packet, rc=%d\n", rc); @@ -1487,7 +1488,7 @@ static int dsi_parse_long_read_resp(const struct mipi_dsi_msg *msg, static int dsi_message_rx(struct dsi_ctrl *dsi_ctrl, const struct mipi_dsi_msg *msg, - u32 flags) + u32 *flags) { int rc = 0; u32 rd_pkt_size, total_read_len, hw_read_cnt; @@ -2691,8 +2692,7 @@ void dsi_ctrl_disable_status_interrupt(struct dsi_ctrl *dsi_ctrl, { unsigned long flags; - if (!dsi_ctrl || dsi_ctrl->irq_info.irq_num == -1 || - intr_idx >= DSI_STATUS_INTERRUPT_COUNT) + if (!dsi_ctrl || intr_idx >= DSI_STATUS_INTERRUPT_COUNT) return; SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_ENTRY); @@ -2705,7 +2705,8 @@ void dsi_ctrl_disable_status_interrupt(struct dsi_ctrl *dsi_ctrl, dsi_ctrl->irq_info.irq_stat_mask); /* don't need irq if no lines are enabled */ - if (dsi_ctrl->irq_info.irq_stat_mask == 0) + if (dsi_ctrl->irq_info.irq_stat_mask == 0 && + dsi_ctrl->irq_info.irq_num != -1) disable_irq_nosync(dsi_ctrl->irq_info.irq_num); } @@ -3088,7 +3089,7 @@ int dsi_ctrl_validate_timing(struct dsi_ctrl *dsi_ctrl, */ int dsi_ctrl_cmd_transfer(struct dsi_ctrl *dsi_ctrl, const struct mipi_dsi_msg *msg, - u32 flags) + u32 *flags) { int rc = 0; @@ -3106,7 +3107,7 @@ int dsi_ctrl_cmd_transfer(struct dsi_ctrl *dsi_ctrl, goto error; } - if (flags & DSI_CTRL_CMD_READ) { + if (*flags & DSI_CTRL_CMD_READ) { rc = dsi_message_rx(dsi_ctrl, msg, flags); if (rc <= 0) DSI_CTRL_ERR(dsi_ctrl, "read message failed read length, rc=%d\n", diff --git a/msm/dsi/dsi_ctrl.h b/msm/dsi/dsi_ctrl.h index 2b731816..23fd9e66 100644 --- a/msm/dsi/dsi_ctrl.h +++ b/msm/dsi/dsi_ctrl.h @@ -554,7 +554,7 @@ int dsi_ctrl_set_tpg_state(struct dsi_ctrl *dsi_ctrl, bool on); */ int dsi_ctrl_cmd_transfer(struct dsi_ctrl *dsi_ctrl, const struct mipi_dsi_msg *msg, - u32 flags); + u32 *flags); /** * dsi_ctrl_cmd_tx_trigger() - Trigger a deferred command. diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index 28f0d7d3..0546d336 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -660,7 +660,7 @@ static int dsi_display_read_status(struct dsi_display_ctrl *ctrl, cmds[i].msg.flags |= MIPI_DSI_MSG_USE_LPM; cmds[i].msg.rx_buf = config->status_buf; cmds[i].msg.rx_len = config->status_cmds_rlen[i]; - rc = dsi_ctrl_cmd_transfer(ctrl->ctrl, &cmds[i].msg, flags); + rc = dsi_ctrl_cmd_transfer(ctrl->ctrl, &cmds[i].msg, &flags); if (rc <= 0) { DSI_ERR("rx cmd transfer failed rc=%d\n", rc); return rc; @@ -2734,7 +2734,8 @@ static int dsi_display_broadcast_cmd(struct dsi_display *display, m_flags |= DSI_CTRL_CMD_LAST_COMMAND; } - if (display->queue_cmd_waits) { + if (display->queue_cmd_waits || + msg->flags & MIPI_DSI_MSG_ASYNC_OVERRIDE) { flags |= DSI_CTRL_CMD_ASYNC_WAIT; m_flags |= DSI_CTRL_CMD_ASYNC_WAIT; } @@ -2744,7 +2745,7 @@ static int dsi_display_broadcast_cmd(struct dsi_display *display, * 2. Trigger commands */ m_ctrl = &display->ctrl[display->cmd_master_idx]; - rc = dsi_ctrl_cmd_transfer(m_ctrl->ctrl, msg, m_flags); + rc = dsi_ctrl_cmd_transfer(m_ctrl->ctrl, msg, &m_flags); if (rc) { DSI_ERR("[%s] cmd transfer failed on master,rc=%d\n", display->name, rc); @@ -2756,7 +2757,7 @@ static int dsi_display_broadcast_cmd(struct dsi_display *display, if (ctrl == m_ctrl) continue; - rc = dsi_ctrl_cmd_transfer(ctrl->ctrl, msg, flags); + rc = dsi_ctrl_cmd_transfer(ctrl->ctrl, msg, &flags); if (rc) { DSI_ERR("[%s] cmd transfer failed, rc=%d\n", display->name, rc); @@ -2894,11 +2895,12 @@ static ssize_t dsi_host_transfer(struct mipi_dsi_host *host, msg->ctrl : 0; u32 cmd_flags = DSI_CTRL_CMD_FETCH_MEMORY; - if (display->queue_cmd_waits) + if (display->queue_cmd_waits || + msg->flags & MIPI_DSI_MSG_ASYNC_OVERRIDE) cmd_flags |= DSI_CTRL_CMD_ASYNC_WAIT; rc = dsi_ctrl_cmd_transfer(display->ctrl[ctrl_idx].ctrl, msg, - cmd_flags); + &cmd_flags); if (rc) { DSI_ERR("[%s] cmd transfer failed, rc=%d\n", display->name, rc); @@ -7536,14 +7538,44 @@ int dsi_display_pre_disable(struct dsi_display *display) if (display->config.panel_mode == DSI_OP_CMD_MODE) dsi_panel_pre_mode_switch_to_video(display->panel); - if (display->config.panel_mode == DSI_OP_VIDEO_MODE) + if (display->config.panel_mode == DSI_OP_VIDEO_MODE) { + /* + * Add unbalanced vote for clock & cmd engine to enable + * async trigger of pre video to cmd mode switch. + */ + rc = dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_ON); + if (rc) { + DSI_ERR("[%s]failed to enable all clocks,rc=%d", + display->name, rc); + goto exit; + } + + rc = dsi_display_cmd_engine_enable(display); + if (rc) { + DSI_ERR("[%s]failed to enable cmd engine,rc=%d", + display->name, rc); + goto error_disable_clks; + } + dsi_panel_pre_mode_switch_to_cmd(display->panel); + } } else { rc = dsi_panel_pre_disable(display->panel); if (rc) DSI_ERR("[%s] panel pre-disable failed, rc=%d\n", display->name, rc); } + goto exit; + +error_disable_clks: + rc = dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_OFF); + if (rc) + DSI_ERR("[%s] failed to disable all DSI clocks, rc=%d\n", + display->name, rc); + +exit: mutex_unlock(&display->display_lock); return rc; } @@ -7646,7 +7678,8 @@ int dsi_display_update_pps(char *pps_cmd, void *disp) int dsi_display_unprepare(struct dsi_display *display) { - int rc = 0; + int rc = 0, i; + struct dsi_display_ctrl *ctrl; if (!display) { DSI_ERR("Invalid params\n"); @@ -7666,6 +7699,24 @@ int dsi_display_unprepare(struct dsi_display *display) DSI_ERR("[%s] panel unprepare failed, rc=%d\n", display->name, rc); } + + /* Remove additional vote added for pre_mode_switch_to_cmd */ + if (display->poms_pending && + display->config.panel_mode == DSI_OP_VIDEO_MODE) { + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl || !ctrl->ctrl->dma_wait_queued) + continue; + flush_workqueue(display->dma_cmd_workq); + cancel_work_sync(&ctrl->ctrl->dma_cmd_wait); + ctrl->ctrl->dma_wait_queued = false; + } + + dsi_display_cmd_engine_disable(display); + dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_OFF); + } + rc = dsi_display_ctrl_host_disable(display); if (rc) DSI_ERR("[%s] failed to disable DSI host, rc=%d\n", diff --git a/msm/dsi/dsi_drm.c b/msm/dsi/dsi_drm.c index fb3df7e6..4bf12fee 100644 --- a/msm/dsi/dsi_drm.c +++ b/msm/dsi/dsi_drm.c @@ -11,6 +11,7 @@ #include "sde_connector.h" #include "dsi_drm.h" #include "sde_trace.h" +#include "sde_encoder.h" #define to_dsi_bridge(x) container_of((x), struct dsi_bridge, base) #define to_dsi_state(x) container_of((x), struct dsi_connector_state, base) @@ -343,6 +344,8 @@ static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge, struct dsi_display *display; struct dsi_display_mode dsi_mode, cur_dsi_mode, *panel_dsi_mode; struct drm_crtc_state *crtc_state; + bool clone_mode = false; + struct drm_encoder *encoder; crtc_state = container_of(mode, struct drm_crtc_state, mode); @@ -407,6 +410,14 @@ static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge, return false; } + drm_for_each_encoder(encoder, crtc_state->crtc->dev) { + if (encoder->crtc != crtc_state->crtc) + continue; + + if (sde_encoder_in_clone_mode(encoder)) + clone_mode = true; + } + /* No panel mode switch when drm pipeline is changing */ if ((dsi_mode.panel_mode != cur_dsi_mode.panel_mode) && (!(dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_VRR)) && @@ -423,13 +434,16 @@ static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge, dsi_mode.dsi_mode_flags |= DSI_MODE_FLAG_DMS; } - /* Reject seamless transition when active changed */ - if (crtc_state->active_changed && + /* Reject seamless transition when active/connectors changed */ + if ((crtc_state->active_changed || + (crtc_state->connectors_changed && clone_mode)) && ((dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_VRR) || (dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_POMS) || (dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK))) { - DSI_ERR("seamless upon active changed 0x%x %d\n", - dsi_mode.dsi_mode_flags, crtc_state->active_changed); + DSI_ERR("seamless on active/conn(%d/%d) changed 0x%x\n", + crtc_state->active_changed, + crtc_state->connectors_changed, + dsi_mode.dsi_mode_flags); return false; } diff --git a/msm/dsi/dsi_panel.c b/msm/dsi/dsi_panel.c index 61c6c7a0..0311c648 100644 --- a/msm/dsi/dsi_panel.c +++ b/msm/dsi/dsi_panel.c @@ -411,6 +411,9 @@ static int dsi_panel_tx_cmd_set(struct dsi_panel *panel, if (cmds->last_command) cmds->msg.flags |= MIPI_DSI_MSG_LASTCOMMAND; + if (type == DSI_CMD_SET_VID_TO_CMD_SWITCH) + cmds->msg.flags |= MIPI_DSI_MSG_ASYNC_OVERRIDE; + len = ops->transfer(panel->host, &cmds->msg); if (len < 0) { rc = len; diff --git a/msm/dsi/dsi_panel.h b/msm/dsi/dsi_panel.h index 9a774970..8ecb346b 100644 --- a/msm/dsi/dsi_panel.h +++ b/msm/dsi/dsi_panel.h @@ -29,6 +29,13 @@ #define DSI_CMD_PPS_HDR_SIZE 7 #define DSI_MODE_MAX 32 +/* + * Defining custom dsi msg flag, + * continued from drm_mipi_dsi.h + * Override to use async transfer + */ +#define MIPI_DSI_MSG_ASYNC_OVERRIDE BIT(4) + enum dsi_panel_rotation { DSI_PANEL_ROTATE_NONE = 0, DSI_PANEL_ROTATE_HV_FLIP,