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

Commit a2ff218d authored by Ingrid Gallardo's avatar Ingrid Gallardo Committed by Gerrit - the friendly Code Review server
Browse files

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



This change adds support to enable qsync feature for
command mode panels.
Feature allows command mode panels to update the refresh
rate to the slowest rate (i.e. 30fps) supported by the
panel whereas the transfer time still remains in the higher
frame rate supported by the panel (i.e. 60fps). Main goal
of this feature is prevent frame drops due the trigger
of the frame got delayed for couple of milliseconds in a
use case where the content of the screen it is being
updated at the highest frame rate.

Change-Id: I53a81b465d0ed8cdf1255561923f862403bb9ab6
Signed-off-by: default avatarIngrid Gallardo <ingridg@codeaurora.org>
Signed-off-by: default avatarSteve Cohen <cohens@codeaurora.org>
parent 5870a109
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -197,6 +197,15 @@ Optional properties:
- qcom,mdss-dsi-te-using-wd:		Boolean entry enables the watchdog timer support to generate the vsync signal
					for command mode panel. By default, panel TE will be used to generate the vsync.
- qcom,mdss-dsi-te-using-te-pin:	Boolean to specify whether using hardware vsync.
- qcom,mdss-dsi-qsync-min-refresh-rate: A u32 entry to specify minimum refresh rate supported by the panel to enable qsync feature.
- qcom,mdss-dsi-qsync-on-commands:	String that specifies the commands to enable qsync feature.
- qcom,mdss-dsi-qsync-on-commands-state: String that specifies the ctrl state for sending qsync on commands.
					"dsi_lp_mode" = DSI low power mode (default)
					"dsi_hs_mode" = DSI high speed mode
- qcom,mdss-dsi-qsync-off-commands:	String that specifies the commands to disable qsync feature.
- qcom,mdss-dsi-qsync-off-commands-state: String that specifies the ctrl state for sending qsync off commands.
					"dsi_lp_mode" = DSI low power mode (default)
					"dsi_hs_mode" = DSI high speed mode
- qcom,mdss-dsi-te-pin-select:		Specifies TE operating mode.
					0 = TE through embedded dcs command
					1 = TE through TE gpio pin. (default)
@@ -599,6 +608,7 @@ Example:
		qcom,mdss-dsi-te-check-enable;
		qcom,mdss-dsi-te-using-wd;
		qcom,mdss-dsi-te-using-te-pin;
		qcom,mdss-dsi-qsync-min-refresh-rate = <30>;
		qcom,mdss-dsi-te-dcs-command = <1>;
		qcom,mdss-dsi-wr-mem-continue = <0x3c>;
		qcom,mdss-dsi-wr-mem-start = <0x2c>;
@@ -712,6 +722,10 @@ Example:
					29 00 00 00 00 00 02 B0 04
					29 00 00 00 00 00 02 F1 00];
				qcom,mdss-dsi-timing-switch-command-state = "dsi_lp_mode";
				qcom,mdss-dsi-qsync-on-commands = [15 01 00 00 00 00 02 51 00];
				qcom,mdss-dsi-qsync-on-commands-state = "dsi_hs_mode";
				qcom,mdss-dsi-qsync-off-commands = [15 01 00 00 00 00 02 51 00];
				qcom,mdss-dsi-qsync-off-commands-state = "dsi_hs_mode";

				qcom,mdss-dsc-slice-height = <16>;
				qcom,mdss-dsc-slice-width = <360>;
+3 −1
Original line number Diff line number Diff line
/*
 * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
 * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -266,6 +266,8 @@ enum dsi_cmd_set_type {
	DSI_CMD_SET_ROI,
	DSI_CMD_SET_TIMING_SWITCH,
	DSI_CMD_SET_POST_TIMING_SWITCH,
	DSI_CMD_SET_QSYNC_ON,
	DSI_CMD_SET_QSYNC_OFF,
	DSI_CMD_SET_MAX
};

+49 −0
Original line number Diff line number Diff line
@@ -4523,6 +4523,8 @@ int dsi_display_get_info(struct drm_connector *connector,
	info->height_mm = phy_props.panel_height_mm;
	info->max_width = 1920;
	info->max_height = 1080;
	info->qsync_min_fps =
		display->panel->qsync_min_fps;

	switch (display->panel->panel_mode) {
	case DSI_OP_VIDEO_MODE:
@@ -5461,6 +5463,43 @@ static int dsi_display_calc_ctrl_roi(const struct dsi_display *display,
	return rc;
}

static int dsi_display_qsync(struct dsi_display *display, bool enable)
{
	int i;
	int rc = 0;

	if (!display->panel->qsync_min_fps) {
		pr_err("%s:ERROR: qsync set, but no fps\n", __func__);
		return 0;
	}

	mutex_lock(&display->display_lock);

	for (i = 0; i < display->ctrl_count; i++) {

		if (enable) {
			/* send the commands to enable qsync */
			rc = dsi_panel_send_qsync_on_dcs(display->panel, i);
			if (rc) {
				pr_err("fail qsync ON cmds rc:%d\n", rc);
				goto exit;
			}
		} else {
			/* send the commands to enable qsync */
			rc = dsi_panel_send_qsync_off_dcs(display->panel, i);
			if (rc) {
				pr_err("fail qsync OFF cmds rc:%d\n", rc);
				goto exit;
			}
		}
	}

