1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. 4 */ 5 6 #define pr_fmt(fmt)"[drm-dp] %s: " fmt, __func__ 7 8 #include <linux/debugfs.h> 9 #include <drm/drm_connector.h> 10 #include <drm/drm_file.h> 11 12 #include "dp_aux.h" 13 #include "dp_ctrl.h" 14 #include "dp_debug.h" 15 #include "dp_display.h" 16 17 #define DEBUG_NAME "msm_dp" 18 19 struct msm_dp_debug_private { 20 struct msm_dp_link *link; 21 struct msm_dp_panel *panel; 22 struct drm_connector *connector; 23 }; 24 25 static int msm_dp_debug_show(struct seq_file *seq, void *p) 26 { 27 struct msm_dp_debug_private *debug = seq->private; 28 u64 lclk = 0; 29 u32 link_params_rate; 30 const struct drm_display_mode *drm_mode; 31 32 if (!debug) 33 return -ENODEV; 34 35 drm_mode = &debug->panel->msm_dp_mode.drm_mode; 36 37 seq_printf(seq, "\tname = %s\n", DEBUG_NAME); 38 seq_printf(seq, "\tdrm_dp_link\n\t\trate = %u\n", 39 debug->panel->link_info.rate); 40 seq_printf(seq, "\t\tnum_lanes = %u\n", 41 debug->panel->link_info.num_lanes); 42 seq_printf(seq, "\t\tcapabilities = %lu\n", 43 debug->panel->link_info.capabilities); 44 seq_printf(seq, "\tdp_panel_info:\n\t\tactive = %dx%d\n", 45 drm_mode->hdisplay, 46 drm_mode->vdisplay); 47 seq_printf(seq, "\t\tback_porch = %dx%d\n", 48 drm_mode->htotal - drm_mode->hsync_end, 49 drm_mode->vtotal - drm_mode->vsync_end); 50 seq_printf(seq, "\t\tfront_porch = %dx%d\n", 51 drm_mode->hsync_start - drm_mode->hdisplay, 52 drm_mode->vsync_start - drm_mode->vdisplay); 53 seq_printf(seq, "\t\tsync_width = %dx%d\n", 54 drm_mode->hsync_end - drm_mode->hsync_start, 55 drm_mode->vsync_end - drm_mode->vsync_start); 56 seq_printf(seq, "\t\tactive_low = %dx%d\n", 57 debug->panel->msm_dp_mode.h_active_low, 58 debug->panel->msm_dp_mode.v_active_low); 59 seq_printf(seq, "\t\th_skew = %d\n", 60 drm_mode->hskew); 61 seq_printf(seq, "\t\trefresh rate = %d\n", 62 drm_mode_vrefresh(drm_mode)); 63 seq_printf(seq, "\t\tpixel clock khz = %d\n", 64 drm_mode->clock); 65 seq_printf(seq, "\t\tbpp = %d\n", 66 debug->panel->msm_dp_mode.bpp); 67 68 /* Link Information */ 69 seq_printf(seq, "\tdp_link:\n\t\ttest_requested = %d\n", 70 debug->link->sink_request); 71 seq_printf(seq, "\t\tnum_lanes = %d\n", 72 debug->link->link_params.num_lanes); 73 link_params_rate = debug->link->link_params.rate; 74 seq_printf(seq, "\t\tbw_code = %d\n", 75 drm_dp_link_rate_to_bw_code(link_params_rate)); 76 lclk = debug->link->link_params.rate * 1000; 77 seq_printf(seq, "\t\tlclk = %lld\n", lclk); 78 seq_printf(seq, "\t\tv_level = %d\n", 79 debug->link->phy_params.v_level); 80 seq_printf(seq, "\t\tp_level = %d\n", 81 debug->link->phy_params.p_level); 82 83 return 0; 84 } 85 DEFINE_SHOW_ATTRIBUTE(msm_dp_debug); 86 87 static int msm_dp_test_data_show(struct seq_file *m, void *data) 88 { 89 const struct msm_dp_debug_private *debug = m->private; 90 const struct drm_connector *connector = debug->connector; 91 u32 bpc; 92 93 if (connector->status == connector_status_connected) { 94 bpc = debug->link->test_video.test_bit_depth; 95 seq_printf(m, "hdisplay: %d\n", 96 debug->link->test_video.test_h_width); 97 seq_printf(m, "vdisplay: %d\n", 98 debug->link->test_video.test_v_height); 99 seq_printf(m, "bpc: %u\n", 100 msm_dp_link_bit_depth_to_bpp(bpc) / 3); 101 } else { 102 seq_puts(m, "0"); 103 } 104 105 return 0; 106 } 107 DEFINE_SHOW_ATTRIBUTE(msm_dp_test_data); 108 109 static int msm_dp_test_type_show(struct seq_file *m, void *data) 110 { 111 const struct msm_dp_debug_private *debug = m->private; 112 const struct drm_connector *connector = debug->connector; 113 114 if (connector->status == connector_status_connected) 115 seq_printf(m, "%02x", DP_TEST_LINK_VIDEO_PATTERN); 116 else 117 seq_puts(m, "0"); 118 119 return 0; 120 } 121 DEFINE_SHOW_ATTRIBUTE(msm_dp_test_type); 122 123 static ssize_t msm_dp_test_active_write(struct file *file, 124 const char __user *ubuf, 125 size_t len, loff_t *offp) 126 { 127 char *input_buffer; 128 int status = 0; 129 const struct msm_dp_debug_private *debug; 130 const struct drm_connector *connector; 131 int val = 0; 132 133 debug = ((struct seq_file *)file->private_data)->private; 134 connector = debug->connector; 135 136 if (len == 0) 137 return 0; 138 139 input_buffer = memdup_user_nul(ubuf, len); 140 if (IS_ERR(input_buffer)) 141 return PTR_ERR(input_buffer); 142 143 DRM_DEBUG_DRIVER("Copied %d bytes from user\n", (unsigned int)len); 144 145 if (connector->status == connector_status_connected) { 146 status = kstrtoint(input_buffer, 10, &val); 147 if (status < 0) { 148 kfree(input_buffer); 149 return status; 150 } 151 DRM_DEBUG_DRIVER("Got %d for test active\n", val); 152 /* To prevent erroneous activation of the compliance 153 * testing code, only accept an actual value of 1 here 154 */ 155 if (val == 1) 156 debug->panel->video_test = true; 157 else 158 debug->panel->video_test = false; 159 } 160 kfree(input_buffer); 161 162 *offp += len; 163 return len; 164 } 165 166 static int msm_dp_test_active_show(struct seq_file *m, void *data) 167 { 168 struct msm_dp_debug_private *debug = m->private; 169 struct drm_connector *connector = debug->connector; 170 171 if (connector->status == connector_status_connected) { 172 if (debug->panel->video_test) 173 seq_puts(m, "1"); 174 else 175 seq_puts(m, "0"); 176 } else { 177 seq_puts(m, "0"); 178 } 179 180 return 0; 181 } 182 183 static int msm_dp_test_active_open(struct inode *inode, 184 struct file *file) 185 { 186 return single_open(file, msm_dp_test_active_show, 187 inode->i_private); 188 } 189 190 static const struct file_operations test_active_fops = { 191 .owner = THIS_MODULE, 192 .open = msm_dp_test_active_open, 193 .read = seq_read, 194 .llseek = seq_lseek, 195 .release = single_release, 196 .write = msm_dp_test_active_write 197 }; 198 199 int msm_dp_debug_init(struct device *dev, struct msm_dp_panel *panel, 200 struct msm_dp_link *link, 201 struct drm_connector *connector, 202 struct dentry *root, bool is_edp) 203 { 204 struct msm_dp_debug_private *debug; 205 206 if (!dev || !panel || !link) { 207 DRM_ERROR("invalid input\n"); 208 return -EINVAL; 209 } 210 211 debug = devm_kzalloc(dev, sizeof(*debug), GFP_KERNEL); 212 if (!debug) 213 return -ENOMEM; 214 215 debug->link = link; 216 debug->panel = panel; 217 218 debugfs_create_file("dp_debug", 0444, root, 219 debug, &msm_dp_debug_fops); 220 221 if (!is_edp) { 222 debugfs_create_file("dp_test_active", 0444, 223 root, 224 debug, &test_active_fops); 225 226 debugfs_create_file("dp_test_data", 0444, 227 root, 228 debug, &msm_dp_test_data_fops); 229 230 debugfs_create_file("dp_test_type", 0444, 231 root, 232 debug, &msm_dp_test_type_fops); 233 } 234 235 return 0; 236 } 237