linux/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
<<
>>
Prefs
   1/*
   2 * Copyright 2018 Advanced Micro Devices, Inc.
   3 *
   4 * Permission is hereby granted, free of charge, to any person obtaining a
   5 * copy of this software and associated documentation files (the "Software"),
   6 * to deal in the Software without restriction, including without limitation
   7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   8 * and/or sell copies of the Software, and to permit persons to whom the
   9 * Software is furnished to do so, subject to the following conditions:
  10 *
  11 * The above copyright notice and this permission notice shall be included in
  12 * all copies or substantial portions of the Software.
  13 *
  14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20 * OTHER DEALINGS IN THE SOFTWARE.
  21 *
  22 * Authors: AMD
  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/* function description
  34 * get/ set DP configuration: lane_count, link_rate, spread_spectrum
  35 *
  36 * valid lane count value: 1, 2, 4
  37 * valid link rate value:
  38 * 06h = 1.62Gbps per lane
  39 * 0Ah = 2.7Gbps per lane
  40 * 0Ch = 3.24Gbps per lane
  41 * 14h = 5.4Gbps per lane
  42 * 1Eh = 8.1Gbps per lane
  43 *
  44 * debugfs is located at /sys/kernel/debug/dri/0/DP-x/link_settings
  45 *
  46 * --- to get dp configuration
  47 *
  48 * cat link_settings
  49 *
  50 * It will list current, verified, reported, preferred dp configuration.
  51 * current -- for current video mode
  52 * verified --- maximum configuration which pass link training
  53 * reported --- DP rx report caps (DPCD register offset 0, 1 2)
  54 * preferred --- user force settings
  55 *
  56 * --- set (or force) dp configuration
  57 *
  58 * echo <lane_count>  <link_rate> > link_settings
  59 *
  60 * for example, to force to  2 lane, 2.7GHz,
  61 * echo 4 0xa > link_settings
  62 *
  63 * spread_spectrum could not be changed dynamically.
  64 *
  65 * in case invalid lane count, link rate are force, no hw programming will be
  66 * done. please check link settings after force operation to see if HW get
  67 * programming.
  68 *
  69 * cat link_settings
  70 *
  71 * check current and preferred settings.
  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; /* r = -EFAULT */
 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        /* 0: lane_count; 1: link_rate */
 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        /* r is bytes not be copied */
 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, &param[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        /* save user force lane_count, link_rate to preferred settings
 224         * spread spectrum will not be changed
 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/* function: get current DP PHY settings: voltage swing, pre-emphasis,
 237 * post-cursor2 (defined by VESA DP specification)
 238 *
 239 * valid values
 240 * voltage swing: 0,1,2,3
 241 * pre-emphasis : 0,1,2,3
 242 * post cursor2 : 0,1,2,3
 243 *
 244 *
 245 * how to use this debugfs
 246 *
 247 * debugfs is located at /sys/kernel/debug/dri/0/DP-x
 248 *
 249 * there will be directories, like DP-1, DP-2,DP-3, etc. for DP display
 250 *
 251 * To figure out which DP-x is the display for DP to be check,
 252 * cd DP-x
 253 * ls -ll
 254 * There should be debugfs file, like link_settings, phy_settings.
 255 * cat link_settings
 256 * from lane_count, link_rate to figure which DP-x is for display to be worked
 257 * on
 258 *
 259 * To get current DP PHY settings,
 260 * cat phy_settings
 261 *
 262 * To change DP PHY settings,
 263 * echo <voltage_swing> <pre-emphasis> <post_cursor2> > phy_settings
 264 * for examle, to change voltage swing to 2, pre-emphasis to 3, post_cursor2 to
 265 * 0,
 266 * echo 2 3 0 > phy_settings
 267 *
 268 * To check if change be applied, get current phy settings by
 269 * cat phy_settings
 270 *
 271 * In case invalid values are set by user, like
 272 * echo 1 4 0 > phy_settings
 273 *
 274 * HW will NOT be programmed by these settings.
 275 * cat phy_settings will show the previous valid settings.
 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; /* r = -EFAULT */
 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        /* r is bytes not be copied */
 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, &param[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        /* get link settings: lane count, link rate */
 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        /* apply phy settings from user */
 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        /* program ASIC registers and DPCD registers */
 413        dc_link_set_drive_settings(dc, &link_lane_settings, link);
 414
 415        kfree(wr_buf);
 416        return bytes_from_user;
 417}
 418
 419/* function description
 420 *
 421 * set PHY layer or Link layer test pattern
 422 * PHY test pattern is used for PHY SI check.
 423 * Link layer test will not affect PHY SI.
 424 *
 425 * Reset Test Pattern:
 426 * 0 = DP_TEST_PATTERN_VIDEO_MODE
 427 *
 428 * PHY test pattern supported:
 429 * 1 = DP_TEST_PATTERN_D102
 430 * 2 = DP_TEST_PATTERN_SYMBOL_ERROR
 431 * 3 = DP_TEST_PATTERN_PRBS7
 432 * 4 = DP_TEST_PATTERN_80BIT_CUSTOM
 433 * 5 = DP_TEST_PATTERN_CP2520_1
 434 * 6 = DP_TEST_PATTERN_CP2520_2 = DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE
 435 * 7 = DP_TEST_PATTERN_CP2520_3
 436 *
 437 * DP PHY Link Training Patterns
 438 * 8 = DP_TEST_PATTERN_TRAINING_PATTERN1
 439 * 9 = DP_TEST_PATTERN_TRAINING_PATTERN2
 440 * a = DP_TEST_PATTERN_TRAINING_PATTERN3
 441 * b = DP_TEST_PATTERN_TRAINING_PATTERN4
 442 *
 443 * DP Link Layer Test pattern
 444 * c = DP_TEST_PATTERN_COLOR_SQUARES
 445 * d = DP_TEST_PATTERN_COLOR_SQUARES_CEA
 446 * e = DP_TEST_PATTERN_VERTICAL_BARS
 447 * f = DP_TEST_PATTERN_HORIZONTAL_BARS
 448 * 10= DP_TEST_PATTERN_COLOR_RAMP
 449 *
 450 * debugfs phy_test_pattern is located at /syskernel/debug/dri/0/DP-x
 451 *
 452 * --- set test pattern
 453 * echo <test pattern #> > test_pattern
 454 *
 455 * If test pattern # is not supported, NO HW programming will be done.
 456 * for DP_TEST_PATTERN_80BIT_CUSTOM, it needs extra 10 bytes of data
 457 * for the user pattern. input 10 bytes data are separated by space
 458 *
 459 * echo 0x4 0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88 0x99 0xaa > test_pattern
 460 *
 461 * --- reset test pattern
 462 * echo 0 > test_pattern
 463 *
 464 * --- HPD detection is disabled when set PHY test pattern
 465 *
 466 * when PHY test pattern (pattern # within [1,7]) is set, HPD pin of HW ASIC
 467 * is disable. User could unplug DP display from DP connected and plug scope to
 468 * check test pattern PHY SI.
 469 * If there is need unplug scope and plug DP display back, do steps below:
 470 * echo 0 > phy_test_pattern
 471 * unplug scope
 472 * plug DP display.
 473 *
 474 * "echo 0 > phy_test_pattern" will re-enable HPD pin again so that video sw
 475 * driver could detect "unplug scope" and "plug DP display"
 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        /* init with defalut 80bit custom pattern */
 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        /* r is bytes not be copied */
 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        /* check number of parameters. isspace could not differ space and \n */
 528        while ((*wr_buf_ptr != 0xa) && (wr_buf_count < wr_buf_size)) {
 529                /* skip space*/
 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                /* skip non-space*/
 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        /* max 11 parameters */
 551        if (param_nums > 11)
 552                param_nums = 11;
 553
 554        wr_buf_ptr = wr_buf; /* reset buf pinter */
 555        wr_buf_count = 0; /* number of char already checked */
 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                /* after strsep, wr_buf_ptr will be moved to after space */
 564                sub_str = strsep(&wr_buf_ptr, delimiter);
 565
 566                r = kstrtol(sub_str, 16, &param[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                        /* not use default value */
 616                        for (i = 0; i < 10; i++)
 617                                custom_pattern[i] = (uint8_t) param[i + 1];
 618                }
 619        }
 620
 621        /* Usage: set DP physical test pattern using debugfs with normal DP
 622         * panel. Then plug out DP panel and connect a scope to measure
 623         * For normal video mode and test pattern generated from CRCT,
 624         * they are visibile to user. So do not disable HPD.
 625         * Video Mode is also set to clear the test pattern, so enable HPD
 626         * because it might have been disabled after a test pattern was set.
 627         * AUX depends on HPD * sequence dependent, do not move!
 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        /* Usage: Set DP physical test pattern using AMDDP with normal DP panel
 662         * Then plug out DP panel and connect a scope to measure DP PHY signal.
 663         * Need disable interrupt to avoid SW driver disable DP output. This is
 664         * done after the test pattern is set.
 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 * Returns the min and max vrr vfreq through the connector's debugfs file.
 676 * Example usage: cat /sys/kernel/debug/dri/0/DP-1/vrr_range
 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 * Writes DTN log state to the user supplied buffer.
 746 * Example usage: cat /sys/kernel/debug/dri/0/amdgpu_dm_dtn_log
 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 * Writes DTN log state to dmesg when triggered via a write.
 785 * Example usage: echo 1 > /sys/kernel/debug/dri/0/amdgpu_dm_dtn_log
 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        /* Write triggers log output via dmesg. */
 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 * Backlight at this moment.  Read only.
 808 * As written to display, taking ABM and backlight lut into account.
 809 * Ranges from 0x0 to 0x10000 (= 100% PWM)
 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 * Backlight value that is being approached.  Read only.
 825 * As written to display, taking ABM and backlight lut into account.
 826 * Ranges from 0x0 to 0x10000 (= 100% PWM)
 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", &current_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