Эх сурвалжийг харах

disp: msm: add qsync refresh rate support per mode

This change adds support for qsync min refresh rate per
timing mode and populates qsync min refresh rate based
on the current fps when qsync is enabled.

Change-Id: I191d1d72e95dd065c8c0b56a6100104c00c6d8f6
Signed-off-by: Yashwanth <[email protected]>
Yashwanth 4 жил өмнө
parent
commit
64b732f335

+ 2 - 0
msm/dsi/dsi_defs.h

@@ -413,6 +413,7 @@ struct dsi_panel_cmd_set {
  * @vdc:              VDC compression configuration.
  * @pclk_scale:       pclk scale factor, target bpp to source bpp
  * @roi_caps:         Panel ROI capabilities.
+ * @qsync_min_fps:        Qsync min fps rate
  */
 struct dsi_mode_info {
 	u32 h_active;
@@ -439,6 +440,7 @@ struct dsi_mode_info {
 	struct msm_display_vdc_info *vdc;
 	struct msm_ratio pclk_scale;
 	struct msm_roi_caps roi_caps;
+	u32 qsync_min_fps;
 };
 
 /**

+ 14 - 24
msm/dsi/dsi_display.c

@@ -6838,6 +6838,7 @@ int dsi_display_get_modes(struct dsi_display *display,
 	struct dsi_dyn_clk_caps *dyn_clk_caps;
 	int i, start, end, rc = -EINVAL;
 	int dsc_modes = 0, nondsc_modes = 0;
+	struct dsi_qsync_capabilities *qsync_caps;
 
 	if (!display || !out_modes) {
 		DSI_ERR("Invalid params\n");
@@ -6868,6 +6869,7 @@ int dsi_display_get_modes(struct dsi_display *display,
 		goto error;
 	}
 
+	qsync_caps = &(display->panel->qsync_caps);
 	dyn_clk_caps = &(display->panel->dyn_clk_caps);
 
 	timing_mode_count = display->panel->num_timing_nodes;
@@ -6963,6 +6965,14 @@ int dsi_display_get_modes(struct dsi_display *display,
 			memcpy(sub_mode, &display_mode, sizeof(display_mode));
 			array_idx++;
 
+			/*
+			 * Populate mode qsync min fps from panel min qsync fps dt property
+			 * in video mode & in command mode where per mode qsync min fps is
+			 * not defined.
+			 */
+			if (!sub_mode->timing.qsync_min_fps && qsync_caps->qsync_min_fps)
+				sub_mode->timing.qsync_min_fps = qsync_caps->qsync_min_fps;
+
 			if (!dfps_caps.dfps_support || !support_video_mode)
 				continue;
 
@@ -6970,6 +6980,10 @@ int dsi_display_get_modes(struct dsi_display *display,
 			curr_refresh_rate = sub_mode->timing.refresh_rate;
 			sub_mode->timing.refresh_rate = dfps_caps.dfps_list[i];
 
+			/* Override with qsync min fps list in dfps usecases */
+			if (qsync_caps->qsync_min_fps && qsync_caps->qsync_min_fps_list_len)
+				sub_mode->timing.qsync_min_fps = qsync_caps->qsync_min_fps_list[i];
+
 			dsi_display_get_dfps_timing(display, sub_mode,
 					curr_refresh_rate);
 			sub_mode->panel_mode_caps = DSI_OP_VIDEO_MODE;
@@ -7080,25 +7094,6 @@ int dsi_display_get_default_lms(void *dsi_display, u32 *num_lm)
 	return rc;
 }
 
-int dsi_display_get_qsync_min_fps(void *display_dsi, u32 mode_fps)
-{
-	struct dsi_display *display = (struct dsi_display *)display_dsi;
-	struct dsi_panel *panel;
-	u32 i;
-
-	if (display == NULL || display->panel == NULL)
-		return -EINVAL;
-
-	panel = display->panel;
-	for (i = 0; i < panel->dfps_caps.dfps_list_len; i++) {
-		if (panel->dfps_caps.dfps_list[i] == mode_fps)
-			return panel->qsync_caps.qsync_min_fps_list[i];
-	}
-	SDE_EVT32(mode_fps);
-	DSI_DEBUG("Invalid mode_fps %d\n", mode_fps);
-	return -EINVAL;
-}
-
 int dsi_display_get_avr_step_req_fps(void *display_dsi, u32 mode_fps)
 {
 	struct dsi_display *display = (struct dsi_display *)display_dsi;
@@ -8061,11 +8056,6 @@ static int dsi_display_qsync(struct dsi_display *display, bool enable)
 	int i;
 	int rc = 0;
 
-	if (!display->panel->qsync_caps.qsync_min_fps) {
-		DSI_ERR("%s:ERROR: qsync set, but no fps\n", __func__);
-		return 0;
-	}
-
 	mutex_lock(&display->display_lock);
 
 	display_for_each_ctrl(i, display) {

+ 0 - 9
msm/dsi/dsi_display.h

@@ -419,15 +419,6 @@ void dsi_display_put_mode(struct dsi_display *display,
  */
 int dsi_display_get_default_lms(void *dsi_display, u32 *num_lm);
 
-/**
- * dsi_display_get_qsync_min_fps() - get qsync min fps for given fps
- * @display:            Handle to display.
- * @mode_fps:           Fps value of current mode
- *
- * Return: Qsync min fps rate or -ve error code.
- */
-int dsi_display_get_qsync_min_fps(void *dsi_display, u32 mode_fps);
-
 /**
  * dsi_display_get_avr_step_req_fps() - get avr step rate for given fps
  * @display:            Handle to display.

+ 28 - 1
msm/dsi/dsi_drm.c

@@ -614,6 +614,7 @@ int dsi_conn_get_mode_info(struct drm_connector *connector,
 	mode_info->mdp_transfer_time_us =
 		dsi_mode->priv_info->mdp_transfer_time_us;
 	mode_info->disable_rsc_solver = dsi_mode->priv_info->disable_rsc_solver;
+	mode_info->qsync_min_fps = dsi_mode->timing.qsync_min_fps;
 
 	memcpy(&mode_info->topology, &dsi_mode->priv_info->topology,
 			sizeof(struct msm_display_topology));
@@ -699,6 +700,32 @@ int dsi_conn_set_avr_step_info(struct dsi_panel *panel, void *info)
 	return 0;
 }
 
+int dsi_conn_get_qsync_min_fps(void *display_dsi, struct drm_connector_state *conn_state)
+{
+	struct dsi_display *display = (struct dsi_display *)display_dsi;
+	int rc = 0;
+	struct dsi_display_mode partial_dsi_mode, *dsi_mode;
+	struct msm_sub_mode new_sub_mode;
+	struct sde_connector_state *sde_conn_state;
+	struct drm_display_mode *drm_mode;
+
+	if (!display || !display->drm_conn || !conn_state)
+		return -EINVAL;
+
+	sde_conn_state = to_sde_connector_state(conn_state);
+	drm_mode = sde_conn_state->msm_mode.base;
+	convert_to_dsi_mode(drm_mode, &partial_dsi_mode);
+	new_sub_mode.dsc_mode = sde_connector_get_property(conn_state, CONNECTOR_PROP_DSC_MODE);
+
+	rc = dsi_display_find_mode(display, &partial_dsi_mode, &new_sub_mode, &dsi_mode);
+	if (rc) {
+		DSI_ERR("invalid mode\n");
+		return rc;
+	}
+
+	return dsi_mode->timing.qsync_min_fps;
+}
+
 int dsi_conn_set_info_blob(struct drm_connector *connector,
 		void *info, void *display, struct msm_mode_info *mode_info)
 {
@@ -761,7 +788,7 @@ int dsi_conn_set_info_blob(struct drm_connector *connector,
 	}
 
 	sde_kms_info_add_keystr(info, "qsync support",
-		panel->qsync_caps.qsync_min_fps ?
+		panel->qsync_caps.qsync_support ?
 			"true" : "false");
 	if (panel->qsync_caps.qsync_min_fps)
 		sde_kms_info_add_keyint(info, "qsync_fps",

+ 8 - 0
msm/dsi/dsi_drm.h

@@ -172,4 +172,12 @@ int dsi_conn_set_dyn_bit_clk(struct drm_connector *connector,
 void dsi_conn_set_submode_blob_info(struct drm_connector *conn,
 		void *info, void *display, struct drm_display_mode *drm_mode);
 
+/**
+ * dsi_conn_get_qsync_min_fps() - get qsync min fps for given fps
+ * @display:            Handle to display.
+ * @conn_state:         Pointer to drm_connector_state structure
+ *
+ * Return: Qsync min fps rate or -ve error code.
+ */
+int dsi_conn_get_qsync_min_fps(void *dsi_display, struct drm_connector_state *conn_state);
 #endif /* _DSI_DRM_H_ */

+ 17 - 2
msm/dsi/dsi_panel.c

@@ -904,6 +904,13 @@ static int dsi_panel_parse_timing(struct dsi_mode_info *mode,
 		       rc);
 		goto error;
 	}
+
+	rc = utils->read_u32(utils->data, "qcom,qsync-mode-min-refresh-rate", &mode->qsync_min_fps);
+	if (rc) {
+		DSI_DEBUG("qsync min fps not defined in timing node\n");
+		rc = 0;
+	}
+
 	DSI_DEBUG("panel vert active:%d front_portch:%d back_porch:%d pulse_width:%d\n",
 		mode->v_active, mode->v_front_porch, mode->v_back_porch,
 		mode->v_sync_width);
@@ -1301,6 +1308,12 @@ static int dsi_panel_parse_qsync_caps(struct dsi_panel *panel,
 	struct dsi_parser_utils *utils = &panel->utils;
 	const char *name = panel->name;
 
+	qsync_caps->qsync_support = utils->read_bool(utils->data, "qcom,qsync-enable");
+	if (!qsync_caps->qsync_support) {
+		DSI_DEBUG("qsync feature not enabled\n");
+		goto error;
+	}
+
 	/**
 	 * "mdss-dsi-qsync-min-refresh-rate" is defined in cmd mode and
 	 *  video mode when there is only one qsync min fps present.
@@ -1373,8 +1386,10 @@ static int dsi_panel_parse_qsync_caps(struct dsi_panel *panel,
 qsync_support:
 	/* allow qsync support only if DFPS is with VFP approach */
 	if ((panel->dfps_caps.dfps_support) &&
-	    !(panel->dfps_caps.type == DSI_DFPS_IMMEDIATE_VFP))
-		panel->qsync_caps.qsync_min_fps = 0;
+	    !(panel->dfps_caps.type == DSI_DFPS_IMMEDIATE_VFP)) {
+		qsync_caps->qsync_support = false;
+		qsync_caps->qsync_min_fps = 0;
+	}
 
 error:
 	if (rc < 0) {

+ 1 - 1
msm/dsi/dsi_panel.h

@@ -89,7 +89,7 @@ struct dsi_dfps_capabilities {
 };
 
 struct dsi_qsync_capabilities {
-	/* qsync disabled if qsync_min_fps = 0 */
+	bool qsync_support;
 	u32 qsync_min_fps;
 	u32 *qsync_min_fps_list;
 	int qsync_min_fps_list_len;

+ 2 - 0
msm/msm_drv.h

@@ -747,6 +747,7 @@ struct msm_dyn_clk_list {
  * @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.
+ * @qsync_min_fps: qsync min fps rate
  */
 struct msm_mode_info {
 	uint32_t frame_rate;
@@ -765,6 +766,7 @@ struct msm_mode_info {
 	u32 allowed_mode_switches;
 	bool disable_rsc_solver;
 	struct msm_dyn_clk_list dyn_clk_list;
+	u32 qsync_min_fps;
 };
 
 /**

+ 3 - 1
msm/sde/sde_connector.c

@@ -2769,6 +2769,7 @@ static int sde_connector_populate_mode_info(struct drm_connector *conn,
 				sde_kms_info_add_keystr(info, "topology", topo_name);
 		}
 
+		sde_kms_info_add_keyint(info, "qsync_min_fps", mode_info.qsync_min_fps);
 		sde_kms_info_add_keyint(info, "has_cwb_crop", sde_kms->catalog->has_cwb_crop);
 		sde_kms_info_add_keyint(info, "has_dedicated_cwb_support",
 			sde_kms->catalog->has_dedicated_cwb_support);
@@ -2986,7 +2987,8 @@ static int _sde_connector_install_properties(struct drm_device *dev,
 			CONNECTOR_PROP_AUTOREFRESH);
 
 	if (connector_type == DRM_MODE_CONNECTOR_DSI) {
-		if (sde_kms->catalog->has_qsync && display_info->qsync_min_fps) {
+		if (sde_kms->catalog->has_qsync && dsi_display && dsi_display->panel &&
+				dsi_display->panel->qsync_caps.qsync_support) {
 			msm_property_install_enum(&c_conn->property_info,
 					"qsync_mode", 0, 0, e_qsync_mode,
 					ARRAY_SIZE(e_qsync_mode), 0,

+ 2 - 2
msm/sde/sde_connector.h

@@ -400,10 +400,10 @@ struct sde_connector_ops {
 	/**
 	 * get_qsync_min_fps - Get qsync min fps from qsync-min-fps-list
 	 * @display: Pointer to private display structure
-	 * @mode_fps: Fps value in dfps list
+	 * @conn_state: Pointer to drm_connector_state structure
 	 * Returns: Qsync min fps value on success
 	 */
-	int (*get_qsync_min_fps)(void *display, u32 mode_fps);
+	int (*get_qsync_min_fps)(void *display, struct drm_connector_state *conn_state);
 
 	/**
 	 * get_avr_step_req - Get the required avr_step for given fps rate

+ 7 - 15
msm/sde/sde_encoder.c

@@ -1028,10 +1028,9 @@ static int _sde_encoder_atomic_check_reserve(struct drm_encoder *drm_enc,
 	return ret;
 }
 
-static void _sde_encoder_get_qsync_fps_callback(
-		struct drm_encoder *drm_enc, u32 *qsync_fps, u32 vrr_fps)
+static void _sde_encoder_get_qsync_fps_callback(struct drm_encoder *drm_enc,
+			u32 *qsync_fps, struct drm_connector_state *conn_state)
 {
-	struct msm_display_info *disp_info;
 	struct sde_encoder_virt *sde_enc;
 	int rc = 0;
 	struct sde_connector *sde_conn;
@@ -1046,25 +1045,17 @@ static void _sde_encoder_get_qsync_fps_callback(
 	}
 
 	sde_enc = to_sde_encoder_virt(drm_enc);
-	disp_info = &sde_enc->disp_info;
-	*qsync_fps = disp_info->qsync_min_fps;
 
-	if (!disp_info->has_qsync_min_fps_list) {
-		return;
-	} else if (!sde_enc->cur_master || !(disp_info->capabilities & MSM_DISPLAY_CAP_VID_MODE)) {
+	if (!sde_enc->cur_master) {
 		SDE_ERROR("invalid qsync settings %d\n", !sde_enc->cur_master);
 		return;
 	}
 
-	/*
-	 * If "dsi-supported-qsync-min-fps-list" is defined, get
-	 * the qsync min fps corresponding to the fps in dfps list
-	 */
 	sde_conn = to_sde_connector(sde_enc->cur_master->connector);
 	if (sde_conn->ops.get_qsync_min_fps)
-		rc = sde_conn->ops.get_qsync_min_fps(sde_conn->display, vrr_fps);
+		rc = sde_conn->ops.get_qsync_min_fps(sde_conn->display, conn_state);
 
-	if (rc <= 0) {
+	if (rc < 0) {
 		SDE_ERROR("invalid qsync min fps %d\n", rc);
 		return;
 	}
@@ -1101,7 +1092,8 @@ static int _sde_encoder_avr_step_check(struct sde_connector *sde_conn,
 	if (!step)
 		return 0;
 
-	_sde_encoder_get_qsync_fps_callback(sde_conn_state->base.best_encoder, &min_fps, nom_fps);
+	_sde_encoder_get_qsync_fps_callback(sde_conn_state->base.best_encoder, &min_fps,
+		&sde_conn_state->base);
 	if (!min_fps || !nom_fps || step % nom_fps || step % min_fps || step < nom_fps ||
 			(vtotal * nom_fps) % step) {
 		SDE_ERROR("invalid avr_step rate! nom:%u min:%u step:%u vtotal:%u\n", nom_fps,

+ 1 - 1
msm/sde/sde_encoder_phys.h

@@ -82,7 +82,7 @@ struct sde_encoder_virt_ops {
 	void (*handle_frame_done)(struct drm_encoder *parent,
 			struct sde_encoder_phys *phys, u32 event);
 	void (*get_qsync_fps)(struct drm_encoder *parent,
-			u32 *qsync_fps, u32 vrr_fps);
+			u32 *qsync_fps, struct drm_connector_state *conn_state);
 };
 
 /**

+ 1 - 1
msm/sde/sde_encoder_phys_cmd.c

@@ -896,7 +896,7 @@ static int _get_tearcheck_threshold(struct sde_encoder_phys *phys_enc)
 
 		if (phys_enc->parent_ops.get_qsync_fps)
 			phys_enc->parent_ops.get_qsync_fps(
-				phys_enc->parent, &qsync_min_fps, 0);
+				phys_enc->parent, &qsync_min_fps, conn->state);
 
 		if (!qsync_min_fps || !default_fps || !yres) {
 			SDE_ERROR_CMDENC(cmd_enc,

+ 2 - 3
msm/sde/sde_encoder_phys_vid.c

@@ -397,7 +397,7 @@ static void sde_encoder_phys_vid_setup_timing_engine(
 	bool is_split_link = false;
 
 	if (!phys_enc || !phys_enc->sde_kms || !phys_enc->hw_ctl ||
-					!phys_enc->hw_intf) {
+			!phys_enc->hw_intf || !phys_enc->connector) {
 		SDE_ERROR("invalid encoder %d\n", !phys_enc);
 		return;
 	}
@@ -470,8 +470,7 @@ static void sde_encoder_phys_vid_setup_timing_engine(
 exit:
 	if (phys_enc->parent_ops.get_qsync_fps)
 		phys_enc->parent_ops.get_qsync_fps(
-			phys_enc->parent, &qsync_min_fps,
-			drm_mode_vrefresh(&phys_enc->cached_mode));
+			phys_enc->parent, &qsync_min_fps, phys_enc->connector->state);
 
 	/* only panels which support qsync will have a non-zero min fps */
 	if (qsync_min_fps) {

+ 1 - 1
msm/sde/sde_kms.c

@@ -1768,7 +1768,7 @@ static int _sde_kms_setup_displays(struct drm_device *dev,
 		.install_properties = NULL,
 		.set_allowed_mode_switch = dsi_conn_set_allowed_mode_switch,
 		.set_dyn_bit_clk = dsi_conn_set_dyn_bit_clk,
-		.get_qsync_min_fps = dsi_display_get_qsync_min_fps,
+		.get_qsync_min_fps = dsi_conn_get_qsync_min_fps,
 		.get_avr_step_req = dsi_display_get_avr_step_req_fps,
 		.prepare_commit = dsi_conn_prepare_commit,
 		.set_submode_info = dsi_conn_set_submode_blob_info,