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

disp: msm: dsi: publish RFI porch values for rate matching calculation

Currently when RFI is used on a video mode panel the horizontal or
vertical front porch values can be adjusted to maintain a constant FPS.
When this feature is enabled, driver is not propagating the new
htotal or vtotal values to usermode for accurate BW and MDP clock
calculation, which may lead to underrun in some usecase.

This change publishes beforehand all the RFI related timing
such as compensation type, hfp or vfp and clock values for
each mode for accurate BW and clock calculation.

Change-Id: Ib89c5e318fe978b0ae2215dedc430e057a9a81b9
Signed-off-by: Amine Najahi <[email protected]>
Amine Najahi 4 жил өмнө
parent
commit
1881acdb2b

+ 1 - 11
msm/dsi/dsi_defs.h

@@ -598,16 +598,6 @@ struct dsi_host_config {
 	struct dsi_lane_map lane_map;
 };
 
-/**
- * struct dyn_clk_list - list of dynamic clock rates.
- * @rates: list of supported clock rates
- * @count: number of supported clock rates
- */
-struct dyn_clk_list {
-	u32 *rates;
-	u32 count;
-};
-
 /**
  * struct dsi_display_mode_priv_info - private mode info that will be attached
  *                             with each drm mode
@@ -646,7 +636,7 @@ struct dsi_display_mode_priv_info {
 	u32 dsi_transfer_time_us;
 	u64 clk_rate_hz;
 	u64 min_dsi_clk_hz;
-	struct dyn_clk_list bit_clk_list;
+	struct msm_dyn_clk_list bit_clk_list;
 
 	struct msm_display_topology topology;
 	struct msm_display_dsc_info dsc;

+ 33 - 10
msm/dsi/dsi_display.c

@@ -6714,14 +6714,18 @@ void dsi_display_adjust_mode_timing(struct dsi_display *display,
 	default:
 		break;
 	}
+
+	dsi_mode->pixel_clk_khz = div_u64(dsi_mode->timing.clk_rate_hz * lanes, bpp);
+	do_div(dsi_mode->pixel_clk_khz, 1000);
+	dsi_mode->pixel_clk_khz *= display->ctrl_count;
 }
 
 static void _dsi_display_populate_bit_clks(struct dsi_display *display, int start, int end)
 {
 	struct dsi_dyn_clk_caps *dyn_clk_caps;
-	struct dsi_display_mode *src;
+	struct dsi_display_mode *src, dst;
 	struct dsi_host_common_cfg *cfg;
-	int i, bpp, lanes = 0;
+	int i, j, bpp, lanes = 0;
 
 	if (!display)
 		return;
@@ -6754,9 +6758,33 @@ static void _dsi_display_populate_bit_clks(struct dsi_display *display, int star
 
 		dsi_display_adjust_mode_timing(display, src, lanes, bpp);
 
-		src->pixel_clk_khz = div_u64(src->timing.clk_rate_hz * lanes, bpp);
-		src->pixel_clk_khz /= 1000;
-		src->pixel_clk_khz *= display->ctrl_count;
+		/* populate mode adjusted values */
+		for (j = 0; j < src->priv_info->bit_clk_list.count; j++) {
+			memcpy(&dst, src, sizeof(struct dsi_display_mode));
+			memcpy(&dst.timing, &src->timing, sizeof(struct dsi_mode_info));
+			dst.timing.clk_rate_hz = src->priv_info->bit_clk_list.rates[j];
+
+			dsi_display_adjust_mode_timing(display, &dst, lanes, bpp);
+
+			/* store the list of RFI matching porches */
+			switch (dyn_clk_caps->type) {
+			case DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_HFP:
+				src->priv_info->bit_clk_list.front_porches[j] =
+						dst.timing.h_front_porch;
+				break;
+
+			case DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_VFP:
+				src->priv_info->bit_clk_list.front_porches[j] =
+						dst.timing.v_front_porch;
+				break;
+
+			default:
+				break;
+			}
+
+			/* store the list of RFI matching pixel clocks */
+			src->priv_info->bit_clk_list.pixel_clks_khz[j] = dst.pixel_clk_khz;
+		}
 	}
 }
 
