From 5644d01f7a07698b70c73791517f7073a375a62c Mon Sep 17 00:00:00 2001 From: Lipsa Rout Date: Tue, 3 Dec 2019 19:02:41 +0530 Subject: [PATCH 01/16] disp: msm: dsi: Update dsi byte interface clock calculation Update dsi byte interface clock as per hardware recommendation. For Phy ver 2.0 and below: byte intf clk equals to byte clk. For Phy ver 3.0 and above: byte intf clk equals to byte clk / 2. Change-Id: Ic3af2e4348403aeacb2e1c73c4dc133db63a51a4 Signed-off-by: Ritesh Kumar Signed-off-by: Lipsa Rout Signed-off-by: Satya Rama Aditya Pinapala --- msm/dsi/dsi_clk.h | 6 +++++- msm/dsi/dsi_clk_manager.c | 15 ++++++++------- msm/dsi/dsi_ctrl.c | 14 ++++++++++---- msm/dsi/dsi_defs.h | 2 ++ msm/dsi/dsi_display.c | 39 +++++++++++++++++++++++++++++++++------ msm/dsi/dsi_phy.c | 5 +++++ msm/dsi/dsi_phy.h | 8 ++++++++ 7 files changed, 71 insertions(+), 18 deletions(-) diff --git a/msm/dsi/dsi_clk.h b/msm/dsi/dsi_clk.h index ff6bfb908f..02765c6e3f 100644 --- a/msm/dsi/dsi_clk.h +++ b/msm/dsi/dsi_clk.h @@ -106,11 +106,13 @@ struct dsi_link_lp_clk_info { /** * struct link_clk_freq - Clock frequency information for Link clocks * @byte_clk_rate: Frequency of DSI byte_clk in KHz. + * @byte_intf_clk_rate: Frequency of DSI byte_intf_clk in KHz. * @pixel_clk_rate: Frequency of DSI pixel_clk in KHz. * @esc_clk_rate: Frequency of DSI escape clock in KHz. */ struct link_clk_freq { u32 byte_clk_rate; + u32 byte_intf_clk_rate; u32 pix_clk_rate; u32 esc_clk_rate; }; @@ -292,10 +294,12 @@ int dsi_clk_set_pixel_clk_rate(void *client, u64 pixel_clk, u32 index); * dsi_clk_set_byte_clk_rate() - set frequency for byte clock * @client: DSI clock client pointer. * @byte_clk: Pixel clock rate in Hz. + * @byte_intf_clk: Byte interface clock rate in Hz. * @index: Index of the DSI controller. * return: error code in case of failure or 0 for success. */ -int dsi_clk_set_byte_clk_rate(void *client, u64 byte_clk, u32 index); +int dsi_clk_set_byte_clk_rate(void *client, u64 byte_clk, + u64 byte_intf_clk, u32 index); /** * dsi_clk_update_parent() - update parent clocks for specified clock diff --git a/msm/dsi/dsi_clk_manager.c b/msm/dsi/dsi_clk_manager.c index 6801a79a1a..c2531bbf23 100644 --- a/msm/dsi/dsi_clk_manager.c +++ b/msm/dsi/dsi_clk_manager.c @@ -130,15 +130,16 @@ int dsi_clk_set_pixel_clk_rate(void *client, u64 pixel_clk, u32 index) * dsi_clk_set_byte_clk_rate() - set frequency for byte clock * @client: DSI clock client pointer. * @byte_clk: Byte clock rate in Hz. + * @byte_intf_clk: Byte interface clock rate in Hz. * @index: Index of the DSI controller. * return: error code in case of failure or 0 for success. */ -int dsi_clk_set_byte_clk_rate(void *client, u64 byte_clk, u32 index) +int dsi_clk_set_byte_clk_rate(void *client, u64 byte_clk, + u64 byte_intf_clk, u32 index) { int rc = 0; struct dsi_clk_client_info *c = client; struct dsi_clk_mngr *mngr; - u64 byte_intf_rate; mngr = c->mngr; rc = clk_set_rate(mngr->link_clks[index].hs_clks.byte_clk, byte_clk); @@ -148,12 +149,14 @@ int dsi_clk_set_byte_clk_rate(void *client, u64 byte_clk, u32 index) mngr->link_clks[index].freq.byte_clk_rate = byte_clk; if (mngr->link_clks[index].hs_clks.byte_intf_clk) { - byte_intf_rate = mngr->link_clks[index].freq.byte_clk_rate / 2; rc = clk_set_rate(mngr->link_clks[index].hs_clks.byte_intf_clk, - byte_intf_rate); + byte_intf_clk); if (rc) DSI_ERR("failed to set clk rate for byte intf clk=%d\n", rc); + else + mngr->link_clks[index].freq.byte_intf_clk_rate = + byte_intf_clk; } return rc; @@ -344,12 +347,10 @@ static int dsi_link_hs_clk_set_rate(struct dsi_link_hs_clk_info *link_hs_clks, /* * If byte_intf_clk is present, set rate for that too. - * For DPHY: byte_intf_clk_rate = byte_clk_rate / 2 - * todo: this needs to be revisited when support for CPHY is added */ if (link_hs_clks->byte_intf_clk) { rc = clk_set_rate(link_hs_clks->byte_intf_clk, - (l_clks->freq.byte_clk_rate / 2)); + l_clks->freq.byte_intf_clk_rate); if (rc) { DSI_ERR("set_rate failed for byte_intf_clk rc = %d\n", rc); diff --git a/msm/dsi/dsi_ctrl.c b/msm/dsi/dsi_ctrl.c index 155feaa28d..6aa7aea0b2 100644 --- a/msm/dsi/dsi_ctrl.c +++ b/msm/dsi/dsi_ctrl.c @@ -877,9 +877,9 @@ static int dsi_ctrl_update_link_freqs(struct dsi_ctrl *dsi_ctrl, { int rc = 0; u32 num_of_lanes = 0; - u32 bpp, frame_time_us; + u32 bpp, frame_time_us, byte_intf_clk_div; u64 h_period, v_period, bit_rate, pclk_rate, bit_rate_per_lane, - byte_clk_rate; + byte_clk_rate, byte_intf_clk_rate; struct dsi_host_common_cfg *host_cfg = &config->common_config; struct dsi_split_link_config *split_link = &host_cfg->split_link; struct dsi_mode_info *timing = &config->video_timing; @@ -924,14 +924,20 @@ static int dsi_ctrl_update_link_freqs(struct dsi_ctrl *dsi_ctrl, do_div(pclk_rate, bpp); byte_clk_rate = bit_rate_per_lane; do_div(byte_clk_rate, 8); + byte_intf_clk_rate = byte_clk_rate; + byte_intf_clk_div = host_cfg->byte_intf_clk_div; + do_div(byte_intf_clk_rate, byte_intf_clk_div); + DSI_CTRL_DEBUG(dsi_ctrl, "bit_clk_rate = %llu, bit_clk_rate_per_lane = %llu\n", bit_rate, bit_rate_per_lane); - DSI_CTRL_DEBUG(dsi_ctrl, "byte_clk_rate = %llu, pclk_rate = %llu\n", - byte_clk_rate, pclk_rate); + DSI_CTRL_DEBUG(dsi_ctrl, "byte_clk_rate = %llu, byte_intf_clk = %llu\n", + byte_clk_rate, byte_intf_clk_rate); + DSI_CTRL_DEBUG(dsi_ctrl, "pclk_rate = %llu\n", pclk_rate); dsi_ctrl->clk_freq.byte_clk_rate = byte_clk_rate; dsi_ctrl->clk_freq.pix_clk_rate = pclk_rate; dsi_ctrl->clk_freq.esc_clk_rate = config->esc_clk_rate_hz; + dsi_ctrl->clk_freq.byte_intf_clk_rate = byte_intf_clk_rate; config->bit_clk_rate_hz = dsi_ctrl->clk_freq.byte_clk_rate * 8; rc = dsi_clk_set_link_frequencies(clk_handle, dsi_ctrl->clk_freq, diff --git a/msm/dsi/dsi_defs.h b/msm/dsi/dsi_defs.h index 4662b88a6a..28378d9d60 100644 --- a/msm/dsi/dsi_defs.h +++ b/msm/dsi/dsi_defs.h @@ -450,6 +450,7 @@ struct dsi_split_link_config { * @ext_bridge_mode: External bridge is connected. * @force_hs_clk_lane: Send continuous clock to the panel. * @dsi_split_link_config: Split Link Configuration. + * @byte_intf_clk_div: Determines the factor for calculating byte intf clock. */ struct dsi_host_common_cfg { enum dsi_pixel_format dst_format; @@ -473,6 +474,7 @@ struct dsi_host_common_cfg { bool ext_bridge_mode; bool force_hs_clk_lane; struct dsi_split_link_config split_link; + u32 byte_intf_clk_div; }; /** diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index 9db551d335..e6a46c0254 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -3861,6 +3861,22 @@ static bool dsi_display_is_seamless_dfps_possible( return true; } +void dsi_display_update_byte_intf_div(struct dsi_display *display) +{ + struct dsi_host_common_cfg *config; + struct dsi_display_ctrl *m_ctrl; + int phy_ver; + + m_ctrl = &display->ctrl[display->cmd_master_idx]; + config = &display->panel->host_config; + + phy_ver = dsi_phy_get_version(m_ctrl->phy); + if (phy_ver <= DSI_PHY_VERSION_2_0) + config->byte_intf_clk_div = 1; + else + config->byte_intf_clk_div = 2; +} + static int dsi_display_update_dsi_bitrate(struct dsi_display *display, u32 bit_clk_rate) { @@ -3883,8 +3899,9 @@ static int dsi_display_update_dsi_bitrate(struct dsi_display *display, display_for_each_ctrl(i, display) { struct dsi_display_ctrl *dsi_disp_ctrl = &display->ctrl[i]; struct dsi_ctrl *ctrl = dsi_disp_ctrl->ctrl; - u32 num_of_lanes = 0, bpp; - u64 bit_rate, pclk_rate, bit_rate_per_lane, byte_clk_rate; + u32 num_of_lanes = 0, bpp, byte_intf_clk_div; + u64 bit_rate, pclk_rate, bit_rate_per_lane, byte_clk_rate, + byte_intf_clk_rate; struct dsi_host_common_cfg *host_cfg; mutex_lock(&ctrl->ctrl_lock); @@ -3914,12 +3931,18 @@ static int dsi_display_update_dsi_bitrate(struct dsi_display *display, do_div(pclk_rate, bpp); byte_clk_rate = bit_rate_per_lane; do_div(byte_clk_rate, 8); + byte_intf_clk_rate = byte_clk_rate; + byte_intf_clk_div = host_cfg->byte_intf_clk_div; + do_div(byte_intf_clk_rate, byte_intf_clk_div); + DSI_DEBUG("bit_clk_rate = %llu, bit_clk_rate_per_lane = %llu\n", bit_rate, bit_rate_per_lane); - DSI_DEBUG("byte_clk_rate = %llu, pclk_rate = %llu\n", - byte_clk_rate, pclk_rate); + DSI_DEBUG("byte_clk_rate = %llu, byte_intf_clk_rate = %llu\n", + byte_clk_rate, byte_intf_clk_rate); + DSI_DEBUG("pclk_rate = %llu\n", pclk_rate); ctrl->clk_freq.byte_clk_rate = byte_clk_rate; + ctrl->clk_freq.byte_intf_clk_rate = byte_intf_clk_rate; ctrl->clk_freq.pix_clk_rate = pclk_rate; rc = dsi_clk_set_link_frequencies(display->dsi_clk_handle, ctrl->clk_freq, ctrl->cell_index); @@ -4013,7 +4036,8 @@ static int _dsi_display_dyn_update_clks(struct dsi_display *display, if (!ctrl->ctrl) continue; rc = dsi_clk_set_byte_clk_rate(display->dsi_clk_handle, - ctrl->ctrl->clk_freq.byte_clk_rate, i); + ctrl->ctrl->clk_freq.byte_clk_rate, + ctrl->ctrl->clk_freq.byte_intf_clk_rate, i); if (rc) { DSI_ERR("failed to set byte rate for index:%d\n", i); goto recover_byte_clk; @@ -4076,7 +4100,8 @@ recover_byte_clk: if (!ctrl->ctrl) continue; dsi_clk_set_byte_clk_rate(display->dsi_clk_handle, - bkp_freq->byte_clk_rate, i); + bkp_freq->byte_clk_rate, + bkp_freq->byte_intf_clk_rate, i); } exit: @@ -4112,6 +4137,7 @@ static int dsi_display_dynamic_clk_switch_vid(struct dsi_display *display, /* back up existing rates to handle failure case */ bkp_freq.byte_clk_rate = m_ctrl->ctrl->clk_freq.byte_clk_rate; + bkp_freq.byte_intf_clk_rate = m_ctrl->ctrl->clk_freq.byte_intf_clk_rate; bkp_freq.pix_clk_rate = m_ctrl->ctrl->clk_freq.pix_clk_rate; bkp_freq.esc_clk_rate = m_ctrl->ctrl->clk_freq.esc_clk_rate; @@ -4939,6 +4965,7 @@ static int dsi_display_bind(struct device *dev, } } + dsi_display_update_byte_intf_div(display); rc = dsi_display_mipi_host_init(display); if (rc) { DSI_ERR("[%s] failed to initialize mipi host, rc=%d\n", diff --git a/msm/dsi/dsi_phy.c b/msm/dsi/dsi_phy.c index 830016e94f..86852737d8 100644 --- a/msm/dsi/dsi_phy.c +++ b/msm/dsi/dsi_phy.c @@ -111,6 +111,11 @@ static const struct of_device_id msm_dsi_phy_of_match[] = { {} }; +int dsi_phy_get_version(struct msm_dsi_phy *phy) +{ + return phy->ver_info->version; +} + static int dsi_phy_regmap_init(struct platform_device *pdev, struct msm_dsi_phy *phy) { diff --git a/msm/dsi/dsi_phy.h b/msm/dsi/dsi_phy.h index 1068304612..dc9d44be2f 100644 --- a/msm/dsi/dsi_phy.h +++ b/msm/dsi/dsi_phy.h @@ -125,6 +125,14 @@ struct msm_dsi_phy *dsi_phy_get(struct device_node *of_node); */ void dsi_phy_put(struct msm_dsi_phy *dsi_phy); +/** + * dsi_phy_get_version() - returns dsi phy version + * @dsi_phy: DSI PHY handle. + * + * Return: phy version + */ +int dsi_phy_get_version(struct msm_dsi_phy *phy); + /** * dsi_phy_drv_init() - initialize dsi phy driver * @dsi_phy: DSI PHY handle. From 5e09ea2aed0813864f3a09496eee276f6e3bf578 Mon Sep 17 00:00:00 2001 From: Lipsa Rout Date: Wed, 11 Dec 2019 17:40:50 +0530 Subject: [PATCH 02/16] disp: msm: dsi: Add support for clk switch with constant FPS There is lag or lead in the FPS during dynamic clock change, along with the increment or decrement in clock. So, HFP or VFP are adjusted to ensure a constant FPS. Change-Id: I87ba7a185104a0f5f1d13734a7e487e728d6b2c0 Signed-off-by: Lipsa Rout Signed-off-by: Satya Rama Aditya Pinapala --- msm/dsi/dsi_defs.h | 16 ++++++ msm/dsi/dsi_display.c | 117 ++++++++++++++++++++++++++++++++++++++---- msm/dsi/dsi_panel.c | 19 +++++++ msm/dsi/dsi_panel.h | 2 + 4 files changed, 143 insertions(+), 11 deletions(-) diff --git a/msm/dsi/dsi_defs.h b/msm/dsi/dsi_defs.h index 28378d9d60..86ca54e8a1 100644 --- a/msm/dsi/dsi_defs.h +++ b/msm/dsi/dsi_defs.h @@ -217,6 +217,22 @@ enum dsi_dfps_type { DSI_DFPS_MAX }; +/** + * enum dsi_dyn_clk_feature_type - Dynamic clock feature support type + * @DSI_DYN_CLK_TYPE_LEGACY: Constant FPS is not supported + * @DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_HFP: Constant FPS supported with + * change in hfp + * @DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_VFP: Constant FPS supported with + * change in vfp + * @DSI_DYN_CLK_TYPE_MAX: + */ +enum dsi_dyn_clk_feature_type { + DSI_DYN_CLK_TYPE_LEGACY = 0, + DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_HFP, + DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_VFP, + DSI_DYN_CLK_TYPE_MAX +}; + /** * enum dsi_cmd_set_type - DSI command set type * @DSI_CMD_SET_PRE_ON: Panel pre on diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index e6a46c0254..e1a9e8ba2c 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -4222,6 +4222,7 @@ static int dsi_display_dfps_update(struct dsi_display *display, struct dsi_dfps_capabilities dfps_caps; int rc = 0; int i = 0; + struct dsi_dyn_clk_caps *dyn_clk_caps; if (!display || !dsi_mode || !display->panel) { DSI_ERR("Invalid params\n"); @@ -4230,8 +4231,9 @@ static int dsi_display_dfps_update(struct dsi_display *display, timing = &dsi_mode->timing; dsi_panel_get_dfps_caps(display->panel, &dfps_caps); - if (!dfps_caps.dfps_support) { - DSI_ERR("dfps not supported\n"); + dyn_clk_caps = &(display->panel->dyn_clk_caps); + if (!dfps_caps.dfps_support && !dyn_clk_caps->maintain_const_fps) { + DSI_ERR("dfps or constant fps not supported\n"); return -ENOTSUPP; } @@ -4508,7 +4510,32 @@ static int dsi_display_set_mode_sub(struct dsi_display *display, display->name, rc); goto error; } - } else if (mode->dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK) { + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + rc = dsi_ctrl_update_host_config(ctrl->ctrl, + &display->config, mode, mode->dsi_mode_flags, + display->dsi_clk_handle); + if (rc) { + DSI_ERR("failed to update ctrl config\n"); + goto error; + } + } + if (priv_info->phy_timing_len) { + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + rc = dsi_phy_set_timing_params(ctrl->phy, + priv_info->phy_timing_val, + priv_info->phy_timing_len, + commit_phy_timing); + if (rc) + DSI_ERR("Fail to add timing params\n"); + } + } + if (!(mode->dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK)) + return rc; + } + + if (mode->dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK) { if (display->panel->panel_mode == DSI_OP_VIDEO_MODE) { rc = dsi_display_dynamic_clk_switch_vid(display, mode); if (rc) @@ -5899,6 +5926,51 @@ int dsi_display_get_mode_count(struct dsi_display *display, return 0; } +void dsi_display_adjust_mode_timing( + struct dsi_dyn_clk_caps *dyn_clk_caps, + struct dsi_display_mode *dsi_mode, + int lanes, int bpp) +{ + u32 new_htotal, new_vtotal, htotal, vtotal, old_htotal; + + if (!dyn_clk_caps->maintain_const_fps) + return; + /* + * When there is a dynamic clock switch, there is small change + * in FPS. To compensate for this difference in FPS, hfp or vfp + * is adjusted. It has been assumed that the refined porch values + * are supported by the panel. This logic can be enhanced further + * in future by taking min/max porches supported by the panel. + */ + switch (dyn_clk_caps->type) { + case DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_HFP: + vtotal = DSI_V_TOTAL(&dsi_mode->timing); + old_htotal = dsi_h_total_dce(&dsi_mode->timing); + new_htotal = (dsi_mode->timing.clk_rate_hz * lanes); + new_htotal /= (bpp * vtotal * dsi_mode->timing.refresh_rate); + if (old_htotal > new_htotal) + dsi_mode->timing.h_front_porch -= + (old_htotal - new_htotal); + else + dsi_mode->timing.h_front_porch += + (new_htotal - old_htotal); + break; + + case DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_VFP: + htotal = dsi_h_total_dce(&dsi_mode->timing); + new_vtotal = (dsi_mode->timing.clk_rate_hz * lanes); + new_vtotal /= (bpp * htotal * dsi_mode->timing.refresh_rate); + dsi_mode->timing.v_front_porch = new_vtotal - + dsi_mode->timing.v_back_porch - + dsi_mode->timing.v_sync_width - + dsi_mode->timing.v_active; + break; + + default: + break; + } +} + static void _dsi_display_populate_bit_clks(struct dsi_display *display, int start, int end, u32 *mode_idx) { @@ -5938,6 +6010,9 @@ static void _dsi_display_populate_bit_clks(struct dsi_display *display, * be based on user or device tree preferrence. */ src->timing.clk_rate_hz = dyn_clk_caps->bit_clk_list[0]; + + dsi_display_adjust_mode_timing(dyn_clk_caps, src, lanes, bpp); + src->pixel_clk_khz = div_u64(src->timing.clk_rate_hz * lanes, bpp); src->pixel_clk_khz /= 1000; @@ -5957,6 +6032,10 @@ static void _dsi_display_populate_bit_clks(struct dsi_display *display, } memcpy(dst, src, sizeof(struct dsi_display_mode)); dst->timing.clk_rate_hz = dyn_clk_caps->bit_clk_list[i]; + + dsi_display_adjust_mode_timing(dyn_clk_caps, dst, lanes, + bpp); + dst->pixel_clk_khz = div_u64(dst->timing.clk_rate_hz * lanes, bpp); dst->pixel_clk_khz /= 1000; @@ -6251,13 +6330,28 @@ int dsi_display_find_mode(struct dsi_display *display, return rc; } +static inline bool dsi_display_mode_switch_dfps(struct dsi_display_mode *cur, + struct dsi_display_mode *adj) +{ + /* + * If there is a change in the hfp or vfp of the current and adjoining + * mode,then either it is a dfps mode switch or dynamic clk change with + * constant fps. + */ + if ((cur->timing.h_front_porch != adj->timing.h_front_porch) || + (cur->timing.v_front_porch != adj->timing.v_front_porch)) + return true; + else + return false; +} + /** * dsi_display_validate_mode_change() - Validate mode change case. * @display: DSI display handle. * @cur_mode: Current mode. * @adj_mode: Mode to be set. * MSM_MODE_FLAG_SEAMLESS_VRR flag is set if there - * is change in fps but vactive and hactive are same. + * is change in hfp or vfp but vactive and hactive are same. * DSI_MODE_FLAG_DYN_CLK flag is set if there * is change in clk but vactive and hactive are same. * Return: error code. @@ -6281,14 +6375,14 @@ int dsi_display_validate_mode_change(struct dsi_display *display, } mutex_lock(&display->display_lock); - + dyn_clk_caps = &(display->panel->dyn_clk_caps); if ((cur_mode->timing.v_active == adj_mode->timing.v_active) && (cur_mode->timing.h_active == adj_mode->timing.h_active)) { - /* dfps change use case */ - if (cur_mode->timing.refresh_rate != - adj_mode->timing.refresh_rate) { + /* dfps and dynamic clock with const fps use case */ + if (dsi_display_mode_switch_dfps(cur_mode, adj_mode)) { dsi_panel_get_dfps_caps(display->panel, &dfps_caps); - if (dfps_caps.dfps_support) { + if (dfps_caps.dfps_support || + dyn_clk_caps->maintain_const_fps) { DSI_DEBUG("Mode switch is seamless variable refresh\n"); adj_mode->dsi_mode_flags |= DSI_MODE_FLAG_VRR; SDE_EVT32(cur_mode->timing.refresh_rate, @@ -6300,10 +6394,11 @@ int dsi_display_validate_mode_change(struct dsi_display *display, /* dynamic clk change use case */ if (cur_mode->pixel_clk_khz != adj_mode->pixel_clk_khz) { - dyn_clk_caps = &(display->panel->dyn_clk_caps); if (dyn_clk_caps->dyn_clk_support) { DSI_DEBUG("dynamic clk change detected\n"); - if (adj_mode->dsi_mode_flags & DSI_MODE_FLAG_VRR) { + if ((adj_mode->dsi_mode_flags & + DSI_MODE_FLAG_VRR) && + (!dyn_clk_caps->maintain_const_fps)) { DSI_ERR("dfps and dyn clk not supported in same commit\n"); rc = -ENOTSUPP; goto error; diff --git a/msm/dsi/dsi_panel.c b/msm/dsi/dsi_panel.c index 3e872e04f1..407aa4d958 100644 --- a/msm/dsi/dsi_panel.c +++ b/msm/dsi/dsi_panel.c @@ -1175,6 +1175,7 @@ static int dsi_panel_parse_dyn_clk_caps(struct dsi_panel *panel) struct dsi_dyn_clk_caps *dyn_clk_caps = &panel->dyn_clk_caps; struct dsi_parser_utils *utils = &panel->utils; const char *name = panel->name; + const char *type; supported = utils->read_bool(utils->data, "qcom,dsi-dyn-clk-enable"); @@ -1207,6 +1208,24 @@ static int dsi_panel_parse_dyn_clk_caps(struct dsi_panel *panel) dyn_clk_caps->dyn_clk_support = true; + type = utils->get_property(utils->data, + "qcom,dsi-dyn-clk-type", NULL); + if (!type) { + dyn_clk_caps->type = DSI_DYN_CLK_TYPE_LEGACY; + dyn_clk_caps->maintain_const_fps = false; + return 0; + } + if (!strcmp(type, "constant-fps-adjust-hfp")) { + dyn_clk_caps->type = DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_HFP; + dyn_clk_caps->maintain_const_fps = true; + } else if (!strcmp(type, "constant-fps-adjust-vfp")) { + dyn_clk_caps->type = DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_VFP; + dyn_clk_caps->maintain_const_fps = true; + } else { + dyn_clk_caps->type = DSI_DYN_CLK_TYPE_LEGACY; + dyn_clk_caps->maintain_const_fps = false; + } + DSI_DEBUG("Dynamic clock type is [%s]\n", type); return 0; } diff --git a/msm/dsi/dsi_panel.h b/msm/dsi/dsi_panel.h index 946bbf0bcb..08ff9a82c3 100644 --- a/msm/dsi/dsi_panel.h +++ b/msm/dsi/dsi_panel.h @@ -82,6 +82,8 @@ struct dsi_dyn_clk_caps { bool dyn_clk_support; u32 *bit_clk_list; u32 bit_clk_list_len; + enum dsi_dyn_clk_feature_type type; + bool maintain_const_fps; }; struct dsi_pinctrl_info { From 81ad4ef40777275a1de65e1d569b0aa2960c7cf0 Mon Sep 17 00:00:00 2001 From: Vara Reddy Date: Mon, 25 Nov 2019 16:47:26 -0800 Subject: [PATCH 03/16] drm/msm/dsi: fix dsi command dma async race condition Change will be removing checking and clearing dsi cmd done interrupt in commit thread and in workqueue context, which can race with dsi isr, when it tries to clear the interrupt. Change-Id: I96e7f8dffed1af3cec0c7668ab1729337d4b260e Signed-off-by: Vara Reddy Signed-off-by: Satya Rama Aditya Pinapala --- msm/dsi/dsi_ctrl.c | 32 +------------------------------- 1 file changed, 1 insertion(+), 31 deletions(-) diff --git a/msm/dsi/dsi_ctrl.c b/msm/dsi/dsi_ctrl.c index 6aa7aea0b2..37d040d989 100644 --- a/msm/dsi/dsi_ctrl.c +++ b/msm/dsi/dsi_ctrl.c @@ -269,10 +269,6 @@ dsi_ctrl_get_aspace(struct dsi_ctrl *dsi_ctrl, static void dsi_ctrl_flush_cmd_dma_queue(struct dsi_ctrl *dsi_ctrl) { - u32 status; - u32 mask = DSI_CMD_MODE_DMA_DONE; - struct dsi_ctrl_hw_ops dsi_hw_ops = dsi_ctrl->hw.ops; - /* * If a command is triggered right after another command, * check if the previous command transfer is completed. If @@ -281,21 +277,8 @@ static void dsi_ctrl_flush_cmd_dma_queue(struct dsi_ctrl *dsi_ctrl) * completed before triggering the next command by * flushing the workqueue. */ - status = dsi_hw_ops.get_interrupt_status(&dsi_ctrl->hw); if (atomic_read(&dsi_ctrl->dma_irq_trig)) { cancel_work_sync(&dsi_ctrl->dma_cmd_wait); - } else if (status & mask) { - atomic_set(&dsi_ctrl->dma_irq_trig, 1); - status |= (DSI_CMD_MODE_DMA_DONE | DSI_BTA_DONE); - dsi_hw_ops.clear_interrupt_status( - &dsi_ctrl->hw, - status); - dsi_ctrl_disable_status_interrupt(dsi_ctrl, - DSI_SINT_CMD_MODE_DMA_DONE); - complete_all(&dsi_ctrl->irq_info.cmd_dma_done); - cancel_work_sync(&dsi_ctrl->dma_cmd_wait); - DSI_CTRL_DEBUG(dsi_ctrl, - "dma_tx done but irq not yet triggered\n"); } else { flush_workqueue(dsi_ctrl->dma_cmd_workq); } @@ -319,24 +302,11 @@ static void dsi_ctrl_dma_cmd_wait_for_done(struct work_struct *work) */ if (atomic_read(&dsi_ctrl->dma_irq_trig)) goto done; - /* - * If IRQ wasn't triggered check interrupt status register for - * transfer done before waiting. - */ - status = dsi_hw_ops.get_interrupt_status(&dsi_ctrl->hw); - if (status & mask) { - status |= (DSI_CMD_MODE_DMA_DONE | DSI_BTA_DONE); - dsi_hw_ops.clear_interrupt_status(&dsi_ctrl->hw, - status); - dsi_ctrl_disable_status_interrupt(dsi_ctrl, - DSI_SINT_CMD_MODE_DMA_DONE); - goto done; - } ret = wait_for_completion_timeout( &dsi_ctrl->irq_info.cmd_dma_done, msecs_to_jiffies(DSI_CTRL_TX_TO_MS)); - if (ret == 0) { + if (ret == 0 && !atomic_read(&dsi_ctrl->dma_irq_trig)) { status = dsi_hw_ops.get_interrupt_status(&dsi_ctrl->hw); if (status & mask) { status |= (DSI_CMD_MODE_DMA_DONE | DSI_BTA_DONE); From bce44eed4701336bb44f29838e6c31d5939dcc02 Mon Sep 17 00:00:00 2001 From: Aravind Venkateswaran Date: Mon, 16 Dec 2019 22:15:35 -0800 Subject: [PATCH 04/16] disp: msm: dsi: add additional validation checks for async cmd wait Disable DSI command transfer async wait feature for DSI read commands and the commands sent in non-embedded mode. CRs-Fixed: 2579259 Change-Id: Ib3b08fbb091711aa4be87400b79d01f0dcc05e71 Signed-off-by: Aravind Venkateswaran Signed-off-by: Satya Rama Aditya Pinapala --- msm/dsi/dsi_ctrl.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/msm/dsi/dsi_ctrl.c b/msm/dsi/dsi_ctrl.c index 37d040d989..9cbb48937f 100644 --- a/msm/dsi/dsi_ctrl.c +++ b/msm/dsi/dsi_ctrl.c @@ -1254,13 +1254,19 @@ static u32 dsi_ctrl_validate_msg_flags(const struct mipi_dsi_msg *msg, u32 flags) { /* - * ASYNC command wait mode is not supported for FIFO commands. - * Waiting after a command is transferred cannot be guaranteed - * if DSI_CTRL_CMD_ASYNC_WAIT flag is set. + * ASYNC command wait mode is not supported for + * - commands sent using DSI FIFO memory + * - DSI read commands + * - DCS commands sent in non-embedded mode + * - whenever an explicit wait time is specificed for the command + * since the wait time cannot be guaranteed in async mode */ if ((flags & DSI_CTRL_CMD_FIFO_STORE) || - msg->wait_ms) + flags & DSI_CTRL_CMD_READ || + flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE || + msg->wait_ms) flags &= ~DSI_CTRL_CMD_ASYNC_WAIT; + return flags; } From e84524efd2dff7d3ad94518fdcbb7484295a4e97 Mon Sep 17 00:00:00 2001 From: Aravind Venkateswaran Date: Mon, 16 Dec 2019 16:34:17 -0800 Subject: [PATCH 05/16] disp: msm: dsi: disable DSI cmd tx async wait for video mode For video mode panels, async wait feature for DCS command transmission may not always be reliable as additional programming would be needed to ensure that the DCS commands are correctly scheduled. Until this feature is properly implemented and validated, disable this for video mode panels to avoid potential DSI command transfer failures. Change-Id: I18c853bc5607cc1cc523b36f6f346b213911c1a9 Signed-off-by: Aravind Venkateswaran Signed-off-by: Satya Rama Aditya Pinapala --- msm/dsi/dsi_ctrl.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/msm/dsi/dsi_ctrl.c b/msm/dsi/dsi_ctrl.c index 9cbb48937f..75bd3bda68 100644 --- a/msm/dsi/dsi_ctrl.c +++ b/msm/dsi/dsi_ctrl.c @@ -1250,7 +1250,8 @@ static void dsi_kickoff_msg_tx(struct dsi_ctrl *dsi_ctrl, } } -static u32 dsi_ctrl_validate_msg_flags(const struct mipi_dsi_msg *msg, +static u32 dsi_ctrl_validate_msg_flags(struct dsi_ctrl *dsi_ctrl, + const struct mipi_dsi_msg *msg, u32 flags) { /* @@ -1260,11 +1261,13 @@ static u32 dsi_ctrl_validate_msg_flags(const struct mipi_dsi_msg *msg, * - DCS commands sent in non-embedded mode * - whenever an explicit wait time is specificed for the command * since the wait time cannot be guaranteed in async mode + * - video mode panels */ if ((flags & DSI_CTRL_CMD_FIFO_STORE) || flags & DSI_CTRL_CMD_READ || flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE || - msg->wait_ms) + msg->wait_ms || + (dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE)) flags &= ~DSI_CTRL_CMD_ASYNC_WAIT; return flags; @@ -1295,7 +1298,7 @@ static int dsi_message_tx(struct dsi_ctrl *dsi_ctrl, goto error; } - flags = dsi_ctrl_validate_msg_flags(msg, flags); + flags = dsi_ctrl_validate_msg_flags(dsi_ctrl, msg, flags); if (dsi_ctrl->dma_wait_queued) dsi_ctrl_flush_cmd_dma_queue(dsi_ctrl); From 10fde7ee16af3c4ae29afcc57ef01363aa4b3556 Mon Sep 17 00:00:00 2001 From: Lipsa Rout Date: Thu, 19 Dec 2019 18:21:24 +0530 Subject: [PATCH 06/16] disp: msm: dsi: Add support for dynamically switch dsi clock Add changes to support dynamic switching of dsi clock feature for phy ver 2.0. This helps to avoid RF interference with DSI clock. Change-Id: I69958d9224665296cc0f272e39dcdfcefbe293d4 Signed-off-by: Ritesh Kumar Signed-off-by: Lipsa Rout Signed-off-by: Satya Rama Aditya Pinapala --- msm/dsi/dsi_catalog.c | 8 + msm/dsi/dsi_catalog.h | 9 +- msm/dsi/dsi_phy_hw_v2_0.c | 337 +++++++++++++++++++++++++++++++++++++- 3 files changed, 352 insertions(+), 2 deletions(-) diff --git a/msm/dsi/dsi_catalog.c b/msm/dsi/dsi_catalog.c index 7d0434365d..349961a187 100644 --- a/msm/dsi/dsi_catalog.c +++ b/msm/dsi/dsi_catalog.c @@ -192,6 +192,14 @@ static void dsi_catalog_phy_2_0_init(struct dsi_phy_hw *phy) dsi_phy_hw_calculate_timing_params; phy->ops.phy_timing_val = dsi_phy_hw_timing_val_v2_0; phy->ops.clamp_ctrl = dsi_phy_hw_v2_0_clamp_ctrl; + phy->ops.dyn_refresh_ops.dyn_refresh_config = + dsi_phy_hw_v2_0_dyn_refresh_config; + phy->ops.dyn_refresh_ops.dyn_refresh_pipe_delay = + dsi_phy_hw_v2_0_dyn_refresh_pipe_delay; + phy->ops.dyn_refresh_ops.dyn_refresh_helper = + dsi_phy_hw_v2_0_dyn_refresh_helper; + phy->ops.dyn_refresh_ops.cache_phy_timings = + dsi_phy_hw_v2_0_cache_phy_timings; } /** diff --git a/msm/dsi/dsi_catalog.h b/msm/dsi/dsi_catalog.h index 2e946ab37b..79c84cfc3a 100644 --- a/msm/dsi/dsi_catalog.h +++ b/msm/dsi/dsi_catalog.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. */ #ifndef _DSI_CATALOG_H_ @@ -80,6 +80,13 @@ void dsi_phy_hw_v2_0_idle_off(struct dsi_phy_hw *phy); int dsi_phy_hw_timing_val_v2_0(struct dsi_phy_per_lane_cfgs *timing_cfg, u32 *timing_val, u32 size); void dsi_phy_hw_v2_0_clamp_ctrl(struct dsi_phy_hw *phy, bool enable); +void dsi_phy_hw_v2_0_dyn_refresh_helper(struct dsi_phy_hw *phy, u32 offset); +void dsi_phy_hw_v2_0_dyn_refresh_config(struct dsi_phy_hw *phy, + struct dsi_phy_cfg *cfg, bool is_master); +void dsi_phy_hw_v2_0_dyn_refresh_pipe_delay(struct dsi_phy_hw *phy, + struct dsi_dyn_clk_delay *delay); +int dsi_phy_hw_v2_0_cache_phy_timings(struct dsi_phy_per_lane_cfgs *timings, + u32 *dst, u32 size); /* Definitions for 10nm PHY hardware driver */ void dsi_phy_hw_v3_0_regulator_enable(struct dsi_phy_hw *phy, diff --git a/msm/dsi/dsi_phy_hw_v2_0.c b/msm/dsi/dsi_phy_hw_v2_0.c index 5206469234..835e2cf3f0 100644 --- a/msm/dsi/dsi_phy_hw_v2_0.c +++ b/msm/dsi/dsi_phy_hw_v2_0.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. */ #include @@ -64,6 +64,83 @@ #define DSIPHY_PLL_CLKBUFLR_EN 0x041C #define DSIPHY_PLL_PLL_BANDGAP 0x0508 +/* dynamic refresh control registers */ +#define DSI_DYN_REFRESH_CTRL 0x000 +#define DSI_DYN_REFRESH_PIPE_DELAY 0x004 +#define DSI_DYN_REFRESH_PIPE_DELAY2 0x008 +#define DSI_DYN_REFRESH_PLL_DELAY 0x00C +#define DSI_DYN_REFRESH_STATUS 0x010 +#define DSI_DYN_REFRESH_PLL_CTRL0 0x014 +#define DSI_DYN_REFRESH_PLL_CTRL1 0x018 +#define DSI_DYN_REFRESH_PLL_CTRL2 0x01C +#define DSI_DYN_REFRESH_PLL_CTRL3 0x020 +#define DSI_DYN_REFRESH_PLL_CTRL4 0x024 +#define DSI_DYN_REFRESH_PLL_CTRL5 0x028 +#define DSI_DYN_REFRESH_PLL_CTRL6 0x02C +#define DSI_DYN_REFRESH_PLL_CTRL7 0x030 +#define DSI_DYN_REFRESH_PLL_CTRL8 0x034 +#define DSI_DYN_REFRESH_PLL_CTRL9 0x038 +#define DSI_DYN_REFRESH_PLL_CTRL10 0x03C +#define DSI_DYN_REFRESH_PLL_CTRL11 0x040 +#define DSI_DYN_REFRESH_PLL_CTRL12 0x044 +#define DSI_DYN_REFRESH_PLL_CTRL13 0x048 +#define DSI_DYN_REFRESH_PLL_CTRL14 0x04C +#define DSI_DYN_REFRESH_PLL_CTRL15 0x050 +#define DSI_DYN_REFRESH_PLL_CTRL16 0x054 +#define DSI_DYN_REFRESH_PLL_CTRL17 0x058 +#define DSI_DYN_REFRESH_PLL_CTRL18 0x05C +#define DSI_DYN_REFRESH_PLL_CTRL19 0x060 +#define DSI_DYN_REFRESH_PLL_CTRL20 0x064 +#define DSI_DYN_REFRESH_PLL_CTRL21 0x068 +#define DSI_DYN_REFRESH_PLL_CTRL22 0x06C +#define DSI_DYN_REFRESH_PLL_CTRL23 0x070 +#define DSI_DYN_REFRESH_PLL_CTRL24 0x074 +#define DSI_DYN_REFRESH_PLL_CTRL25 0x078 +#define DSI_DYN_REFRESH_PLL_CTRL26 0x07C +#define DSI_DYN_REFRESH_PLL_CTRL27 0x080 +#define DSI_DYN_REFRESH_PLL_CTRL28 0x084 +#define DSI_DYN_REFRESH_PLL_CTRL29 0x088 +#define DSI_DYN_REFRESH_PLL_CTRL30 0x08C +#define DSI_DYN_REFRESH_PLL_CTRL31 0x090 +#define DSI_DYN_REFRESH_PLL_UPPER_ADDR 0x094 +#define DSI_DYN_REFRESH_PLL_UPPER_ADDR2 0x098 + +#define DSIPHY_DLN0_CFG1 0x0104 +#define DSIPHY_DLN0_TIMING_CTRL_4 0x0118 +#define DSIPHY_DLN0_TIMING_CTRL_5 0x011C +#define DSIPHY_DLN0_TIMING_CTRL_6 0x0120 +#define DSIPHY_DLN0_TIMING_CTRL_7 0x0124 +#define DSIPHY_DLN0_TIMING_CTRL_8 0x0128 + +#define DSIPHY_DLN1_CFG1 0x0184 +#define DSIPHY_DLN1_TIMING_CTRL_4 0x0198 +#define DSIPHY_DLN1_TIMING_CTRL_5 0x019C +#define DSIPHY_DLN1_TIMING_CTRL_6 0x01A0 +#define DSIPHY_DLN1_TIMING_CTRL_7 0x01A4 +#define DSIPHY_DLN1_TIMING_CTRL_8 0x01A8 + +#define DSIPHY_DLN2_CFG1 0x0204 +#define DSIPHY_DLN2_TIMING_CTRL_4 0x0218 +#define DSIPHY_DLN2_TIMING_CTRL_5 0x021C +#define DSIPHY_DLN2_TIMING_CTRL_6 0x0220 +#define DSIPHY_DLN2_TIMING_CTRL_7 0x0224 +#define DSIPHY_DLN2_TIMING_CTRL_8 0x0228 + +#define DSIPHY_DLN3_CFG1 0x0284 +#define DSIPHY_DLN3_TIMING_CTRL_4 0x0298 +#define DSIPHY_DLN3_TIMING_CTRL_5 0x029C +#define DSIPHY_DLN3_TIMING_CTRL_6 0x02A0 +#define DSIPHY_DLN3_TIMING_CTRL_7 0x02A4 +#define DSIPHY_DLN3_TIMING_CTRL_8 0x02A8 + +#define DSIPHY_CKLN_CFG1 0x0304 +#define DSIPHY_CKLN_TIMING_CTRL_4 0x0318 +#define DSIPHY_CKLN_TIMING_CTRL_5 0x031C +#define DSIPHY_CKLN_TIMING_CTRL_6 0x0320 +#define DSIPHY_CKLN_TIMING_CTRL_7 0x0324 +#define DSIPHY_CKLN_TIMING_CTRL_8 0x0328 + +#define DSIPHY_PLL_RESETSM_CNTRL5 0x043c /** * regulator_enable() - enable regulators for DSI PHY * @phy: Pointer to DSI PHY hardware object. @@ -299,3 +376,261 @@ void dsi_phy_hw_v2_0_clamp_ctrl(struct dsi_phy_hw *phy, bool enable) DSI_PHY_DBG(phy, "clamp disabled\n"); } } + +void dsi_phy_hw_v2_0_dyn_refresh_config(struct dsi_phy_hw *phy, + struct dsi_phy_cfg *cfg, bool is_master) +{ + u32 glbl_tst_cntrl; + + if (is_master) { + glbl_tst_cntrl = DSI_R32(phy, DSIPHY_CMN_GLBL_TEST_CTRL); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL0, + DSIPHY_CMN_GLBL_TEST_CTRL, + DSIPHY_PLL_PLL_BANDGAP, + glbl_tst_cntrl | BIT(1), 0x1); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL1, + DSIPHY_PLL_RESETSM_CNTRL5, + DSIPHY_PLL_PLL_BANDGAP, 0x0D, 0x03); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL2, + DSIPHY_PLL_RESETSM_CNTRL5, + DSIPHY_CMN_PLL_CNTRL, 0x1D, 0x00); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL3, + DSIPHY_CMN_CTRL_1, DSIPHY_DLN0_CFG1, 0x20, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL4, + DSIPHY_DLN1_CFG1, DSIPHY_DLN2_CFG1, 0, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL5, + DSIPHY_DLN3_CFG1, DSIPHY_CKLN_CFG1, 0, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL6, + DSIPHY_DLN0_TIMING_CTRL_4, + DSIPHY_DLN1_TIMING_CTRL_4, + cfg->timing.lane[0][0], cfg->timing.lane[1][0]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL7, + DSIPHY_DLN2_TIMING_CTRL_4, + DSIPHY_DLN3_TIMING_CTRL_4, + cfg->timing.lane[2][0], cfg->timing.lane[3][0]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL8, + DSIPHY_CKLN_TIMING_CTRL_4, + DSIPHY_DLN0_TIMING_CTRL_5, + cfg->timing.lane[4][0], cfg->timing.lane[0][1]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL9, + DSIPHY_DLN1_TIMING_CTRL_5, + DSIPHY_DLN2_TIMING_CTRL_5, + cfg->timing.lane[1][1], cfg->timing.lane[2][1]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL10, + DSIPHY_DLN3_TIMING_CTRL_5, + DSIPHY_CKLN_TIMING_CTRL_5, + cfg->timing.lane[3][1], cfg->timing.lane[4][1]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL11, + DSIPHY_DLN0_TIMING_CTRL_6, + DSIPHY_DLN1_TIMING_CTRL_6, + cfg->timing.lane[0][2], cfg->timing.lane[1][2]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL12, + DSIPHY_DLN2_TIMING_CTRL_6, + DSIPHY_DLN3_TIMING_CTRL_6, + cfg->timing.lane[2][2], cfg->timing.lane[3][2]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL13, + DSIPHY_CKLN_TIMING_CTRL_6, + DSIPHY_DLN0_TIMING_CTRL_7, + cfg->timing.lane[4][2], cfg->timing.lane[0][3]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL14, + DSIPHY_DLN1_TIMING_CTRL_7, + DSIPHY_DLN2_TIMING_CTRL_7, + cfg->timing.lane[1][3], cfg->timing.lane[2][3]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL15, + DSIPHY_DLN3_TIMING_CTRL_7, + DSIPHY_CKLN_TIMING_CTRL_7, + cfg->timing.lane[3][3], cfg->timing.lane[4][3]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, + DSI_DYN_REFRESH_PLL_CTRL16, + DSIPHY_DLN0_TIMING_CTRL_8, + DSIPHY_DLN1_TIMING_CTRL_8, + cfg->timing.lane[0][4], cfg->timing.lane[1][4]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL17, + DSIPHY_DLN2_TIMING_CTRL_8, + DSIPHY_DLN3_TIMING_CTRL_8, + cfg->timing.lane[2][4], cfg->timing.lane[3][4]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL18, + DSIPHY_CKLN_TIMING_CTRL_8, DSIPHY_CMN_CTRL_1, + cfg->timing.lane[4][4], 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL30, + DSIPHY_CMN_GLBL_TEST_CTRL, + DSIPHY_CMN_GLBL_TEST_CTRL, + ((glbl_tst_cntrl) & (~BIT(2))), + ((glbl_tst_cntrl) & (~BIT(2)))); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL31, + DSIPHY_CMN_GLBL_TEST_CTRL, + DSIPHY_CMN_GLBL_TEST_CTRL, + ((glbl_tst_cntrl) & (~BIT(2))), + ((glbl_tst_cntrl) & (~BIT(2)))); + } else { + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL0, + DSIPHY_DLN0_CFG1, DSIPHY_DLN1_CFG1, 0, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL1, + DSIPHY_DLN2_CFG1, DSIPHY_DLN3_CFG1, 0x0, 0x0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL2, + DSIPHY_CKLN_CFG1, DSIPHY_DLN0_TIMING_CTRL_4, + 0x0, cfg->timing.lane[0][0]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL3, + DSIPHY_DLN1_TIMING_CTRL_4, + DSIPHY_DLN2_TIMING_CTRL_4, + cfg->timing.lane[1][0], cfg->timing.lane[2][0]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL4, + DSIPHY_DLN3_TIMING_CTRL_4, + DSIPHY_CKLN_TIMING_CTRL_4, + cfg->timing.lane[3][0], cfg->timing.lane[4][0]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL5, + DSIPHY_DLN0_TIMING_CTRL_5, + DSIPHY_DLN1_TIMING_CTRL_5, + cfg->timing.lane[0][1], cfg->timing.lane[1][1]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL6, + DSIPHY_DLN2_TIMING_CTRL_5, + DSIPHY_DLN3_TIMING_CTRL_5, + cfg->timing.lane[2][1], cfg->timing.lane[3][1]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL7, + DSIPHY_CKLN_TIMING_CTRL_5, + DSIPHY_DLN0_TIMING_CTRL_6, + cfg->timing.lane[4][1], cfg->timing.lane[0][2]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL8, + DSIPHY_DLN1_TIMING_CTRL_6, + DSIPHY_DLN2_TIMING_CTRL_6, + cfg->timing.lane[1][2], cfg->timing.lane[2][2]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL9, + DSIPHY_DLN3_TIMING_CTRL_6, + DSIPHY_CKLN_TIMING_CTRL_6, + cfg->timing.lane[3][2], cfg->timing.lane[4][2]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL10, + DSIPHY_DLN0_TIMING_CTRL_7, + DSIPHY_DLN1_TIMING_CTRL_7, + cfg->timing.lane[0][3], cfg->timing.lane[1][3]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL11, + DSIPHY_DLN2_TIMING_CTRL_7, + DSIPHY_DLN3_TIMING_CTRL_7, + cfg->timing.lane[2][3], cfg->timing.lane[3][3]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL12, + DSIPHY_CKLN_TIMING_CTRL_7, + DSIPHY_DLN0_TIMING_CTRL_8, + cfg->timing.lane[4][3], cfg->timing.lane[0][4]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL13, + DSIPHY_DLN1_TIMING_CTRL_8, + DSIPHY_DLN2_TIMING_CTRL_8, + cfg->timing.lane[1][4], cfg->timing.lane[2][4]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL14, + DSIPHY_DLN3_TIMING_CTRL_8, + DSIPHY_CKLN_TIMING_CTRL_8, + cfg->timing.lane[3][4], cfg->timing.lane[4][4]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL15, + 0x0110, 0x0110, 0, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL16, + 0x0110, 0x0110, 0, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL17, + 0x0110, 0x0110, 0, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL18, + 0x0110, 0x0110, 0, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL19, + 0x0110, 0x0110, 0, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL20, + 0x0110, 0x0110, 0, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL21, + 0x0110, 0x0110, 0, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL22, + 0x0110, 0x0110, 0, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL23, + 0x0110, 0x0110, 0, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL24, + 0x0110, 0x0110, 0, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL25, + 0x0110, 0x0110, 0, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL26, + 0x0110, 0x0110, 0, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL27, + 0x0110, 0x0110, 0, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL28, + 0x0110, 0x0110, 0, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL29, + 0x0110, 0x0110, 0, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL30, + 0x0110, 0x0110, 0, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL31, + 0x0110, 0x0110, 0, 0); + DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_UPPER_ADDR, + 0x0); + DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_UPPER_ADDR2, + 0x0); + } + + wmb(); /* make sure phy timings are updated*/ +} + +void dsi_phy_hw_v2_0_dyn_refresh_pipe_delay(struct dsi_phy_hw *phy, + struct dsi_dyn_clk_delay *delay) +{ + if (!delay) + return; + + DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_PIPE_DELAY, + delay->pipe_delay); + DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_PIPE_DELAY2, + delay->pipe_delay2); + DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_DELAY, + delay->pll_delay); +} + +void dsi_phy_hw_v2_0_dyn_refresh_helper(struct dsi_phy_hw *phy, u32 offset) +{ + u32 reg; + + /* + * if no offset is mentioned then this means we want to clear + * the dynamic refresh ctrl register which is the last step + * of dynamic refresh sequence. + */ + if (!offset) { + reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL); + reg &= ~(BIT(0) | BIT(8)); + DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg); + wmb(); /* ensure dynamic fps is cleared */ + return; + } + + if (offset & BIT(DYN_REFRESH_INTF_SEL)) { + reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL); + reg |= BIT(13); + DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg); + } + + if (offset & BIT(DYN_REFRESH_SWI_CTRL)) { + reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL); + reg |= BIT(0); + DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg); + } + + if (offset & BIT(DYN_REFRESH_SW_TRIGGER)) { + reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL); + reg |= BIT(8); + DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg); + wmb(); /* ensure dynamic fps is triggered */ + } +} + +int dsi_phy_hw_v2_0_cache_phy_timings(struct dsi_phy_per_lane_cfgs *timings, + u32 *dst, u32 size) +{ + int i, j, count = 0; + + if (!timings || !dst || !size) + return -EINVAL; + + if (size != (DSI_LANE_MAX * DSI_MAX_SETTINGS)) { + pr_err("size mis-match\n"); + return -EINVAL; + } + + for (i = DSI_LOGICAL_LANE_0; i < DSI_LANE_MAX; i++) { + for (j = 0; j < DSI_MAX_SETTINGS; j++) { + dst[count] = timings->lane[i][j]; + count++; + } + } + + return 0; +} From 4a85d3152c0274afd2bc52159ea4bf515d086b69 Mon Sep 17 00:00:00 2001 From: Satya Rama Aditya Pinapala Date: Tue, 17 Mar 2020 16:49:03 -0700 Subject: [PATCH 07/16] disp: msm: dsi: Fix porch calculation issue for constant fps For constant fps feature, porch is calculated based on supported clk rates. Currently, data type of local variables used for porch calculation is u32 which leads to incorrect porch calculation for higher clk rates. So, update the data type to u64. Change-Id: I8eb04487d1dcce05989448c0b063e56752af412b Signed-off-by: Lipsa Rout Signed-off-by: Ritesh Kumar Signed-off-by: Satya Rama Aditya Pinapala --- msm/dsi/dsi_display.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index e1a9e8ba2c..5434bf8337 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -5931,7 +5931,7 @@ void dsi_display_adjust_mode_timing( struct dsi_display_mode *dsi_mode, int lanes, int bpp) { - u32 new_htotal, new_vtotal, htotal, vtotal, old_htotal; + u64 new_htotal, new_vtotal, htotal, vtotal, old_htotal, div; if (!dyn_clk_caps->maintain_const_fps) return; @@ -5946,8 +5946,9 @@ void dsi_display_adjust_mode_timing( case DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_HFP: vtotal = DSI_V_TOTAL(&dsi_mode->timing); old_htotal = dsi_h_total_dce(&dsi_mode->timing); - new_htotal = (dsi_mode->timing.clk_rate_hz * lanes); - new_htotal /= (bpp * vtotal * dsi_mode->timing.refresh_rate); + new_htotal = dsi_mode->timing.clk_rate_hz * lanes; + div = bpp * vtotal * dsi_mode->timing.refresh_rate; + do_div(new_htotal, div); if (old_htotal > new_htotal) dsi_mode->timing.h_front_porch -= (old_htotal - new_htotal); @@ -5958,8 +5959,9 @@ void dsi_display_adjust_mode_timing( case DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_VFP: htotal = dsi_h_total_dce(&dsi_mode->timing); - new_vtotal = (dsi_mode->timing.clk_rate_hz * lanes); - new_vtotal /= (bpp * htotal * dsi_mode->timing.refresh_rate); + new_vtotal = dsi_mode->timing.clk_rate_hz * lanes; + div = bpp * htotal * dsi_mode->timing.refresh_rate; + do_div(new_vtotal, div); dsi_mode->timing.v_front_porch = new_vtotal - dsi_mode->timing.v_back_porch - dsi_mode->timing.v_sync_width - From 8fbd145c74d5b0dc284cbe01656f3c253976cbb3 Mon Sep 17 00:00:00 2001 From: Lei Chen Date: Tue, 24 Dec 2019 16:57:45 +0800 Subject: [PATCH 08/16] disp: msm: dsi: update panel mode parsing message for POMS It should not be an error that panel mode isn't specified in timing node, so add this change to lower the log level from error to info. Change-Id: I49bd1fec1c09697d9829a8e0767dfa3cf2cff512 Signed-off-by: Lei Chen Signed-off-by: Satya Rama Aditya Pinapala --- msm/dsi/dsi_panel.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/msm/dsi/dsi_panel.c b/msm/dsi/dsi_panel.c index 407aa4d958..3f45664bea 100644 --- a/msm/dsi/dsi_panel.c +++ b/msm/dsi/dsi_panel.c @@ -3698,9 +3698,11 @@ int dsi_panel_get_mode(struct dsi_panel *panel, if (panel->panel_mode_switch_enabled) { rc = dsi_panel_parse_panel_mode_caps(mode, utils); if (rc) { - DSI_ERR("PMS: failed to parse panel mode\n"); rc = 0; mode->panel_mode = panel->panel_mode; + DSI_INFO( + "POMS: panel mode isn't specified in timing[%d]\n", + child_idx); } } else { mode->panel_mode = panel->panel_mode; From 9652f27293f8bbfbbc11f9171e927a08b19d3b0a Mon Sep 17 00:00:00 2001 From: Dhaval Patel Date: Fri, 27 Dec 2019 11:53:56 -0800 Subject: [PATCH 09/16] disp: msm: avoid esd check during pm_suspend state Avoid esd check during pm_suspend state because core clock enable will fail. This change adds additional check and also adds the clock enable failure check. Change-Id: Ie8bfa4f74d323ff15a07fb037675f07ab942f016 Signed-off-by: Dhaval Patel Signed-off-by: Satya Rama Aditya Pinapala --- msm/dsi/dsi_display.c | 6 ++++-- msm/sde/sde_connector.c | 5 ++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index 5434bf8337..daa0c20a9a 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -801,7 +801,7 @@ int dsi_display_check_status(struct drm_connector *connector, void *display, struct dsi_display *dsi_display = display; struct dsi_panel *panel; u32 status_mode; - int rc = 0x1; + int rc = 0x1, ret; u32 mask; if (!dsi_display || !dsi_display->panel) @@ -839,8 +839,10 @@ int dsi_display_check_status(struct drm_connector *connector, void *display, goto exit; } - dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + ret = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, DSI_ALL_CLKS, DSI_CLK_ON); + if (ret) + goto release_panel_lock; /* Mask error interrupts before attempting ESD read */ mask = BIT(DSI_FIFO_OVERFLOW) | BIT(DSI_FIFO_UNDERFLOW); diff --git a/msm/sde/sde_connector.c b/msm/sde/sde_connector.c index 92e63651ed..240381582e 100644 --- a/msm/sde/sde_connector.c +++ b/msm/sde/sde_connector.c @@ -2167,6 +2167,7 @@ static void sde_connector_check_status_work(struct work_struct *work) { struct sde_connector *conn; int rc = 0; + struct device *dev; conn = container_of(to_delayed_work(work), struct sde_connector, status_work); @@ -2176,7 +2177,9 @@ static void sde_connector_check_status_work(struct work_struct *work) } mutex_lock(&conn->lock); - if (!conn->ops.check_status || + dev = conn->base.dev->dev; + + if (!conn->ops.check_status || dev->power.is_suspended || (conn->dpms_mode != DRM_MODE_DPMS_ON)) { SDE_DEBUG("dpms mode: %d\n", conn->dpms_mode); mutex_unlock(&conn->lock); From fda33778de8da0dfd6c898b3f6362edfacd539e7 Mon Sep 17 00:00:00 2001 From: Lei Chen Date: Fri, 22 Nov 2019 23:38:55 +0800 Subject: [PATCH 10/16] disp: msm: dsi: reject POMS commit with active changed Reject composition if panel mode switch is requested during power on/off commits. Change-Id: I3a5b28fd9f5bd927537824033a1c8dc838366d5b Signed-off-by: Lei Chen Signed-off-by: Satya Rama Aditya Pinapala --- msm/dsi/dsi_drm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/msm/dsi/dsi_drm.c b/msm/dsi/dsi_drm.c index 90f03add80..ac8282305d 100644 --- a/msm/dsi/dsi_drm.c +++ b/msm/dsi/dsi_drm.c @@ -426,6 +426,7 @@ static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge, /* Reject seamless transition when active changed */ if (crtc_state->active_changed && ((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); From 64675ef266b42c398ae3ed477ddaf336432c80db Mon Sep 17 00:00:00 2001 From: Lei Chen Date: Thu, 5 Dec 2019 13:41:47 +0800 Subject: [PATCH 11/16] disp: msm: dsi: add panel mode restriction for DFPS and RFI Add this change to ensure that DFPS and RFI happen in the same panel mode for avoiding unexpected panel mode switch. Change-Id: I6783b320e73a88e8f75cb83bcce85e50f798b6ab Signed-off-by: Lei Chen Signed-off-by: Satya Rama Aditya Pinapala --- msm/dsi/dsi_display.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index daa0c20a9a..1a14941db6 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -6381,7 +6381,8 @@ int dsi_display_validate_mode_change(struct dsi_display *display, mutex_lock(&display->display_lock); dyn_clk_caps = &(display->panel->dyn_clk_caps); if ((cur_mode->timing.v_active == adj_mode->timing.v_active) && - (cur_mode->timing.h_active == adj_mode->timing.h_active)) { + (cur_mode->timing.h_active == adj_mode->timing.h_active) && + (cur_mode->panel_mode == adj_mode->panel_mode)) { /* dfps and dynamic clock with const fps use case */ if (dsi_display_mode_switch_dfps(cur_mode, adj_mode)) { dsi_panel_get_dfps_caps(display->panel, &dfps_caps); From 918f7479ddb7f373234fc27221448df1291822e2 Mon Sep 17 00:00:00 2001 From: Satya Rama Aditya Pinapala Date: Mon, 13 Jan 2020 15:08:55 -0800 Subject: [PATCH 12/16] disp: msm: dsi: do not skip DSI CTRL init for DMS on first frame For command mode panels, if a dynamic mode switch occurs on the first frame, the current code skips DSI controller initialization and registering for error handlers. This causes the software state to be uninitialized for DSI CTRL, resulting in command transfer failures and eventual crash. The change ensures that initialization is complete even if the DMS occurs on first frame. Change-Id: I83e3336f7c09424b6c7b95826c30b37974ec29ab Signed-off-by: Lipsa Rout Signed-off-by: Satya Rama Aditya Pinapala --- msm/dsi/dsi_display.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index 1a14941db6..a8dcb66efb 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -6921,12 +6921,14 @@ int dsi_display_prepare(struct dsi_display *display) goto error; } - /* update dsi ctrl for new mode */ - rc = dsi_display_pre_switch(display); - if (rc) - DSI_ERR("[%s] panel pre-prepare-res-switch failed, rc=%d\n", + if (!display->is_cont_splash_enabled) { + /* update dsi ctrl for new mode */ + rc = dsi_display_pre_switch(display); + if (rc) + DSI_ERR("[%s] panel pre-switch failed, rc=%d\n", display->name, rc); - goto error; + goto error; + } } if (!(mode->dsi_mode_flags & DSI_MODE_FLAG_POMS) && From 294db87b1fdf4f6c885eddbe2d25373db543c962 Mon Sep 17 00:00:00 2001 From: Vara Reddy Date: Tue, 17 Dec 2019 16:50:41 -0800 Subject: [PATCH 13/16] drm/msm/dsi: set cmd dma done mask before triggering cmds Make sure that cmd dma done mask is set before sending dma commands. This will make sure that we don't timeout if the refcnt's are not properly handled. Many oem's have their own customizations around this which maynot handle the refcnt's correctly. Change-Id: If7f5ed1fae20b57f6e9147cae2caa3c5097466c9 Signed-off-by: Vara Reddy Signed-off-by: Satya Rama Aditya Pinapala --- msm/dsi/dsi_ctrl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/msm/dsi/dsi_ctrl.c b/msm/dsi/dsi_ctrl.c index 75bd3bda68..800ee5efa7 100644 --- a/msm/dsi/dsi_ctrl.c +++ b/msm/dsi/dsi_ctrl.c @@ -2677,6 +2677,10 @@ void dsi_ctrl_enable_status_interrupt(struct dsi_ctrl *dsi_ctrl, dsi_ctrl->hw.ops.enable_status_interrupts(&dsi_ctrl->hw, dsi_ctrl->irq_info.irq_stat_mask); } + + if (intr_idx == DSI_SINT_CMD_MODE_DMA_DONE) + dsi_ctrl->hw.ops.enable_status_interrupts(&dsi_ctrl->hw, + dsi_ctrl->irq_info.irq_stat_mask); ++(dsi_ctrl->irq_info.irq_stat_refcount[intr_idx]); if (event_info) From df28b30edf3edc349470d62d507d9b5ef267e90e Mon Sep 17 00:00:00 2001 From: Vara Reddy Date: Tue, 7 Jan 2020 15:24:36 -0800 Subject: [PATCH 14/16] drm/msm/dsi: update recommended non-embedded mode sequence Removing dsi soft reset logic while arbitrating transferring embedded mode and non-embedded dsi commands. This change follows the recommended sequence for kona. Change-Id: I05eef0c6cfd671f48fbfdf7cb2cab788e42bb1e5 Signed-off-by: Vara Reddy Signed-off-by: Satya Rama Aditya Pinapala --- msm/dsi/dsi_ctrl.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/msm/dsi/dsi_ctrl.c b/msm/dsi/dsi_ctrl.c index 800ee5efa7..248e44922a 100644 --- a/msm/dsi/dsi_ctrl.c +++ b/msm/dsi/dsi_ctrl.c @@ -1244,7 +1244,8 @@ static void dsi_kickoff_msg_tx(struct dsi_ctrl *dsi_ctrl, * result in smmu write faults with DSI as client. */ if (flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE) { - dsi_hw_ops.soft_reset(&dsi_ctrl->hw); + if (dsi_ctrl->version < DSI_CTRL_VERSION_2_4) + dsi_hw_ops.soft_reset(&dsi_ctrl->hw); dsi_ctrl->cmd_len = 0; } } @@ -3185,7 +3186,8 @@ int dsi_ctrl_cmd_tx_trigger(struct dsi_ctrl *dsi_ctrl, u32 flags) BIT(DSI_FIFO_OVERFLOW), false); if (flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE) { - dsi_hw_ops.soft_reset(&dsi_ctrl->hw); + if (dsi_ctrl->version < DSI_CTRL_VERSION_2_4) + dsi_hw_ops.soft_reset(&dsi_ctrl->hw); dsi_ctrl->cmd_len = 0; } } From 7d33aeb87e98119adddcc725049ad4a6d388ca88 Mon Sep 17 00:00:00 2001 From: Neeraj Upadhyay Date: Thu, 9 Jan 2020 14:16:44 +0530 Subject: [PATCH 15/16] disp: msm: dsi: Fix compilation error with -fno-builtin removed Fix compilation error observed with -fno-builtin compilation flag removed. Change-Id: I07ac73db206fab3a1b648d7b656e002c6d347b3b Signed-off-by: Neeraj Upadhyay Signed-off-by: Satya Rama Aditya Pinapala --- msm/dsi/dsi_parser.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/msm/dsi/dsi_parser.c b/msm/dsi/dsi_parser.c index fb587c3c36..cef5fe70cf 100644 --- a/msm/dsi/dsi_parser.c +++ b/msm/dsi/dsi_parser.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #include @@ -239,15 +239,18 @@ static bool dsi_parser_parse_prop(struct device *dev, { bool found = false; char *out = strsep(&buf, "="); + size_t buf_len; if (!out || !buf) goto end; - prop->raw = devm_kzalloc(dev, strlen(buf) + 1, GFP_KERNEL); + buf_len = strlen(buf); + + prop->raw = devm_kzalloc(dev, buf_len + 1, GFP_KERNEL); if (!prop->raw) goto end; - strlcpy(prop->raw, buf, strlen(buf) + 1); + strlcpy(prop->raw, buf, buf_len + 1); found = true; From 38425972754927230361151a90acd7db27d953cd Mon Sep 17 00:00:00 2001 From: Lei Chen Date: Thu, 19 Dec 2019 14:34:38 +0800 Subject: [PATCH 16/16] disp: msm: dsi: disallow backlight update during panel mode switch DSI controller and clock will be disabled/enabled during panel mode switch, so disallow backlight update during panel mode switch to avoiding DSI exception. Change-Id: I37e2f3c9aa929555593ffb53950521150ee7698f Signed-off-by: Lei Chen Signed-off-by: Satya Rama Aditya Pinapala --- msm/dsi/dsi_drm.c | 17 +++++++---------- msm/sde/sde_connector.c | 27 ++++++++++++++++----------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/msm/dsi/dsi_drm.c b/msm/dsi/dsi_drm.c index ac8282305d..fbb8aa7a92 100644 --- a/msm/dsi/dsi_drm.c +++ b/msm/dsi/dsi_drm.c @@ -253,6 +253,7 @@ static void dsi_bridge_enable(struct drm_bridge *bridge) static void dsi_bridge_disable(struct drm_bridge *bridge) { int rc = 0; + int private_flags; struct dsi_display *display; struct dsi_bridge *c_bridge = to_dsi_bridge(bridge); @@ -261,18 +262,14 @@ static void dsi_bridge_disable(struct drm_bridge *bridge) return; } display = c_bridge->display; + private_flags = + bridge->encoder->crtc->state->adjusted_mode.private_flags; if (display && display->drm_conn) { - if (bridge->encoder->crtc->state->adjusted_mode.private_flags & - MSM_MODE_FLAG_SEAMLESS_POMS) { - display->poms_pending = true; - /* Disable ESD thread, during panel mode switch */ - sde_connector_schedule_status_work(display->drm_conn, - false); - } else { - display->poms_pending = false; - sde_connector_helper_bridge_disable(display->drm_conn); - } + display->poms_pending = + private_flags & MSM_MODE_FLAG_SEAMLESS_POMS; + + sde_connector_helper_bridge_disable(display->drm_conn); } rc = dsi_display_pre_disable(c_bridge->display); diff --git a/msm/sde/sde_connector.c b/msm/sde/sde_connector.c index 240381582e..4720d6cfaf 100644 --- a/msm/sde/sde_connector.c +++ b/msm/sde/sde_connector.c @@ -94,8 +94,7 @@ static int sde_backlight_device_update_status(struct backlight_device *bd) if (!bl_lvl && brightness) bl_lvl = 1; - if (display->panel->bl_config.bl_update == - BL_UPDATE_DELAY_UNTIL_FIRST_FRAME && !c_conn->allow_bl_update) { + if (!c_conn->allow_bl_update) { c_conn->unset_bl_level = bl_lvl; return 0; } @@ -532,9 +531,7 @@ static int _sde_connector_update_bl_scale(struct sde_connector *c_conn) bl_config = &dsi_display->panel->bl_config; - if (dsi_display->panel->bl_config.bl_update == - BL_UPDATE_DELAY_UNTIL_FIRST_FRAME && - !c_conn->allow_bl_update) { + if (!c_conn->allow_bl_update) { c_conn->unset_bl_level = bl_config->bl_level; return 0; } @@ -797,21 +794,29 @@ void sde_connector_helper_bridge_disable(struct drm_connector *connector) { int rc; struct sde_connector *c_conn = NULL; + struct dsi_display *display; + bool poms_pending = false; if (!connector) return; - rc = _sde_connector_update_dirty_properties(connector); - if (rc) { - SDE_ERROR("conn %d final pre kickoff failed %d\n", - connector->base.id, rc); - SDE_EVT32(connector->base.id, SDE_EVTLOG_ERROR); + c_conn = to_sde_connector(connector); + if (c_conn->connector_type == DRM_MODE_CONNECTOR_DSI) { + display = (struct dsi_display *) c_conn->display; + poms_pending = display->poms_pending; } + if (!poms_pending) { + rc = _sde_connector_update_dirty_properties(connector); + if (rc) { + SDE_ERROR("conn %d final pre kickoff failed %d\n", + connector->base.id, rc); + SDE_EVT32(connector->base.id, SDE_EVTLOG_ERROR); + } + } /* Disable ESD thread */ sde_connector_schedule_status_work(connector, false); - c_conn = to_sde_connector(connector); if (c_conn->bl_device) { c_conn->bl_device->props.power = FB_BLANK_POWERDOWN; c_conn->bl_device->props.state |= BL_CORE_FBBLANK;