[PATCH 12/54] drm/amd/display: set-read link rate and lane count through debugfs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Hersen Wu <hersenxs.wu@xxxxxxx>

 function description
 get/ set DP configuration: lane_count, link_rate, spread_spectrum

  valid lane count value: 1, 2, 4
  valid link rate value:
  06h = 1.62Gbps per lane
  0Ah = 2.7Gbps per lane
  0Ch = 3.24Gbps per lane
  14h = 5.4Gbps per lane
  1Eh = 8.1Gbps per lane

  debugfs is located at /sys/kernel/debug/dri/0/DP-x/link_settings

  --- to get dp configuration

  xxd -l 300 phy_settings

  It will list current, verified, reported, preferred dp configuration.
  current -- for current video mode
  verified --- maximum configuration which pass link training
  reported --- DP rx report caps (DPCD register offset 0, 1 2)
  preferred --- user force settings

  --- set (or force) dp configuration

  echo <lane_count>  <link_rate>

  for example, to force to  2 lane, 2.7GHz,
  echo 4 0xa > link_settings

  spread_spectrum could not be changed dynamically.

  in case invalid lane count, link rate are force, no hw programming will be
  done. please check link settings after force operation to see if HW get
  programming.

  xxd -l 300 link_settings

  check current and preferred settings.

Signed-off-by: Hersen Wu <hersenxs.wu at amd.com>
Reviewed-by: Hersen Wu <hersenxs.wu at amd.com>
Acked-by: Harry Wentland <harry.wentland at amd.com>
---
 .../amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 227 +++++++++++++++---
 1 file changed, 196 insertions(+), 31 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
index cf5ea69e46ad..9ff8833b52c4 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
@@ -26,38 +26,211 @@
 #include <linux/debugfs.h>
 
 #include "dc.h"
-#include "dc_link.h"
 
 #include "amdgpu.h"
 #include "amdgpu_dm.h"
 #include "amdgpu_dm_debugfs.h"
 
