Przeglądaj źródła

disp: msm: add capability to dynamically update the transfer time

This change adds a connector OP, that will be used to update frame
transfer time dynamically at the request from user space.

It also adds parsing for new device tree entries that set the minimum
and maximum trasnfer times on a mode basis. These min and max transfer
times are also published to userspace through the connector mode info
capabilities blob.

Change-Id: I12aedf96a51ff7feb2c5b3b1353d3c4ec8dcb068
Signed-off-by: Satya Rama Aditya Pinapala <[email protected]>
Signed-off-by: Nilaan Gunabalachandran <[email protected]>
Nilaan Gunabalachandran 3 lat temu
rodzic
commit
e5fcf7f263

+ 6 - 0
msm/dsi/dsi_defs.h

@@ -613,6 +613,10 @@ struct dsi_host_config {
  * @panel_prefill_lines:  Panel prefill lines for RSC
  * @mdp_transfer_time_us:   Specifies the mdp transfer time for command mode
  *                          panels in microseconds.
+ * @mdp_transfer_time_us_min:   Specifies the minimum possible mdp transfer time
+ *                              for command mode panels in microseconds.
+ * @mdp_transfer_time_us_max:   Specifies the maximum possible mdp transfer time
+ *                              for command mode panels in microseconds.
  * @dsi_transfer_time_us: Specifies the dsi transfer time for cmd panels.
  * @qsync_min_fps:        Qsync min fps value for the mode
  * @clk_rate_hz:          DSI bit clock per lane in hz.
@@ -640,6 +644,8 @@ struct dsi_display_mode_priv_info {
 	u32 panel_jitter_denom;
 	u32 panel_prefill_lines;
 	u32 mdp_transfer_time_us;
+	u32 mdp_transfer_time_us_min;
+	u32 mdp_transfer_time_us_max;
 	u32 dsi_transfer_time_us;
 	u32 qsync_min_fps;
 	u64 clk_rate_hz;

+ 40 - 0
msm/dsi/dsi_display.c

@@ -7311,6 +7311,46 @@ int dsi_display_get_avr_step_req_fps(void *display_dsi, u32 mode_fps)
 	return step;
 }
 
+int dsi_display_update_transfer_time(void *display, u32 transfer_time)
+{
+	struct dsi_display *disp = (struct dsi_display *)display;
+	int rc = 0, i = 0;
+	u32 transfer_time_min, transfer_time_max;
+	struct dsi_display_ctrl *ctrl;
+
+	if (!disp->panel || !disp->panel->cur_mode || !disp->panel->cur_mode->priv_info)
+		return -EINVAL;
+
+	transfer_time_min = disp->panel->cur_mode->priv_info->mdp_transfer_time_us_min;
+	transfer_time_max = disp->panel->cur_mode->priv_info->mdp_transfer_time_us_max;
+
+	if (!transfer_time_min || !transfer_time_max)
+		return 0;
+
+	if (transfer_time < transfer_time_min || transfer_time > transfer_time_max) {
+		DSI_ERR("invalid transfer time %u, min: %u, max: %u\n",
+			transfer_time, transfer_time_min, transfer_time_max);
+		return -EINVAL;
+	}
+
+	disp->panel->cur_mode->priv_info->mdp_transfer_time_us = transfer_time;
+	disp->panel->cur_mode->priv_info->dsi_transfer_time_us = transfer_time;
+
+	display_for_each_ctrl(i, disp) {
+		ctrl = &disp->ctrl[i];
+		rc = dsi_ctrl_update_host_config(ctrl->ctrl, &disp->config,
+				disp->panel->cur_mode, 0x0,
+				disp->dsi_clk_handle);
+		if (rc) {
+			DSI_ERR("[%s] failed to update ctrl config, rc=%d\n", disp->name, rc);
+			return rc;
+		}
+	}
+	atomic_set(&disp->clkrate_change_pending, 1);
+
+	return 0;
+}
+
 static bool dsi_display_match_timings(const struct dsi_display_mode *mode1,
 		struct dsi_display_mode *mode2, unsigned int match_flags)
 {

+ 9 - 0
msm/dsi/dsi_display.h

@@ -831,4 +831,13 @@ int dsi_display_restore_bit_clk(struct dsi_display *display, struct dsi_display_
 bool dsi_display_mode_match(const struct dsi_display_mode *mode1,
 		struct dsi_display_mode *mode2, unsigned int match_flags);
 
+/**
+ * dsi_display_update_transfer_time() - update DSI transfer time and clocks
+ * @display:     handle to display
+ * @transfer_time: transfer time value to be updated
+ *
+ * Return: error code
+ */
+int dsi_display_update_transfer_time(void *display, u32 transfer_time);
+
 #endif /* _DSI_DISPLAY_H_ */

+ 3 - 2
msm/dsi/dsi_drm.c

@@ -634,8 +634,9 @@ int dsi_conn_get_mode_info(struct drm_connector *connector,
 	mode_info->jitter_denom = dsi_mode->priv_info->panel_jitter_denom;
 	mode_info->dfps_maxfps = dsi_drm_get_dfps_maxfps(display);
 	mode_info->panel_mode_caps = dsi_mode->panel_mode_caps;
-	mode_info->mdp_transfer_time_us =
-		dsi_mode->priv_info->mdp_transfer_time_us;
+	mode_info->mdp_transfer_time_us = dsi_mode->priv_info->mdp_transfer_time_us;
+	mode_info->mdp_transfer_time_us_min = dsi_mode->priv_info->mdp_transfer_time_us_min;
+	mode_info->mdp_transfer_time_us_max = dsi_mode->priv_info->mdp_transfer_time_us_max;
 	mode_info->disable_rsc_solver = dsi_mode->priv_info->disable_rsc_solver;
 	mode_info->qsync_min_fps = dsi_mode->timing.qsync_min_fps;
 	mode_info->wd_jitter = dsi_mode->priv_info->wd_jitter;

+ 22 - 5
msm/dsi/dsi_panel.c

@@ -782,6 +782,7 @@ static int dsi_panel_parse_timing(struct dsi_mode_info *mode,
 	u64 tmp64 = 0;
 	struct dsi_display_mode *display_mode;
 	struct dsi_display_mode_priv_info *priv_info;
+	u32 usecs_fps = 0;
 
 	display_mode = container_of(mode, struct dsi_display_mode, timing);
 
@@ -804,11 +805,22 @@ static int dsi_panel_parse_timing(struct dsi_mode_info *mode,
 
 	rc = utils->read_u32(utils->data, "qcom,mdss-mdp-transfer-time-us",
 				&mode->mdp_transfer_time_us);
-	if (!rc)
-		display_mode->priv_info->mdp_transfer_time_us =
-			mode->mdp_transfer_time_us;
-	else
-		display_mode->priv_info->mdp_transfer_time_us = 0;
+	if (rc)
+		mode->mdp_transfer_time_us = 0;
+
+	rc = utils->read_u32(utils->data, "qcom,mdss-mdp-transfer-time-us-min",
+				&priv_info->mdp_transfer_time_us_min);
+	if (rc)
+		priv_info->mdp_transfer_time_us_min = 0;
+	else if (!rc && mode->mdp_transfer_time_us < priv_info->mdp_transfer_time_us_min)
+		mode->mdp_transfer_time_us = priv_info->mdp_transfer_time_us_min;
+
+	rc = utils->read_u32(utils->data, "qcom,mdss-mdp-transfer-time-us-max",
+				&priv_info->mdp_transfer_time_us_max);
+	if (rc)
+		priv_info->mdp_transfer_time_us_max = 0;
+	else if (!rc && mode->mdp_transfer_time_us > priv_info->mdp_transfer_time_us_max)
+		mode->mdp_transfer_time_us = priv_info->mdp_transfer_time_us_max;
 
 	priv_info->disable_rsc_solver = utils->read_bool(utils->data, "qcom,disable-rsc-solver");
 
@@ -821,6 +833,11 @@ static int dsi_panel_parse_timing(struct dsi_mode_info *mode,
 		goto error;
 	}
 
+	usecs_fps = DIV_ROUND_UP((1 * 1000 * 1000), mode->refresh_rate);
+	if (mode->mdp_transfer_time_us > usecs_fps)
+		mode->mdp_transfer_time_us = 0;
+	priv_info->mdp_transfer_time_us = mode->mdp_transfer_time_us;
+
 	rc = utils->read_u32(utils->data, "qcom,mdss-dsi-panel-width",
 				  &mode->h_active);
 	if (rc) {

+ 7 - 0
msm/msm_drv.h

@@ -223,6 +223,7 @@ enum msm_mdp_conn_property {
 	CONNECTOR_PROP_DIMMING_CTRL,
 	CONNECTOR_PROP_DIMMING_MIN_BL,
 	CONNECTOR_PROP_EARLY_FENCE_LINE,
+	CONNECTOR_PROP_DYN_TRANSFER_TIME,
 
 	/* enum/bitmask properties */
 	CONNECTOR_PROP_TOPOLOGY_NAME,
@@ -790,6 +791,10 @@ struct msm_display_wd_jitter_config {
  * @panel_mode_caps   panel mode capabilities
  * @mdp_transfer_time_us   Specifies the mdp transfer time for command mode
  *                         panels in microseconds.
+ * @mdp_transfer_time_us_min   Specifies the minimum possible mdp transfer time
+ *                             for command mode panels in microseconds.
+ * @mdp_transfer_time_us_max   Specifies the maximum possible mdp transfer time
+ *                             for command mode panels in microseconds.
  * @allowed_mode_switches: bit mask to indicate supported mode switch.
  * @disable_rsc_solver: Dynamically disable RSC solver for the timing mode due to lower bitclk rate.
  * @dyn_clk_list: List of dynamic clock rates for RFI.
@@ -810,6 +815,8 @@ struct msm_mode_info {
 	bool wide_bus_en;
 	u32 panel_mode_caps;
 	u32 mdp_transfer_time_us;
+	u32 mdp_transfer_time_us_min;
+	u32 mdp_transfer_time_us_max;
 	u32 allowed_mode_switches;
 	bool disable_rsc_solver;
 	struct msm_dyn_clk_list dyn_clk_list;

+ 26 - 0
msm/sde/sde_connector.c

@@ -1686,6 +1686,20 @@ end:
 	return rc;
 }
 
+static int _sde_connector_set_prop_dyn_transfer_time(struct sde_connector *c_conn, uint64_t val)
+{
+	int rc = 0;
+
+	if (!c_conn->ops.update_transfer_time)
+		return rc;
+
+	rc = c_conn->ops.update_transfer_time(c_conn->display, val);
+	if (rc)
+		SDE_ERROR_CONN(c_conn, "updating transfer time failed, val: %u, rc %d\n", val, rc);
+
+	return rc;
+}
+
 static int sde_connector_atomic_set_property(struct drm_connector *connector,
 		struct drm_connector_state *state,
 		struct drm_property *property,
@@ -1776,6 +1790,9 @@ static int sde_connector_atomic_set_property(struct drm_connector *connector,
 		if (rc)
 			SDE_ERROR_CONN(c_conn, "dynamic bit clock set failed, rc: %d", rc);
 
+		break;
+	case CONNECTOR_PROP_DYN_TRANSFER_TIME:
+		_sde_connector_set_prop_dyn_transfer_time(c_conn, val);
 		break;
 	default:
 		break;
@@ -2879,6 +2896,13 @@ static int sde_connector_populate_mode_info(struct drm_connector *conn,
 		sde_kms_info_add_keyint(info, "mdp_transfer_time_us",
 			mode_info.mdp_transfer_time_us);
 
+		if (mode_info.mdp_transfer_time_us_min && mode_info.mdp_transfer_time_us_max) {
+			sde_kms_info_add_keyint(info, "mdp_transfer_time_us_min",
+					mode_info.mdp_transfer_time_us_min);
+			sde_kms_info_add_keyint(info, "mdp_transfer_time_us_max",
+					mode_info.mdp_transfer_time_us_max);
+		}
+
 		sde_kms_info_add_keyint(info, "allowed_mode_switch",
 			mode_info.allowed_mode_switches);
 
@@ -3044,6 +3068,8 @@ static int _sde_connector_install_properties(struct drm_device *dev,
 			msm_property_install_range(&c_conn->property_info, "dyn_bit_clk",
 					0x0, 0, ~0, 0, CONNECTOR_PROP_DYN_BIT_CLK);
 
+		msm_property_install_range(&c_conn->property_info, "dyn_transfer_time",
+				 0x0, 0, 1000000, 0, CONNECTOR_PROP_DYN_TRANSFER_TIME);
 
 		mutex_lock(&c_conn->base.dev->mode_config.mutex);
 		sde_connector_fill_modes(&c_conn->base,

+ 7 - 0
msm/sde/sde_connector.h

@@ -431,6 +431,13 @@ struct sde_connector_ops {
 	 */
 	int (*get_num_lm_from_mode)(void *display, const struct drm_display_mode *mode);
 
+	/*
+	 * update_transfer_time - Update transfer time
+	 * @display: Pointer to private display structure
+	 * @transfer_time: new transfer time to be updated
+	 */
+	int (*update_transfer_time)(void *display, u32 transfer_time);
+
 };
 
 /**

+ 3 - 0
msm/sde/sde_kms.c

@@ -1787,6 +1787,7 @@ static int _sde_kms_setup_displays(struct drm_device *dev,
 		.prepare_commit = dsi_conn_prepare_commit,
 		.set_submode_info = dsi_conn_set_submode_blob_info,
 		.get_num_lm_from_mode = dsi_conn_get_lm_from_mode,
+		.update_transfer_time = dsi_display_update_transfer_time,
 	};
 	static const struct sde_connector_ops wb_ops = {
 		.post_init =    sde_wb_connector_post_init,
@@ -1807,6 +1808,7 @@ static int _sde_kms_setup_displays(struct drm_device *dev,
 		.install_properties = NULL,
 		.set_dyn_bit_clk = NULL,
 		.set_allowed_mode_switch = NULL,
+		.update_transfer_time = NULL,
 	};
 	static const struct sde_connector_ops dp_ops = {
 		.post_init  = dp_connector_post_init,
@@ -1829,6 +1831,7 @@ static int _sde_kms_setup_displays(struct drm_device *dev,
 		.install_properties = dp_connector_install_properties,
 		.set_allowed_mode_switch = NULL,
 		.set_dyn_bit_clk = NULL,
+		.update_transfer_time = NULL,
 	};
 	struct msm_display_info info;
 	struct drm_encoder *encoder;