exit:
	SDE_EVT32(enable, display->panel->qsync_min_fps, rc);
	mutex_unlock(&display->display_lock);
	return rc;
}

static int dsi_display_set_roi(struct dsi_display *display,
		struct msm_roi_list *rois)
{
@@ -5524,11 +5563,21 @@ int dsi_display_pre_kickoff(struct drm_connector *connector,
{
	int rc = 0;
	int i;
	bool enable;

	/* check and setup MISR */
	if (display->misr_enable)
		_dsi_display_setup_misr(display);

	if (params->qsync_update) {
		enable = (params->qsync_mode > 0) ? true : false;
		rc = dsi_display_qsync(display, enable);
		if (rc)
			pr_err("%s failed to send qsync commands",
				__func__);
		SDE_EVT32(params->qsync_mode, rc);
	}

	rc = dsi_display_set_roi(display, params->rois);

	/* dynamic DSI clock setting */
+2 −0
Original line number Diff line number Diff line
@@ -439,6 +439,8 @@ int dsi_conn_set_info_blob(struct drm_connector *connector,
		sde_kms_info_add_keystr(info, "panel mode", "command");
		sde_kms_info_add_keyint(info, "mdp_transfer_time_us",
				panel->cmd_config.mdp_transfer_time_us);
		sde_kms_info_add_keystr(info, "qsync support",
				panel->qsync_min_fps ? "true" : "false");
		break;
	default:
		pr_debug("invalid panel type:%d\n", panel->panel_mode);
+70 −0
Original line number Diff line number Diff line
@@ -1054,6 +1054,24 @@ static int dsi_panel_parse_host_config(struct dsi_panel *panel)
	return rc;
}

static int dsi_panel_parse_qsync_caps(struct dsi_panel *panel,
				     struct device_node *of_node)
{
	int rc = 0;
	u32 val = 0;

	rc = of_property_read_u32(of_node,
				  "qcom,mdss-dsi-qsync-min-refresh-rate",
				  &val);
	if (rc)
		pr_err("[%s] qsync min fps not defined rc:%d\n",
			panel->name, rc);

	panel->qsync_min_fps = val;

	return rc;
}

static int dsi_panel_parse_dfps_caps(struct dsi_panel *panel)
{
	int rc = 0;
@@ -1386,6 +1404,8 @@ const char *cmd_set_prop_map[DSI_CMD_SET_MAX] = {
	"ROI not parsed from DTSI, generated dynamically",
	"qcom,mdss-dsi-timing-switch-command",
	"qcom,mdss-dsi-post-mode-switch-on-command",
	"qcom,mdss-dsi-qsync-on-commands",
	"qcom,mdss-dsi-qsync-off-commands",
};

const char *cmd_set_state_map[DSI_CMD_SET_MAX] = {
@@ -1410,6 +1430,8 @@ const char *cmd_set_state_map[DSI_CMD_SET_MAX] = {
	"ROI not parsed from DTSI, generated dynamically",
	"qcom,mdss-dsi-timing-switch-command-state",
	"qcom,mdss-dsi-post-mode-switch-on-command-state",
	"qcom,mdss-dsi-qsync-on-commands-state",
	"qcom,mdss-dsi-qsync-off-commands-state",
};

static int dsi_panel_get_cmd_pkt_count(const char *data, u32 length, u32 *cnt)
@@ -2785,6 +2807,10 @@ struct dsi_panel *dsi_panel_get(struct device *parent,
	if (rc)
		pr_err("failed to parse dfps configuration, rc=%d\n", rc);

	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) {
		pr_err("failed to parse panel physical dimension, rc=%d\n", rc);
@@ -3404,6 +3430,50 @@ static int dsi_panel_roi_prepare_dcs_cmds(struct dsi_panel_cmd_set *set,
	return rc;
}

int dsi_panel_send_qsync_on_dcs(struct dsi_panel *panel,
		int ctrl_idx)
{
	int rc = 0;

	if (!panel) {
		pr_err("invalid params\n");
		return -EINVAL;
	}

	mutex_lock(&panel->panel_lock);

	pr_debug("ctrl:%d qsync on\n", ctrl_idx);
	rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_QSYNC_ON);
	if (rc)
		pr_err("[%s] failed to send DSI_CMD_SET_QSYNC_ON cmds rc=%d\n",
		       panel->name, rc);

	mutex_unlock(&panel->panel_lock);
	return rc;
}

int dsi_panel_send_qsync_off_dcs(struct dsi_panel *panel,
		int ctrl_idx)
{
	int rc = 0;

	if (!panel) {
		pr_err("invalid params\n");
		return -EINVAL;
	}

	mutex_lock(&panel->panel_lock);

	pr_debug("ctrl:%d qsync off\n", ctrl_idx);
	rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_QSYNC_OFF);
	if (rc)
		pr_err("[%s] failed to send DSI_CMD_SET_QSYNC_OFF cmds rc=%d\n",
		       panel->name, rc);

	mutex_unlock(&panel->panel_lock);
	return rc;
}

int dsi_panel_send_roi_dcs(struct dsi_panel *panel, int ctrl_idx,
		struct dsi_rect *roi)
{
Loading