-static ssize_t dp_link_rate_debugfs_read(struct file *f, char __user *buf,
+/* function description
+ * get/ set DP configuration: lane_count, link_rate, spread_spectrum
+ *
+ * valid lane count value: 1, 2, 4
+ * valid link rate value:
+ * 06h = 1.62Gbps per lane
+ * 0Ah = 2.7Gbps per lane
+ * 0Ch = 3.24Gbps per lane
+ * 14h = 5.4Gbps per lane
+ * 1Eh = 8.1Gbps per lane
+ *
+ * debugfs is located at /sys/kernel/debug/dri/0/DP-x/link_settings
+ *
+ * --- to get dp configuration
+ *
+ * xxd -l 300 phy_settings
+ *
+ * It will list current, verified, reported, preferred dp configuration.
+ * current -- for current video mode
+ * verified --- maximum configuration which pass link training
+ * reported --- DP rx report caps (DPCD register offset 0, 1 2)
+ * preferred --- user force settings
+ *
+ * --- set (or force) dp configuration
+ *
+ * echo <lane_count>  <link_rate>
+ *
+ * for example, to force to  2 lane, 2.7GHz,
+ * echo 4 0xa > link_settings
+ *
+ * spread_spectrum could not be changed dynamically.
+ *
+ * in case invalid lane count, link rate are force, no hw programming will be
+ * done. please check link settings after force operation to see if HW get
+ * programming.
+ *
+ * xxd -l 300 link_settings
+ *
+ * check current and preferred settings.
+ *
+ */
+static ssize_t dp_link_settings_read(struct file *f, char __user *buf,
 				 size_t size, loff_t *pos)
 {
-	/* TODO: create method to read link rate */
-	return 1;
-}
+	struct amdgpu_dm_connector *connector = file_inode(f)->i_private;
+	struct dc_link *link = connector->dc_link;
+	char *rd_buf = NULL;
+	char *rd_buf_ptr = NULL;
+	uint32_t rd_buf_size = 320;
+	int bytes_to_user;
+	uint8_t str_len = 0;
+	int r;
 
-static ssize_t dp_link_rate_debugfs_write(struct file *f, const char __user *buf,
-				 size_t size, loff_t *pos)
-{
-	/* TODO: create method to write link rate */
-	return 1;
-}
+	if (size == 0)
+		return 0;
 
-static ssize_t dp_lane_count_debugfs_read(struct file *f, char __user *buf,
-				 size_t size, loff_t *pos)
-{
-	/* TODO: create method to read lane count */
-	return 1;
+	rd_buf = kcalloc(rd_buf_size, sizeof(char), GFP_KERNEL);
+	if (!rd_buf)
+		return 0;
+
+	rd_buf_ptr = rd_buf;
+
+	str_len = strlen("Current:  %d  %d  %d  ");
+	snprintf(rd_buf_ptr, str_len, "Current:  %d  %d  %d  ",
+			link->cur_link_settings.lane_count,
+			link->cur_link_settings.link_rate,
+			link->cur_link_settings.link_spread);
+	rd_buf_ptr = rd_buf_ptr + str_len;
+
+	str_len = strlen("Verified:  %d  %d  %d  ");
+	snprintf(rd_buf_ptr, str_len, "Verified:  %d  %d  %d  ",
+			link->verified_link_cap.lane_count,
+			link->verified_link_cap.link_rate,
+			link->verified_link_cap.link_spread);
+	rd_buf_ptr = rd_buf_ptr + str_len;
+
+	str_len = strlen("Reported:  %d  %d  %d  ");
+	snprintf(rd_buf_ptr, str_len, "Reported:  %d  %d  %d  ",
+			link->reported_link_cap.lane_count,
+			link->reported_link_cap.link_rate,
+			link->reported_link_cap.link_spread);
+	rd_buf_ptr = rd_buf_ptr + str_len;
+
+	str_len = strlen("Preferred:  %d  %d  %d  ");
+	snprintf(rd_buf_ptr, str_len, "Preferred:  %d  %d  %d  ",
+			link->preferred_link_setting.lane_count,
+			link->preferred_link_setting.link_rate,
+			link->preferred_link_setting.link_spread);
+
+	r = copy_to_user(buf, rd_buf, rd_buf_size);
+
+	bytes_to_user = rd_buf_size - r;
+
+	if (r > rd_buf_size) {
+		bytes_to_user = 0;
+		DRM_DEBUG_DRIVER("data not copy to user");
+	}
+
+	kfree(rd_buf);
+	return bytes_to_user;
 }
 
-static ssize_t dp_lane_count_debugfs_write(struct file *f, const char __user *buf,
+static ssize_t dp_link_settings_write(struct file *f, const char __user *buf,
 				 size_t size, loff_t *pos)
 {
-	/* TODO: create method to write lane count */
-	return 1;
+	struct amdgpu_dm_connector *connector = file_inode(f)->i_private;
+	struct dc_link *link = connector->dc_link;
+	struct dc *dc = (struct dc *)link->dc;
+	struct dc_link_settings prefer_link_settings;
+	char *wr_buf = NULL;
+	char *wr_buf_ptr = NULL;
+	uint32_t wr_buf_size = 40;
+	int r;
+	int bytes_from_user;
+	char *sub_str;
+	/* 0: lane_count; 1: link_rate */
+	uint8_t param_index = 0;
+	long param[2];
+	const char delimiter[3] = {' ', '\n', '\0'};
+	bool valid_input = false;
+
+	if (size == 0)
+		return 0;
+
+	wr_buf = kcalloc(wr_buf_size, sizeof(char), GFP_KERNEL);
+	if (!wr_buf)
+		return 0;
+	wr_buf_ptr = wr_buf;
+
+	r = copy_from_user(wr_buf_ptr, buf, wr_buf_size);
+
+	/* r is bytes not be copied */
+	if (r >= wr_buf_size) {
+		kfree(wr_buf);
+		DRM_DEBUG_DRIVER("user data not read\n");
+		return 0;
+	}
+
+	bytes_from_user = wr_buf_size - r;
+
+	while (isspace(*wr_buf_ptr))
+		wr_buf_ptr++;
+
+	while ((*wr_buf_ptr != '\0') && (param_index < 2)) {
+
+		sub_str = strsep(&wr_buf_ptr, delimiter);
+
+		r = kstrtol(sub_str, 16, &param[param_index]);
+
+		if (r)
+			DRM_DEBUG_DRIVER(" -EINVAL convert error happens!\n");
+
+		param_index++;
+		while (isspace(*wr_buf_ptr))
+			wr_buf_ptr++;
+	}
+
+	DRM_DEBUG_DRIVER("Lane_count:  %lx\n", param[0]);
+	DRM_DEBUG_DRIVER("link_rate:  %lx\n", param[1]);
+
+	switch (param[0]) {
+	case LANE_COUNT_ONE:
+	case LANE_COUNT_TWO:
+	case LANE_COUNT_FOUR:
+		valid_input = true;
+		break;
+	default:
+		break;
+	}
+
+	switch (param[1]) {
+	case LINK_RATE_LOW:
+	case LINK_RATE_HIGH:
+	case LINK_RATE_RBR2:
+	case LINK_RATE_HIGH2:
+	case LINK_RATE_HIGH3:
+		valid_input = true;
+		break;
+	default:
+		break;
+	}
+
+	if (!valid_input) {
+		kfree(wr_buf);
+		DRM_DEBUG_DRIVER("Invalid Input value  exceed  No HW will be programmed\n");
+		return bytes_from_user;
+	}
+
+	/* save user force lane_count, link_rate to preferred settings
+	 * spread spectrum will not be changed
+	 */
+	prefer_link_settings.link_spread = link->cur_link_settings.link_spread;
+	prefer_link_settings.lane_count = param[0];
+	prefer_link_settings.link_rate = param[1];
+
+	dc_link_set_preferred_link_settings(dc, &prefer_link_settings, link);
+
+	kfree(wr_buf);
+
+	return bytes_from_user;
 }
 
 static ssize_t dp_voltage_swing_debugfs_read(struct file *f, char __user *buf,
@@ -102,17 +275,10 @@ static ssize_t dp_phy_test_pattern_debugfs_write(struct file *f, const char __us
 	return 1;
 }
 
-static const struct file_operations dp_link_rate_fops = {
-	.owner = THIS_MODULE,
-	.read = dp_link_rate_debugfs_read,
-	.write = dp_link_rate_debugfs_write,
-	.llseek = default_llseek
-};
-
-static const struct file_operations dp_lane_count_fops = {
+static const struct file_operations dp_link_settings_debugfs_fops = {
 	.owner = THIS_MODULE,
-	.read = dp_lane_count_debugfs_read,
-	.write = dp_lane_count_debugfs_write,
+	.read = dp_link_settings_read,
+	.write = dp_link_settings_write,
 	.llseek = default_llseek
 };
 
@@ -141,8 +307,7 @@ static const struct {
 	char *name;
 	const struct file_operations *fops;
 } dp_debugfs_entries[] = {
-		{"link_rate", &dp_link_rate_fops},
-		{"lane_count", &dp_lane_count_fops},
+		{"link_settings", &dp_link_settings_debugfs_fops},
 		{"voltage_swing", &dp_voltage_swing_fops},
 		{"pre_emphasis", &dp_pre_emphasis_fops},
 		{"phy_test_pattern", &dp_phy_test_pattern_fops}
-- 
2.17.1



[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux