1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26#include <linux/debugfs.h>
27
28#include "dc.h"
29#include "amdgpu.h"
30#include "amdgpu_dm.h"
31#include "amdgpu_dm_debugfs.h"
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74static ssize_t dp_link_settings_read(struct file *f, char __user *buf,
75 size_t size, loff_t *pos)
76{
77 struct amdgpu_dm_connector *connector = file_inode(f)->i_private;
78 struct dc_link *link = connector->dc_link;
79 char *rd_buf = NULL;
80 char *rd_buf_ptr = NULL;
81 const uint32_t rd_buf_size = 100;
82 uint32_t result = 0;
83 uint8_t str_len = 0;
84 int r;
85
86 if (*pos & 3 || size & 3)
87 return -EINVAL;
88
89 rd_buf = kcalloc(rd_buf_size, sizeof(char), GFP_KERNEL);
90 if (!rd_buf)
91 return 0;
92
93 rd_buf_ptr = rd_buf;
94
95 str_len = strlen("Current: %d %d %d ");
96 snprintf(rd_buf_ptr, str_len, "Current: %d %d %d ",
97 link->cur_link_settings.lane_count,
98 link->cur_link_settings.link_rate,
99 link->cur_link_settings.link_spread);
100 rd_buf_ptr += str_len;
101
102 str_len = strlen("Verified: %d %d %d ");
103 snprintf(rd_buf_ptr, str_len, "Verified: %d %d %d ",
104 link->verified_link_cap.lane_count,
105 link->verified_link_cap.link_rate,
106 link->verified_link_cap.link_spread);
107 rd_buf_ptr += str_len;
108
109 str_len = strlen("Reported: %d %d %d ");
110 snprintf(rd_buf_ptr, str_len, "Reported: %d %d %d ",
111 link->reported_link_cap.lane_count,
112 link->reported_link_cap.link_rate,
113 link->reported_link_cap.link_spread);
114 rd_buf_ptr += str_len;
115
116 str_len = strlen("Preferred: %d %d %d ");
117 snprintf(rd_buf_ptr, str_len, "Preferred: %d %d %d\n",
118 link->preferred_link_setting.lane_count,
119 link->preferred_link_setting.link_rate,
120 link->preferred_link_setting.link_spread);
121
122 while (size) {
123 if (*pos >= rd_buf_size)
124 break;
125
126 r = put_user(*(rd_buf + result), buf);
127 if (r)
128 return r;
129
130 buf += 1;
131 size -= 1;
132 *pos += 1;
133 result += 1;
134 }
135
136 kfree(rd_buf);
137 return result;
138}
139
140static ssize_t dp_link_settings_write(struct file *f, const char __user *buf,
141 size_t size, loff_t *pos)
142{
143 struct amdgpu_dm_connector *connector = file_inode(f)->i_private;
144 struct dc_link *link = connector->dc_link;
145 struct dc *dc = (struct dc *)link->dc;
146 struct dc_link_settings prefer_link_settings;
147 char *wr_buf = NULL;
148 char *wr_buf_ptr = NULL;
149 const uint32_t wr_buf_size = 40;
150 int r;
151 int bytes_from_user;
152 char *sub_str;
153
154 uint8_t param_index = 0;
155 long param[2];
156 const char delimiter[3] = {' ', '\n', '\0'};
157 bool valid_input = false;
158
159 if (size == 0)
160 return -EINVAL;
161
162 wr_buf = kcalloc(wr_buf_size, sizeof(char), GFP_KERNEL);
163 if (!wr_buf)
164 return -EINVAL;
165 wr_buf_ptr = wr_buf;
166
167 r = copy_from_user(wr_buf_ptr, buf, wr_buf_size);
168
169
170 if (r >= wr_buf_size) {
171 kfree(wr_buf);
172 DRM_DEBUG_DRIVER("user data not read\n");
173 return -EINVAL;
174 }
175
176 bytes_from_user = wr_buf_size - r;
177
178 while (isspace(*wr_buf_ptr))
179 wr_buf_ptr++;
180
181 while ((*wr_buf_ptr != '\0') && (param_index < 2)) {
182
183 sub_str = strsep(&wr_buf_ptr, delimiter);
184
185 r = kstrtol(sub_str, 16, ¶m[param_index]);
186
187 if (r)
188 DRM_DEBUG_DRIVER("string to int convert error code: %d\n", r);
189
190 param_index++;
191 while (isspace(*wr_buf_ptr))
192 wr_buf_ptr++;
193 }
194
195 switch (param[0]) {
196 case LANE_COUNT_ONE:
197 case LANE_COUNT_TWO:
198 case LANE_COUNT_FOUR:
199 valid_input = true;
200 break;
201 default:
202 break;
203 }
204
205 switch (param[1]) {
206 case LINK_RATE_LOW:
207 case LINK_RATE_HIGH:
208 case LINK_RATE_RBR2:
209 case LINK_RATE_HIGH2:
210 case LINK_RATE_HIGH3:
211 valid_input = true;
212 break;
213 default:
214 break;
215 }
216
217 if (!valid_input) {
218 kfree(wr_buf);
219 DRM_DEBUG_DRIVER("Invalid Input value No HW will be programmed\n");
220 return bytes_from_user;
221 }
222
223
224
225
226 prefer_link_settings.link_spread = link->cur_link_settings.link_spread;
227 prefer_link_settings.lane_count = param[0];
228 prefer_link_settings.link_rate = param[1];
229
230 dc_link_set_preferred_link_settings(dc, &prefer_link_settings, link);
231
232 kfree(wr_buf);
233 return bytes_from_user;
234}
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277static ssize_t dp_phy_settings_read(struct file *f, char __user *buf,
278 size_t size, loff_t *pos)
279{
280 struct amdgpu_dm_connector *connector = file_inode(f)->i_private;
281 struct dc_link *link = connector->dc_link;
282 char *rd_buf = NULL;
283 const uint32_t rd_buf_size = 20;
284 uint32_t result = 0;
285 int r;
286
287 if (*pos & 3 || size & 3)
288 return -EINVAL;
289
290 rd_buf = kcalloc(rd_buf_size, sizeof(char), GFP_KERNEL);
291 if (!rd_buf)
292 return -EINVAL;
293
294 snprintf(rd_buf, rd_buf_size, " %d %d %d ",
295 link->cur_lane_setting.VOLTAGE_SWING,
296 link->cur_lane_setting.PRE_EMPHASIS,
297 link->cur_lane_setting.POST_CURSOR2);
298
299 while (size) {
300 if (*pos >= rd_buf_size)
301 break;
302
303 r = put_user((*(rd_buf + result)), buf);
304 if (r)
305 return r;
306
307 buf += 1;
308 size -= 1;
309 *pos += 1;
310 result += 1;
311 }
312
313 kfree(rd_buf);
314 return result;
315}
316
317static ssize_t dp_phy_settings_write(struct file *f, const char __user *buf,
318 size_t size, loff_t *pos)
319{
320 struct amdgpu_dm_connector *connector = file_inode(f)->i_private;
321 struct dc_link *link = connector->dc_link;
322 struct dc *dc = (struct dc *)link->dc;
323 char *wr_buf = NULL;
324 char *wr_buf_ptr = NULL;
325 uint32_t wr_buf_size = 40;
326 int r;
327 int bytes_from_user;
328 char *sub_str;
329 uint8_t param_index = 0;
330 long param[3];
331 const char delimiter[3] = {' ', '\n', '\0'};
332 bool use_prefer_link_setting;
333 struct link_training_settings link_lane_settings;
334
335 if (size == 0)
336 return 0;
337
338 wr_buf = kcalloc(wr_buf_size, sizeof(char), GFP_KERNEL);
339 if (!wr_buf)
340 return 0;
341 wr_buf_ptr = wr_buf;
342
343 r = copy_from_user(wr_buf_ptr, buf, wr_buf_size);
344
345
346 if (r >= wr_buf_size) {
347 kfree(wr_buf);
348 DRM_DEBUG_DRIVER("user data not be read\n");
349 return 0;
350 }
351
352 bytes_from_user = wr_buf_size - r;
353
354 while (isspace(*wr_buf_ptr))
355 wr_buf_ptr++;
356
357 while ((*wr_buf_ptr != '\0') && (param_index < 3)) {
358
359 sub_str = strsep(&wr_buf_ptr, delimiter);
360
361 r = kstrtol(sub_str, 16, ¶m[param_index]);
362
363 if (r)
364 DRM_DEBUG_DRIVER("string to int convert error code: %d\n", r);
365
366 param_index++;
367 while (isspace(*wr_buf_ptr))
368 wr_buf_ptr++;
369 }
370
371 if ((param[0] > VOLTAGE_SWING_MAX_LEVEL) ||
372 (param[1] > PRE_EMPHASIS_MAX_LEVEL) ||
373 (param[2] > POST_CURSOR2_MAX_LEVEL)) {
374 kfree(wr_buf);
375 DRM_DEBUG_DRIVER("Invalid Input No HW will be programmed\n");
376 return bytes_from_user;
377 }
378
379
380 use_prefer_link_setting =
381 ((link->preferred_link_setting.link_rate != LINK_RATE_UNKNOWN) &&
382 (link->test_pattern_enabled));
383
384 memset(&link_lane_settings, 0, sizeof(link_lane_settings));
385
386 if (use_prefer_link_setting) {
387 link_lane_settings.link_settings.lane_count =
388 link->preferred_link_setting.lane_count;
389 link_lane_settings.link_settings.link_rate =
390 link->preferred_link_setting.link_rate;
391 link_lane_settings.link_settings.link_spread =
392 link->preferred_link_setting.link_spread;
393 } else {
394 link_lane_settings.link_settings.lane_count =
395 link->cur_link_settings.lane_count;
396 link_lane_settings.link_settings.link_rate =
397 link->cur_link_settings.link_rate;
398 link_lane_settings.link_settings.link_spread =
399 link->cur_link_settings.link_spread;
400 }
401
402
403 for (r = 0; r < link_lane_settings.link_settings.lane_count; r++) {
404 link_lane_settings.lane_settings[r].VOLTAGE_SWING =
405 (enum dc_voltage_swing) (param[0]);
406 link_lane_settings.lane_settings[r].PRE_EMPHASIS =
407 (enum dc_pre_emphasis) (param[1]);
408 link_lane_settings.lane_settings[r].POST_CURSOR2 =
409 (enum dc_post_cursor2) (param[2]);
410 }
411
412
413 dc_link_set_drive_settings(dc, &link_lane_settings, link);
414
415 kfree(wr_buf);
416 return bytes_from_user;
417}
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477static ssize_t dp_phy_test_pattern_debugfs_write(struct file *f, const char __user *buf,
478 size_t size, loff_t *pos)
479{
480 struct amdgpu_dm_connector *connector = file_inode(f)->i_private;
481 struct dc_link *link = connector->dc_link;
482 char *wr_buf = NULL;
483 char *wr_buf_ptr = NULL;
484 uint32_t wr_buf_size = 100;
485 uint32_t wr_buf_count = 0;
486 int r;
487 int bytes_from_user;
488 char *sub_str = NULL;
489 uint8_t param_index = 0;
490 uint8_t param_nums = 0;
491 long param[11] = {0x0};
492 const char delimiter[3] = {' ', '\n', '\0'};
493 enum dp_test_pattern test_pattern = DP_TEST_PATTERN_UNSUPPORTED;
494 bool disable_hpd = false;
495 bool valid_test_pattern = false;
496
497 uint8_t custom_pattern[10] = {
498 0x1f, 0x7c, 0xf0, 0xc1, 0x07,
499 0x1f, 0x7c, 0xf0, 0xc1, 0x07
500 };
501 struct dc_link_settings prefer_link_settings = {LANE_COUNT_UNKNOWN,
502 LINK_RATE_UNKNOWN, LINK_SPREAD_DISABLED};
503 struct dc_link_settings cur_link_settings = {LANE_COUNT_UNKNOWN,
504 LINK_RATE_UNKNOWN, LINK_SPREAD_DISABLED};
505 struct link_training_settings link_training_settings;
506 int i;
507
508 if (size == 0)
509 return 0;
510
511 wr_buf = kcalloc(wr_buf_size, sizeof(char), GFP_KERNEL);
512 if (!wr_buf)
513 return 0;
514 wr_buf_ptr = wr_buf;
515
516 r = copy_from_user(wr_buf_ptr, buf, wr_buf_size);
517
518
519 if (r >= wr_buf_size) {
520 kfree(wr_buf);
521 DRM_DEBUG_DRIVER("user data not be read\n");
522 return 0;
523 }
524
525 bytes_from_user = wr_buf_size - r;
526
527
528 while ((*wr_buf_ptr != 0xa) && (wr_buf_count < wr_buf_size)) {
529
530 while (isspace(*wr_buf_ptr) && (wr_buf_count < wr_buf_size)) {
531 wr_buf_ptr++;
532 wr_buf_count++;
533 }
534
535 if (wr_buf_count == wr_buf_size)
536 break;
537
538
539 while ((!isspace(*wr_buf_ptr)) && (wr_buf_count < wr_buf_size)) {
540 wr_buf_ptr++;
541 wr_buf_count++;
542 }
543
544 param_nums++;
545
546 if (wr_buf_count == wr_buf_size)
547 break;
548 }
549
550
551 if (param_nums > 11)
552 param_nums = 11;
553
554 wr_buf_ptr = wr_buf;
555 wr_buf_count = 0;
556
557 while (isspace(*wr_buf_ptr) && (wr_buf_count < wr_buf_size)) {
558 wr_buf_ptr++;
559 wr_buf_count++;
560 }
561
562 while (param_index < param_nums) {
563
564 sub_str = strsep(&wr_buf_ptr, delimiter);
565
566 r = kstrtol(sub_str, 16, ¶m[param_index]);
567
568 if (r)
569 DRM_DEBUG_DRIVER("string to int convert error code: %d\n", r);
570
571 param_index++;
572 }
573
574 test_pattern = param[0];
575
576 switch (test_pattern) {
577 case DP_TEST_PATTERN_VIDEO_MODE:
578 case DP_TEST_PATTERN_COLOR_SQUARES:
579 case DP_TEST_PATTERN_COLOR_SQUARES_CEA:
580 case DP_TEST_PATTERN_VERTICAL_BARS:
581 case DP_TEST_PATTERN_HORIZONTAL_BARS:
582 case DP_TEST_PATTERN_COLOR_RAMP:
583 valid_test_pattern = true;
584 break;
585
586 case DP_TEST_PATTERN_D102:
587 case DP_TEST_PATTERN_SYMBOL_ERROR:
588 case DP_TEST_PATTERN_PRBS7:
589 case DP_TEST_PATTERN_80BIT_CUSTOM:
590 case DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE:
591 case DP_TEST_PATTERN_TRAINING_PATTERN4:
592 disable_hpd = true;
593 valid_test_pattern = true;
594 break;
595
596 default:
597 valid_test_pattern = false;
598 test_pattern = DP_TEST_PATTERN_UNSUPPORTED;
599 break;
600 }
601
602 if (!valid_test_pattern) {
603 kfree(wr_buf);
604 DRM_DEBUG_DRIVER("Invalid Test Pattern Parameters\n");
605 return bytes_from_user;
606 }
607
608 if (test_pattern == DP_TEST_PATTERN_80BIT_CUSTOM) {
609 for (i = 0; i < 10; i++) {
610 if ((uint8_t) param[i + 1] != 0x0)
611 break;
612 }
613
614 if (i < 10) {
615
616 for (i = 0; i < 10; i++)
617 custom_pattern[i] = (uint8_t) param[i + 1];
618 }
619 }
620
621
622
623
624
625
626
627
628
629 if (!disable_hpd)
630 dc_link_enable_hpd(link);
631
632 prefer_link_settings.lane_count = link->verified_link_cap.lane_count;
633 prefer_link_settings.link_rate = link->verified_link_cap.link_rate;
634 prefer_link_settings.link_spread = link->verified_link_cap.link_spread;
635
636 cur_link_settings.lane_count = link->cur_link_settings.lane_count;
637 cur_link_settings.link_rate = link->cur_link_settings.link_rate;
638 cur_link_settings.link_spread = link->cur_link_settings.link_spread;
639
640 link_training_settings.link_settings = cur_link_settings;
641
642
643 if (test_pattern != DP_TEST_PATTERN_VIDEO_MODE) {
644 if (prefer_link_settings.lane_count != LANE_COUNT_UNKNOWN &&
645 prefer_link_settings.link_rate != LINK_RATE_UNKNOWN &&
646 (prefer_link_settings.lane_count != cur_link_settings.lane_count ||
647 prefer_link_settings.link_rate != cur_link_settings.link_rate))
648 link_training_settings.link_settings = prefer_link_settings;
649 }
650
651 for (i = 0; i < (unsigned int)(link_training_settings.link_settings.lane_count); i++)
652 link_training_settings.lane_settings[i] = link->cur_lane_setting;
653
654 dc_link_set_test_pattern(
655 link,
656 test_pattern,
657 &link_training_settings,
658 custom_pattern,
659 10);
660
661
662
663
664
665
666 if (valid_test_pattern && disable_hpd)
667 dc_link_disable_hpd(link);
668
669 kfree(wr_buf);
670
671 return bytes_from_user;
672}
673
674
675
676
677
678static int vrr_range_show(struct seq_file *m, void *data)
679{
680 struct drm_connector *connector = m->private;
681 struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
682
683 if (connector->status != connector_status_connected)
684 return -ENODEV;
685
686 seq_printf(m, "Min: %u\n", (unsigned int)aconnector->min_vfreq);
687 seq_printf(m, "Max: %u\n", (unsigned int)aconnector->max_vfreq);
688
689 return 0;
690}
691DEFINE_SHOW_ATTRIBUTE(vrr_range);
692
693static const struct file_operations dp_link_settings_debugfs_fops = {
694 .owner = THIS_MODULE,
695 .read = dp_link_settings_read,
696 .write = dp_link_settings_write,
697 .llseek = default_llseek
698};
699
700static const struct file_operations dp_phy_settings_debugfs_fop = {
701 .owner = THIS_MODULE,
702 .read = dp_phy_settings_read,
703 .write = dp_phy_settings_write,
704 .llseek = default_llseek
705};
706
707static const struct file_operations dp_phy_test_pattern_fops = {
708 .owner = THIS_MODULE,
709 .write = dp_phy_test_pattern_debugfs_write,
710 .llseek = default_llseek
711};
712
713static const struct {
714 char *name;
715 const struct file_operations *fops;
716} dp_debugfs_entries[] = {
717 {"link_settings", &dp_link_settings_debugfs_fops},
718 {"phy_settings", &dp_phy_settings_debugfs_fop},
719 {"test_pattern", &dp_phy_test_pattern_fops},
720 {"vrr_range", &vrr_range_fops}
721};
722
723int connector_debugfs_init(struct amdgpu_dm_connector *connector)
724{
725 int i;
726 struct dentry *ent, *dir = connector->base.debugfs_entry;
727
728 if (connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort ||
729 connector->base.connector_type == DRM_MODE_CONNECTOR_eDP) {
730 for (i = 0; i < ARRAY_SIZE(dp_debugfs_entries); i++) {
731 ent = debugfs_create_file(dp_debugfs_entries[i].name,
732 0644,
733 dir,
734 connector,
735 dp_debugfs_entries[i].fops);
736 if (IS_ERR(ent))
737 return PTR_ERR(ent);
738 }
739 }
740
741 return 0;
742}
743
744
745
746
747
748static ssize_t dtn_log_read(
749 struct file *f,
750 char __user *buf,
751 size_t size,
752 loff_t *pos)
753{
754 struct amdgpu_device *adev = file_inode(f)->i_private;
755 struct dc *dc = adev->dm.dc;
756 struct dc_log_buffer_ctx log_ctx = { 0 };
757 ssize_t result = 0;
758
759 if (!buf || !size)
760 return -EINVAL;
761
762 if (!dc->hwss.log_hw_state)
763 return 0;
764
765 dc->hwss.log_hw_state(dc, &log_ctx);
766
767 if (*pos < log_ctx.pos) {
768 size_t to_copy = log_ctx.pos - *pos;
769
770 to_copy = min(to_copy, size);
771
772 if (!copy_to_user(buf, log_ctx.buf + *pos, to_copy)) {
773 *pos += to_copy;
774 result = to_copy;
775 }
776 }
777
778 kfree(log_ctx.buf);
779
780 return result;
781}
782
783
784
785
786
787static ssize_t dtn_log_write(
788 struct file *f,
789 const char __user *buf,
790 size_t size,
791 loff_t *pos)
792{
793 struct amdgpu_device *adev = file_inode(f)->i_private;
794 struct dc *dc = adev->dm.dc;
795
796
797 if (size == 0)
798 return 0;
799
800 if (dc->hwss.log_hw_state)
801 dc->hwss.log_hw_state(dc, NULL);
802
803 return size;
804}
805
806
807
808
809
810
811static int current_backlight_read(struct seq_file *m, void *data)
812{
813 struct drm_info_node *node = (struct drm_info_node *)m->private;
814 struct drm_device *dev = node->minor->dev;
815 struct amdgpu_device *adev = dev->dev_private;
816 struct dc *dc = adev->dm.dc;
817 unsigned int backlight = dc_get_current_backlight_pwm(dc);
818
819 seq_printf(m, "0x%x\n", backlight);
820 return 0;
821}
822
823
824
825
826
827
828static int target_backlight_read(struct seq_file *m, void *data)
829{
830 struct drm_info_node *node = (struct drm_info_node *)m->private;
831 struct drm_device *dev = node->minor->dev;
832 struct amdgpu_device *adev = dev->dev_private;
833 struct dc *dc = adev->dm.dc;
834 unsigned int backlight = dc_get_target_backlight_pwm(dc);
835
836 seq_printf(m, "0x%x\n", backlight);
837 return 0;
838}
839
840static const struct drm_info_list amdgpu_dm_debugfs_list[] = {
841 {"amdgpu_current_backlight_pwm", ¤t_backlight_read},
842 {"amdgpu_target_backlight_pwm", &target_backlight_read},
843};
844
845int dtn_debugfs_init(struct amdgpu_device *adev)
846{
847 static const struct file_operations dtn_log_fops = {
848 .owner = THIS_MODULE,
849 .read = dtn_log_read,
850 .write = dtn_log_write,
851 .llseek = default_llseek
852 };
853
854 struct drm_minor *minor = adev->ddev->primary;
855 struct dentry *ent, *root = minor->debugfs_root;
856 int ret;
857
858 ret = amdgpu_debugfs_add_files(adev, amdgpu_dm_debugfs_list,
859 ARRAY_SIZE(amdgpu_dm_debugfs_list));
860 if (ret)
861 return ret;
862
863 ent = debugfs_create_file(
864 "amdgpu_dm_dtn_log",
865 0644,
866 root,
867 adev,
868 &dtn_log_fops);
869
870 return PTR_ERR_OR_ZERO(ent);
871}
872