From 32509a98153e65061d347751d9a436f155a19365 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: I79fa81531d9f479d84d3873b5e855fcd73dc88c3 Signed-off-by: Mahadevan --- msm/sde/sde_encoder.c | 24 +++++++++++++++++++++++- msm/sde/sde_hw_intf.c | 14 ++++++++++++++ msm/sde/sde_hw_intf.h | 2 ++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index acb746a9..e3b64b70 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -1449,7 +1449,27 @@ static void _sde_encoder_update_vsync_source(struct sde_encoder_virt *sde_enc, } } +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) @@ -3258,8 +3278,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 23c8299f..c10c175b 100644 --- a/msm/sde/sde_hw_intf.c +++ b/msm/sde/sde_hw_intf.c @@ -97,6 +97,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 static struct sde_intf_cfg *_intf_offset(enum sde_intf intf, struct sde_mdss_cfg *m, @@ -739,6 +740,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) { @@ -964,6 +976,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 = diff --git a/msm/sde/sde_hw_intf.h b/msm/sde/sde_hw_intf.h index f33ac1dc..d97bff0a 100644 --- a/msm/sde/sde_hw_intf.h +++ b/msm/sde/sde_hw_intf.h @@ -95,6 +95,7 @@ struct intf_wd_jitter_params { * @configure_wd_jitter: Configure WD jitter. * @bind_pingpong_blk: enable/disable the connection with pingpong which will * feed pixels to this interface + * @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, @@ -134,6 +135,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