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