/* * Copyright 2018 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Authors: AMD *
*/
/* parse_write_buffer_into_params - Helper function to parse debugfs write buffer into an array * * Function takes in attributes passed to debugfs write entry * and writes into param array. * The user passes max_param_num to identify maximum number of * parameters that could be parsed. *
*/ staticint parse_write_buffer_into_params(char *wr_buf, uint32_t wr_buf_size, long *param, constchar __user *buf, int max_param_num,
uint8_t *param_nums)
{ char *wr_buf_ptr = NULL;
uint32_t wr_buf_count = 0; int r; char *sub_str = NULL; constchar delimiter[3] = {' ', '\n', '\0'};
uint8_t param_index = 0;
*param_nums = 0;
wr_buf_ptr = wr_buf;
/* r is bytes not be copied */ if (copy_from_user(wr_buf_ptr, buf, wr_buf_size)) {
DRM_DEBUG_DRIVER("user data could not be read successfully\n"); return -EFAULT;
}
/* check number of parameters. isspace could not differ space and \n */ while ((*wr_buf_ptr != 0xa) && (wr_buf_count < wr_buf_size)) { /* skip space*/ while (isspace(*wr_buf_ptr) && (wr_buf_count < wr_buf_size)) {
wr_buf_ptr++;
wr_buf_count++;
}
if (*param_nums > max_param_num)
*param_nums = max_param_num;
wr_buf_ptr = wr_buf; /* reset buf pointer */
wr_buf_count = 0; /* number of char already checked */
while (isspace(*wr_buf_ptr) && (wr_buf_count < wr_buf_size)) {
wr_buf_ptr++;
wr_buf_count++;
}
while (param_index < *param_nums) { /* after strsep, wr_buf_ptr will be moved to after space */
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++;
}
return 0;
}
/* 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 * * cat /sys/kernel/debug/dri/0/DP-x/link_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> > link_settings * * for example, to force to 2 lane, 2.7GHz, * echo 4 0xa > /sys/kernel/debug/dri/0/DP-x/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. * * cat /sys/kernel/debug/dri/0/DP-x/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)
{ 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; const uint32_t rd_buf_size = 100;
uint32_t result = 0;
uint8_t str_len = 0; int r;
if (*pos & 3 || size & 3) return -EINVAL;
rd_buf = kcalloc(rd_buf_size, sizeof(char), GFP_KERNEL); if (!rd_buf) return 0;
if (param_nums <= 0) {
kfree(wr_buf);
DRM_DEBUG_DRIVER("user data not be read\n"); return -EINVAL;
}
switch (param[0]) { case LANE_COUNT_ONE: case LANE_COUNT_TWO: case LANE_COUNT_FOUR: break; default:
valid_input = false; break;
}
switch (param[1]) { case LINK_RATE_LOW: case LINK_RATE_HIGH: case LINK_RATE_RBR2: case LINK_RATE_HIGH2: case LINK_RATE_HIGH3: case LINK_RATE_UHBR10: case LINK_RATE_UHBR13_5: case LINK_RATE_UHBR20: break; default:
valid_input = false; break;
}
if (!valid_input) {
kfree(wr_buf);
DRM_DEBUG_DRIVER("Invalid Input value No HW will be programmed\n");
mutex_lock(&adev->dm.dc_lock);
dc_link_set_preferred_training_settings(dc, NULL, NULL, link, false);
mutex_unlock(&adev->dm.dc_lock); return size;
}
/* 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.use_link_rate_set = false;
prefer_link_settings.lane_count = param[0];
prefer_link_settings.link_rate = param[1];
/* Change MST link setting * * 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 * 3E8h = 10.0Gbps per lane * 546h = 13.5Gbps per lane * 7D0h = 20.0Gbps per lane * * debugfs is located at /sys/kernel/debug/dri/0/DP-x/mst_link_settings * * for example, to force to 2 lane, 10.0GHz, * echo 2 0x3e8 > /sys/kernel/debug/dri/0/DP-x/mst_link_settings * * Valid input will trigger hotplug event to get new link setting applied * Invalid input will trigger training setting reset * * The usage can be referred to link_settings entry *
*/ static ssize_t dp_mst_link_setting(struct file *f, constchar __user *buf,
size_t size, loff_t *pos)
{ struct amdgpu_dm_connector *aconnector = file_inode(f)->i_private; struct dc_link *link = aconnector->dc_link; struct amdgpu_device *adev = drm_to_adev(aconnector->base.dev); struct dc *dc = (struct dc *)link->dc; struct dc_link_settings prefer_link_settings = {0}; char *wr_buf = NULL; const uint32_t wr_buf_size = 40; /* 0: lane_count; 1: link_rate */ int max_param_num = 2;
uint8_t param_nums = 0; long param[2]; bool valid_input = true;
if (!dp_mst_is_end_device(aconnector)) return -EINVAL;
if (size == 0) return -EINVAL;
wr_buf = kcalloc(wr_buf_size, sizeof(char), GFP_KERNEL); if (!wr_buf) return -ENOSPC;
if (param_nums <= 0) {
kfree(wr_buf);
DRM_DEBUG_DRIVER("user data not be read\n"); return -EINVAL;
}
switch (param[0]) { case LANE_COUNT_ONE: case LANE_COUNT_TWO: case LANE_COUNT_FOUR: break; default:
valid_input = false; break;
}
switch (param[1]) { case LINK_RATE_LOW: case LINK_RATE_HIGH: case LINK_RATE_RBR2: case LINK_RATE_HIGH2: case LINK_RATE_HIGH3: case LINK_RATE_UHBR10: case LINK_RATE_UHBR13_5: case LINK_RATE_UHBR20: break; default:
valid_input = false; break;
}
if (!valid_input) {
kfree(wr_buf);
DRM_DEBUG_DRIVER("Invalid Input value No HW will be programmed\n");
mutex_lock(&adev->dm.dc_lock);
dc_link_set_preferred_training_settings(dc, NULL, NULL, link, false);
mutex_unlock(&adev->dm.dc_lock); return -EINVAL;
}
/* 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.use_link_rate_set = false;
prefer_link_settings.lane_count = param[0];
prefer_link_settings.link_rate = param[1];
/* skip immediate retrain, and train to new link setting after hotplug event triggered */
mutex_lock(&adev->dm.dc_lock);
dc_link_set_preferred_training_settings(dc, &prefer_link_settings, NULL, link, true);
mutex_unlock(&adev->dm.dc_lock);
/* 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)
{ 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;
if (*pos & 3 || size & 3) return -EINVAL;
rd_buf = kcalloc(rd_buf_size, sizeof(char), GFP_KERNEL); if (!rd_buf) return -EINVAL;
if (param_nums <= 0) {
kfree(wr_buf);
DRM_DEBUG_DRIVER("user data not be read\n"); return -EINVAL;
}
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 size;
}
/* get link settings: lane count, link rate */
use_prefer_link_setting =
((link->preferred_link_setting.link_rate != LINK_RATE_UNKNOWN) &&
(link->test_pattern_enabled));
/* apply phy settings from user */ for (r = 0; r < link_lane_settings.link_settings.lane_count; r++) {
link_lane_settings.hw_lane_settings[r].VOLTAGE_SWING =
(enum dc_voltage_swing) (param[0]);
link_lane_settings.hw_lane_settings[r].PRE_EMPHASIS =
(enum dc_pre_emphasis) (param[1]);
link_lane_settings.hw_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 size;
}
/* function description * * set PHY layer or Link layer test pattern * PHY test pattern is used for PHY SI check. * Link layer test will not affect PHY SI. * * Reset Test Pattern: * 0 = DP_TEST_PATTERN_VIDEO_MODE * * PHY test pattern supported: * 1 = DP_TEST_PATTERN_D102 * 2 = DP_TEST_PATTERN_SYMBOL_ERROR * 3 = DP_TEST_PATTERN_PRBS7 * 4 = DP_TEST_PATTERN_80BIT_CUSTOM * 5 = DP_TEST_PATTERN_CP2520_1 * 6 = DP_TEST_PATTERN_CP2520_2 = DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE * 7 = DP_TEST_PATTERN_CP2520_3 * * DP PHY Link Training Patterns * 8 = DP_TEST_PATTERN_TRAINING_PATTERN1 * 9 = DP_TEST_PATTERN_TRAINING_PATTERN2 * a = DP_TEST_PATTERN_TRAINING_PATTERN3 * b = DP_TEST_PATTERN_TRAINING_PATTERN4 * * DP Link Layer Test pattern * c = DP_TEST_PATTERN_COLOR_SQUARES * d = DP_TEST_PATTERN_COLOR_SQUARES_CEA * e = DP_TEST_PATTERN_VERTICAL_BARS * f = DP_TEST_PATTERN_HORIZONTAL_BARS * 10= DP_TEST_PATTERN_COLOR_RAMP * * debugfs phy_test_pattern is located at /syskernel/debug/dri/0/DP-x * * --- set test pattern * echo <test pattern #> > test_pattern * * If test pattern # is not supported, NO HW programming will be done. * for DP_TEST_PATTERN_80BIT_CUSTOM, it needs extra 10 bytes of data * for the user pattern. input 10 bytes data are separated by space * * echo 0x4 0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88 0x99 0xaa > test_pattern * * --- reset test pattern * echo 0 > test_pattern * * --- HPD detection is disabled when set PHY test pattern * * when PHY test pattern (pattern # within [1,7]) is set, HPD pin of HW ASIC * is disable. User could unplug DP display from DP connected and plug scope to * check test pattern PHY SI. * If there is need unplug scope and plug DP display back, do steps below: * echo 0 > phy_test_pattern * unplug scope * plug DP display. * * "echo 0 > phy_test_pattern" will re-enable HPD pin again so that video sw * driver could detect "unplug scope" and "plug DP display"
*/ static ssize_t dp_phy_test_pattern_debugfs_write(struct file *f, constchar __user *buf,
size_t size, loff_t *pos)
{ struct amdgpu_dm_connector *connector = file_inode(f)->i_private; struct dc_link *link = connector->dc_link; char *wr_buf = NULL;
uint32_t wr_buf_size = 100; long param[11] = {0x0}; int max_param_num = 11; enum dp_test_pattern test_pattern = DP_TEST_PATTERN_UNSUPPORTED; bool disable_hpd = false; bool valid_test_pattern = false;
uint8_t param_nums = 0; /* init with default 80bit custom pattern */
uint8_t custom_pattern[10] = {
0x1f, 0x7c, 0xf0, 0xc1, 0x07,
0x1f, 0x7c, 0xf0, 0xc1, 0x07
}; struct dc_link_settings prefer_link_settings = {LANE_COUNT_UNKNOWN,
LINK_RATE_UNKNOWN, LINK_SPREAD_DISABLED}; struct dc_link_settings cur_link_settings = {LANE_COUNT_UNKNOWN,
LINK_RATE_UNKNOWN, LINK_SPREAD_DISABLED}; struct link_training_settings link_training_settings = {0}; int i;
if (size == 0) return -EINVAL;
wr_buf = kcalloc(wr_buf_size, sizeof(char), GFP_KERNEL); if (!wr_buf) return -ENOSPC;
if (param_nums <= 0) {
kfree(wr_buf);
DRM_DEBUG_DRIVER("user data not be read\n"); return -EINVAL;
}
test_pattern = param[0];
switch (test_pattern) { case DP_TEST_PATTERN_VIDEO_MODE: case DP_TEST_PATTERN_COLOR_SQUARES: case DP_TEST_PATTERN_COLOR_SQUARES_CEA: case DP_TEST_PATTERN_VERTICAL_BARS: case DP_TEST_PATTERN_HORIZONTAL_BARS: case DP_TEST_PATTERN_COLOR_RAMP:
valid_test_pattern = true; break;
case DP_TEST_PATTERN_D102: case DP_TEST_PATTERN_SYMBOL_ERROR: case DP_TEST_PATTERN_PRBS7: case DP_TEST_PATTERN_80BIT_CUSTOM: case DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE: case DP_TEST_PATTERN_TRAINING_PATTERN4:
disable_hpd = true;
valid_test_pattern = true; break;
if (!valid_test_pattern) {
kfree(wr_buf);
DRM_DEBUG_DRIVER("Invalid Test Pattern Parameters\n"); return size;
}
if (test_pattern == DP_TEST_PATTERN_80BIT_CUSTOM) { for (i = 0; i < 10; i++) { if ((uint8_t) param[i + 1] != 0x0) break;
}
if (i < 10) { /* not use default value */ for (i = 0; i < 10; i++)
custom_pattern[i] = (uint8_t) param[i + 1];
}
}
/* Usage: set DP physical test pattern using debugfs with normal DP * panel. Then plug out DP panel and connect a scope to measure * For normal video mode and test pattern generated from CRCT, * they are visibile to user. So do not disable HPD. * Video Mode is also set to clear the test pattern, so enable HPD * because it might have been disabled after a test pattern was set. * AUX depends on HPD * sequence dependent, do not move!
*/ if (!disable_hpd)
dc_link_enable_hpd(link);
for (i = 0; i < (unsignedint)(link_training_settings.link_settings.lane_count); i++)
link_training_settings.hw_lane_settings[i] = link->cur_lane_setting[i];
/* Usage: Set DP physical test pattern using AMDDP with normal DP panel * Then plug out DP panel and connect a scope to measure DP PHY signal. * Need disable interrupt to avoid SW driver disable DP output. This is * done after the test pattern is set.
*/ if (valid_test_pattern && disable_hpd)
dc_link_disable_hpd(link);
/* DMCUB tracebuffer is a ring. If it rolled over, print a hint that * entries are being overwritten.
*/ if (num_entries > max_entries)
seq_printf(m, "...\n");
/* To print entries chronologically, start from the first entry till the * top of buffer, then from base of buffer to first entry.
*/ for (i = first_entry; i < num_entries; ++i) { struct dmub_debugfs_trace_entry *entry = &entries[i];
seq_printf(m, "trace_code=%u tick_count=%u param0=%u param1=%u\n",
entry->trace_code, entry->tick_count, entry->param0,
entry->param1);
} for (i = 0; i < first_entry; ++i) { struct dmub_debugfs_trace_entry *entry = &entries[i];
/* * Returns the current colorspace for the crtc. * Example usage: cat /sys/kernel/debug/dri/0/crtc-0/amdgpu_current_colorspace
*/ staticint amdgpu_current_colorspace_show(struct seq_file *m, void *data)
{ struct drm_crtc *crtc = m->private; struct drm_device *dev = crtc->dev; struct dm_crtc_state *dm_crtc_state = NULL; int res = -ENODEV;
mutex_lock(&dev->mode_config.mutex);
drm_modeset_lock(&crtc->mutex, NULL); if (crtc->state == NULL) goto unlock;
dm_crtc_state = to_dm_crtc_state(crtc->state); if (dm_crtc_state->stream == NULL) goto unlock;
switch (dm_crtc_state->stream->output_color_space) { case COLOR_SPACE_SRGB:
seq_puts(m, "sRGB"); break; case COLOR_SPACE_YCBCR601: case COLOR_SPACE_YCBCR601_LIMITED:
seq_puts(m, "BT601_YCC"); break; case COLOR_SPACE_YCBCR709: case COLOR_SPACE_YCBCR709_LIMITED:
seq_puts(m, "BT709_YCC"); break; case COLOR_SPACE_ADOBERGB:
seq_puts(m, "opRGB"); break; case COLOR_SPACE_2020_RGB_FULLRANGE:
seq_puts(m, "BT2020_RGB"); break; case COLOR_SPACE_2020_YCBCR_LIMITED:
seq_puts(m, "BT2020_YCC"); break; default: goto unlock;
}
res = 0;
/* * Returns the HDCP capability of the Display (1.4 for now). * * NOTE* Not all HDMI displays report their HDCP caps even when they are capable. * Since its rare for a display to not be HDCP 1.4 capable, we set HDMI as always capable. * * Example usage: cat /sys/kernel/debug/dri/0/DP-1/hdcp_sink_capability * or cat /sys/kernel/debug/dri/0/HDMI-A-1/hdcp_sink_capability
*/ staticint hdcp_sink_capability_show(struct seq_file *m, void *data)
{ struct drm_connector *connector = m->private; struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); bool hdcp_cap, hdcp2_cap;
if (connector->status != connector_status_connected) return -ENODEV;
/* * Returns the number of segments used if ODM Combine mode is enabled. * Example usage: cat /sys/kernel/debug/dri/0/DP-1/odm_combine_segments
*/ staticint odm_combine_segments_show(struct seq_file *m, void *unused)
{ struct drm_connector *connector = m->private; struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); struct dc_link *link = aconnector->dc_link; struct pipe_ctx *pipe_ctx = NULL; int i, segments = -EOPNOTSUPP;
for (i = 0; i < MAX_PIPES; i++) {
pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i]; if (pipe_ctx->stream &&
pipe_ctx->stream->link == link) break;
}
if (connector->status != connector_status_connected) return -ENODEV;
if (pipe_ctx && pipe_ctx->stream_res.tg &&
pipe_ctx->stream_res.tg->funcs->get_odm_combine_segments)
pipe_ctx->stream_res.tg->funcs->get_odm_combine_segments(pipe_ctx->stream_res.tg, &segments);
seq_printf(m, "%d\n", segments); return 0;
}
/* function description * * generic SDP message access for testing * * debugfs sdp_message is located at /syskernel/debug/dri/0/DP-x * * SDP header * Hb0 : Secondary-Data Packet ID * Hb1 : Secondary-Data Packet type * Hb2 : Secondary-Data-packet-specific header, Byte 0 * Hb3 : Secondary-Data-packet-specific header, Byte 1 * * for using custom sdp message: input 4 bytes SDP header and 32 bytes raw data
*/ static ssize_t dp_sdp_message_debugfs_write(struct file *f, constchar __user *buf,
size_t size, loff_t *pos)
{ int r;
uint8_t data[36] = {0}; struct amdgpu_dm_connector *connector = file_inode(f)->i_private; struct dm_crtc_state *acrtc_state;
uint32_t write_size = 36;
if (connector->base.status != connector_status_connected) return -ENODEV;
/* function: Read link's DSC & FEC capabilities * * * Access it with the following command (you need to specify * connector like DP-1): * * cat /sys/kernel/debug/dri/0/DP-X/dp_dsc_fec_support *
*/ staticint dp_dsc_fec_support_show(struct seq_file *m, void *data)
{ struct drm_connector *connector = m->private; struct drm_modeset_acquire_ctx ctx; struct drm_device *dev = connector->dev; struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); int ret = 0; bool try_again = false; bool is_fec_supported = false; bool is_dsc_supported = false; struct dpcd_caps dpcd_caps;
drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE); do {
try_again = false;
ret = drm_modeset_lock(&dev->mode_config.connection_mutex, &ctx); if (ret) { if (ret == -EDEADLK) {
ret = drm_modeset_backoff(&ctx); if (!ret) {
try_again = true; continue;
}
} break;
} if (connector->status != connector_status_connected) {
ret = -ENODEV; break;
}
dpcd_caps = aconnector->dc_link->dpcd_caps; if (aconnector->mst_output_port) { /* aconnector sets dsc_aux during get_modes call * if MST connector has it means it can either * enable DSC on the sink device or on MST branch * its connected to.
*/ if (aconnector->dsc_aux) {
is_fec_supported = true;
is_dsc_supported = true;
}
} else {
is_fec_supported = dpcd_caps.fec_cap.raw & 0x1;
is_dsc_supported = dpcd_caps.dsc_caps.dsc_basic_caps.raw[0] & 0x1;
}
} while (try_again);
/* function: read DSC status on the connector * * The read function: dp_dsc_clock_en_read * returns current status of DSC clock on the connector. * The return is a boolean flag: 1 or 0. * * Access it with the following command (you need to specify * connector like DP-1): * * cat /sys/kernel/debug/dri/0/DP-X/dsc_clock_en * * Expected output: * 1 - means that DSC is currently enabled * 0 - means that DSC is disabled
*/ static ssize_t dp_dsc_clock_en_read(struct file *f, char __user *buf,
size_t size, loff_t *pos)
{ char *rd_buf = NULL; struct amdgpu_dm_connector *aconnector = file_inode(f)->i_private; struct display_stream_compressor *dsc; struct dcn_dsc_state dsc_state = {0}; const uint32_t rd_buf_size = 10; struct pipe_ctx *pipe_ctx;
ssize_t result = 0; int i, r, str_len = 10;
r = put_user(*(rd_buf + result), buf); if (r) {
kfree(rd_buf); return r; /* r = -EFAULT */
}
buf += 1;
size -= 1;
*pos += 1;
result += 1;
}
kfree(rd_buf); return result;
}
/* function: write force DSC on the connector * * The write function: dp_dsc_clock_en_write * enables to force DSC on the connector. * User can write to either force enable or force disable DSC * on the next modeset or set it to driver default * * Accepted inputs: * 0 - default DSC enablement policy * 1 - force enable DSC on the connector * 2 - force disable DSC on the connector (might cause fail in atomic_check) * * Writing DSC settings is done with the following command: * - To force enable DSC (you need to specify * connector like DP-1): * * echo 0x1 > /sys/kernel/debug/dri/0/DP-X/dsc_clock_en * * - To return to default state set the flag to zero and * let driver deal with DSC automatically * (you need to specify connector like DP-1): * * echo 0x0 > /sys/kernel/debug/dri/0/DP-X/dsc_clock_en *
*/ static ssize_t dp_dsc_clock_en_write(struct file *f, constchar __user *buf,
size_t size, loff_t *pos)
{ struct amdgpu_dm_connector *aconnector = file_inode(f)->i_private; struct drm_connector *connector = &aconnector->base; struct drm_device *dev = connector->dev; struct drm_crtc *crtc = NULL; struct dm_crtc_state *dm_crtc_state = NULL; struct pipe_ctx *pipe_ctx; int i; char *wr_buf = NULL;
uint32_t wr_buf_size = 42; int max_param_num = 1; long param[1] = {0};
uint8_t param_nums = 0;
unlock: if (crtc)
drm_modeset_unlock(&crtc->mutex);
drm_modeset_unlock(&dev->mode_config.connection_mutex);
mutex_unlock(&dev->mode_config.mutex);
done:
kfree(wr_buf); return size;
}
/* function: read DSC slice width parameter on the connector * * The read function: dp_dsc_slice_width_read * returns dsc slice width used in the current configuration * The return is an integer: 0 or other positive number * * Access the status with the following command: * * cat /sys/kernel/debug/dri/0/DP-X/dsc_slice_width * * 0 - means that DSC is disabled * * Any other number more than zero represents the * slice width currently used by DSC in pixels *
*/ static ssize_t dp_dsc_slice_width_read(struct file *f, char __user *buf,
size_t size, loff_t *pos)
{ char *rd_buf = NULL; struct amdgpu_dm_connector *aconnector = file_inode(f)->i_private; struct display_stream_compressor *dsc; struct dcn_dsc_state dsc_state = {0}; const uint32_t rd_buf_size = 100; struct pipe_ctx *pipe_ctx;
ssize_t result = 0; int i, r, str_len = 30;
r = put_user(*(rd_buf + result), buf); if (r) {
kfree(rd_buf); return r; /* r = -EFAULT */
}
buf += 1;
size -= 1;
*pos += 1;
result += 1;
}
kfree(rd_buf); return result;
}
/* function: write DSC slice width parameter * * The write function: dp_dsc_slice_width_write * overwrites automatically generated DSC configuration * of slice width. * * The user has to write the slice width divisible by the * picture width. * * Also the user has to write width in hexidecimal * rather than in decimal. * * Writing DSC settings is done with the following command: * - To force overwrite slice width: (example sets to 1920 pixels) * * echo 0x780 > /sys/kernel/debug/dri/0/DP-X/dsc_slice_width * * - To stop overwriting and let driver find the optimal size, * set the width to zero: * * echo 0x0 > /sys/kernel/debug/dri/0/DP-X/dsc_slice_width *
*/ static ssize_t dp_dsc_slice_width_write(struct file *f, constchar __user *buf,
size_t size, loff_t *pos)
{ struct amdgpu_dm_connector *aconnector = file_inode(f)->i_private; struct pipe_ctx *pipe_ctx; struct drm_connector *connector = &aconnector->base; struct drm_device *dev = connector->dev; struct drm_crtc *crtc = NULL; struct dm_crtc_state *dm_crtc_state = NULL; int i; char *wr_buf = NULL;
uint32_t wr_buf_size = 42; int max_param_num = 1; long param[1] = {0};
uint8_t param_nums = 0;
unlock: if (crtc)
drm_modeset_unlock(&crtc->mutex);
drm_modeset_unlock(&dev->mode_config.connection_mutex);
mutex_unlock(&dev->mode_config.mutex);
done:
kfree(wr_buf); return size;
}
/* function: read DSC slice height parameter on the connector * * The read function: dp_dsc_slice_height_read * returns dsc slice height used in the current configuration * The return is an integer: 0 or other positive number * * Access the status with the following command: * * cat /sys/kernel/debug/dri/0/DP-X/dsc_slice_height * * 0 - means that DSC is disabled * * Any other number more than zero represents the * slice height currently used by DSC in pixels *
*/ static ssize_t dp_dsc_slice_height_read(struct file *f, char __user *buf,
size_t size, loff_t *pos)
{ char *rd_buf = NULL; struct amdgpu_dm_connector *aconnector = file_inode(f)->i_private; struct display_stream_compressor *dsc; struct dcn_dsc_state dsc_state = {0}; const uint32_t rd_buf_size = 100; struct pipe_ctx *pipe_ctx;
ssize_t result = 0; int i, r, str_len = 30;
r = put_user(*(rd_buf + result), buf); if (r) {
kfree(rd_buf); return r; /* r = -EFAULT */
}
buf += 1;
size -= 1;
*pos += 1;
result += 1;
}
kfree(rd_buf); return result;
}
/* function: write DSC slice height parameter * * The write function: dp_dsc_slice_height_write * overwrites automatically generated DSC configuration * of slice height. * * The user has to write the slice height divisible by the * picture height. * * Also the user has to write height in hexidecimal * rather than in decimal. * * Writing DSC settings is done with the following command: * - To force overwrite slice height (example sets to 128 pixels): * * echo 0x80 > /sys/kernel/debug/dri/0/DP-X/dsc_slice_height * * - To stop overwriting and let driver find the optimal size, * set the height to zero: * * echo 0x0 > /sys/kernel/debug/dri/0/DP-X/dsc_slice_height *
*/ static ssize_t dp_dsc_slice_height_write(struct file *f, constchar __user *buf,
size_t size, loff_t *pos)
{ struct amdgpu_dm_connector *aconnector = file_inode(f)->i_private; struct drm_connector *connector = &aconnector->base; struct drm_device *dev = connector->dev; struct drm_crtc *crtc = NULL; struct dm_crtc_state *dm_crtc_state = NULL; struct pipe_ctx *pipe_ctx; int i; char *wr_buf = NULL;
uint32_t wr_buf_size = 42; int max_param_num = 1;
uint8_t param_nums = 0; long param[1] = {0};
unlock: if (crtc)
drm_modeset_unlock(&crtc->mutex);
drm_modeset_unlock(&dev->mode_config.connection_mutex);
mutex_unlock(&dev->mode_config.mutex);
done:
kfree(wr_buf); return size;
}
/* function: read DSC target rate on the connector in bits per pixel * * The read function: dp_dsc_bits_per_pixel_read * returns target rate of compression in bits per pixel * The return is an integer: 0 or other positive integer * * Access it with the following command: * * cat /sys/kernel/debug/dri/0/DP-X/dsc_bits_per_pixel * * 0 - means that DSC is disabled
*/ static ssize_t dp_dsc_bits_per_pixel_read(struct file *f, char __user *buf,
size_t size, loff_t *pos)
{ char *rd_buf = NULL; struct amdgpu_dm_connector *aconnector = file_inode(f)->i_private; struct display_stream_compressor *dsc; struct dcn_dsc_state dsc_state = {0}; const uint32_t rd_buf_size = 100; struct pipe_ctx *pipe_ctx;
ssize_t result = 0; int i, r, str_len = 30;
unlock: if (crtc)
drm_modeset_unlock(&crtc->mutex);
drm_modeset_unlock(&dev->mode_config.connection_mutex);
mutex_unlock(&dev->mode_config.mutex);
done:
kfree(wr_buf); return size;
}
/* function: read DSC picture width parameter on the connector * * The read function: dp_dsc_pic_width_read * returns dsc picture width used in the current configuration * It is the same as h_addressable of the current * display's timing * The return is an integer: 0 or other positive integer * If 0 then DSC is disabled. * * Access it with the following command: * * cat /sys/kernel/debug/dri/0/DP-X/dsc_pic_width * * 0 - means that DSC is disabled
*/ static ssize_t dp_dsc_pic_width_read(struct file *f, char __user *buf,
size_t size, loff_t *pos)
{ char *rd_buf = NULL; struct amdgpu_dm_connector *aconnector = file_inode(f)->i_private; struct display_stream_compressor *dsc; struct dcn_dsc_state dsc_state = {0}; const uint32_t rd_buf_size = 100; struct pipe_ctx *pipe_ctx;
ssize_t result = 0; int i, r, str_len = 30;
r = put_user(*(rd_buf + result), buf); if (r) {
kfree(rd_buf); return r; /* r = -EFAULT */
}
buf += 1;
size -= 1;
*pos += 1;
result += 1;
}
kfree(rd_buf); return result;
}
/* function: read DSC chunk size parameter on the connector * * The read function: dp_dsc_chunk_size_read * returns dsc chunk size set in the current configuration * The value is calculated automatically by DSC code * and depends on slice parameters and bpp target rate * The return is an integer: 0 or other positive integer * If 0 then DSC is disabled. * * Access it with the following command: * * cat /sys/kernel/debug/dri/0/DP-X/dsc_chunk_size * * 0 - means that DSC is disabled
*/ static ssize_t dp_dsc_chunk_size_read(struct file *f, char __user *buf,
size_t size, loff_t *pos)
{ char *rd_buf = NULL; struct amdgpu_dm_connector *aconnector = file_inode(f)->i_private; struct display_stream_compressor *dsc; struct dcn_dsc_state dsc_state = {0}; const uint32_t rd_buf_size = 100; struct pipe_ctx *pipe_ctx;
ssize_t result = 0; int i, r, str_len = 30;
r = put_user(*(rd_buf + result), buf); if (r) {
kfree(rd_buf); return r; /* r = -EFAULT */
}
buf += 1;
size -= 1;
*pos += 1;
result += 1;
}
kfree(rd_buf); return result;
}
/* function: read DSC slice bpg offset on the connector * * The read function: dp_dsc_slice_bpg_offset_read * returns dsc bpg slice offset set in the current configuration * The value is calculated automatically by DSC code * and depends on slice parameters and bpp target rate * The return is an integer: 0 or other positive integer * If 0 then DSC is disabled. * * Access it with the following command: * * cat /sys/kernel/debug/dri/0/DP-X/dsc_slice_bpg_offset * * 0 - means that DSC is disabled
*/ static ssize_t dp_dsc_slice_bpg_offset_read(struct file *f, char __user *buf,
size_t size, loff_t *pos)
{ char *rd_buf = NULL; struct amdgpu_dm_connector *aconnector = file_inode(f)->i_private;
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.88 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.