From 497405aaf1235ac2ab2633257cd436372576dd8a Mon Sep 17 00:00:00 2001 From: Mahadevan Date: Thu, 8 Dec 2022 20:57:41 +0530 Subject: [PATCH] disp: msm: sde: wait for a vsync on suspend The current scenario is as follows commit N with autorefresh enabled and frame starts processing. On suspend commit N+1, during virt_disable software resets CTL path after autorefresh config is disabled. Since in hardware frame is still processing sw reset is causing fifo underflow. This change waits for vsync so that current autorefresh frame transaction completes before issuing a CTL_SW_RESET. Change-Id: Ib0662837e54b14cea6ab835a1093a2f048c473be Signed-off-by: Mahadevan Signed-off-by: Akash Gajjar --- msm/sde/sde_encoder.c | 25 ++++++++++++++++++++++++- msm/sde/sde_hw_intf.c | 14 ++++++++++++++ msm/sde/sde_hw_intf.h | 2 ++ 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index c92ee1ad43..e83c0d305d 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -1619,6 +1619,27 @@ static void sde_encoder_control_te(struct sde_encoder_virt *sde_enc, bool enable } } +static void _sde_encoder_wait_for_vsync_on_autorefresh_busy(struct sde_encoder_phys *phys_enc) +{ + u32 autorefresh_status; + int ret = 0; + + if (!phys_enc || !phys_enc->hw_intf || !phys_enc->hw_intf->ops.get_autorefresh_status) { + SDE_ERROR("invalid params\n"); + return; + } + + autorefresh_status = phys_enc->hw_intf->ops.get_autorefresh_status(phys_enc->hw_intf); + if (autorefresh_status) { + ret = sde_encoder_wait_for_event(phys_enc->parent, MSM_ENC_VBLANK); + if (ret) { + autorefresh_status = phys_enc->hw_intf->ops.get_autorefresh_status( + phys_enc->hw_intf); + SDE_ERROR("wait for vblank timed out, autorefresh_status:%d\n", + autorefresh_status); + } + } +} int sde_encoder_helper_switch_vsync(struct drm_encoder *drm_enc, bool watchdog_te) @@ -3694,8 +3715,10 @@ static void sde_encoder_virt_disable(struct drm_encoder *drm_enc) for (i = 0; i < sde_enc->num_phys_encs; i++) { struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; - if (phys && phys->ops.disable_autorefresh) + if (phys && phys->ops.disable_autorefresh) { phys->ops.disable_autorefresh(phys); + _sde_encoder_wait_for_vsync_on_autorefresh_busy(phys); + } } /* wait for idle */ diff --git a/msm/sde/sde_hw_intf.c b/msm/sde/sde_hw_intf.c index 126e273d9e..3a0dc761c5 100644 --- a/msm/sde/sde_hw_intf.c +++ b/msm/sde/sde_hw_intf.c @@ -102,6 +102,7 @@ #define INTF_TEAR_LINE_COUNT 0x2B0 #define INTF_TEAR_AUTOREFRESH_CONFIG 0x2B4 #define INTF_TEAR_TEAR_DETECT_CTRL 0x2B8 +#define INTF_TEAR_AUTOREFRESH_STATUS 0x2C0 #define INTF_TEAR_PROG_FETCH_START 0x2C4 #define INTF_TEAR_DSI_DMA_SCHD_CTRL0 0x2C8 #define INTF_TEAR_DSI_DMA_SCHD_CTRL1 0x2CC @@ -827,6 +828,17 @@ static int sde_hw_intf_get_autorefresh_config(struct sde_hw_intf *intf, return 0; } +static u32 sde_hw_intf_get_autorefresh_status(struct sde_hw_intf *intf) +{ + struct sde_hw_blk_reg_map *c; + u32 val; + + c = &intf->hw; + val = SDE_REG_READ(c, INTF_TEAR_AUTOREFRESH_STATUS); + + return val; +} + static int sde_hw_intf_poll_timeout_wr_ptr(struct sde_hw_intf *intf, u32 timeout_us) { @@ -1095,6 +1107,8 @@ static void _setup_intf_ops(struct sde_hw_intf_ops *ops, ops->get_vsync_info = sde_hw_intf_get_vsync_info; ops->setup_autorefresh = sde_hw_intf_setup_autorefresh_config; ops->get_autorefresh = sde_hw_intf_get_autorefresh_config; + ops->get_autorefresh_status = + sde_hw_intf_get_autorefresh_status; ops->poll_timeout_wr_ptr = sde_hw_intf_poll_timeout_wr_ptr; ops->vsync_sel = sde_hw_intf_vsync_sel; ops->check_and_reset_tearcheck = sde_hw_intf_v1_check_and_reset_tearcheck; diff --git a/msm/sde/sde_hw_intf.h b/msm/sde/sde_hw_intf.h index a051cdd54e..26a8abb8c7 100644 --- a/msm/sde/sde_hw_intf.h +++ b/msm/sde/sde_hw_intf.h @@ -104,6 +104,7 @@ struct intf_wd_jitter_params { * @get_wd_ltj_status: Read WD long term jitter status. * @bind_pingpong_blk: enable/disable the connection with pingpong which will * feed pixels to this interface + * @get_autorefresh_status: Check the status of autorefresh is busy or idle */ struct sde_hw_intf_ops { void (*setup_timing_gen)(struct sde_hw_intf *intf, @@ -147,6 +148,7 @@ struct sde_hw_intf_ops { void (*bind_pingpong_blk)(struct sde_hw_intf *intf, bool enable, const enum sde_pingpong pp); + u32 (*get_autorefresh_status)(struct sde_hw_intf *intf); /** * enables vysnc generation and sets up init value of