@@ -8579,11 +8607,6 @@ int dsi_display_update_dyn_bit_clk(struct dsi_display *display,
 
 	dsi_display_adjust_mode_timing(display, mode, lanes, bpp);
 
-	/* adjust pixel clock based on dynamic bit clock */
-	mode->pixel_clk_khz = div_u64(mode->timing.clk_rate_hz * lanes, bpp);
-	do_div(mode->pixel_clk_khz, 1000);
-	mode->pixel_clk_khz *= display->ctrl_count;
-
 	SDE_EVT32(display->dyn_bit_clk, mode->priv_info->min_dsi_clk_hz, mode->pixel_clk_khz);
 	DSI_DEBUG("dynamic bit clk:%u, min dsi clk:%llu, lanes:%d, bpp:%d, pck:%d Khz\n",
 			display->dyn_bit_clk, mode->priv_info->min_dsi_clk_hz, lanes, bpp,

+ 63 - 35
msm/dsi/dsi_drm.c

@@ -589,12 +589,13 @@ int dsi_conn_get_mode_info(struct drm_connector *connector,
 	struct dsi_display_mode partial_dsi_mode, *dsi_mode = NULL;
 	struct dsi_mode_info *timing;
 	int src_bpp, tar_bpp, rc = 0;
+	struct dsi_display *dsi_display = (struct dsi_display *) display;
 
 	if (!drm_mode || !mode_info)
 		return -EINVAL;
 
 	convert_to_dsi_mode(drm_mode, &partial_dsi_mode);
-	rc = dsi_display_find_mode(display, &partial_dsi_mode, sub_mode, &dsi_mode);
+	rc = dsi_display_find_mode(dsi_display, &partial_dsi_mode, NULL, &dsi_mode);
 	if (rc || !dsi_mode->priv_info)
 		return -EINVAL;
 
@@ -607,7 +608,6 @@ int dsi_conn_get_mode_info(struct drm_connector *connector,
 	mode_info->jitter_numer = dsi_mode->priv_info->panel_jitter_numer;
 	mode_info->jitter_denom = dsi_mode->priv_info->panel_jitter_denom;
 	mode_info->dfps_maxfps = dsi_drm_get_dfps_maxfps(display);
-	mode_info->clk_rate = dsi_mode->timing.clk_rate_hz;
 	mode_info->panel_mode_caps = dsi_mode->panel_mode_caps;
 	mode_info->mdp_transfer_time_us =
 		dsi_mode->priv_info->mdp_transfer_time_us;
@@ -617,12 +617,23 @@ int dsi_conn_get_mode_info(struct drm_connector *connector,
 			sizeof(struct msm_display_topology));
 
 	if (dsi_mode->priv_info->bit_clk_list.count) {
-		mode_info->bit_clk_rates =
-				dsi_mode->priv_info->bit_clk_list.rates;
-		mode_info->bit_clk_count =
-				dsi_mode->priv_info->bit_clk_list.count;
+		struct msm_dyn_clk_list *dyn_clk_list = &mode_info->dyn_clk_list;
+
+		dyn_clk_list->rates = dsi_mode->priv_info->bit_clk_list.rates;
+		dyn_clk_list->count = dsi_mode->priv_info->bit_clk_list.count;
+		dyn_clk_list->type = dsi_display->panel->dyn_clk_caps.type;
+		dyn_clk_list->front_porches = dsi_mode->priv_info->bit_clk_list.front_porches;
+		dyn_clk_list->pixel_clks_khz = dsi_mode->priv_info->bit_clk_list.pixel_clks_khz;
+
+		rc = dsi_display_restore_bit_clk(dsi_display, dsi_mode);
+		if (rc) {
+			DSI_ERR("[%s] bit clk rate cannot be restored\n", dsi_display->name);
+			return rc;
+		}
 	}
 
+	mode_info->clk_rate = dsi_mode->timing.clk_rate_hz;
+
 	if (dsi_mode->priv_info->dsc_enabled) {
 		mode_info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_DSC;
 		mode_info->topology.comp_type = MSM_DISPLAY_COMPRESSION_DSC;
@@ -845,6 +856,12 @@ void dsi_conn_set_submode_blob_info(struct drm_connector *conn,
 	struct dsi_display_mode partial_dsi_mode;
 	int count, i;
 	int preferred_submode_idx = -EINVAL;
+	enum dsi_dyn_clk_feature_type dyn_clk_type;
+	char *dyn_clk_types[DSI_DYN_CLK_TYPE_MAX] = {
+		[DSI_DYN_CLK_TYPE_LEGACY] = "none",
+		[DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_HFP] = "hfp",
+		[DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_VFP] = "vfp",
+	};
 
 	if (!conn || !display || !drm_mode) {
 		DSI_ERR("Invalid params\n");
@@ -861,35 +878,46 @@ void dsi_conn_set_submode_blob_info(struct drm_connector *conn,
 		u32 panel_mode_caps = 0;
 		const char *topo_name = NULL;
 
-		if (dsi_display_mode_match(&partial_dsi_mode, dsi_mode,
-				DSI_MODE_MATCH_FULL_TIMINGS)) {
-
-			sde_kms_info_add_keyint(info, "submode_idx", i);
-
-			if (dsi_mode->is_preferred)
-				preferred_submode_idx = i;
-
-			if (dsi_mode->panel_mode_caps & DSI_OP_CMD_MODE)
-				panel_mode_caps |= DRM_MODE_FLAG_CMD_MODE_PANEL;
-			if (dsi_mode->panel_mode_caps & DSI_OP_VIDEO_MODE)
-				panel_mode_caps |= DRM_MODE_FLAG_VID_MODE_PANEL;
-
-			sde_kms_info_add_keyint(info, "panel_mode_capabilities",
-				panel_mode_caps);
-
-			sde_kms_info_add_keyint(info, "dsc_mode",
-				dsi_mode->priv_info->dsc_enabled ? MSM_DISPLAY_DSC_MODE_ENABLED :
-					MSM_DISPLAY_DSC_MODE_DISABLED);
-			topo_name = sde_conn_get_topology_name(conn,
-				dsi_mode->priv_info->topology);
-			if (topo_name)
-				sde_kms_info_add_keystr(info, "topology", topo_name);
-
-			if (dsi_mode->priv_info->bit_clk_list.count > 0)
-				sde_kms_info_add_list(info, "dyn_bitclk_list",
-						dsi_mode->priv_info->bit_clk_list.rates,
-						dsi_mode->priv_info->bit_clk_list.count);
-		}
+		if (!dsi_display_mode_match(&partial_dsi_mode, dsi_mode,
+				DSI_MODE_MATCH_FULL_TIMINGS))
+			continue;
+
+		sde_kms_info_add_keyint(info, "submode_idx", i);
+
+		if (dsi_mode->is_preferred)
+			preferred_submode_idx = i;
+
+		if (dsi_mode->panel_mode_caps & DSI_OP_CMD_MODE)
+			panel_mode_caps |= DRM_MODE_FLAG_CMD_MODE_PANEL;
+		if (dsi_mode->panel_mode_caps & DSI_OP_VIDEO_MODE)
+			panel_mode_caps |= DRM_MODE_FLAG_VID_MODE_PANEL;
+
+		sde_kms_info_add_keyint(info, "panel_mode_capabilities",
+			panel_mode_caps);
+
+		sde_kms_info_add_keyint(info, "dsc_mode",
+			dsi_mode->priv_info->dsc_enabled ? MSM_DISPLAY_DSC_MODE_ENABLED :
+				MSM_DISPLAY_DSC_MODE_DISABLED);
+		topo_name = sde_conn_get_topology_name(conn,
+			dsi_mode->priv_info->topology);
+		if (topo_name)
+			sde_kms_info_add_keystr(info, "topology", topo_name);
+
+		if (!dsi_mode->priv_info->bit_clk_list.count)
+			continue;
+
+		dyn_clk_type = dsi_display->panel->dyn_clk_caps.type;
+		sde_kms_info_add_list(info, "dyn_bitclk_list",
+				dsi_mode->priv_info->bit_clk_list.rates,
+				dsi_mode->priv_info->bit_clk_list.count);
+		sde_kms_info_add_keystr(info, "dyn_fp_type",
+				dyn_clk_types[dyn_clk_type]);
+		sde_kms_info_add_list(info, "dyn_fp_list",
+				dsi_mode->priv_info->bit_clk_list.front_porches,
+				dsi_mode->priv_info->bit_clk_list.count);
+		sde_kms_info_add_list(info, "dyn_pclk_list",
+				dsi_mode->priv_info->bit_clk_list.pixel_clks_khz,
+				dsi_mode->priv_info->bit_clk_list.count);
 	}
 
 	if (preferred_submode_idx >= 0)

+ 31 - 6
msm/dsi/dsi_panel.c

@@ -1388,7 +1388,7 @@ static int dsi_panel_parse_dyn_clk_list(struct dsi_display_mode *mode,
 		struct dsi_parser_utils *utils)
 {
 	int i, rc = 0;
-	struct dyn_clk_list *bit_clk_list;
+	struct msm_dyn_clk_list *bit_clk_list;
 
 	if (!mode || !mode->priv_info) {
 		DSI_ERR("invalid arguments\n");
@@ -1398,26 +1398,51 @@ static int dsi_panel_parse_dyn_clk_list(struct dsi_display_mode *mode,
 	bit_clk_list = &mode->priv_info->bit_clk_list;
 
 	bit_clk_list->count = utils->count_u32_elems(utils->data, "qcom,dsi-dyn-clk-list");
-	if (bit_clk_list->count < 1)
-		return 0;
+	if (bit_clk_list->count < 1 || bit_clk_list->count > 100) {
+		DSI_ERR("invalid number of bit clock values, must be between 1 and 100\n");
+		return -EINVAL;
+	}
 
 	bit_clk_list->rates = kcalloc(bit_clk_list->count, sizeof(u32), GFP_KERNEL);
 	if (!bit_clk_list->rates) {
 		DSI_ERR("failed to allocate space for bit clock list\n");
-		return -ENOMEM;
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	bit_clk_list->front_porches = kcalloc(bit_clk_list->count, sizeof(u32), GFP_KERNEL);
+	if (!bit_clk_list->front_porches) {
+		DSI_ERR("failed to allocate space for front porch list\n");
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	bit_clk_list->pixel_clks_khz = kcalloc(bit_clk_list->count, sizeof(u32), GFP_KERNEL);
+	if (!bit_clk_list->pixel_clks_khz) {
+		DSI_ERR("failed to allocate space for pclk list\n");
+		rc = -ENOMEM;
+		goto error;
 	}
 
 	rc = utils->read_u32_array(utils->data, "qcom,dsi-dyn-clk-list",
 			bit_clk_list->rates, bit_clk_list->count);
 	if (rc) {
-		DSI_ERR("failed to parse supported bit clk list, rc=%d\n", rc);
-		return -EINVAL;
+		DSI_ERR("failed to parse supported bit clk list values, rc=%d\n", rc);
+		goto error;
 	}
 
 	for (i = 0; i < bit_clk_list->count; i++)
 		DSI_DEBUG("bit clk rate[%d]:%d\n", i, bit_clk_list->rates[i]);
 
 	return 0;
+
+error:
+	bit_clk_list->count = 0;
+	kfree(bit_clk_list->rates);
+	kfree(bit_clk_list->front_porches);
+	kfree(bit_clk_list->pixel_clks_khz);
+
+	return rc;
 }
 
 static int dsi_panel_parse_dyn_clk_caps(struct dsi_panel *panel)

+ 18 - 4
msm/msm_drv.h

@@ -712,6 +712,22 @@ struct msm_display_topology {
 	enum msm_display_compression_type comp_type;
 };
 
+/**
+ * struct msm_dyn_clk_list - list of dynamic clock rates.
+ * @count: number of supported clock rates
+ * @rates: list of supported clock rates
+ * @type: dynamic clock feature support type
+ * @front_porches: list of clock rate matching porch compensation values
+ * @pixel_clks_khz: list of clock rate matching pixel clock values
+ */
+struct msm_dyn_clk_list {
+	u32 count;
+	u32 *rates;
+	u32 type;
+	u32 *front_porches;
+	u32 *pixel_clks_khz;
+};
+
 /**
  * struct msm_mode_info - defines all msm custom mode info
  * @frame_rate:      frame_rate of the mode
@@ -729,9 +745,8 @@ struct msm_display_topology {
  * @mdp_transfer_time_us   Specifies the mdp transfer time for command mode
  *                         panels in microseconds.
  * @allowed_mode_switches: bit mask to indicate supported mode switch.
- * @bit_clk_rates: list of supported bit clock rates
- * @bit_clk_count: number of supported bit clock rates
  * @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.
  */
 struct msm_mode_info {
 	uint32_t frame_rate;
@@ -748,9 +763,8 @@ struct msm_mode_info {
 	u32 panel_mode_caps;
 	u32 mdp_transfer_time_us;
 	u32 allowed_mode_switches;
-	u32 *bit_clk_rates;
-	u32 bit_clk_count;
 	bool disable_rsc_solver;
+	struct msm_dyn_clk_list dyn_clk_list;
 };
 
 /**