Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit afead867 authored by Steve Cohen's avatar Steve Cohen
Browse files

drm/msm/sde: add support for qsync video mode



Add support to enable qsync/AVR feature for video mode panels.
This feature allows video mode panels to update the refresh
rate anywhere from default (60fps) down to the slowest rate
supported by the panel.  This helps to reduce frame drops when
the commit arrives a little late but still within the panel's
supported refresh rate range.

Change-Id: I6546d0663ed7962f0c576d100c539038843bf4b1
Signed-off-by: default avatarSteve Cohen <cohens@codeaurora.org>
parent 180e3a30
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -242,6 +242,8 @@ enum dsi_dfps_type {
 * @DSI_CMD_SET_ROI:			   Panel ROI update
 * @DSI_CMD_SET_TIMING_SWITCH:             Timing switch
 * @DSI_CMD_SET_POST_TIMING_SWITCH:        Post timing switch
 * @DSI_CMD_SET_QSYNC_ON                   Enable qsync mode
 * @DSI_CMD_SET_QSYNC_OFF                  Disable qsync mode
 * @DSI_CMD_SET_MAX
 */
enum dsi_cmd_set_type {
+2 −0
Original line number Diff line number Diff line
@@ -434,6 +434,8 @@ int dsi_conn_set_info_blob(struct drm_connector *connector,
	switch (panel->panel_mode) {
	case DSI_OP_VIDEO_MODE:
		sde_kms_info_add_keystr(info, "panel mode", "video");
		sde_kms_info_add_keystr(info, "qsync support",
				panel->qsync_min_fps ? "true" : "false");
		break;
	case DSI_OP_CMD_MODE:
		sde_kms_info_add_keystr(info, "panel mode", "command");
+6 −3
Original line number Diff line number Diff line
@@ -2807,9 +2807,12 @@ struct dsi_panel *dsi_panel_get(struct device *parent,
	if (rc)
		pr_err("failed to parse dfps configuration, rc=%d\n", rc);

	if (!(panel->dfps_caps.dfps_support)) {
		/* qsync and dfps are mutually exclusive features */
		rc = dsi_panel_parse_qsync_caps(panel, of_node);
		if (rc)
			pr_err("failed to parse qsync features, rc=%d\n", rc);
	}

	rc = dsi_panel_parse_phy_props(panel);
	if (rc) {
+2 −0
Original line number Diff line number Diff line
@@ -1309,6 +1309,8 @@ 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);
		SDE_EVT32(DRMID(phys_enc->parent),
				tc_cfg.sync_threshold_start);
	}

	SDE_DEBUG_CMDENC(cmd_enc, "pp:%d pending_cnt %d\n",
+81 −1
Original line number Diff line number Diff line
@@ -341,6 +341,54 @@ static bool sde_encoder_phys_vid_mode_fixup(
	return true;
}

/* vid_enc timing_params must be configured before calling this function */
static void _sde_encoder_phys_vid_setup_avr(
		struct sde_encoder_phys *phys_enc)
{
	struct sde_encoder_phys_vid *vid_enc;
	struct drm_display_mode mode;

	vid_enc = to_sde_encoder_phys_vid(phys_enc);
	mode = phys_enc->cached_mode;
	if (vid_enc->base.hw_intf->ops.avr_setup) {
		struct intf_avr_params avr_params = {0};
		u32 qsync_min_fps = 0;
		u32 default_fps = mode.vrefresh;
		int ret;

		if (phys_enc->parent_ops.get_qsync_fps)
			phys_enc->parent_ops.get_qsync_fps(
				phys_enc->parent, &qsync_min_fps);

		if (!qsync_min_fps || !default_fps) {
			SDE_ERROR_VIDENC(vid_enc,
					"wrong qsync params %d %d\n",
					qsync_min_fps, default_fps);
			return;
		}

		if (qsync_min_fps >= default_fps) {
			SDE_ERROR_VIDENC(vid_enc,
				"qsync fps %d must be less than default %d\n",
				qsync_min_fps, default_fps);
			return;
		}

		avr_params.default_fps = default_fps;
		avr_params.min_fps = qsync_min_fps;

		ret = vid_enc->base.hw_intf->ops.avr_setup(
				vid_enc->base.hw_intf,
				&vid_enc->timing_params, &avr_params);
		if (ret)
			SDE_ERROR_VIDENC(vid_enc,
				"bad settings, can't configure AVR\n");

		SDE_EVT32(DRMID(phys_enc->parent), default_fps,
				qsync_min_fps, ret);
	}
}

static void sde_encoder_phys_vid_setup_timing_engine(
		struct sde_encoder_phys *phys_enc)
{
@@ -387,7 +435,7 @@ static void sde_encoder_phys_vid_setup_timing_engine(
	if (phys_enc->sde_kms->splash_data.cont_splash_en) {
		SDE_DEBUG_VIDENC(vid_enc,
			"skipping intf programming since cont splash is enabled\n");
		return;
		goto exit;
	}

	fmt = sde_get_sde_format(fmt_fourcc);
@@ -412,6 +460,9 @@ static void sde_encoder_phys_vid_setup_timing_engine(
	}
	spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);
	programmable_fetch_config(phys_enc, &timing_params);

exit:
	_sde_encoder_phys_vid_setup_avr(phys_enc);
}

static void sde_encoder_phys_vid_vblank_irq(void *arg, int irq_idx)
@@ -847,6 +898,7 @@ static int sde_encoder_phys_vid_prepare_for_kickoff(
	struct sde_encoder_phys_vid *vid_enc;
	struct sde_hw_ctl *ctl;
	int rc;
	struct intf_avr_params avr_params;

	if (!phys_enc || !params || !phys_enc->hw_ctl) {
		SDE_ERROR("invalid encoder/parameters\n");
@@ -882,6 +934,22 @@ static int sde_encoder_phys_vid_prepare_for_kickoff(
		vid_enc->error_count = 0;
	}

	if (sde_connector_qsync_updated(phys_enc->connector)) {
		avr_params.avr_mode = sde_connector_get_property(
				phys_enc->connector->state,
				CONNECTOR_PROP_QSYNC_MODE);

		if (vid_enc->base.hw_intf->ops.avr_ctrl) {
			vid_enc->base.hw_intf->ops.avr_ctrl(
					vid_enc->base.hw_intf,
					&avr_params);
		}

		SDE_EVT32(DRMID(phys_enc->parent),
				phys_enc->hw_intf->idx - INTF_0,
				avr_params.avr_mode);
	}

	programmable_rot_fetch_config(phys_enc,
			params->inline_rotate_prefill, params->is_primary);

@@ -968,6 +1036,7 @@ static void sde_encoder_phys_vid_handle_post_kickoff(
{
	unsigned long lock_flags;
	struct sde_encoder_phys_vid *vid_enc;
	u32 avr_mode;

	if (!phys_enc) {
		SDE_ERROR("invalid encoder\n");
@@ -989,6 +1058,17 @@ static void sde_encoder_phys_vid_handle_post_kickoff(
		spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);
		phys_enc->enable_state = SDE_ENC_ENABLED;
	}

	avr_mode = sde_connector_get_property(
			phys_enc->connector->state,
			CONNECTOR_PROP_QSYNC_MODE);

	if (avr_mode && vid_enc->base.hw_intf->ops.avr_trigger) {
		vid_enc->base.hw_intf->ops.avr_trigger(vid_enc->base.hw_intf);
		SDE_EVT32(DRMID(phys_enc->parent),
				phys_enc->hw_intf->idx - INTF_0,
				SDE_EVTLOG_FUNC_CASE9);
	}
}

static void sde_encoder_phys_vid_irq_control(struct sde_encoder_phys *phys_enc,
Loading