Переглянути джерело

disp: msm: sde: add underrun line count information

Add underrun line count information for each underrun.

Change-Id: I34a740c33240fa8d444f4bbc3b8b014b0282fca1
Signed-off-by: Dhaval Patel <[email protected]>
Dhaval Patel 5 роки тому
батько
коміт
9438f3448b

+ 4 - 0
msm/sde/sde_encoder.c

@@ -2887,12 +2887,16 @@ static void sde_encoder_vblank_callback(struct drm_encoder *drm_enc,
 static void sde_encoder_underrun_callback(struct drm_encoder *drm_enc,
 		struct sde_encoder_phys *phy_enc)
 {
+	struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
 	if (!phy_enc)
 		return;
 
 	SDE_ATRACE_BEGIN("encoder_underrun_callback");
 	atomic_inc(&phy_enc->underrun_cnt);
 	SDE_EVT32(DRMID(drm_enc), atomic_read(&phy_enc->underrun_cnt));
+	if (sde_enc->cur_master->ops.get_underrun_line_count)
+		sde_enc->cur_master->ops.get_underrun_line_count(
+				sde_enc->cur_master);
 
 	trace_sde_encoder_underrun(DRMID(drm_enc),
 		atomic_read(&phy_enc->underrun_cnt));

+ 3 - 0
msm/sde/sde_encoder_phys.h

@@ -133,6 +133,8 @@ struct sde_encoder_virt_ops {
  *                              unitl transaction is complete.
  * @wait_for_active:		Wait for display scan line to be in active area
  * @setup_vsync_source:		Configure vsync source selection for cmd mode.
+ * @get_underrun_line_count:	Obtain and log current internal vertical line
+ *                              count and underrun line count
  */
 
 struct sde_encoder_phys_ops {
@@ -185,6 +187,7 @@ struct sde_encoder_phys_ops {
 	int (*wait_for_active)(struct sde_encoder_phys *phys);
 	void (*setup_vsync_source)(struct sde_encoder_phys *phys,
 			u32 vsync_source, bool is_dummy);
+	u32 (*get_underrun_line_count)(struct sde_encoder_phys *phys);
 };
 
 /**

+ 29 - 0
msm/sde/sde_encoder_phys_vid.c

@@ -1174,6 +1174,33 @@ static int sde_encoder_phys_vid_get_line_count(
 	return phys_enc->hw_intf->ops.get_line_count(phys_enc->hw_intf);
 }
 
+static u32 sde_encoder_phys_vid_get_underrun_line_count(
+		struct sde_encoder_phys *phys_enc)
+{
+	u32 underrun_linecount = 0xebadebad;
+	struct intf_status intf_status = {0};
+
+	if (!phys_enc)
+		return -EINVAL;
+
+	if (!sde_encoder_phys_vid_is_master(phys_enc) || !phys_enc->hw_intf)
+		return -EINVAL;
+
+	if (phys_enc->hw_intf->ops.get_status)
+		phys_enc->hw_intf->ops.get_status(phys_enc->hw_intf,
+			&intf_status);
+
+	if (phys_enc->hw_intf->ops.get_underrun_line_count)
+		underrun_linecount =
+		  phys_enc->hw_intf->ops.get_underrun_line_count(
+			phys_enc->hw_intf);
+
+	SDE_EVT32(DRMID(phys_enc->parent), underrun_linecount,
+		intf_status.frame_count, intf_status.line_count);
+
+	return underrun_linecount;
+}
+
 static int sde_encoder_phys_vid_wait_for_active(
 			struct sde_encoder_phys *phys_enc)
 {
@@ -1268,6 +1295,8 @@ static void sde_encoder_phys_vid_init_ops(struct sde_encoder_phys_ops *ops)
 	ops->wait_dma_trigger = sde_encoder_phys_vid_wait_dma_trigger;
 	ops->wait_for_active = sde_encoder_phys_vid_wait_for_active;
 	ops->prepare_commit = sde_encoder_phys_vid_prepare_for_commit;
+	ops->get_underrun_line_count =
+		sde_encoder_phys_vid_get_underrun_line_count;
 }
 
 struct sde_encoder_phys *sde_encoder_phys_vid_init(

+ 19 - 0
msm/sde/sde_hw_intf.c

@@ -62,6 +62,7 @@
 #define INTF_MISR_SIGNATURE             0x184
 
 #define INTF_MUX                        0x25C
+#define INTF_UNDERRUN_COUNT             0x268
 #define INTF_STATUS                     0x26C
 #define INTF_AVR_CONTROL                0x270
 #define INTF_AVR_MODE                   0x274
@@ -484,6 +485,23 @@ static u32 sde_hw_intf_get_line_count(struct sde_hw_intf *intf)
 	return SDE_REG_READ(c, INTF_LINE_COUNT);
 }
 
+static u32 sde_hw_intf_get_underrun_line_count(struct sde_hw_intf *intf)
+{
+	struct sde_hw_blk_reg_map *c;
+	u32 hsync_period;
+
+	if (!intf)
+		return 0;
+
+	c = &intf->hw;
+	hsync_period = SDE_REG_READ(c, INTF_HSYNC_CTL);
+	hsync_period = ((hsync_period & 0xffff0000) >> 16);
+
+	return hsync_period ?
+		SDE_REG_READ(c, INTF_UNDERRUN_COUNT) / hsync_period :
+		0xebadebad;
+}
+
 static int sde_hw_intf_setup_te_config(struct sde_hw_intf *intf,
 		struct sde_hw_tear_check *te)
 {
@@ -695,6 +713,7 @@ static void _setup_intf_ops(struct sde_hw_intf_ops *ops,
 	ops->setup_misr = sde_hw_intf_setup_misr;
 	ops->collect_misr = sde_hw_intf_collect_misr;
 	ops->get_line_count = sde_hw_intf_get_line_count;
+	ops->get_underrun_line_count = sde_hw_intf_get_underrun_line_count;
 	ops->avr_setup = sde_hw_intf_avr_setup;
 	ops->avr_trigger = sde_hw_intf_avr_trigger;
 	ops->avr_ctrl = sde_hw_intf_avr_ctrl;

+ 3 - 0
msm/sde/sde_hw_intf.h

@@ -68,6 +68,8 @@ struct intf_avr_params {
  * @ setup_misr: enables/disables MISR in HW register
  * @ collect_misr: reads and stores MISR data from HW register
  * @ get_line_count: reads current vertical line counter
+ * @ get_underrun_line_count: reads current underrun pixel clock count and
+ *                            converts it into line count
  * @bind_pingpong_blk: enable/disable the connection with pingpong which will
  *                     feed pixels to this interface
  */
@@ -100,6 +102,7 @@ struct sde_hw_intf_ops {
 	 * is used for command mode panels
 	 */
 	u32 (*get_line_count)(struct sde_hw_intf *intf);
+	u32 (*get_underrun_line_count)(struct sde_hw_intf *intf);
 
 	void (*bind_pingpong_blk)(struct sde_hw_intf *intf,
 			bool enable,