From 41f52e39875ada9e1987883cf1f4b463e101a710 Mon Sep 17 00:00:00 2001 From: Nilaan Gunabalachandran Date: Thu, 19 Mar 2020 15:17:41 -0400 Subject: [PATCH 1/4] disp: msm: dsi: maintain validated dsi msg flags This change fixes the usecase where dsi msg flags validated only during command transfer. This fix maintains the flags between transfer and trigger calls. It also adds a new async override flag to be used to bypass validate function. Change-Id: Ie12acd3d7b01099bba65ca37cec61091408b81c5 Signed-off-by: Nilaan Gunabalachandran Signed-off-by: Satya Rama Aditya Pinapala --- msm/dsi/dsi_ctrl.c | 55 ++++++++++++++++++++++--------------------- msm/dsi/dsi_ctrl.h | 2 +- msm/dsi/dsi_display.c | 8 +++---- msm/dsi/dsi_panel.h | 7 ++++++ 4 files changed, 40 insertions(+), 32 deletions(-) diff --git a/msm/dsi/dsi_ctrl.c b/msm/dsi/dsi_ctrl.c index 360739b8..d8222ddb 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" @@ -1251,9 +1252,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 @@ -1263,20 +1264,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; @@ -1288,10 +1289,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"); @@ -1299,16 +1300,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; @@ -1343,12 +1344,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; @@ -1368,19 +1369,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); @@ -1408,7 +1409,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); @@ -1470,7 +1471,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; @@ -3071,7 +3072,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; @@ -3089,7 +3090,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 6c665a33..a10aca40 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -677,7 +677,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; @@ -2733,7 +2733,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); @@ -2745,7 +2745,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); @@ -2887,7 +2887,7 @@ static ssize_t dsi_host_transfer(struct mipi_dsi_host *host, 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); 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, From a5cae7c0f3d01592c04d249175889f698765ce03 Mon Sep 17 00:00:00 2001 From: Nilaan Gunabalachandran Date: Wed, 12 Feb 2020 16:47:45 -0500 Subject: [PATCH 2/4] disp: msm: dsi: make panel commands async for vid to cmd switch Optimize pre mode switch panel command by transferring async. This removes the time waited until subsequent dma_done irq. Change-Id: I2e2516fdd641e85d1f1b221a6ea7999c868edf00 Signed-off-by: Nilaan Gunabalachandran Signed-off-by: Satya Rama Aditya Pinapala --- msm/dsi/dsi_display.c | 59 ++++++++++++++++++++++++++++++++++++++++--- msm/dsi/dsi_panel.c | 3 +++ 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index a10aca40..353ba459 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -2723,7 +2723,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; } @@ -2883,7 +2884,8 @@ 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, @@ -7514,14 +7516,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; } @@ -7624,7 +7656,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"); @@ -7644,6 +7677,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_panel.c b/msm/dsi/dsi_panel.c index a04e4dde..efd46c9f 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; From 92ecce28737b019d2dba328be3fba29fb9cd02e2 Mon Sep 17 00:00:00 2001 From: Lei Chen Date: Fri, 13 Mar 2020 23:21:21 +0800 Subject: [PATCH 3/4] disp: msm: Subtract DSI interrupt count after interrupt was destroyed DSI interrupt may be destroyed before it is disabled, it will cause to the interrupt count can't be cleared, so subtrace DSI interrupt count in disable function even it was destroyed. Change-Id: I430b0281957db588c7405d5775d0c10f2f498b36 Signed-off-by: Lei Chen Signed-off-by: Satya Rama Aditya Pinapala --- msm/dsi/dsi_ctrl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/msm/dsi/dsi_ctrl.c b/msm/dsi/dsi_ctrl.c index d8222ddb..2effaea8 100644 --- a/msm/dsi/dsi_ctrl.c +++ b/msm/dsi/dsi_ctrl.c @@ -2675,8 +2675,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); @@ -2689,7 +2688,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); } From eaa0b9cc158ddf6f0c4c5cca820dec9ee6474a29 Mon Sep 17 00:00:00 2001 From: Krishna Manikandan Date: Thu, 2 Apr 2020 12:43:57 +0530 Subject: [PATCH 4/4] disp: msm: dsi: avoid seamless request for cwb transitions There are some scenarios where a dfps request during cwb session will result in cwb encoder not getting disabled once the cwb session is over. Add support to fail the commit if any VRR or dynamic clock change request is received during CWB transitions to handle this. Change-Id: Id3f192f79eac4ad0d7301bd34f7151fec243d685 Signed-off-by: Krishna Manikandan Signed-off-by: Satya Rama Aditya Pinapala --- msm/dsi/dsi_drm.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/msm/dsi/dsi_drm.c b/msm/dsi/dsi_drm.c index 19a41015..24a75d39 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; }