Prechádzať zdrojové kódy

disp: msm: sde: add support for TE level trigger

During qsync frequency step down, it is possible for the changing
frame window to lead to frame buffers being transferred when it
is unsafe to update. Pineapple r2 hardware supports using the
panel's TE level, instead of the start window, to trigger the
frame transfer.

This change enables using TE level during QSYNC or AVR, if the
hardware supports it.

Change-Id: Ie675edaaeb80921c639905395b709f4c67134fc7
Signed-off-by: Amine Najahi <[email protected]>
Amine Najahi 2 rokov pred
rodič
commit
fea2f25ccf

+ 1 - 1
msm/dsi/dsi_display.c

@@ -6779,6 +6779,7 @@ int dsi_display_get_info(struct drm_connector *connector,
 	info->has_qsync_min_fps_list = (display->panel->qsync_caps.qsync_min_fps_list_len > 0);
 	info->avr_step_fps = display->panel->avr_caps.avr_step_fps;
 	info->poms_align_vsync = display->panel->poms_align_vsync;
+	info->is_te_using_watchdog_timer = is_sim_panel(display);
 
 	switch (display->panel->panel_mode) {
 	case DSI_OP_VIDEO_MODE:
@@ -6792,7 +6793,6 @@ int dsi_display_get_info(struct drm_connector *connector,
 		info->capabilities |= MSM_DISPLAY_CAP_CMD_MODE;
 		if (display->panel->panel_mode_switch_enabled)
 			info->capabilities |= MSM_DISPLAY_CAP_VID_MODE;
-		info->is_te_using_watchdog_timer = is_sim_panel(display);
 		break;
 	default:
 		DSI_ERR("unknwown dsi panel mode %d\n",

+ 23 - 3
msm/sde/sde_encoder_phys_cmd.c

@@ -1599,7 +1599,8 @@ static void sde_encoder_phys_cmd_enable_helper(
 	sde_enc = to_sde_encoder_virt(phys_enc->parent);
 	if (sde_enc->idle_pc_restore) {
 		qsync_mode = sde_connector_get_qsync_mode(phys_enc->connector);
-		if (qsync_mode)
+		if (qsync_mode && !test_bit(SDE_INTF_TE_LEVEL_TRIGGER,
+				&phys_enc->hw_intf->cap->features))
 			sde_enc->restore_te_rd_ptr = true;
 	}
 
@@ -1804,6 +1805,8 @@ static int sde_encoder_phys_cmd_prepare_for_kickoff(
 	struct sde_encoder_virt *sde_enc;
 	int ret = 0;
 	bool recovery_events;
+	u32 qsync_mode = 0;
+	bool panel_dead = false;
 
 	if (!phys_enc || !phys_enc->hw_pp) {
 		SDE_ERROR("invalid encoder\n");
@@ -1811,6 +1814,7 @@ static int sde_encoder_phys_cmd_prepare_for_kickoff(
 	}
 	SDE_DEBUG_CMDENC(cmd_enc, "pp %d\n", phys_enc->hw_pp->idx - PINGPONG_0);
 
+	sde_enc = to_sde_encoder_virt(phys_enc->parent);
 	phys_enc->frame_trigger_mode = params->frame_trigger_mode;
 	SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0,
 			atomic_read(&phys_enc->pending_kickoff_cnt),
@@ -1859,11 +1863,20 @@ static int sde_encoder_phys_cmd_prepare_for_kickoff(
 		else if (phys_enc->hw_pp->ops.update_tearcheck)
 			phys_enc->hw_pp->ops.update_tearcheck(
 					phys_enc->hw_pp, &tc_cfg);
+
+		qsync_mode = sde_connector_get_qsync_mode(phys_enc->connector);
+		panel_dead = sde_connector_panel_dead(phys_enc->connector);
+
+		if (cmd_enc->base.hw_intf->ops.enable_te_level_trigger &&
+				!sde_enc->disp_info.is_te_using_watchdog_timer)
+			cmd_enc->base.hw_intf->ops.enable_te_level_trigger(cmd_enc->base.hw_intf,
+					qsync_mode && !panel_dead);
+
 		SDE_EVT32(DRMID(phys_enc->parent), tc_cfg.sync_threshold_start, tc_cfg.start_pos,
-				SDE_EVTLOG_FUNC_CASE3);
+				qsync_mode, sde_enc->disp_info.is_te_using_watchdog_timer,
+				panel_dead, SDE_EVTLOG_FUNC_CASE3);
 	}
 
-	sde_enc = to_sde_encoder_virt(phys_enc->parent);
 	if (sde_enc->restore_te_rd_ptr) {
 		sde_encoder_restore_tearcheck_rd_ptr(phys_enc);
 		sde_enc->restore_te_rd_ptr = false;
@@ -2051,13 +2064,20 @@ static int _sde_encoder_phys_cmd_handle_wr_ptr_timeout(
 	bool switch_te;
 	int ret = -ETIMEDOUT;
 	unsigned long lock_flags;
+	struct sde_encoder_virt *sde_enc;
 
 	switch_te = _sde_encoder_phys_cmd_needs_vsync_change(
 				phys_enc, profile_timestamp);
+	sde_enc = to_sde_encoder_virt(phys_enc->parent);
 
 	SDE_EVT32(DRMID(phys_enc->parent), switch_te, SDE_EVTLOG_FUNC_ENTRY);
 
 	if (sde_connector_panel_dead(phys_enc->connector)) {
+		if (cmd_enc->base.hw_intf->ops.enable_te_level_trigger &&
+				!sde_enc->disp_info.is_te_using_watchdog_timer)
+			cmd_enc->base.hw_intf->ops.enable_te_level_trigger(cmd_enc->base.hw_intf,
+					false);
+
 		ret = _sde_encoder_phys_cmd_wait_for_wr_ptr(phys_enc);
 	} else if (switch_te) {
 		SDE_DEBUG_CMDENC(cmd_enc,

+ 7 - 1
msm/sde/sde_encoder_phys_vid.c

@@ -393,8 +393,14 @@ static void _sde_encoder_phys_vid_avr_ctrl(struct sde_encoder_phys *phys_enc)
 	if (vid_enc->base.hw_intf->ops.avr_ctrl)
 		vid_enc->base.hw_intf->ops.avr_ctrl(vid_enc->base.hw_intf, &avr_params);
 
+	if (vid_enc->base.hw_intf->ops.enable_te_level_trigger &&
+			!sde_enc->disp_info.is_te_using_watchdog_timer)
+		vid_enc->base.hw_intf->ops.enable_te_level_trigger(vid_enc->base.hw_intf,
+				(avr_step_state == AVR_STEP_ENABLE));
+
 	SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_intf->idx - INTF_0, avr_params.avr_mode,
-			avr_params.avr_step_lines, info->avr_step_fps, avr_step_state);
+			avr_params.avr_step_lines, info->avr_step_fps, avr_step_state,
+			sde_enc->disp_info.is_te_using_watchdog_timer);
 }
 
 static void sde_encoder_phys_vid_setup_timing_engine(

+ 1 - 0
msm/sde/sde_hw_catalog.c

@@ -2508,6 +2508,7 @@ static int sde_intf_parse_dt(struct device_node *np,
 			set_bit(SDE_INTF_WD_LTJ_CTL, &intf->features);
 			set_bit(SDE_INTF_TE_DEASSERT_DETECT, &intf->features);
 			set_bit(SDE_INTF_VSYNC_TS_SRC_EN, &intf->features);
+			set_bit(SDE_INTF_TE_LEVEL_TRIGGER, &intf->features);
 		}
 	}
 

+ 2 - 0
msm/sde/sde_hw_catalog.h

@@ -636,6 +636,7 @@ enum {
  * @SDE_INTF_WD_LTJ_CTL         INTF block has WD long term jitter control support
  * @SDE_INTF_TE_DEASSERT_DETECT INTF block has TE Deassert detect support
  * @SDE_INTF_VSYNC_TS_SRC_EN    INTF block has VSYNC timestamp source selection support
+ * @SDE_INTF_TE_LEVEL_TRIGGER   INTF block has TE Level trigger gating support
  * @SDE_INTF_MAX
  */
 enum {
@@ -655,6 +656,7 @@ enum {
 	SDE_INTF_WD_LTJ_CTL,
 	SDE_INTF_TE_DEASSERT_DETECT,
 	SDE_INTF_VSYNC_TS_SRC_EN,
+	SDE_INTF_TE_LEVEL_TRIGGER,
 	SDE_INTF_MAX
 };
 

+ 20 - 4
msm/sde/sde_hw_intf.c

@@ -451,6 +451,21 @@ static void sde_hw_intf_enable_timing_engine(struct sde_hw_intf *intf, u8 enable
 	}
 }
 
+static void sde_hw_intf_enable_te_level_trigger(struct sde_hw_intf *intf, bool enable)
+{
+	struct sde_hw_blk_reg_map *c = &intf->hw;
+	u32 intf_cfg = 0;
+
+	intf_cfg = SDE_REG_READ(c, INTF_CONFIG);
+
+	if (enable)
+		intf_cfg |= BIT(22);
+	else
+		intf_cfg &= ~BIT(22);
+
+	SDE_REG_WRITE(c, INTF_CONFIG, intf_cfg);
+}
+
 static void sde_hw_intf_setup_prg_fetch(
 		struct sde_hw_intf *intf,
 		const struct intf_prog_fetch *fetch)
@@ -1081,10 +1096,11 @@ static void _setup_intf_ops(struct sde_hw_intf_ops *ops,
 		ops->get_autorefresh = sde_hw_intf_get_autorefresh_config;
 		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;
-		ops->override_tear_rd_ptr_val =
-			sde_hw_intf_override_tear_rd_ptr_val;
+		ops->check_and_reset_tearcheck = sde_hw_intf_v1_check_and_reset_tearcheck;
+		ops->override_tear_rd_ptr_val = sde_hw_intf_override_tear_rd_ptr_val;
+
+		if (cap & BIT(SDE_INTF_TE_LEVEL_TRIGGER))
+			ops->enable_te_level_trigger = sde_hw_intf_enable_te_level_trigger;
 	}
 
 	if (cap & BIT(SDE_INTF_RESET_COUNTER))

+ 5 - 0
msm/sde/sde_hw_intf.h

@@ -222,6 +222,11 @@ struct sde_hw_intf_ops {
 	void (*avr_ctrl)(struct sde_hw_intf *intf,
 			const struct intf_avr_params *avr_params);
 
+	/**
+	 * Enable trigger based on TE level
+	 */
+	void (*enable_te_level_trigger)(struct sde_hw_intf *intf, bool enable);
+
 	/**
 	 * Indicates the AVR armed status
 	 *