aboutsummaryrefslogtreecommitdiffstats
path: root/common/recipes-kernel/linux/linux-yocto-4.14.71/4918-drm-amd-display-Linux-set-read-lane-settings-through.patch
diff options
context:
space:
mode:
Diffstat (limited to 'common/recipes-kernel/linux/linux-yocto-4.14.71/4918-drm-amd-display-Linux-set-read-lane-settings-through.patch')
-rw-r--r--common/recipes-kernel/linux/linux-yocto-4.14.71/4918-drm-amd-display-Linux-set-read-lane-settings-through.patch471
1 files changed, 471 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/linux-yocto-4.14.71/4918-drm-amd-display-Linux-set-read-lane-settings-through.patch b/common/recipes-kernel/linux/linux-yocto-4.14.71/4918-drm-amd-display-Linux-set-read-lane-settings-through.patch
new file mode 100644
index 00000000..329bba63
--- /dev/null
+++ b/common/recipes-kernel/linux/linux-yocto-4.14.71/4918-drm-amd-display-Linux-set-read-lane-settings-through.patch
@@ -0,0 +1,471 @@
+From 45d70ac2a30007c809265fdba76840b936cff95f Mon Sep 17 00:00:00 2001
+From: Hersen Wu <hersenxs.wu@amd.com>
+Date: Fri, 15 Jun 2018 10:32:50 -0400
+Subject: [PATCH 4918/5725] drm/amd/display: Linux set/read lane settings
+ through debugfs
+
+ function: get current DP PHY settings: voltage swing, pre-emphasis,
+ post-cursor2 (defined by VESA DP specification)
+
+ valid values: voltage swing: 0,1,2,3 pre-emphasis : 0,1,2,3
+ post cursor2 : 0,1,2,3
+
+ debugfs file phy_setings is located at /sys/kernel/debug/dri/0/DP-x
+
+ there will be directories, like DP-1, DP-2,DP-3, etc. for DP display
+
+ --- to figure out which DP-x is the display for DP to be check,
+ cd DP-x
+ ls -ll
+ There should be debugfs file, like link_settings, phy_settings.
+ cat link_settings
+ from lane_count, link_rate to figure which DP-x is for display to be
+ worked on
+
+ --- to get current DP PHY settings,
+ cat phy_settings
+
+ --- to change DP PHY settings,
+ echo <voltage_swing> <pre-emphasis> <post_cursor2> > phy_settings
+
+ for examle, to change voltage swing to 2, pre-emphasis to 3,
+ post_cursor2 to 0,
+ echo 2 3 0 > phy_settings
+
+ --- to check if change be applied, get current phy settings by
+ cat phy_settings
+
+ --- in case invalid values are set by user, like
+ echo 1 4 0 > phy_settings
+
+ HW will NOT be programmed by these settings.
+
+cat phy_settings will show the previous valid settings.
+
+Signed-off-by: Hersen Wu <hersenxs.wu@amd.com>
+Reviewed-by: Harry Wentland <Harry.Wentland@amd.com>
+Reviewed-by: Hersen Wu <hersenxs.wu@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+---
+ .../drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 266 ++++++++++++++++-----
+ 1 file changed, 207 insertions(+), 59 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 8ddbf219..f20ba9d 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,7 +26,6 @@
+ #include <linux/debugfs.h>
+
+ #include "dc.h"
+-
+ #include "amdgpu.h"
+ #include "amdgpu_dm.h"
+ #include "amdgpu_dm_debugfs.h"
+@@ -46,7 +45,7 @@
+ *
+ * --- to get dp configuration
+ *
+- * xxd -l 300 phy_settings
++ * cat link_settings
+ *
+ * It will list current, verified, reported, preferred dp configuration.
+ * current -- for current video mode
+@@ -56,7 +55,7 @@
+ *
+ * --- set (or force) dp configuration
+ *
+- * echo <lane_count> <link_rate>
++ * echo <lane_count> <link_rate> > link_settings
+ *
+ * for example, to force to 2 lane, 2.7GHz,
+ * echo 4 0xa > link_settings
+@@ -67,7 +66,7 @@
+ * done. please check link settings after force operation to see if HW get
+ * programming.
+ *
+- * xxd -l 300 link_settings
++ * cat link_settings
+ *
+ * check current and preferred settings.
+ *
+@@ -79,13 +78,13 @@ static ssize_t dp_link_settings_read(struct file *f, char __user *buf,
+ 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;
++ const uint32_t rd_buf_size = 100;
++ uint32_t result = 0;
+ uint8_t str_len = 0;
+ int r;
+
+- if (size == 0)
+- return 0;
++ if (*pos & 3 || size & 3)
++ return -EINVAL;
+
+ rd_buf = kcalloc(rd_buf_size, sizeof(char), GFP_KERNEL);
+ if (!rd_buf)
+@@ -98,39 +97,44 @@ static ssize_t dp_link_settings_read(struct file *f, char __user *buf,
+ 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;
++ 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;
++ 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;
++ rd_buf_ptr += str_len;
+
+ str_len = strlen("Preferred: %d %d %d ");
+- snprintf(rd_buf_ptr, str_len, "Preferred: %d %d %d ",
++ snprintf(rd_buf_ptr, str_len, "Preferred: %d %d %d\n",
+ 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);
++ while (size) {
++ if (*pos >= rd_buf_size)
++ break;
+
+- bytes_to_user = rd_buf_size - r;
++ r = put_user(*(rd_buf + result), buf);
++ if (r)
++ return r; /* r = -EFAULT */
+
+- if (r > rd_buf_size) {
+- bytes_to_user = 0;
+- DRM_DEBUG_DRIVER("data not copy to user");
++ buf += 1;
++ size -= 1;
++ *pos += 1;
++ result += 1;
+ }
+
+ kfree(rd_buf);
+- return bytes_to_user;
++ return result;
+ }
+
+ static ssize_t dp_link_settings_write(struct file *f, const char __user *buf,
+@@ -142,7 +146,7 @@ static ssize_t dp_link_settings_write(struct file *f, const char __user *buf,
+ struct dc_link_settings prefer_link_settings;
+ char *wr_buf = NULL;
+ char *wr_buf_ptr = NULL;
+- uint32_t wr_buf_size = 40;
++ const uint32_t wr_buf_size = 40;
+ int r;
+ int bytes_from_user;
+ char *sub_str;
+@@ -153,11 +157,11 @@ static ssize_t dp_link_settings_write(struct file *f, const char __user *buf,
+ bool valid_input = false;
+
+ if (size == 0)
+- return 0;
++ return -EINVAL;
+
+ wr_buf = kcalloc(wr_buf_size, sizeof(char), GFP_KERNEL);
+ if (!wr_buf)
+- return 0;
++ return -EINVAL;
+ wr_buf_ptr = wr_buf;
+
+ r = copy_from_user(wr_buf_ptr, buf, wr_buf_size);
+@@ -166,7 +170,7 @@ static ssize_t dp_link_settings_write(struct file *f, const char __user *buf,
+ if (r >= wr_buf_size) {
+ kfree(wr_buf);
+ DRM_DEBUG_DRIVER("user data not read\n");
+- return 0;
++ return -EINVAL;
+ }
+
+ bytes_from_user = wr_buf_size - r;
+@@ -181,16 +185,13 @@ static ssize_t dp_link_settings_write(struct file *f, const char __user *buf,
+ r = kstrtol(sub_str, 16, &param[param_index]);
+
+ if (r)
+- DRM_DEBUG_DRIVER(" -EINVAL convert error happens!\n");
++ DRM_DEBUG_DRIVER("string to int convert error code: %d\n", r);
+
+ 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:
+@@ -213,9 +214,10 @@ static ssize_t dp_link_settings_write(struct file *f, const char __user *buf,
+ break;
+ }
+
+- if (!valid_input) {
++ if (!valid_input || (param[0] > link->reported_link_cap.lane_count) ||
++ (param[1] > link->reported_link_cap.link_rate)) {
+ kfree(wr_buf);
+- DRM_DEBUG_DRIVER("Invalid Input value exceed No HW will be programmed\n");
++ DRM_DEBUG_DRIVER("Invalid Input value No HW will be programmed\n");
+ return bytes_from_user;
+ }
+
+@@ -229,36 +231,190 @@ static ssize_t dp_link_settings_write(struct file *f, const char __user *buf,
+ 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,
++/* function: get current DP PHY settings: voltage swing, pre-emphasis,
++ * post-cursor2 (defined by VESA DP specification)
++ *
++ * valid values
++ * voltage swing: 0,1,2,3
++ * pre-emphasis : 0,1,2,3
++ * post cursor2 : 0,1,2,3
++ *
++ *
++ * how to use this debugfs
++ *
++ * debugfs is located at /sys/kernel/debug/dri/0/DP-x
++ *
++ * there will be directories, like DP-1, DP-2,DP-3, etc. for DP display
++ *
++ * To figure out which DP-x is the display for DP to be check,
++ * cd DP-x
++ * ls -ll
++ * There should be debugfs file, like link_settings, phy_settings.
++ * cat link_settings
++ * from lane_count, link_rate to figure which DP-x is for display to be worked
++ * on
++ *
++ * To get current DP PHY settings,
++ * cat phy_settings
++ *
++ * To change DP PHY settings,
++ * echo <voltage_swing> <pre-emphasis> <post_cursor2> > phy_settings
++ * for examle, to change voltage swing to 2, pre-emphasis to 3, post_cursor2 to
++ * 0,
++ * echo 2 3 0 > phy_settings
++ *
++ * To check if change be applied, get current phy settings by
++ * cat phy_settings
++ *
++ * In case invalid values are set by user, like
++ * echo 1 4 0 > phy_settings
++ *
++ * HW will NOT be programmed by these settings.
++ * cat phy_settings will show the previous valid settings.
++ */
++static ssize_t dp_phy_settings_read(struct file *f, char __user *buf,
+ size_t size, loff_t *pos)
+ {
+- /* TODO: create method to read voltage swing */
+- return 1;
+-}
++ struct amdgpu_dm_connector *connector = file_inode(f)->i_private;
++ struct dc_link *link = connector->dc_link;
++ char *rd_buf = NULL;
++ const uint32_t rd_buf_size = 20;
++ uint32_t result = 0;
++ int r;
+
+-static ssize_t dp_voltage_swing_debugfs_write(struct file *f, const char __user *buf,
+- size_t size, loff_t *pos)
+-{
+- /* TODO: create method to write voltage swing */
+- return 1;
+-}
++ if (*pos & 3 || size & 3)
++ return -EINVAL;
+
+-static ssize_t dp_pre_emphasis_debugfs_read(struct file *f, char __user *buf,
+- size_t size, loff_t *pos)
+-{
+- /* TODO: create method to read pre-emphasis */
+- return 1;
++ rd_buf = kcalloc(rd_buf_size, sizeof(char), GFP_KERNEL);
++ if (!rd_buf)
++ return -EINVAL;
++
++ snprintf(rd_buf, rd_buf_size, " %d %d %d ",
++ link->cur_lane_setting.VOLTAGE_SWING,
++ link->cur_lane_setting.PRE_EMPHASIS,
++ link->cur_lane_setting.POST_CURSOR2);
++
++ while (size) {
++ if (*pos >= rd_buf_size)
++ break;
++
++ r = put_user((*(rd_buf + result)), buf);
++ if (r)
++ return r; /* r = -EFAULT */
++
++ buf += 1;
++ size -= 1;
++ *pos += 1;
++ result += 1;
++ }
++
++ kfree(rd_buf);
++ return result;
+ }
+
+-static ssize_t dp_pre_emphasis_debugfs_write(struct file *f, const char __user *buf,
++static ssize_t dp_phy_settings_write(struct file *f, const char __user *buf,
+ size_t size, loff_t *pos)
+ {
+- /* TODO: create method to write pre-emphasis */
+- 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;
++ char *wr_buf = NULL;
++ char *wr_buf_ptr = NULL;
++ uint32_t wr_buf_size = 40;
++ int r;
++ int bytes_from_user;
++ char *sub_str;
++ uint8_t param_index = 0;
++ long param[3];
++ const char delimiter[3] = {' ', '\n', '\0'};
++ bool use_prefer_link_setting;
++ struct link_training_settings link_lane_settings;
++
++ 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 be 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 < 3)) {
++
++ sub_str = strsep(&wr_buf_ptr, delimiter);
++
++ r = kstrtol(sub_str, 16, &param[param_index]);
++
++ if (r)
++ DRM_DEBUG_DRIVER("string to int convert error code: %d\n", r);
++
++ param_index++;
++ while (isspace(*wr_buf_ptr))
++ wr_buf_ptr++;
++ }
++
++ if ((param[0] > VOLTAGE_SWING_MAX_LEVEL) ||
++ (param[1] > PRE_EMPHASIS_MAX_LEVEL) ||
++ (param[2] > POST_CURSOR2_MAX_LEVEL)) {
++ kfree(wr_buf);
++ DRM_DEBUG_DRIVER("Invalid Input No HW will be programmed\n");
++ return bytes_from_user;
++ }
++
++ /* get link settings: lane count, link rate */
++ use_prefer_link_setting =
++ ((link->preferred_link_setting.link_rate != LINK_RATE_UNKNOWN) &&
++ (link->test_pattern_enabled));
++
++ memset(&link_lane_settings, 0, sizeof(link_lane_settings));
++
++ if (use_prefer_link_setting) {
++ link_lane_settings.link_settings.lane_count =
++ link->preferred_link_setting.lane_count;
++ link_lane_settings.link_settings.link_rate =
++ link->preferred_link_setting.link_rate;
++ link_lane_settings.link_settings.link_spread =
++ link->preferred_link_setting.link_spread;
++ } else {
++ link_lane_settings.link_settings.lane_count =
++ link->cur_link_settings.lane_count;
++ link_lane_settings.link_settings.link_rate =
++ link->cur_link_settings.link_rate;
++ link_lane_settings.link_settings.link_spread =
++ link->cur_link_settings.link_spread;
++ }
++
++ /* apply phy settings from user */
++ for (r = 0; r < link_lane_settings.link_settings.lane_count; r++) {
++ link_lane_settings.lane_settings[r].VOLTAGE_SWING =
++ (enum dc_voltage_swing) (param[0]);
++ link_lane_settings.lane_settings[r].PRE_EMPHASIS =
++ (enum dc_pre_emphasis) (param[1]);
++ link_lane_settings.lane_settings[r].POST_CURSOR2 =
++ (enum dc_post_cursor2) (param[2]);
++ }
++
++ /* program ASIC registers and DPCD registers */
++ dc_link_set_drive_settings(dc, &link_lane_settings, link);
++
++ kfree(wr_buf);
++ return bytes_from_user;
+ }
+
+ /* function description
+@@ -483,17 +639,10 @@ static const struct file_operations dp_link_settings_debugfs_fops = {
+ .llseek = default_llseek
+ };
+
+-static const struct file_operations dp_voltage_swing_fops = {
+- .owner = THIS_MODULE,
+- .read = dp_voltage_swing_debugfs_read,
+- .write = dp_voltage_swing_debugfs_write,
+- .llseek = default_llseek
+-};
+-
+-static const struct file_operations dp_pre_emphasis_fops = {
++static const struct file_operations dp_phy_settings_debugfs_fop = {
+ .owner = THIS_MODULE,
+- .read = dp_pre_emphasis_debugfs_read,
+- .write = dp_pre_emphasis_debugfs_write,
++ .read = dp_phy_settings_read,
++ .write = dp_phy_settings_write,
+ .llseek = default_llseek
+ };
+
+@@ -508,8 +657,7 @@ static const struct {
+ const struct file_operations *fops;
+ } dp_debugfs_entries[] = {
+ {"link_settings", &dp_link_settings_debugfs_fops},
+- {"voltage_swing", &dp_voltage_swing_fops},
+- {"pre_emphasis", &dp_pre_emphasis_fops},
++ {"phy_settings", &dp_phy_settings_debugfs_fop},
+ {"test_pattern", &dp_phy_test_pattern_fops}
+ };
+
+--
+2.7.4
+