Преглед на файлове

disp: msm: sde: add new interface for RFI feature

Add a new connector range property and a new entry to the panel
capability blob to publish the list of supported RFI frequencies.
In addition, add the required functions to set, validate and update
DSI bit clock rate value to trigger an internal seamless mode switch
and reconfigure DSI clock and PLL.

Change-Id: I7d19cc369f8c5528709f2f20a51ef02180ebdea4
Signed-off-by: Amine Najahi <[email protected]>
Amine Najahi преди 4 години
родител
ревизия
d4def5bd8c
променени са 11 файла, в които са добавени 278 реда и са изтрити 44 реда
  1. 89 6
      msm/dsi/dsi_display.c
  2. 22 1
      msm/dsi/dsi_display.h
  3. 76 31
      msm/dsi/dsi_drm.c
  4. 10 4
      msm/dsi/dsi_drm.h
  5. 1 0
      msm/msm_drv.h
  6. 3 0
      msm/msm_kms.h
  7. 25 1
      msm/sde/sde_connector.c
  8. 16 0
      msm/sde/sde_connector.h
  9. 3 0
      msm/sde/sde_kms.c
  10. 10 0
      msm/sde/sde_kms.h
  11. 23 1
      msm/sde/sde_kms_utils.c

+ 89 - 6
msm/dsi/dsi_display.c

@@ -6726,6 +6726,29 @@ 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)
+{
+	u32 clk_rate_hz = 0;
+
+	if (!display || !mode || !mode->priv_info) {
+		DSI_ERR("invalid arguments\n");
+		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;
+
+	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);
+
+	return 0;
+}
+
 void dsi_display_put_mode(struct dsi_display *display,
 	struct dsi_display_mode *mode)
 {
@@ -7237,9 +7260,11 @@ int dsi_display_set_mode(struct dsi_display *display,
 		}
 	}
 
-	/*For dynamic DSI setting, use specified clock rate */
-	if (display->cached_clk_rate > 0)
-		adj_mode.priv_info->clk_rate_hz = display->cached_clk_rate;
+	rc = dsi_display_restore_bit_clk(display, &adj_mode);
+	if (rc) {
+		DSI_ERR("[%s] bit clk rate cannot be restored\n", display->name);
+		goto error;
+	}
 
 	rc = dsi_display_validate_mode_set(display, &adj_mode, flags);
 	if (rc) {
@@ -7253,11 +7278,13 @@ int dsi_display_set_mode(struct dsi_display *display,
 		goto error;
 	}
 
-	DSI_INFO("mdp_transfer_time=%d, hactive=%d, vactive=%d, fps=%d\n",
+	DSI_INFO("mdp_transfer_time=%d, hactive=%d, vactive=%d, fps=%d, clk_rate=%llu\n",
 			adj_mode.priv_info->mdp_transfer_time_us,
-			timing.h_active, timing.v_active, timing.refresh_rate);
+			timing.h_active, timing.v_active, timing.refresh_rate,
+			adj_mode.priv_info->clk_rate_hz);
 	SDE_EVT32(adj_mode.priv_info->mdp_transfer_time_us,
-			timing.h_active, timing.v_active, timing.refresh_rate);
+			timing.h_active, timing.v_active, timing.refresh_rate,
+			adj_mode.priv_info->clk_rate_hz);
 
 	memcpy(display->panel->cur_mode, &adj_mode, sizeof(adj_mode));
 error:
@@ -8366,6 +8393,62 @@ int dsi_display_update_pps(char *pps_cmd, void *disp)
 	return 0;
 }
 
