浏览代码

disp: msm: sde: expose early-wb-fence option for 2-pass composition

Add a writeback connector property EARLY-FENCE-LINE to give usermode
the control on when to trigger the retire fence. This option is useful
in 2-pass composition, where the writeback triggers the retire-fence
early based on the prog-line which allows primary to start the fetch
before wb transaction is fully completed. This helps to keep the clks
and bw low. WB hardware generates the line-ptr-irq when wb output reaches
the configured prog-line. Retire fence is triggered based on the irq by
default and wb-done handles for cases where line-ptr-irq is missed.

Change-Id: I20867979693dc3447f77da24cd7e88305947fb6d
Signed-off-by: Veera Sundaram Sankaran <[email protected]>
Veera Sundaram Sankaran 4 年之前
父节点
当前提交
762252400d
共有 4 个文件被更改,包括 79 次插入8 次删除
  1. 1 0
      msm/msm_drv.h
  2. 2 0
      msm/sde/sde_encoder_phys.h
  3. 72 8
      msm/sde/sde_encoder_phys_wb.c
  4. 4 0
      msm/sde/sde_wb.c

+ 1 - 0
msm/msm_drv.h

@@ -218,6 +218,7 @@ enum msm_mdp_conn_property {
 	CONNECTOR_PROP_DYN_BIT_CLK,
 	CONNECTOR_PROP_DIMMING_CTRL,
 	CONNECTOR_PROP_DIMMING_MIN_BL,
+	CONNECTOR_PROP_EARLY_FENCE_LINE,
 
 	/* enum/bitmask properties */
 	CONNECTOR_PROP_TOPOLOGY_NAME,

+ 2 - 0
msm/sde/sde_encoder_phys.h

@@ -437,6 +437,7 @@ struct sde_encoder_phys_cmd {
  * @bo_disable:		Buffer object(s) to use during the disabling state
  * @fb_disable:		Frame buffer to use during the disabling state
  * @crtc		Pointer to drm_crtc
+ * @prog_line:		Cached programmable line value used to trigger early wb-fence
  */
 struct sde_encoder_phys_wb {
 	struct sde_encoder_phys base;
@@ -455,6 +456,7 @@ struct sde_encoder_phys_wb {
 	struct drm_gem_object *bo_disable[SDE_MAX_PLANES];
 	struct drm_framebuffer *fb_disable;
 	struct drm_crtc *crtc;
+	u32 prog_line;
 };
 
 /**

+ 72 - 8
msm/sde/sde_encoder_phys_wb.c

@@ -682,7 +682,7 @@ static int _sde_enc_phys_wb_validate_cwb(struct sde_encoder_phys *phys_enc,
 	int out_width = 0, out_height = 0;
 	int ds_srcw = 0, ds_srch = 0, ds_outw = 0, ds_outh = 0;
 	const struct sde_format *fmt;
-	int data_pt;
+	int data_pt, prog_line;
 	int ds_in_use = false;
 	int i = 0;
 	int ret = 0;
@@ -710,6 +710,12 @@ static int _sde_enc_phys_wb_validate_cwb(struct sde_encoder_phys *phys_enc,
 		return -EINVAL;
 	}
 
+	prog_line = sde_connector_get_property(conn_state, CONNECTOR_PROP_EARLY_FENCE_LINE);
+	if (prog_line) {
+		SDE_ERROR("early fence not supported with CWB, prog_line:%d\n", prog_line);
+		return -EINVAL;
+	}
+
 	data_pt = sde_crtc_get_property(cstate, CRTC_PROP_CAPTURE_OUTPUT);
 
 	/* compute cumulative ds output dimensions if in use */
@@ -1139,6 +1145,24 @@ static void _sde_encoder_phys_wb_update_flush(struct sde_encoder_phys *phys_enc)
 			hw_wb->idx - WB_0);
 }
 
+static void _sde_encoder_phys_wb_setup_prog_line(struct sde_encoder_phys *phys_enc)
+{
+	struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
+	struct sde_wb_device *wb_dev = wb_enc->wb_dev;
+	struct drm_connector_state *state = wb_dev->connector->state;
+	struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
+	u32 prog_line;
+
+	if (phys_enc->in_clone_mode || !hw_wb->ops.set_prog_line_count)
+		return;
+
+	prog_line = sde_connector_get_property(state, CONNECTOR_PROP_EARLY_FENCE_LINE);
+	if (wb_enc->prog_line != prog_line) {
+		wb_enc->prog_line = prog_line;
+		hw_wb->ops.set_prog_line_count(hw_wb, prog_line);
+	}
+}
+
 /**
  * sde_encoder_phys_wb_setup - setup writeback encoder
  * @phys_enc:	Pointer to physical encoder
@@ -1213,12 +1237,16 @@ static void sde_encoder_phys_wb_setup(
 	sde_encoder_phys_wb_setup_cdp(phys_enc, wb_enc->wb_fmt);
 
 	_sde_encoder_phys_wb_setup_cwb(phys_enc, true);
+
+	_sde_encoder_phys_wb_setup_prog_line(phys_enc);
 }
 
 static void sde_encoder_phys_wb_ctl_start_irq(void *arg, int irq_idx)
 {
 	struct sde_encoder_phys_wb *wb_enc = arg;
 	struct sde_encoder_phys *phys_enc;
+	struct sde_hw_wb *hw_wb;
+	u32 line_cnt = 0;
 
 	if (!wb_enc)
 		return;
@@ -1227,7 +1255,11 @@ static void sde_encoder_phys_wb_ctl_start_irq(void *arg, int irq_idx)
 	if (atomic_add_unless(&phys_enc->pending_ctl_start_cnt, -1, 0))
 		wake_up_all(&phys_enc->pending_kickoff_wq);
 
-	SDE_EVT32_IRQ(DRMID(phys_enc->parent), WBID(wb_enc));
+	hw_wb = wb_enc->hw_wb;
+	if (hw_wb->ops.get_line_count)
+		line_cnt = hw_wb->ops.get_line_count(hw_wb);
+
+	SDE_EVT32_IRQ(DRMID(phys_enc->parent), WBID(wb_enc), line_cnt);
 }
 
 static void _sde_encoder_phys_wb_frame_done_helper(void *arg, bool frame_error)
@@ -1242,11 +1274,23 @@ static void _sde_encoder_phys_wb_frame_done_helper(void *arg, bool frame_error)
 
 	if (phys_enc->parent_ops.handle_frame_done &&
 			atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0)) {
-		event |= SDE_ENCODER_FRAME_EVENT_DONE
-				| SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE;
+		event |= SDE_ENCODER_FRAME_EVENT_DONE;
+
+		/*
+		 * signal retire-fence during wb-done
+		 * - when prog_line is not configured
+		 * - when prog_line is configured and line-ptr-irq is missed
+		 */
+		if (!wb_enc->prog_line || (wb_enc->prog_line &&
+				(atomic_read(&phys_enc->pending_kickoff_cnt) <
+					atomic_read(&phys_enc->pending_retire_fence_cnt)))) {
+			atomic_add_unless(&phys_enc->pending_retire_fence_cnt, -1, 0);
+			event |= SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE;
+		}
 
 		if (phys_enc->in_clone_mode)
-			event |= SDE_ENCODER_FRAME_EVENT_CWB_DONE;
+			event |= SDE_ENCODER_FRAME_EVENT_CWB_DONE
+					| SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE;
 		else
 			event |= SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE;
 
@@ -1258,7 +1302,9 @@ static void _sde_encoder_phys_wb_frame_done_helper(void *arg, bool frame_error)
 
 end:
 	SDE_EVT32_IRQ(DRMID(phys_enc->parent), WBID(wb_enc), phys_enc->in_clone_mode,
-			phys_enc->enable_state, event, frame_error);
+			phys_enc->enable_state, event, atomic_read(&phys_enc->pending_kickoff_cnt),
+			atomic_read(&phys_enc->pending_retire_fence_cnt),
+			frame_error);
 
 	wake_up_all(&phys_enc->pending_kickoff_wq);
 }
