diff --git a/msm/sde/sde_crtc.c b/msm/sde/sde_crtc.c index e4d3728490..d50bb11f10 100644 --- a/msm/sde/sde_crtc.c +++ b/msm/sde/sde_crtc.c @@ -388,6 +388,8 @@ static ssize_t vsync_event_show(struct device *device, { struct drm_crtc *crtc; struct sde_crtc *sde_crtc; + struct drm_encoder *encoder; + int avr_status = -EPIPE; if (!device || !buf) { SDE_ERROR("invalid input param(s)\n"); @@ -396,8 +398,21 @@ static ssize_t vsync_event_show(struct device *device, crtc = dev_get_drvdata(device); sde_crtc = to_sde_crtc(crtc); - return scnprintf(buf, PAGE_SIZE, "VSYNC=%llu\n", - ktime_to_ns(sde_crtc->vblank_last_cb_time)); + + mutex_lock(&sde_crtc->crtc_lock); + if (sde_crtc->enabled) { + drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) { + if (sde_encoder_in_clone_mode(encoder)) + continue; + + avr_status = sde_encoder_get_avr_status(encoder); + break; + } + } + mutex_unlock(&sde_crtc->crtc_lock); + + return scnprintf(buf, PAGE_SIZE, "VSYNC=%llu\nAVR_STATUS=%d\n", + ktime_to_ns(sde_crtc->vblank_last_cb_time), avr_status); } static ssize_t retire_frame_event_show(struct device *device, diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index ba2bc45722..0c5c4fc980 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -4378,6 +4378,27 @@ void sde_encoder_get_transfer_time(struct drm_encoder *drm_enc, *transfer_time_us = info->mdp_transfer_time_us; } +int sde_encoder_get_avr_status(struct drm_encoder *drm_enc) +{ + struct sde_encoder_virt *sde_enc; + struct sde_encoder_phys *master; + bool is_vid_mode; + + if (!drm_enc) + return -EINVAL; + + sde_enc = to_sde_encoder_virt(drm_enc); + master = sde_enc->cur_master; + is_vid_mode = sde_encoder_check_curr_mode(drm_enc, MSM_DISPLAY_CAP_VID_MODE); + if (!master || !is_vid_mode || !sde_connector_get_qsync_mode(master->connector)) + return -ENODATA; + + if (!master->hw_intf->ops.get_avr_status) + return -EOPNOTSUPP; + + return master->hw_intf->ops.get_avr_status(master->hw_intf); +} + int sde_encoder_helper_reset_mixers(struct sde_encoder_phys *phys_enc, struct drm_framebuffer *fb) { diff --git a/msm/sde/sde_encoder.h b/msm/sde/sde_encoder.h index a496726ef0..54d0a6eee5 100644 --- a/msm/sde/sde_encoder.h +++ b/msm/sde/sde_encoder.h @@ -392,6 +392,12 @@ enum sde_intf_mode sde_encoder_get_intf_mode(struct drm_encoder *encoder); */ u32 sde_encoder_get_frame_count(struct drm_encoder *encoder); +/** + * sde_encoder_get_avr_status - get combined avr_status from all intfs for given virt encoder + * @drm_enc: Pointer to drm encoder structure + */ +int sde_encoder_get_avr_status(struct drm_encoder *drm_enc); + /* * sde_encoder_get_vblank_timestamp - get the last vsync timestamp * @encoder: Pointer to drm encoder object diff --git a/msm/sde/sde_hw_catalog.c b/msm/sde/sde_hw_catalog.c index 7a9831a49a..7ba228ce1f 100644 --- a/msm/sde/sde_hw_catalog.c +++ b/msm/sde/sde_hw_catalog.c @@ -2431,6 +2431,7 @@ static int sde_intf_parse_dt(struct device_node *np, set_bit(SDE_INTF_WD_TIMER, &intf->features); set_bit(SDE_INTF_RESET_COUNTER, &intf->features); set_bit(SDE_INTF_VSYNC_TIMESTAMP, &intf->features); + set_bit(SDE_INTF_AVR_STATUS, &intf->features); } } diff --git a/msm/sde/sde_hw_catalog.h b/msm/sde/sde_hw_catalog.h index 973e4079b9..02ebdfe511 100644 --- a/msm/sde/sde_hw_catalog.h +++ b/msm/sde/sde_hw_catalog.h @@ -508,6 +508,7 @@ enum { * @SDE_INTF_STATUS INTF block has INTF_STATUS register * @SDE_INTF_RESET_COUNTER INTF block has frame/line counter reset support * @SDE_INTF_VSYNC_TIMESTAMP INTF block has vsync timestamp logged + * @SDE_INTF_AVR_STATUS INTF block has AVR_STATUS field in AVR_CONTROL register * @SDE_INTF_MAX */ enum { @@ -518,6 +519,7 @@ enum { SDE_INTF_STATUS, SDE_INTF_RESET_COUNTER, SDE_INTF_VSYNC_TIMESTAMP, + SDE_INTF_AVR_STATUS, SDE_INTF_MAX }; diff --git a/msm/sde/sde_hw_intf.c b/msm/sde/sde_hw_intf.c index 3644570c3e..e0652c7d68 100644 --- a/msm/sde/sde_hw_intf.c +++ b/msm/sde/sde_hw_intf.c @@ -184,6 +184,20 @@ static void sde_hw_intf_avr_ctrl(struct sde_hw_intf *ctx, SDE_REG_WRITE(c, INTF_AVR_MODE, avr_mode); } +static u32 sde_hw_intf_get_avr_status(struct sde_hw_intf *ctx) +{ + struct sde_hw_blk_reg_map *c; + u32 avr_ctrl; + + if (!ctx) + return false; + + c = &ctx->hw; + avr_ctrl = SDE_REG_READ(c, INTF_AVR_CONTROL); + + return avr_ctrl >> 31; +} + static inline void _check_and_set_comp_bit(struct sde_hw_intf *ctx, bool dsc_4hs_merge, bool compression_en, u32 *intf_cfg2) { @@ -868,6 +882,9 @@ static void _setup_intf_ops(struct sde_hw_intf_ops *ops, if (cap & BIT(SDE_INTF_WD_TIMER)) ops->setup_vsync_source = sde_hw_intf_setup_vsync_source; + if (cap & BIT(SDE_INTF_AVR_STATUS)) + ops->get_avr_status = sde_hw_intf_get_avr_status; + if (cap & BIT(SDE_INTF_TE)) { ops->setup_tearcheck = sde_hw_intf_setup_te_config; ops->enable_tearcheck = sde_hw_intf_enable_te; diff --git a/msm/sde/sde_hw_intf.h b/msm/sde/sde_hw_intf.h index dfc631f77e..1867d79a31 100644 --- a/msm/sde/sde_hw_intf.h +++ b/msm/sde/sde_hw_intf.h @@ -194,6 +194,13 @@ struct sde_hw_intf_ops { void (*avr_ctrl)(struct sde_hw_intf *intf, const struct intf_avr_params *avr_params); + /** + * Indicates the AVR armed status + * + * @return: false if a trigger is pending, else true while AVR is enabled + */ + u32 (*get_avr_status)(struct sde_hw_intf *intf); + /** * Enable/disable 64 bit compressed data input to interface block */