blob: 82e34df829117c3bb4acad976ee1376cc29b0e9c [file] [log] [blame]
Samantha Tran2d1ed732017-07-31 17:30:14 -07001/*
2 * Copyright (c) 2017, The Linux Foundation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 */
14
15#define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__
16
17#include <linux/debugfs.h>
18
19#include "dp_parser.h"
20#include "dp_power.h"
21#include "dp_catalog.h"
22#include "dp_aux.h"
23#include "dp_ctrl.h"
24#include "dp_debug.h"
25#include "drm_connector.h"
26#include "dp_display.h"
27
28#define DEBUG_NAME "drm_dp"
29
30struct dp_debug_private {
31 struct dentry *root;
32
33 struct dp_usbpd *usbpd;
34 struct dp_link *link;
35 struct dp_panel *panel;
36 struct drm_connector **connector;
37 struct device *dev;
38
39 struct dp_debug dp_debug;
40};
41
42static ssize_t dp_debug_write_hpd(struct file *file,
43 const char __user *user_buff, size_t count, loff_t *ppos)
44{
45 struct dp_debug_private *debug = file->private_data;
46 char buf[SZ_8];
47 size_t len = 0;
48 int hpd;
49
50 if (!debug)
51 return -ENODEV;
52
53 if (*ppos)
54 return 0;
55
56 /* Leave room for termination char */
57 len = min_t(size_t, count, SZ_8 - 1);
58 if (copy_from_user(buf, user_buff, len))
59 goto end;
60
61 buf[len] = '\0';
62
63 if (kstrtoint(buf, 10, &hpd) != 0)
64 goto end;
65
66 debug->usbpd->connect(debug->usbpd, hpd);
67end:
68 return -len;
69}
70
71static ssize_t dp_debug_write_edid_modes(struct file *file,
72 const char __user *user_buff, size_t count, loff_t *ppos)
73{
74 struct dp_debug_private *debug = file->private_data;
75 char buf[SZ_32];
76 size_t len = 0;
77 int hdisplay = 0, vdisplay = 0, vrefresh = 0;
78
79 if (!debug)
80 return -ENODEV;
81
82 if (*ppos)
83 goto end;
84
85 /* Leave room for termination char */
86 len = min_t(size_t, count, SZ_32 - 1);
87 if (copy_from_user(buf, user_buff, len))
88 goto clear;
89
90 buf[len] = '\0';
91
92 if (sscanf(buf, "%d %d %d", &hdisplay, &vdisplay, &vrefresh) != 3)
93 goto clear;
94
95 if (!hdisplay || !vdisplay || !vrefresh)
96 goto clear;
97
98 debug->dp_debug.debug_en = true;
99 debug->dp_debug.hdisplay = hdisplay;
100 debug->dp_debug.vdisplay = vdisplay;
101 debug->dp_debug.vrefresh = vrefresh;
102 goto end;
103clear:
104 pr_debug("clearing debug modes\n");
105 debug->dp_debug.debug_en = false;
106end:
107 return len;
108}
109
110static ssize_t dp_debug_read_connected(struct file *file,
111 char __user *user_buff, size_t count, loff_t *ppos)
112{
113 struct dp_debug_private *debug = file->private_data;
114 char buf[SZ_8];
115 u32 len = 0;
116
117 if (!debug)
118 return -ENODEV;
119
120 if (*ppos)
121 return 0;
122
123 len += snprintf(buf, SZ_8, "%d\n", debug->usbpd->hpd_high);
124
125 if (copy_to_user(user_buff, buf, len))
126 return -EFAULT;
127
128 *ppos += len;
129 return len;
130}
131
132static ssize_t dp_debug_read_edid_modes(struct file *file,
133 char __user *user_buff, size_t count, loff_t *ppos)
134{
135 struct dp_debug_private *debug = file->private_data;
136 char *buf;
137 u32 len = 0;
138 int rc = 0;
139 struct drm_connector *connector;
140 struct drm_display_mode *mode;
141
142 if (!debug) {
143 pr_err("invalid data\n");
144 rc = -ENODEV;
145 goto error;
146 }
147
148 connector = *debug->connector;
149
150 if (!connector) {
151 pr_err("connector is NULL\n");
152 rc = -EINVAL;
153 goto error;
154 }
155
156 if (*ppos)
157 goto error;
158
159 buf = kzalloc(SZ_4K, GFP_KERNEL);
160 if (!buf) {
161 rc = -ENOMEM;
162 goto error;
163 }
164
165 list_for_each_entry(mode, &connector->modes, head) {
166 len += snprintf(buf + len, SZ_4K - len,
167 "%s %d %d %d %d %d %d %d %d %d 0x%x\n",
168 mode->name, mode->vrefresh, mode->hdisplay,
169 mode->hsync_start, mode->hsync_end, mode->htotal,
170 mode->vdisplay, mode->vsync_start, mode->vsync_end,
171 mode->vtotal, mode->flags);
172 }
173
174 if (copy_to_user(user_buff, buf, len)) {
175 kfree(buf);
176 rc = -EFAULT;
177 goto error;
178 }
179
180 *ppos += len;
181 kfree(buf);
182
183 return len;
184error:
185 return rc;
186}
187
188static int dp_debug_check_buffer_overflow(int rc, int *max_size, int *len)
189{
190 if (rc >= *max_size) {
191 pr_err("buffer overflow\n");
192 return -EINVAL;
193 }
194 *len += rc;
195 *max_size = SZ_4K - *len;
196
197 return 0;
198}
199
200static ssize_t dp_debug_read_info(struct file *file, char __user *user_buff,
201 size_t count, loff_t *ppos)
202{
203 struct dp_debug_private *debug = file->private_data;
204 char *buf;
205 u32 len = 0, rc = 0;
206 u64 lclk = 0;
207 u32 max_size = SZ_4K;
208
209 if (!debug)
210 return -ENODEV;
211
212 if (*ppos)
213 return 0;
214
215 buf = kzalloc(SZ_4K, GFP_KERNEL);
216 if (!buf)
217 return -ENOMEM;
218
219 rc = snprintf(buf + len, max_size, "\tname = %s\n", DEBUG_NAME);
220 if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
221 goto error;
222
223 rc = snprintf(buf + len, max_size,
224 "\tdp_panel\n\t\tmax_pclk_khz = %d\n",
225 debug->panel->max_pclk_khz);
226 if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
227 goto error;
228
229 rc = snprintf(buf + len, max_size,
230 "\tdrm_dp_link\n\t\trate = %u\n",
231 debug->panel->link_info.rate);
232 if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
233 goto error;
234
235 rc = snprintf(buf + len, max_size,
236 "\t\tnum_lanes = %u\n",
237 debug->panel->link_info.num_lanes);
238 if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
239 goto error;
240
241 rc = snprintf(buf + len, max_size,
242 "\t\tcapabilities = %lu\n",
243 debug->panel->link_info.capabilities);
244 if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
245 goto error;
246
247 rc = snprintf(buf + len, max_size,
248 "\tdp_panel_info:\n\t\tactive = %dx%d\n",
249 debug->panel->pinfo.h_active,
250 debug->panel->pinfo.v_active);
251 if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
252 goto error;
253
254 rc = snprintf(buf + len, max_size,
255 "\t\tback_porch = %dx%d\n",
256 debug->panel->pinfo.h_back_porch,
257 debug->panel->pinfo.v_back_porch);
258 if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
259 goto error;
260
261 rc = snprintf(buf + len, max_size,
262 "\t\tfront_porch = %dx%d\n",
263 debug->panel->pinfo.h_front_porch,
264 debug->panel->pinfo.v_front_porch);
265 if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
266 goto error;
267
268 rc = snprintf(buf + len, max_size,
269 "\t\tsync_width = %dx%d\n",
270 debug->panel->pinfo.h_sync_width,
271 debug->panel->pinfo.v_sync_width);
272 if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
273 goto error;
274
275 rc = snprintf(buf + len, max_size,
276 "\t\tactive_low = %dx%d\n",
277 debug->panel->pinfo.h_active_low,
278 debug->panel->pinfo.v_active_low);
279 if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
280 goto error;
281
282 rc = snprintf(buf + len, max_size,
283 "\t\th_skew = %d\n",
284 debug->panel->pinfo.h_skew);
285 if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
286 goto error;
287
288 rc = snprintf(buf + len, max_size,
289 "\t\trefresh rate = %d\n",
290 debug->panel->pinfo.refresh_rate);
291 if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
292 goto error;
293
294 rc = snprintf(buf + len, max_size,
295 "\t\tpixel clock khz = %d\n",
296 debug->panel->pinfo.pixel_clk_khz);
297 if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
298 goto error;
299
300 rc = snprintf(buf + len, max_size,
301 "\t\tbpp = %d\n",
302 debug->panel->pinfo.bpp);
303 if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
304 goto error;
305
306 /* Link Information */
307 rc = snprintf(buf + len, max_size,
308 "\tdp_link:\n\t\ttest_requested = %d\n",
309 debug->link->test_requested);
310 if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
311 goto error;
312
313 rc = snprintf(buf + len, max_size,
314 "\t\tlane_count = %d\n", debug->link->lane_count);
315 if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
316 goto error;
317
318 rc = snprintf(buf + len, max_size,
319 "\t\tbw_code = %d\n", debug->link->bw_code);
320 if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
321 goto error;
322
323 lclk = drm_dp_bw_code_to_link_rate(debug->link->bw_code) * 1000;
324 rc = snprintf(buf + len, max_size,
325 "\t\tlclk = %lld\n", lclk);
326 if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
327 goto error;
328
329 rc = snprintf(buf + len, max_size,
330 "\t\tv_level = %d\n", debug->link->v_level);
331 if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
332 goto error;
333
334 rc = snprintf(buf + len, max_size,
335 "\t\tp_level = %d\n", debug->link->p_level);
336 if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
337 goto error;
338
339 if (copy_to_user(user_buff, buf, len))
340 goto error;
341
342 *ppos += len;
343
344 kfree(buf);
345 return len;
346error:
347 kfree(buf);
348 return -EINVAL;
349}
350
351static const struct file_operations dp_debug_fops = {
352 .open = simple_open,
353 .read = dp_debug_read_info,
354};
355
356static const struct file_operations edid_modes_fops = {
357 .open = simple_open,
358 .read = dp_debug_read_edid_modes,
359 .write = dp_debug_write_edid_modes,
360};
361
362static const struct file_operations hpd_fops = {
363 .open = simple_open,
364 .write = dp_debug_write_hpd,
365};
366
367static const struct file_operations connected_fops = {
368 .open = simple_open,
369 .read = dp_debug_read_connected,
370};
371
372static int dp_debug_init(struct dp_debug *dp_debug)
373{
374 int rc = 0;
375 struct dp_debug_private *debug = container_of(dp_debug,
376 struct dp_debug_private, dp_debug);
377 struct dentry *dir, *file, *edid_modes;
378 struct dentry *hpd, *connected;
379 struct dentry *root = debug->root;
380
381 dir = debugfs_create_dir(DEBUG_NAME, NULL);
382 if (IS_ERR_OR_NULL(dir)) {
383 rc = PTR_ERR(dir);
384 pr_err("[%s] debugfs create dir failed, rc = %d\n",
385 DEBUG_NAME, rc);
386 goto error;
387 }
388
389 file = debugfs_create_file("dp_debug", 0444, dir,
390 debug, &dp_debug_fops);
391 if (IS_ERR_OR_NULL(file)) {
392 rc = PTR_ERR(file);
393 pr_err("[%s] debugfs create file failed, rc=%d\n",
394 DEBUG_NAME, rc);
395 goto error_remove_dir;
396 }
397
398 edid_modes = debugfs_create_file("edid_modes", 0644, dir,
399 debug, &edid_modes_fops);
400 if (IS_ERR_OR_NULL(edid_modes)) {
401 rc = PTR_ERR(edid_modes);
402 pr_err("[%s] debugfs create edid_modes failed, rc=%d\n",
403 DEBUG_NAME, rc);
404 goto error_remove_dir;
405 }
406
407 hpd = debugfs_create_file("hpd", 0644, dir,
408 debug, &hpd_fops);
409 if (IS_ERR_OR_NULL(hpd)) {
410 rc = PTR_ERR(hpd);
411 pr_err("[%s] debugfs hpd failed, rc=%d\n",
412 DEBUG_NAME, rc);
413 goto error_remove_dir;
414 }
415
416 connected = debugfs_create_file("connected", 0444, dir,
417 debug, &connected_fops);
418 if (IS_ERR_OR_NULL(connected)) {
419 rc = PTR_ERR(connected);
420 pr_err("[%s] debugfs connected failed, rc=%d\n",
421 DEBUG_NAME, rc);
422 goto error_remove_dir;
423 }
424
425 root = dir;
426 return rc;
427error_remove_dir:
428 debugfs_remove(dir);
429error:
430 return rc;
431}
432
433struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel,
434 struct dp_usbpd *usbpd, struct dp_link *link,
435 struct drm_connector **connector)
436{
437 int rc = 0;
438 struct dp_debug_private *debug;
439 struct dp_debug *dp_debug;
440
441 if (!dev || !panel || !usbpd || !link) {
442 pr_err("invalid input\n");
443 rc = -EINVAL;
444 goto error;
445 }
446
447 debug = devm_kzalloc(dev, sizeof(*debug), GFP_KERNEL);
448 if (!debug) {
449 rc = -ENOMEM;
450 goto error;
451 }
452
453 debug->dp_debug.debug_en = false;
454 debug->usbpd = usbpd;
455 debug->link = link;
456 debug->panel = panel;
457 debug->dev = dev;
458 debug->connector = connector;
459
460 dp_debug = &debug->dp_debug;
461 dp_debug->vdisplay = 0;
462 dp_debug->hdisplay = 0;
463 dp_debug->vrefresh = 0;
464
465 dp_debug_init(dp_debug);
466
467 return dp_debug;
468error:
469 return ERR_PTR(rc);
470}
471
472static int dp_debug_deinit(struct dp_debug *dp_debug)
473{
474 struct dp_debug_private *debug;
475
476 if (!dp_debug)
477 return -EINVAL;
478
479 debug = container_of(dp_debug, struct dp_debug_private, dp_debug);
480
481 debugfs_remove(debug->root);
482
483 return 0;
484}
485
486void dp_debug_put(struct dp_debug *dp_debug)
487{
488 struct dp_debug_private *debug;
489
490 if (!dp_debug)
491 return;
492
493 debug = container_of(dp_debug, struct dp_debug_private, dp_debug);
494
495 dp_debug_deinit(dp_debug);
496
497 kzfree(debug);
498}