@@ -1287,13 +1333,24 @@ static void sde_encoder_phys_wb_lineptr_irq(void *arg, int irq_idx)
 {
 	struct sde_encoder_phys_wb *wb_enc = arg;
 	struct sde_encoder_phys *phys_enc;
+	struct sde_hw_wb *hw_wb;
+	u32 event = 0, line_cnt = 0;
 
-	if (!wb_enc)
+	if (!wb_enc || !wb_enc->prog_line)
 		return;
 
 	phys_enc = &wb_enc->base;
+	if (phys_enc->parent_ops.handle_frame_done &&
+			atomic_add_unless(&phys_enc->pending_retire_fence_cnt, -1, 0)) {
+		event = SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE;
+		phys_enc->parent_ops.handle_frame_done(phys_enc->parent, phys_enc, event);
+	}
+
+	hw_wb = wb_enc->hw_wb;
+	if (hw_wb->ops.get_line_count)
+		line_cnt = hw_wb->ops.get_line_count(hw_wb);
 
-	SDE_EVT32_IRQ(DRMID(phys_enc->parent), WBID(wb_enc));
+	SDE_EVT32_IRQ(DRMID(phys_enc->parent), WBID(wb_enc), event, wb_enc->prog_line, line_cnt);
 }
 
 /**
@@ -1338,6 +1395,9 @@ static void sde_encoder_phys_wb_irq_ctrl(
 		sde_encoder_helper_register_irq(phys, INTR_IDX_WB_DONE);
 		sde_encoder_helper_register_irq(phys, INTR_IDX_CTL_START);
 
+		if (test_bit(SDE_WB_PROG_LINE, &wb_cfg->features))
+			sde_encoder_helper_register_irq(phys, INTR_IDX_WB_LINEPTR);
+
 		for (index = 0; index < max_num_of_irqs; index++)
 			if (irq_table[index + pp] != SDE_NONE)
 				sde_encoder_helper_register_irq(phys, irq_table[index + pp]);
@@ -1345,6 +1405,9 @@ static void sde_encoder_phys_wb_irq_ctrl(
 		sde_encoder_helper_unregister_irq(phys, INTR_IDX_WB_DONE);
 		sde_encoder_helper_unregister_irq(phys, INTR_IDX_CTL_START);
 
+		if (test_bit(SDE_WB_PROG_LINE, &wb_cfg->features))
+			sde_encoder_helper_unregister_irq(phys, INTR_IDX_WB_LINEPTR);
+
 		for (index = 0; index < max_num_of_irqs; index++)
 			if (irq_table[index + pp] != SDE_NONE)
 				sde_encoder_helper_unregister_irq(phys, irq_table[index + pp]);
@@ -1522,6 +1585,7 @@ static int _sde_encoder_phys_wb_wait_for_ctl_start(struct sde_encoder_phys *phys
 
 	SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc), phys_enc->in_clone_mode,
 			atomic_read(&phys_enc->pending_kickoff_cnt),
+			atomic_read(&phys_enc->pending_retire_fence_cnt),
 			atomic_read(&phys_enc->pending_ctl_start_cnt));
 
 	wait_info.wq = &phys_enc->pending_kickoff_wq;

+ 4 - 0
msm/sde/sde_wb.c

@@ -564,6 +564,10 @@ int sde_wb_connector_post_init(struct drm_connector *connector, void *display)
 			ARRAY_SIZE(e_fb_translation_mode), 0,
 			CONNECTOR_PROP_FB_TRANSLATION_MODE);
 
+	if (wb_dev->wb_cfg->features & BIT(SDE_WB_PROG_LINE))
+		msm_property_install_range(&c_conn->property_info, "early_fence_line",
+			0x0, 0, UINT_MAX, 0, CONNECTOR_PROP_EARLY_FENCE_LINE);
+
 	sde_wb_connector_install_dither_property(wb_dev, c_conn);
 
 	return 0;