From 41db5f1931ec73f2d909752e09ffb691fecdaaa1 Mon Sep 17 00:00:00 2001 From: Hersen Wu Date: Fri, 15 Jun 2018 14:25:48 -0400 Subject: [PATCH] drm/amd/display: set-read link rate and lane count through debugfs 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 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 Reviewed-by: Hersen Wu Acked-by: Harry Wentland Signed-off-by: Alex Deucher --- .../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 #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 + * + * 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, ¶m[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.30.2