+int dsi_display_update_dyn_bit_clk(struct dsi_display *display,
+			struct dsi_display_mode *mode)
+{
+	struct dsi_dyn_clk_caps *dyn_clk_caps;
+	struct dsi_host_common_cfg *host_cfg;
+	int bpp, lanes = 0;
+
+	if (!display || !mode) {
+		DSI_ERR("invalid arguments\n");
+		return -EINVAL;
+	}
+
+	dyn_clk_caps = &(display->panel->dyn_clk_caps);
+	if (!dyn_clk_caps->dyn_clk_support) {
+		DSI_DEBUG("dynamic bit clock support not enabled\n");
+		return 0;
+	} else if (!display->dyn_bit_clk_pending) {
+		DSI_DEBUG("dynamic bit clock rate not updated\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);
+		return -EINVAL;
+	}
+
+	/* update mode clk rate with user value */
+	mode->timing.clk_rate_hz = display->dyn_bit_clk;
+	mode->priv_info->clk_rate_hz = display->dyn_bit_clk;
+
+	host_cfg = &(display->panel->host_config);
+	bpp = dsi_pixel_format_to_bpp(host_cfg->dst_format);
+
+	if (host_cfg->data_lanes & DSI_DATA_LANE_0)
+		lanes++;
+	if (host_cfg->data_lanes & DSI_DATA_LANE_1)
+		lanes++;
+	if (host_cfg->data_lanes & DSI_DATA_LANE_2)
+		lanes++;
+	if (host_cfg->data_lanes & DSI_DATA_LANE_3)
+		lanes++;
+
+	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;
+	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);
+
+	display->dyn_bit_clk_pending = false;
+
+	return 0;
+}
+
 int dsi_display_dump_clks_state(struct dsi_display *display)
 {
 	int rc = 0;

+ 22 - 1
msm/dsi/dsi_display.h

@@ -154,6 +154,8 @@ struct dsi_display_ext_bridge {
  *		      index into the ctrl[MAX_DSI_CTRLS_PER_DISPLAY] array.
  * @cmd_master_idx:   The master controller for sending DSI commands to panel.
  * @video_master_idx: The master controller for enabling video engine.
+ * @dyn_bit_clk:      The DSI bit clock rate dynamically set by user mode client.
+ * @dyn_bit_clk_pending: Flag indicating the pending DSI dynamic bit clock rate change.
  * @cached_clk_rate:  The cached DSI clock rate set dynamically by sysfs.
  * @clkrate_change_pending: Flag indicating the pending DSI clock re-enabling.
  * @clock_info:       Clock sourcing for DSI display.
@@ -225,7 +227,9 @@ struct dsi_display {
 	u32 video_master_idx;
 
 	/* dynamic DSI clock info*/
-	u32  cached_clk_rate;
+	u32 dyn_bit_clk;
+	bool dyn_bit_clk_pending;
+	u32 cached_clk_rate;
 	atomic_t clkrate_change_pending;
 
 	struct dsi_display_clk_info clock_info;
@@ -776,4 +780,21 @@ int dsi_display_get_panel_vfp(void *display,
  */
 int dsi_display_dump_clks_state(struct dsi_display *display);
 
+/**
+ * dsi_display_update_dyn_bit_clk() - update mode timing to compensate for dynamic bit clock
+ * @display:         Handle to display
+ * @mode:            Mode to be updated
+ * Return: Zero on Success
+ */
+int dsi_display_update_dyn_bit_clk(struct dsi_display *display, struct dsi_display_mode *mode);
+
+/**
+ * dsi_display_restore_bit_clk() - restore mode bit clock rate value from dynamic bit clock
+ * @display:         Handle to display
+ * @mode:            Mode to be updated
+ * Return: Zero on Success
+ */
+int dsi_display_restore_bit_clk(struct dsi_display *display, struct dsi_display_mode *mode);
+
+
 #endif /* _DSI_DISPLAY_H_ */

+ 76 - 31
msm/dsi/dsi_drm.c

@@ -342,7 +342,9 @@ static void dsi_bridge_mode_set(struct drm_bridge *bridge,
 				const struct drm_display_mode *mode,
 				const struct drm_display_mode *adjusted_mode)
 {
-	struct dsi_bridge *c_bridge = to_dsi_bridge(bridge);
+	int rc = 0;
+	struct dsi_bridge *c_bridge = NULL;
+	struct dsi_display *display;
 	struct drm_connector *conn;
 	struct sde_connector_state *conn_state;
 
@@ -351,6 +353,18 @@ static void dsi_bridge_mode_set(struct drm_bridge *bridge,
 		return;
 	}
 
+	c_bridge = to_dsi_bridge(bridge);
+	if (!c_bridge) {
+		DSI_ERR("invalid dsi bridge\n");
+		return;
+	}
+
+	display = c_bridge->display;
+	if (!display || !display->drm_conn || !display->drm_conn->state) {
+		DSI_ERR("invalid display\n");
+		return;
+	}
+
 	memset(&(c_bridge->dsi_mode), 0x0, sizeof(struct dsi_display_mode));
 	convert_to_dsi_mode(adjusted_mode, &(c_bridge->dsi_mode));
 	conn = sde_encoder_get_connector(bridge->dev, bridge->encoder);
@@ -366,9 +380,11 @@ static void dsi_bridge_mode_set(struct drm_bridge *bridge,
 	msm_parse_mode_priv_info(&conn_state->msm_mode,
 					&(c_bridge->dsi_mode));
 
-	/* restore bit_clk_rate also for dynamic clk use cases */
-	c_bridge->dsi_mode.timing.clk_rate_hz =
-		dsi_drm_find_bit_clk_rate(c_bridge->display, adjusted_mode);
+	rc = dsi_display_restore_bit_clk(display, &c_bridge->dsi_mode);
+	if (rc) {
+		DSI_ERR("[%s] bit clk rate cannot be restored\n", display->name);
+		return;
+	}
 
 	DSI_DEBUG("clk_rate: %llu\n", c_bridge->dsi_mode.timing.clk_rate_hz);
 }
@@ -436,6 +452,18 @@ static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge,
 	dsi_mode.timing.dsc_enabled = dsi_mode.priv_info->dsc_enabled;
 	dsi_mode.timing.dsc = &dsi_mode.priv_info->dsc;
 
+	rc = dsi_display_restore_bit_clk(display, &dsi_mode);
+	if (rc) {
+		DSI_ERR("[%s] bit clk rate cannot be restored\n", display->name);
+		return false;
+	}
+
+	rc = dsi_display_update_dyn_bit_clk(display, &dsi_mode);
+	if (rc) {
+		DSI_ERR("[%s] failed to update bit clock\n", display->name);
+		return false;
+	}
+
 	rc = dsi_display_validate_mode(c_bridge->display, &dsi_mode,
 			DSI_VALIDATE_FLAG_ALLOW_ADJUST);
 	if (rc) {
@@ -517,33 +545,6 @@ u32 dsi_drm_get_dfps_maxfps(void *display)
 	return dfps_maxfps;
 }
 
-u64 dsi_drm_find_bit_clk_rate(void *display,
-			      const struct drm_display_mode *drm_mode)
-{
-	int i = 0, count = 0;
-	struct dsi_display *dsi_display = display;
-	struct dsi_display_mode *dsi_mode;
-	u64 bit_clk_rate = 0;
-
-	if (!dsi_display || !drm_mode)
-		return 0;
-
-	dsi_display_get_mode_count(dsi_display, &count);
-
-	for (i = 0; i < count; i++) {
-		dsi_mode = &dsi_display->modes[i];
-		if ((dsi_mode->timing.v_active == drm_mode->vdisplay) &&
-		    (dsi_mode->timing.h_active == drm_mode->hdisplay) &&
-		    (dsi_mode->pixel_clk_khz == drm_mode->clock) &&
-		    (dsi_mode->timing.refresh_rate == drm_mode_vrefresh(drm_mode))) {
-			bit_clk_rate = dsi_mode->timing.clk_rate_hz;
-			break;
-		}
-	}
-
-	return bit_clk_rate;
-}
-
 int dsi_conn_get_mode_info(struct drm_connector *connector,
 		const struct drm_display_mode *drm_mode,
 		struct msm_mode_info *mode_info,
@@ -696,6 +697,11 @@ 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");
@@ -1288,3 +1294,42 @@ void dsi_conn_set_allowed_mode_switch(struct drm_connector *connector,
 		mode_idx++;
 	}
 }
+
+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");
+		return -EINVAL;
+	}
+
+	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;
+	DSI_DEBUG("update dynamic bit clock rate to %llu\n", display->dyn_bit_clk);
+
+	return 0;
+}

+ 10 - 4
msm/dsi/dsi_drm.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
  */
 
 #ifndef _DSI_DRM_H_
@@ -134,9 +134,6 @@ int dsi_conn_post_kickoff(struct drm_connector *connector,
 void dsi_convert_to_drm_mode(const struct dsi_display_mode *dsi_mode,
 				struct drm_display_mode *drm_mode);
 
-u64 dsi_drm_find_bit_clk_rate(void *display,
-			      const struct drm_display_mode *drm_mode);
-
 /**
  * dsi_conn_prepare_commit - program pre commit time features
  * @display: Pointer to private display structure
@@ -154,4 +151,13 @@ int dsi_conn_prepare_commit(void *display,
 void dsi_conn_set_allowed_mode_switch(struct drm_connector *connector,
 		void *display);
 
+/**
+ * dsi_conn_set_dyn_bit_clk - set target dynamic clock rate
+ * @connector: Pointer to drm connector structure
+ * @value: Target dynamic clock rate
+ * Returns: Zero on success
+ */
+int dsi_conn_set_dyn_bit_clk(struct drm_connector *connector,
+		uint64_t value);
+
 #endif /* _DSI_DRM_H_ */

+ 1 - 0
msm/msm_drv.h

@@ -211,6 +211,7 @@ enum msm_mdp_conn_property {
 	CONNECTOR_PROP_BL_SCALE,
 	CONNECTOR_PROP_SV_BL_SCALE,
 	CONNECTOR_PROP_SUPPORTED_COLORSPACES,
+	CONNECTOR_PROP_DYN_BIT_CLK,
 
 	/* enum/bitmask properties */
 	CONNECTOR_PROP_TOPOLOGY_NAME,

+ 3 - 0
msm/msm_kms.h

@@ -292,6 +292,9 @@ static inline bool msm_is_private_mode_changed(
 	if (msm_is_mode_seamless_poms(msm_mode))
 		return true;
 
+	if (msm_is_mode_seamless_dyn_clk(msm_mode))
+		return true;
+
 	return false;
 }
 

+ 25 - 1
msm/sde/sde_connector.c

@@ -1595,6 +1595,15 @@ static int sde_connector_atomic_set_property(struct drm_connector *connector,
 			c_conn->expected_panel_mode =
 				MSM_DISPLAY_CMD_MODE;
 		break;
+	case CONNECTOR_PROP_DYN_BIT_CLK:
+		if (!c_conn->ops.set_dyn_bit_clk)
+			break;
+
+		rc = c_conn->ops.set_dyn_bit_clk(connector, val);
+		if (rc)
+			SDE_ERROR_CONN(c_conn, "dynamic bit clock set failed, rc: %d", rc);
+
+		break;
 	default:
 		break;
 	}
@@ -2752,9 +2761,11 @@ static int _sde_connector_install_properties(struct drm_device *dev,
 	struct msm_display_info *display_info)
 {
 	struct dsi_display *dsi_display;
-	int rc;
+	int rc, i;
 	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);
@@ -2788,6 +2799,19 @@ static int _sde_connector_install_properties(struct drm_device *dev,
 				CONNECTOR_PROP_HDR_INFO);
 		}
 
+		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);
+
+			msm_property_install_range(&c_conn->property_info, "dyn_bit_clk",
+					0x0, 0, max_bit_clk, max_bit_clk,
+					CONNECTOR_PROP_DYN_BIT_CLK);
+		}
+
 		mutex_lock(&c_conn->base.dev->mode_config.mutex);
 		sde_connector_fill_modes(&c_conn->base,
 						dev->mode_config.max_width,

+ 16 - 0
msm/sde/sde_connector.h

@@ -374,6 +374,14 @@ struct sde_connector_ops {
 	void (*set_allowed_mode_switch)(struct drm_connector *connector,
 			void *display);
 
+	/**
+	 * set_dyn_bit_clk - set target dynamic clock rate
+	 * @connector: Pointer to drm connector structure
+	 * @value: Target dynamic clock rate
+	 * Returns: Zero on success
+	 */
+	int (*set_dyn_bit_clk)(struct drm_connector *connector, uint64_t value);
+
 	/**
 	 * get_qsync_min_fps - Get qsync min fps from qsync-min-fps-list
 	 * @display: Pointer to private display structure
@@ -961,6 +969,14 @@ int sde_connector_set_blob_data(struct drm_connector *conn,
  */
 int sde_connector_roi_v1_check_roi(struct drm_connector_state *conn_state);
 
+/**
+ * sde_connector_set_dyn_bit_clk - set dynamic bit clock
+ * @conn: Pointer to drm_connector struct
+ * @value: Property value
+ * Returns: Zero on success
+ */
+int sde_connector_set_dyn_bit_clk(struct drm_connector *conn, uint64_t value);
+
 /**
  * sde_connector_schedule_status_work - manage ESD thread
  * conn: Pointer to drm_connector struct

+ 3 - 0
msm/sde/sde_kms.c

@@ -1736,6 +1736,7 @@ static int _sde_kms_setup_displays(struct drm_device *dev,
 		.cmd_receive = dsi_display_cmd_receive,
 		.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,
 		.prepare_commit = dsi_conn_prepare_commit,
 	};
@@ -1756,6 +1757,7 @@ static int _sde_kms_setup_displays(struct drm_device *dev,
 		.get_panel_vfp = NULL,
 		.cmd_receive = NULL,
 		.install_properties = NULL,
+		.set_dyn_bit_clk = NULL,
 		.set_allowed_mode_switch = NULL,
 	};
 	static const struct sde_connector_ops dp_ops = {
@@ -1778,6 +1780,7 @@ static int _sde_kms_setup_displays(struct drm_device *dev,
 		.cmd_receive = NULL,
 		.install_properties = dp_connector_install_properties,
 		.set_allowed_mode_switch = NULL,
+		.set_dyn_bit_clk = NULL,
 	};
 	struct msm_display_info info;
 	struct drm_encoder *encoder;

+ 10 - 0
msm/sde/sde_kms.h

@@ -611,6 +611,16 @@ void sde_kms_info_append_format(struct sde_kms_info *info,
  */
 void sde_kms_info_stop(struct sde_kms_info *info);
 
+/**
+ * sde_kms_info_add_list - add a space separated list to 'sde_kms_info'
+ * @info: Pointer to sde_kms_info structure
+ * @key: Pointer to key string
+ * @item: Pointer to array of integer values
+ * @size: Number of integers to parse
+ */
+void sde_kms_info_add_list(struct sde_kms_info *info,
+		const char *key, uint32_t *item, size_t size);
+
 /**
  * sde_kms_rect_intersect - intersect two rectangles
  * @r1: first rectangle

+ 23 - 1
msm/sde/sde_kms_utils.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
  */
 
 #define pr_fmt(fmt)	"sde-kms_utils:[%s] " fmt, __func__
@@ -91,6 +91,28 @@ void sde_kms_info_append(struct sde_kms_info *info,
 	}
 }
 
+void sde_kms_info_add_list(struct sde_kms_info *info, const char *key, uint32_t *value, size_t size)
+{
+	uint32_t i, len;
+
+	if (!info || !key || !value || !size)
+		return;
+
+	sde_kms_info_start(info, key);
+	for (i = 0; i < size; i++) {
+		len = scnprintf(info->data + info->staged_len,
+				SDE_KMS_INFO_MAX_SIZE - info->len, "%d ",
+				value[i]);
+
+		/* check if snprintf truncated the string */
+		if ((info->staged_len + len) < SDE_KMS_INFO_MAX_SIZE) {
+			info->staged_len += len;
+			info->start = false;
+		}
+	}
+	sde_kms_info_stop(info);
+}
+
 void sde_kms_info_append_format(struct sde_kms_info *info,
 		uint32_t pixel_format,
 		uint64_t modifier)