From a63678a17273760d0588b3d83b3cc9afa3ef913d Mon Sep 17 00:00:00 2001 From: Rajeev Nandan Date: Tue, 1 Mar 2022 18:10:50 +0530 Subject: [PATCH 1/5] disp: msm: dsi: Fix DMA window scheduling programming In DMA start window scheduling, TRIG_CTRL.COMMAND_MODE_DMA_TRIGGER_SEL is programmed to SW + DMA start window trigger. But if DMS switch comes after command is scheduled, COMMAND_MODE_DMA_TRIGGER_SEL gets reprogrammed to SW trigger leading to command transfer failure. Program the COMMAND_MODE_DMA_TRIGGER_SEL only from the CMD DMA Tx path. Change-Id: I01062497bb70aa5fdcb25be3715c7cbc4c68b681 Signed-off-by: Ritesh Kumar Signed-off-by: Rajeev Nandan --- msm/dsi/dsi_catalog.c | 3 ++- msm/dsi/dsi_catalog.h | 4 +++- msm/dsi/dsi_ctrl.c | 5 +++++ msm/dsi/dsi_ctrl_hw.h | 10 ++++++++++ msm/dsi/dsi_ctrl_hw_2_2.c | 11 +++++++---- msm/dsi/dsi_ctrl_hw_cmn.c | 29 ++++++++++++++++++++++++++--- 6 files changed, 53 insertions(+), 9 deletions(-) diff --git a/msm/dsi/dsi_catalog.c b/msm/dsi/dsi_catalog.c index 44a366fb140e..abfff0c593f5 100644 --- a/msm/dsi/dsi_catalog.c +++ b/msm/dsi/dsi_catalog.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. - * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -66,6 +66,7 @@ static void dsi_catalog_cmn_init(struct dsi_ctrl_hw *ctrl, dsi_ctrl_hw_cmn_wait4dynamic_refresh_done; ctrl->ops.hs_req_sel = dsi_ctrl_hw_cmn_hs_req_sel; ctrl->ops.vid_engine_busy = dsi_ctrl_hw_cmn_vid_engine_busy; + ctrl->ops.init_cmddma_trig_ctrl = dsi_ctrl_hw_cmn_init_cmddma_trig_ctrl; switch (version) { case DSI_CTRL_VERSION_1_4: diff --git a/msm/dsi/dsi_catalog.h b/msm/dsi/dsi_catalog.h index a35206c94f8c..ae035e6ff9b0 100644 --- a/msm/dsi/dsi_catalog.h +++ b/msm/dsi/dsi_catalog.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. - * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _DSI_CATALOG_H_ @@ -214,6 +214,8 @@ void dsi_ctrl_hw_cmn_error_intr_ctrl(struct dsi_ctrl_hw *ctrl, bool en); u32 dsi_ctrl_hw_cmn_get_error_mask(struct dsi_ctrl_hw *ctrl); u32 dsi_ctrl_hw_cmn_get_hw_version(struct dsi_ctrl_hw *ctrl); int dsi_ctrl_hw_cmn_wait_for_cmd_mode_mdp_idle(struct dsi_ctrl_hw *ctrl); +void dsi_ctrl_hw_cmn_init_cmddma_trig_ctrl(struct dsi_ctrl_hw *ctrl, + struct dsi_host_common_cfg *cfg); /* Definitions specific to 1.4 DSI controller hardware */ int dsi_ctrl_hw_14_wait_for_lane_idle(struct dsi_ctrl_hw *ctrl, u32 lanes); diff --git a/msm/dsi/dsi_ctrl.c b/msm/dsi/dsi_ctrl.c index c3846c19a067..7a5f3335e9b0 100644 --- a/msm/dsi/dsi_ctrl.c +++ b/msm/dsi/dsi_ctrl.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -1356,6 +1357,10 @@ static void dsi_kickoff_msg_tx(struct dsi_ctrl *dsi_ctrl, dsi_hw_ops.reset_trig_ctrl(&dsi_ctrl->hw, &dsi_ctrl->host_config.common_config); + if (dsi_hw_ops.init_cmddma_trig_ctrl) + dsi_hw_ops.init_cmddma_trig_ctrl(&dsi_ctrl->hw, + &dsi_ctrl->host_config.common_config); + /* * Always enable DMA scheduling for video mode panel. * diff --git a/msm/dsi/dsi_ctrl_hw.h b/msm/dsi/dsi_ctrl_hw.h index 8bbcf552a99c..3de278c7ba14 100644 --- a/msm/dsi/dsi_ctrl_hw.h +++ b/msm/dsi/dsi_ctrl_hw.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _DSI_CTRL_HW_H_ @@ -866,6 +867,15 @@ struct dsi_ctrl_hw_ops { void (*reset_trig_ctrl)(struct dsi_ctrl_hw *ctrl, struct dsi_host_common_cfg *cfg); + /** + * hw.ops.init_cmddma_trig_ctrl() - Initialize the default trigger used + * for command mode DMA path. + * @ctrl: Pointer to the controller host hardware. + * @cfg: Common configuration parameters. + */ + void (*init_cmddma_trig_ctrl)(struct dsi_ctrl_hw *ctrl, + struct dsi_host_common_cfg *cfg); + /** * hw.ops.log_line_count() - reads the MDP interface line count * registers. diff --git a/msm/dsi/dsi_ctrl_hw_2_2.c b/msm/dsi/dsi_ctrl_hw_2_2.c index 5ae0929e09a0..99579f058d9f 100644 --- a/msm/dsi/dsi_ctrl_hw_2_2.c +++ b/msm/dsi/dsi_ctrl_hw_2_2.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. */ #include #include "dsi_ctrl_hw.h" @@ -243,14 +244,16 @@ void dsi_ctrl_hw_22_configure_cmddma_window(struct dsi_ctrl_hw *ctrl, void dsi_ctrl_hw_22_reset_trigger_controls(struct dsi_ctrl_hw *ctrl, struct dsi_host_common_cfg *cfg) { - u32 reg = 0; + u32 reg; const u8 trigger_map[DSI_TRIGGER_MAX] = { 0x0, 0x2, 0x1, 0x4, 0x5, 0x6 }; - reg |= (cfg->te_mode == DSI_TE_ON_EXT_PIN) ? BIT(31) : 0; - reg |= (trigger_map[cfg->dma_cmd_trigger] & 0x7); - reg |= (trigger_map[cfg->mdp_cmd_trigger] & 0x7) << 4; + reg = DSI_R32(ctrl, DSI_TRIG_CTRL); + reg &= ~BIT(16); /* Reset DMA_TRG_MUX */ + reg &= ~(0xF); /* Reset DMA_TRIGGER_SEL */ + reg |= (trigger_map[cfg->dma_cmd_trigger] & 0xF); DSI_W32(ctrl, DSI_TRIG_CTRL, reg); + DSI_W32(ctrl, DSI_DMA_SCHEDULE_CTRL2, 0x0); DSI_W32(ctrl, DSI_DMA_SCHEDULE_CTRL, 0x0); ctrl->reset_trig_ctrl = false; diff --git a/msm/dsi/dsi_ctrl_hw_cmn.c b/msm/dsi/dsi_ctrl_hw_cmn.c index dceee163c15e..df9954da0454 100644 --- a/msm/dsi/dsi_ctrl_hw_cmn.c +++ b/msm/dsi/dsi_ctrl_hw_cmn.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -86,13 +87,20 @@ static void dsi_split_link_setup(struct dsi_ctrl_hw *ctrl, static void dsi_setup_trigger_controls(struct dsi_ctrl_hw *ctrl, struct dsi_host_common_cfg *cfg) { - u32 reg = 0; + u32 reg; const u8 trigger_map[DSI_TRIGGER_MAX] = { 0x0, 0x2, 0x1, 0x4, 0x5, 0x6 }; - reg |= (cfg->te_mode == DSI_TE_ON_EXT_PIN) ? BIT(31) : 0; - reg |= (trigger_map[cfg->dma_cmd_trigger] & 0x7); + reg = DSI_R32(ctrl, DSI_TRIG_CTRL); + + if (cfg->te_mode == DSI_TE_ON_EXT_PIN) + reg |= BIT(31); + else + reg &= ~BIT(31); + + reg &= ~(0x7 << 4); reg |= (trigger_map[cfg->mdp_cmd_trigger] & 0x7) << 4; + DSI_W32(ctrl, DSI_TRIG_CTRL, reg); } @@ -1741,3 +1749,18 @@ bool dsi_ctrl_hw_cmn_vid_engine_busy(struct dsi_ctrl_hw *ctrl) return false; } + +void dsi_ctrl_hw_cmn_init_cmddma_trig_ctrl(struct dsi_ctrl_hw *ctrl, + struct dsi_host_common_cfg *cfg) +{ + u32 reg; + const u8 trigger_map[DSI_TRIGGER_MAX] = { + 0x0, 0x2, 0x1, 0x4, 0x5, 0x6 }; + + /* Initialize the default trigger used for Command Mode DMA path. */ + reg = DSI_R32(ctrl, DSI_TRIG_CTRL); + reg &= ~BIT(16); /* Reset DMA_TRG_MUX */ + reg &= ~(0xF); /* Reset DMA_TRIGGER_SEL */ + reg |= (trigger_map[cfg->dma_cmd_trigger] & 0xF); + DSI_W32(ctrl, DSI_TRIG_CTRL, reg); +} From 9e5185ad698f9bf09632508a227d93f7c885d649 Mon Sep 17 00:00:00 2001 From: Kashish Jain Date: Wed, 2 Mar 2022 15:24:41 +0530 Subject: [PATCH 2/5] disp: msm: dsi: handle panel detection after a pp done timeout It has been observed that TE check may fail even if status read is passing. Panel detection should be successful only if both TE check and register read (if supported) pass. Change-Id: I8d2c5d4139561fe533fc148124b7dde54b63c24e Signed-off-by: Kashish Jain --- msm/dsi/dsi_display.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index e6c03fc7f6c0..de15e02389a8 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -885,16 +885,17 @@ int dsi_display_check_status(struct drm_connector *connector, void *display, panel->esd_config.esd_enabled = false; } - if (rc <= 0 && te_check_override) + /* + * TE check may fail even if status read is passing. In case of + * te_check_override, check the status both from reg read and TE. + */ + if (rc > 0 && te_check_override) rc = dsi_display_status_check_te(dsi_display, te_rechecks); /* Unmask error interrupts if check passed*/ if (rc > 0) { dsi_display_set_ctrl_esd_check_flag(dsi_display, false); dsi_display_mask_ctrl_error_interrupts(dsi_display, mask, false); - if (te_check_override && panel->esd_config.esd_enabled == false) - rc = dsi_display_status_check_te(dsi_display, - te_rechecks); } dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, From 9a6ed8620ef75cd7162fc73e63402c25bea8466f Mon Sep 17 00:00:00 2001 From: Venkata Prahlad Valluru Date: Tue, 12 Apr 2022 22:36:32 +0530 Subject: [PATCH 3/5] disp: msm: sde: unset and set clk parents during pm_suspend Currently link clk parent set/unset are done as part of dsi_prepare and dsi_unprepare, but in case of deepsleep with display ON, these will not be called. Due to mismatch in parent between clk framework and actual parent, subsequent clk_set_parent will early return without setting the parent. To avoid this condition, do set parent to xo, as part of pm_suspend and restore to link clk source in pm_resume. Change-Id: I626899304580f9d9fbcc92cd8b139cd89cd48999 Signed-off-by: Venkata Prahlad Valluru --- msm/dsi/dsi_display.c | 9 ++++++--- msm/dsi/dsi_display.h | 16 +++++++++++++++ msm/sde/sde_kms.c | 45 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 3 deletions(-) diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index e6c03fc7f6c0..1d6aa9ba0a66 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -2659,7 +2659,7 @@ error: } #ifdef CONFIG_DEEPSLEEP -static int dsi_display_unset_clk_src(struct dsi_display *display) +int dsi_display_unset_clk_src(struct dsi_display *display) { int rc = 0; int i; @@ -2684,13 +2684,13 @@ static int dsi_display_unset_clk_src(struct dsi_display *display) return 0; } #else -static inline int dsi_display_unset_clk_src(struct dsi_display *display) +inline int dsi_display_unset_clk_src(struct dsi_display *display) { return 0; } #endif -static int dsi_display_set_clk_src(struct dsi_display *display) +int dsi_display_set_clk_src(struct dsi_display *display) { int rc = 0; int i; @@ -4200,6 +4200,9 @@ static int dsi_display_parse_dt(struct dsi_display *display) /* Parse TE data */ dsi_display_parse_te_data(display); + display->needs_clk_src_reset = of_property_read_bool(of_node, + "qcom,needs-clk-src-reset"); + /* Parse all external bridges from port 0 */ display_for_each_ctrl(i, display) { display->ext_bridge[i].node_of = diff --git a/msm/dsi/dsi_display.h b/msm/dsi/dsi_display.h index e2932a0d530d..cac84cd6a8a8 100644 --- a/msm/dsi/dsi_display.h +++ b/msm/dsi/dsi_display.h @@ -214,6 +214,7 @@ struct dsi_display { int disp_te_gpio; bool is_te_irq_enabled; struct completion esd_te_gate; + bool needs_clk_src_reset; u32 ctrl_count; struct dsi_display_ctrl ctrl[MAX_DSI_CTRLS_PER_DISPLAY]; @@ -801,4 +802,19 @@ int dsi_display_dump_clks_state(struct dsi_display *display); */ void dsi_display_dfps_update_parent(struct dsi_display *display); +/** + * dsi_display_unset_clk_src() - reset the clocks source to default + * @display: Handle to display + * + * Return: Zero on Success + */ +int dsi_display_unset_clk_src(struct dsi_display *display); + +/** + * dsi_display_set_clk_src() - set the clocks source + * @display: Handle to display + * + * Return: Zero on Success + */ +int dsi_display_set_clk_src(struct dsi_display *display); #endif /* _DSI_DISPLAY_H_ */ diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c index b9609ec6fc0f..9a11a6654f8f 100644 --- a/msm/sde/sde_kms.c +++ b/msm/sde/sde_kms.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -3713,6 +3714,44 @@ void sde_kms_display_early_wakeup(struct drm_device *dev, drm_connector_list_iter_end(&conn_iter); } +#ifdef CONFIG_DEEPSLEEP +static int _sde_kms_pm_set_clk_src(struct sde_kms *sde_kms, bool enable) +{ + int i, rc = 0; + void *display; + struct dsi_display *dsi_display; + + if (mem_sleep_current == PM_SUSPEND_MEM) { + SDE_INFO("Deepsleep\n"); + + for (i = 0; i < sde_kms->dsi_display_count; i++) { + display = sde_kms->dsi_displays[i]; + dsi_display = (struct dsi_display *)display; + + if (!dsi_display->needs_clk_src_reset) + continue; + + if (enable) + rc = dsi_display_set_clk_src(dsi_display); + else + rc = dsi_display_unset_clk_src(dsi_display); + + if (rc) { + SDE_ERROR("failed to set clks rc:%d\n", rc); + return rc; + } + } + } + + return rc; +} +#else +static inline int _sde_kms_pm_set_clk_src(struct sde_kms *sde_kms, bool enable) +{ + return 0; +} +#endif + static void _sde_kms_pm_suspend_idle_helper(struct sde_kms *sde_kms, struct device *dev) { @@ -3904,6 +3943,9 @@ unlock: pm_runtime_put_sync(dev); pm_runtime_get_noresume(dev); + /* reset clock source based on PM suspend state */ + _sde_kms_pm_set_clk_src(sde_kms, false); + /* dump clock state before entering suspend */ if (sde_kms->pm_suspend_clk_dump) _sde_kms_dump_clks_state(sde_kms); @@ -3941,6 +3983,9 @@ retry: goto end; } + /* reset clock source based on PM suspend state */ + _sde_kms_pm_set_clk_src(sde_kms, true); + sde_kms->suspend_block = false; if (sde_kms->suspend_state) { From 43cb27c18710ee7746c2fa6fd592f24d72b440ec Mon Sep 17 00:00:00 2001 From: Srihitha Tangudu Date: Tue, 12 Apr 2022 12:52:02 +0530 Subject: [PATCH 4/5] disp: msm: dsi: handle read cmd tx failure from dsi host transfer Currently we are handling only write command transfer failures from dsi host transfer path. Modify check to handle read command transfer failures. Change-Id: Iee1dbf46a4374819e6d6425eb5acece8ec1fb8b1 Signed-off-by: Srihitha Tangudu --- msm/dsi/dsi_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index e6c03fc7f6c0..dc297f78093d 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -3340,7 +3340,7 @@ static ssize_t dsi_host_transfer(struct mipi_dsi_host *host, rc = dsi_ctrl_cmd_transfer(display->ctrl[ctrl_idx].ctrl, msg, &cmd_flags); - if (rc) { + if (rc < 0) { DSI_ERR("[%s] cmd transfer failed, rc=%d\n", display->name, rc); goto error_disable_cmd_engine; From 2b8416530035b98895acc05de9ef21e685a55017 Mon Sep 17 00:00:00 2001 From: Sai Srujana Oruganti Date: Mon, 18 Apr 2022 15:38:49 +0530 Subject: [PATCH 5/5] disp: msm: dsi: avoid setting ulp load to disable load When there is no ulp load entry, ulp load should be set to enable load. Change-Id: I531108b4d2137cf9262874bc411ff06592302374 Signed-off-by: Sai Srujana Oruganti --- msm/dsi/dsi_pwr.c | 1 - 1 file changed, 1 deletion(-) diff --git a/msm/dsi/dsi_pwr.c b/msm/dsi/dsi_pwr.c index 44bb745ad275..4dee0409d87c 100644 --- a/msm/dsi/dsi_pwr.c +++ b/msm/dsi/dsi_pwr.c @@ -68,7 +68,6 @@ static int dsi_pwr_parse_supply_node(struct dsi_parser_utils *utils, rc = utils->read_u32(node, "qcom,supply-ulp-load", &tmp); if (rc) { DSI_DEBUG("ulp-load not specified\n"); - rc = 0; } regs->vregs[i].ulp_load = (!rc ? tmp : regs->vregs[i].enable_load);