From f258fee6c3c076a406be3388d4099f1b1a45b39c Mon Sep 17 00:00:00 2001 From: David Francis Date: Tue, 5 Mar 2019 10:04:15 -0500 Subject: [PATCH] drm/amd/display: Add debugfs dpcd interface [Why] We need arbitrary read/write over DP AUX DPCD for debugging [How] Three debugfs entries Set the target address by writing to "aux_dpcd_address" (The first four bytes written are used) Set the transaction size in bytes by writing to "aux_dpcd_size" (The first four bytes written are used) Start a transaction by reading/writing "aux_dpcd_data" Do note: there is no concerrency protection at all Accessing these entries in quick succession can lead to strange behaviour Signed-off-by: David Francis Reviewed-by: Harry Wentland Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 4 + .../amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 107 +++++++++++++++++- 3 files changed, 112 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 8b5fc420d1c1..ef247831bab6 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -4395,6 +4395,8 @@ static int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm, DRM_ERROR("Failed to create debugfs for connector"); goto out_free; } + aconnector->debugfs_dpcd_address = 0; + aconnector->debugfs_dpcd_size = 0; #endif if (connector_type == DRM_MODE_CONNECTOR_DisplayPort diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h index f741ea35c3ab..773ef5ca8441 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -238,6 +238,10 @@ struct amdgpu_dm_connector { struct mutex hpd_lock; bool fake_enable; +#ifdef CONFIG_DEBUG_FS + uint32_t debugfs_dpcd_address; + uint32_t debugfs_dpcd_size; +#endif }; #define to_amdgpu_dm_connector(x) container_of(x, struct amdgpu_dm_connector, base) 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 842ddd37fb81..1a9e3d3dfa38 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 @@ -29,6 +29,7 @@ #include "amdgpu.h" #include "amdgpu_dm.h" #include "amdgpu_dm_debugfs.h" +#include "dm_helpers.h" /* function description * get/ set DP configuration: lane_count, link_rate, spread_spectrum @@ -731,6 +732,88 @@ static ssize_t dp_sdp_message_debugfs_write(struct file *f, const char __user *b DEFINE_SHOW_ATTRIBUTE(vrr_range); +static ssize_t dp_dpcd_address_write(struct file *f, const char __user *buf, + size_t size, loff_t *pos) +{ + int r; + struct amdgpu_dm_connector *connector = file_inode(f)->i_private; + + if (size < sizeof(connector->debugfs_dpcd_address)) + return 0; + + r = copy_from_user(&connector->debugfs_dpcd_address, + buf, sizeof(connector->debugfs_dpcd_address)); + + return size - r; +} + +static ssize_t dp_dpcd_size_write(struct file *f, const char __user *buf, + size_t size, loff_t *pos) +{ + int r; + struct amdgpu_dm_connector *connector = file_inode(f)->i_private; + + if (size < sizeof(connector->debugfs_dpcd_size)) + return 0; + + r = copy_from_user(&connector->debugfs_dpcd_size, + buf, sizeof(connector->debugfs_dpcd_size)); + + if (connector->debugfs_dpcd_size > 256) + connector->debugfs_dpcd_size = 0; + + return size - r; +} + +static ssize_t dp_dpcd_data_write(struct file *f, const char __user *buf, + size_t size, loff_t *pos) +{ + int r; + char *data; + struct amdgpu_dm_connector *connector = file_inode(f)->i_private; + struct dc_link *link = connector->dc_link; + uint32_t write_size = connector->debugfs_dpcd_size; + + if (size < write_size) + return 0; + + data = kzalloc(write_size, GFP_KERNEL); + if (!data) + return 0; + + r = copy_from_user(data, buf, write_size); + + dm_helpers_dp_write_dpcd(link->ctx, link, + connector->debugfs_dpcd_address, data, write_size - r); + kfree(data); + return write_size - r; +} + +static ssize_t dp_dpcd_data_read(struct file *f, char __user *buf, + size_t size, loff_t *pos) +{ + int r; + char *data; + struct amdgpu_dm_connector *connector = file_inode(f)->i_private; + struct dc_link *link = connector->dc_link; + uint32_t read_size = connector->debugfs_dpcd_size; + + if (size < read_size) + return 0; + + data = kzalloc(read_size, GFP_KERNEL); + if (!data) + return 0; + + dm_helpers_dp_read_dpcd(link->ctx, link, + connector->debugfs_dpcd_address, data, read_size); + + r = copy_to_user(buf, data, read_size); + + kfree(data); + return read_size - r; +} + static const struct file_operations dp_link_settings_debugfs_fops = { .owner = THIS_MODULE, .read = dp_link_settings_read, @@ -757,6 +840,25 @@ static const struct file_operations sdp_message_fops = { .llseek = default_llseek }; +static const struct file_operations dp_dpcd_address_debugfs_fops = { + .owner = THIS_MODULE, + .write = dp_dpcd_address_write, + .llseek = default_llseek +}; + +static const struct file_operations dp_dpcd_size_debugfs_fops = { + .owner = THIS_MODULE, + .write = dp_dpcd_size_write, + .llseek = default_llseek +}; + +static const struct file_operations dp_dpcd_data_debugfs_fops = { + .owner = THIS_MODULE, + .read = dp_dpcd_data_read, + .write = dp_dpcd_data_write, + .llseek = default_llseek +}; + static const struct { char *name; const struct file_operations *fops; @@ -765,7 +867,10 @@ static const struct { {"phy_settings", &dp_phy_settings_debugfs_fop}, {"test_pattern", &dp_phy_test_pattern_fops}, {"vrr_range", &vrr_range_fops}, - {"sdp_message", &sdp_message_fops} + {"sdp_message", &sdp_message_fops}, + {"aux_dpcd_address", &dp_dpcd_address_debugfs_fops}, + {"aux_dpcd_size", &dp_dpcd_size_debugfs_fops}, + {"aux_dpcd_data", &dp_dpcd_data_debugfs_fops} }; int connector_debugfs_init(struct amdgpu_dm_connector *connector) -- 2.30.2