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); +} diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index e6c03fc7f6c0..255ce9e0cca5 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, @@ -2659,7 +2660,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 +2685,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; @@ -3340,7 +3341,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; @@ -4200,6 +4201,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/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); 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) {