Pārlūkot izejas kodu

disp: msm: sde: add multi-mode RFI support

Currently, RFI feature only supports panel that contains
a single timing node. This limits the feature availability
for panel with multiple modes or with DFPS support.

This change adds support for RFI on panels that contains
multiple timing nodes.

Change-Id: I3a7aadf7b6da3518350b2eb815602b13b5c259f5
Signed-off-by: Amine Najahi <[email protected]>
Amine Najahi 4 gadi atpakaļ
vecāks
revīzija
c5f2bd7401
7 mainītis faili ar 102 papildinājumiem un 75 dzēšanām
  1. 12 0
      msm/dsi/dsi_defs.h
  2. 25 13
      msm/dsi/dsi_display.c
  3. 9 24
      msm/dsi/dsi_drm.c
  4. 42 23
      msm/dsi/dsi_panel.c
  5. 0 2
      msm/dsi/dsi_panel.h
  6. 4 0
      msm/msm_drv.h
  7. 10 13
      msm/sde/sde_connector.c

+ 12 - 0
msm/dsi/dsi_defs.h

@@ -587,6 +587,16 @@ 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
@@ -600,6 +610,7 @@ struct dsi_host_config {
  * @dsi_transfer_time_us: Specifies the dsi transfer time for cmd panels.
  * @clk_rate_hz:          DSI bit clock per lane in hz.
  * @min_dsi_clk_hz:       Min dsi clk per lane to transfer frame in vsync time.
+ * @bit_clk_list:         List of dynamic bit clock rates supported.
  * @topology:             Topology selected for the panel
  * @dsc:                  DSC compression info
  * @vdc:                  VDC compression info
@@ -623,6 +634,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_display_topology topology;
 	struct msm_display_dsc_info dsc;

+ 25 - 13
msm/dsi/dsi_display.c

@@ -6678,12 +6678,11 @@ static void _dsi_display_populate_bit_clks(struct dsi_display *display,
 		src = &display->modes[i];
 		if (!src)
 			return;
-		/*
-		 * TODO: currently setting the first bit rate in
-		 * the list as preferred rate. But ideally should
-		 * be based on user or device tree preferrence.
-		 */
-		src->timing.clk_rate_hz = dyn_clk_caps->bit_clk_list[0];
+
+		if (!src->priv_info->bit_clk_list.count)
+			continue;
+
+		src->timing.clk_rate_hz = src->priv_info->bit_clk_list.rates[0];
 
 		dsi_display_adjust_mode_timing(display, src, lanes, bpp);
 
@@ -6728,6 +6727,7 @@ static void _dsi_display_populate_bit_clks(struct dsi_display *display,
 
 int dsi_display_restore_bit_clk(struct dsi_display *display, struct dsi_display_mode *mode)
 {
+	int i;
 	u32 clk_rate_hz = 0;
 
 	if (!display || !mode || !mode->priv_info) {
@@ -6735,17 +6735,24 @@ int dsi_display_restore_bit_clk(struct dsi_display *display, struct dsi_display_
 		return -EINVAL;
 	}
 
-	/* for dynamic DSI use specified clock rate otherwise restore clock rate */
-	if (display->dyn_bit_clk > 0)
-		clk_rate_hz = display->dyn_bit_clk;
-	else if (display->cached_clk_rate > 0)
-		clk_rate_hz = display->cached_clk_rate;
+	clk_rate_hz = display->cached_clk_rate;
+
+	if (mode->priv_info->bit_clk_list.count) {
+		/* use first entry as the default bit clk rate */
+		clk_rate_hz = mode->priv_info->bit_clk_list.rates[0];
+
+		for (i = 0; i < mode->priv_info->bit_clk_list.count; i++) {
+			if (display->dyn_bit_clk == mode->priv_info->bit_clk_list.rates[i])
+				clk_rate_hz = display->dyn_bit_clk;
+		}
+	}
 
 	mode->timing.clk_rate_hz = clk_rate_hz;
 	mode->priv_info->clk_rate_hz = clk_rate_hz;
-	DSI_DEBUG("dyn_bit_clk:%u, cached_clk_rate:%u, clk_rate_hz:%u\n",
-			display->dyn_bit_clk, display->cached_clk_rate, clk_rate_hz);
 
+	SDE_EVT32(clk_rate_hz, display->cached_clk_rate, display->dyn_bit_clk);
+	DSI_DEBUG("clk_rate_hz:%u, cached_clk_rate:%u, dyn_bit_clk:%u\n",
+			clk_rate_hz, display->cached_clk_rate, display->dyn_bit_clk);
 	return 0;
 }
 
@@ -8412,6 +8419,9 @@ int dsi_display_update_dyn_bit_clk(struct dsi_display *display,
 	} else if (!display->dyn_bit_clk_pending) {
 		DSI_DEBUG("dynamic bit clock rate not updated\n");
 		return 0;
+	} else if (!display->dyn_bit_clk) {
+		DSI_DEBUG("dynamic bit clock rate cleared\n");
+		return 0;
 	} else if (display->dyn_bit_clk < mode->priv_info->min_dsi_clk_hz) {
 		DSI_ERR("dynamic bit clock rate %llu smaller than minimum value:%llu\n",
 				display->dyn_bit_clk, mode->priv_info->min_dsi_clk_hz);
@@ -8440,6 +8450,8 @@ int dsi_display_update_dyn_bit_clk(struct dsi_display *display,
 	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,
 			mode->pixel_clk_khz);

+ 9 - 24
msm/dsi/dsi_drm.c

@@ -579,6 +579,13 @@ int dsi_conn_get_mode_info(struct drm_connector *connector,
 	memcpy(&mode_info->topology, &dsi_mode->priv_info->topology,
 			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;
+	}
+
 	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;
@@ -697,11 +704,6 @@ int dsi_conn_set_info_blob(struct drm_connector *connector,
 	sde_kms_info_add_keystr(info, "dyn bitclk support",
 			panel->dyn_clk_caps.dyn_clk_support ? "true" : "false");
 
-	if (panel->dyn_clk_caps.dyn_clk_support)
-		sde_kms_info_add_list(info, "dyn_bitclk_list",
-				panel->dyn_clk_caps.bit_clk_list,
-				panel->dyn_clk_caps.bit_clk_list_len);
-
 	switch (panel->phy_props.rotation) {
 	case DSI_PANEL_ROTATE_NONE:
 		sde_kms_info_add_keystr(info, "panel orientation", "none");
@@ -1297,12 +1299,8 @@ void dsi_conn_set_allowed_mode_switch(struct drm_connector *connector,
 
 int dsi_conn_set_dyn_bit_clk(struct drm_connector *connector, uint64_t value)
 {
-	int i;
-	bool is_valid = false;
 	struct sde_connector *c_conn = NULL;
-	struct sde_connector_state *c_state;
 	struct dsi_display *display;
-	struct dsi_dyn_clk_caps *dyn_clk_caps;
 
 	if (!connector) {
 		DSI_ERR("invalid connector\n");
@@ -1310,25 +1308,12 @@ int dsi_conn_set_dyn_bit_clk(struct drm_connector *connector, uint64_t value)
 	}
 
 	c_conn = to_sde_connector(connector);
-	c_state = to_sde_connector_state(connector->state);
-
 	display = (struct dsi_display *) c_conn->display;
-	dyn_clk_caps = &display->panel->dyn_clk_caps;
-
-	for (i = 0; i < dyn_clk_caps->bit_clk_list_len; i++) {
-		if (dyn_clk_caps->bit_clk_list[i] == value) {
-			is_valid = true;
-			break;
-		}
-	}
-
-	if (!is_valid) {
-		DSI_ERR("invalid dynamic bit clock rate selection %llu\n", value);
-		return -EINVAL;
-	}
 
 	display->dyn_bit_clk = value;
 	display->dyn_bit_clk_pending = true;
+
+	SDE_EVT32(display->dyn_bit_clk);
 	DSI_DEBUG("update dynamic bit clock rate to %llu\n", display->dyn_bit_clk);
 
 	return 0;

+ 42 - 23
msm/dsi/dsi_panel.c

@@ -1326,13 +1326,48 @@ error:
 	return rc;
 }
 
+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;
+
+	if (!mode || !mode->priv_info) {
+		DSI_ERR("invalid arguments\n");
+		return -EINVAL;
+	}
+
+	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;
+
+	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 = 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;
+	}
+
+	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;
+}
+
 static int dsi_panel_parse_dyn_clk_caps(struct dsi_panel *panel)
 {
 	int rc = 0;
 	bool supported = false;
 	struct dsi_dyn_clk_caps *dyn_clk_caps = &panel->dyn_clk_caps;
 	struct dsi_parser_utils *utils = &panel->utils;
-	const char *name = panel->name;
 	const char *type;
 
 	supported = utils->read_bool(utils->data, "qcom,dsi-dyn-clk-enable");
@@ -1342,28 +1377,6 @@ static int dsi_panel_parse_dyn_clk_caps(struct dsi_panel *panel)
 		return rc;
 	}
 
-	dyn_clk_caps->bit_clk_list_len = utils->count_u32_elems(utils->data,
-			"qcom,dsi-dyn-clk-list");
-
-	if (dyn_clk_caps->bit_clk_list_len < 1) {
-		DSI_ERR("[%s] failed to get supported bit clk list\n", name);
-		return -EINVAL;
-	}
-
-	dyn_clk_caps->bit_clk_list = kcalloc(dyn_clk_caps->bit_clk_list_len,
-			sizeof(u32), GFP_KERNEL);
-	if (!dyn_clk_caps->bit_clk_list)
-		return -ENOMEM;
-
-	rc = utils->read_u32_array(utils->data, "qcom,dsi-dyn-clk-list",
-			dyn_clk_caps->bit_clk_list,
-			dyn_clk_caps->bit_clk_list_len);
-
-	if (rc) {
-		DSI_ERR("[%s] failed to parse supported bit clk list\n", name);
-		return -EINVAL;
-	}
-
 	dyn_clk_caps->dyn_clk_support = true;
 
 	type = utils->get_property(utils->data,
@@ -4032,6 +4045,12 @@ int dsi_panel_get_mode(struct dsi_panel *panel,
 			goto parse_fail;
 		}
 
+		if (panel->dyn_clk_caps.dyn_clk_support) {
+			rc = dsi_panel_parse_dyn_clk_list(mode, utils);
+			if (rc)
+				DSI_ERR("failed to parse dynamic clk rates, rc=%d\n", rc);
+		}
+
 		rc = dsi_panel_parse_dsc_params(mode, utils);
 		if (rc) {
 			DSI_ERR("failed to parse dsc params, rc=%d\n", rc);

+ 0 - 2
msm/dsi/dsi_panel.h

@@ -97,8 +97,6 @@ struct dsi_qsync_capabilities {
 
 struct dsi_dyn_clk_caps {
 	bool dyn_clk_support;
-	u32 *bit_clk_list;
-	u32 bit_clk_list_len;
 	enum dsi_dyn_clk_feature_type type;
 	bool maintain_const_fps;
 };

+ 4 - 0
msm/msm_drv.h

@@ -703,6 +703,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
  */
 struct msm_mode_info {
 	uint32_t frame_rate;
@@ -719,6 +721,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;
 };
 
 /**

+ 10 - 13
msm/sde/sde_connector.c

@@ -2623,6 +2623,12 @@ static int sde_connector_populate_mode_info(struct drm_connector *conn,
 		sde_kms_info_add_keyint(info, "bit_clk_rate",
 					mode_info.clk_rate);
 
+		if (mode_info.bit_clk_count > 0)
+			sde_kms_info_add_list(info, "dyn_bitclk_list",
+					mode_info.bit_clk_rates,
+					mode_info.bit_clk_count);
+
+
 		topology_idx = (int)sde_rm_get_topology_name(&sde_kms->rm,
 					mode_info.topology);
 		if (topology_idx < SDE_RM_TOPOLOGY_MAX) {
@@ -2761,11 +2767,9 @@ static int _sde_connector_install_properties(struct drm_device *dev,
 	struct msm_display_info *display_info)
 {
 	struct dsi_display *dsi_display;
-	int rc, i;
+	int rc;
 	struct drm_connector *connector;
 	u64 panel_id = ~0x0;
-	struct dsi_dyn_clk_caps *dyn_clk_caps;
-	u32 max_bit_clk;
 
 	msm_property_install_blob(&c_conn->property_info, "capabilities",
 			DRM_MODE_PROP_IMMUTABLE, CONNECTOR_PROP_SDE_INFO);
@@ -2800,17 +2804,10 @@ static int _sde_connector_install_properties(struct drm_device *dev,
 		}
 
 		if (dsi_display && dsi_display->panel &&
-				dsi_display->panel->dyn_clk_caps.dyn_clk_support) {
-
-			dyn_clk_caps = &dsi_display->panel->dyn_clk_caps;
-			max_bit_clk = dyn_clk_caps->bit_clk_list[0];
-			for (i = 1; i < dyn_clk_caps->bit_clk_list_len; i++)
-				max_bit_clk = max(dyn_clk_caps->bit_clk_list[i], max_bit_clk);
-
+				dsi_display->panel->dyn_clk_caps.dyn_clk_support)
 			msm_property_install_range(&c_conn->property_info, "dyn_bit_clk",
-					0x0, 0, max_bit_clk, max_bit_clk,
-					CONNECTOR_PROP_DYN_BIT_CLK);
-		}
+					0x0, 0, ~0, 0, CONNECTOR_PROP_DYN_BIT_CLK);
+
 
 		mutex_lock(&c_conn->base.dev->mode_config.mutex);
 		sde_connector_fill_modes(&c_conn->base,