소스 검색

disp: msm: sde: report AVR_STATUS in vsync_event sysfs node

Report the AVR_STATUS which indicates if there's a pending
trigger when Adaptive Variable Refresh feature is enabled.
This allows SW to detect whether the old frame is repeated
or if the new frame was taken when the trigger is very
close to Vsync.

Change-Id: I6b04482e5c4c3bb92bad426c529c1fd3612d41c3
Signed-off-by: Steve Cohen <[email protected]>
Steve Cohen 4 년 전
부모
커밋
61e6723732
7개의 변경된 파일71개의 추가작업 그리고 2개의 파일을 삭제
  1. 17 2
      msm/sde/sde_crtc.c
  2. 21 0
      msm/sde/sde_encoder.c
  3. 6 0
      msm/sde/sde_encoder.h
  4. 1 0
      msm/sde/sde_hw_catalog.c
  5. 2 0
      msm/sde/sde_hw_catalog.h
  6. 17 0
      msm/sde/sde_hw_intf.c
  7. 7 0
      msm/sde/sde_hw_intf.h

+ 17 - 2
msm/sde/sde_crtc.c

@@ -387,6 +387,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");
@@ -395,8 +397,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,

+ 21 - 0
msm/sde/sde_encoder.c

@@ -4374,6 +4374,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)
 {

+ 6 - 0
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

+ 1 - 0
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);
 		}
 	}
 

+ 2 - 0
msm/sde/sde_hw_catalog.h

@@ -506,6 +506,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 {
@@ -516,6 +517,7 @@ enum {
 	SDE_INTF_STATUS,
 	SDE_INTF_RESET_COUNTER,
 	SDE_INTF_VSYNC_TIMESTAMP,
+	SDE_INTF_AVR_STATUS,
 	SDE_INTF_MAX
 };
 

+ 17 - 0
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;

+ 7 - 0
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
 	 */