drm/amd/display: hook dp test pattern through debugfs
authorHersen Wu <hersenxs.wu@amd.com>
Tue, 19 Jun 2018 16:14:29 +0000 (12:14 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Fri, 13 Jul 2018 19:49:02 +0000 (14:49 -0500)
 set PHY layer or Link layer test pattern
 PHY test pattern is used for PHY SI check.
 Link layer test will not affect PHY SI.

 - normal video mode
  0 = DP_TEST_PATTERN_VIDEO_MODE

 - PHY test pattern supported
  1 = DP_TEST_PATTERN_D102
  2 = DP_TEST_PATTERN_SYMBOL_ERROR
  3 = DP_TEST_PATTERN_PRBS7
  4 = DP_TEST_PATTERN_80BIT_CUSTOM
  5 = DP_TEST_PATTERN_CP2520_1
  6 = DP_TEST_PATTERN_CP2520_2 = DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE
  7 = DP_TEST_PATTERN_CP2520_3

 - DP PHY Link Training Patterns
  8 = DP_TEST_PATTERN_TRAINING_PATTERN1
  9 = DP_TEST_PATTERN_TRAINING_PATTERN2
  0xa = DP_TEST_PATTERN_TRAINING_PATTERN3
  0xb = DP_TEST_PATTERN_TRAINING_PATTERN4

 - DP Link Layer Test pattern
  0xc = DP_TEST_PATTERN_COLOR_SQUARES
  0xd = DP_TEST_PATTERN_COLOR_SQUARES_CEA
  0xe = DP_TEST_PATTERN_VERTICAL_BARS
  0xf = DP_TEST_PATTERN_HORIZONTAL_BARS
  0x10= DP_TEST_PATTERN_COLOR_RAMP

 debugfs phy_test_pattern is located at /syskernel/debug/dri/0/DP-x

 --- set test pattern
  echo <test pattern #> > test_pattern

 - custom test pattern
  If test pattern # is not supported, NO HW programming will be done
  for DP_TEST_PATTERN_80BIT_CUSTOM, it needs extra 10 bytes of data
  for the user pattern. input 10 bytes data are separated by space

  echo 0x4 0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88 0x99 0xaa >
  test_pattern

 --- reset test pattern
  echo 0 > test_pattern

 --- HPD detection is disabled when set PHY test pattern

  when PHY test pattern (pattern # within [1,7]) is set, HPD pin of
  HW ASIC is disable. User could unplug DP display from DP connected
  and plug scope to check test pattern PHY SI.
  If there is need unplug scope and plug DP display back, do steps
  below:
  echo 0 > phy_test_pattern
  unplug scope
  plug DP display.

  "echo 0 > phy_test_pattern" will re-enable HPD pin again so that
  video sw driver could detect "unplug scope" and "plug DP display"

Signed-off-by: Hersen Wu <hersenxs.wu@amd.com>
Reviewed-by: Harry Wentland <Harry.Wentland@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c

index 9ff8833b52c486f024c16ebd2c263b477c1d4db2..8ddbf219dd23060b644d44aed7e719a01ad9bf92 100644 (file)
@@ -261,18 +261,219 @@ static ssize_t dp_pre_emphasis_debugfs_write(struct file *f, const char __user *
        return 1;
 }
 
-static ssize_t dp_phy_test_pattern_debugfs_read(struct file *f, char __user *buf,
-                                size_t size, loff_t *pos)
-{
-       /* TODO: create method to read PHY test pattern */
-       return 1;
-}
-
+/* function description
+ *
+ * set PHY layer or Link layer test pattern
+ * PHY test pattern is used for PHY SI check.
+ * Link layer test will not affect PHY SI.
+ *
+ * Reset Test Pattern:
+ * 0 = DP_TEST_PATTERN_VIDEO_MODE
+ *
+ * PHY test pattern supported:
+ * 1 = DP_TEST_PATTERN_D102
+ * 2 = DP_TEST_PATTERN_SYMBOL_ERROR
+ * 3 = DP_TEST_PATTERN_PRBS7
+ * 4 = DP_TEST_PATTERN_80BIT_CUSTOM
+ * 5 = DP_TEST_PATTERN_CP2520_1
+ * 6 = DP_TEST_PATTERN_CP2520_2 = DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE
+ * 7 = DP_TEST_PATTERN_CP2520_3
+ *
+ * DP PHY Link Training Patterns
+ * 8 = DP_TEST_PATTERN_TRAINING_PATTERN1
+ * 9 = DP_TEST_PATTERN_TRAINING_PATTERN2
+ * a = DP_TEST_PATTERN_TRAINING_PATTERN3
+ * b = DP_TEST_PATTERN_TRAINING_PATTERN4
+ *
+ * DP Link Layer Test pattern
+ * c = DP_TEST_PATTERN_COLOR_SQUARES
+ * d = DP_TEST_PATTERN_COLOR_SQUARES_CEA
+ * e = DP_TEST_PATTERN_VERTICAL_BARS
+ * f = DP_TEST_PATTERN_HORIZONTAL_BARS
+ * 10= DP_TEST_PATTERN_COLOR_RAMP
+ *
+ * debugfs phy_test_pattern is located at /syskernel/debug/dri/0/DP-x
+ *
+ * --- set test pattern
+ * echo <test pattern #> > test_pattern
+ *
+ * If test pattern # is not supported, NO HW programming will be done.
+ * for DP_TEST_PATTERN_80BIT_CUSTOM, it needs extra 10 bytes of data
+ * for the user pattern. input 10 bytes data are separated by space
+ *
+ * echo 0x4 0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88 0x99 0xaa > test_pattern
+ *
+ * --- reset test pattern
+ * echo 0 > test_pattern
+ *
+ * --- HPD detection is disabled when set PHY test pattern
+ *
+ * when PHY test pattern (pattern # within [1,7]) is set, HPD pin of HW ASIC
+ * is disable. User could unplug DP display from DP connected and plug scope to
+ * check test pattern PHY SI.
+ * If there is need unplug scope and plug DP display back, do steps below:
+ * echo 0 > phy_test_pattern
+ * unplug scope
+ * plug DP display.
+ *
+ * "echo 0 > phy_test_pattern" will re-enable HPD pin again so that video sw
+ * driver could detect "unplug scope" and "plug DP display"
+ */
 static ssize_t dp_phy_test_pattern_debugfs_write(struct file *f, const char __user *buf,
                                 size_t size, loff_t *pos)
 {
-       /* TODO: create method to write PHY test pattern */
-       return 1;
+       struct amdgpu_dm_connector *connector = file_inode(f)->i_private;
+       struct dc_link *link = connector->dc_link;
+       char *wr_buf = NULL;
+       char *wr_buf_ptr = NULL;
+       uint32_t wr_buf_size = 100;
+       int r;
+       int bytes_from_user;
+       char *sub_str;
+       uint8_t param_index = 0;
+       long param[11];
+       const char delimiter[3] = {' ', '\n', '\0'};
+       enum dp_test_pattern test_pattern = DP_TEST_PATTERN_UNSUPPORTED;
+       bool disable_hpd = false;
+       bool valid_test_pattern = false;
+       uint8_t custom_pattern[10] = {0};
+       struct dc_link_settings prefer_link_settings = {LANE_COUNT_UNKNOWN,
+                       LINK_RATE_UNKNOWN, LINK_SPREAD_DISABLED};
+       struct dc_link_settings cur_link_settings = {LANE_COUNT_UNKNOWN,
+                       LINK_RATE_UNKNOWN, LINK_SPREAD_DISABLED};
+       struct link_training_settings link_training_settings;
+       int i;
+
+       if (size == 0)
+               return 0;
+
+       wr_buf = kcalloc(wr_buf_size, sizeof(char), GFP_KERNEL);
+       if (!wr_buf)
+               return 0;
+       wr_buf_ptr = wr_buf;
+
+       r = copy_from_user(wr_buf_ptr, buf, wr_buf_size);
+
+       /* r is bytes not be copied */
+       if (r >= wr_buf_size) {
+               kfree(wr_buf);
+               DRM_DEBUG_DRIVER("user data not be read\n");
+               return 0;
+       }
+
+       bytes_from_user = wr_buf_size - r;
+
+       while (isspace(*wr_buf_ptr))
+               wr_buf_ptr++;
+
+       while ((*wr_buf_ptr != '\0') && (param_index < 1)) {
+               sub_str = strsep(&wr_buf_ptr, delimiter);
+               r = kstrtol(sub_str, 16, &param[param_index]);
+
+               if (r)
+                       DRM_DEBUG_DRIVER("string to int convert error code: %d\n", r);
+
+               param_index++;
+               while (isspace(*wr_buf_ptr))
+                       wr_buf_ptr++;
+
+               /* DP_TEST_PATTERN_80BIT_CUSTOM need extra 80 bits
+                * whci are 10 bytes separte by space
+                */
+               if (param[0] != 0x4)
+                       break;
+       }
+
+       test_pattern = param[0];
+
+       switch (test_pattern) {
+       case DP_TEST_PATTERN_VIDEO_MODE:
+       case DP_TEST_PATTERN_COLOR_SQUARES:
+       case DP_TEST_PATTERN_COLOR_SQUARES_CEA:
+       case DP_TEST_PATTERN_VERTICAL_BARS:
+       case DP_TEST_PATTERN_HORIZONTAL_BARS:
+       case DP_TEST_PATTERN_COLOR_RAMP:
+               valid_test_pattern = true;
+               break;
+
+       case DP_TEST_PATTERN_D102:
+       case DP_TEST_PATTERN_SYMBOL_ERROR:
+       case DP_TEST_PATTERN_PRBS7:
+       case DP_TEST_PATTERN_80BIT_CUSTOM:
+       case DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE:
+       case DP_TEST_PATTERN_TRAINING_PATTERN4:
+               disable_hpd = true;
+               valid_test_pattern = true;
+               break;
+
+       default:
+               valid_test_pattern = false;
+               test_pattern = DP_TEST_PATTERN_UNSUPPORTED;
+               break;
+       }
+
+       if (!valid_test_pattern) {
+               kfree(wr_buf);
+               DRM_DEBUG_DRIVER("Invalid Test Pattern Parameters\n");
+               return bytes_from_user;
+       }
+
+       if (test_pattern == DP_TEST_PATTERN_80BIT_CUSTOM) {
+               for (i = 0; i < 10; i++)
+                       custom_pattern[i] = (uint8_t) param[i + 1];
+       }
+
+       /* Usage: set DP physical test pattern using debugfs with normal DP
+        * panel. Then plug out DP panel and connect a scope to measure
+        * For normal video mode and test pattern generated from CRCT,
+        * they are visibile to user. So do not disable HPD.
+        * Video Mode is also set to clear the test pattern, so enable HPD
+        * because it might have been disabled after a test pattern was set.
+        * AUX depends on HPD * sequence dependent, do not move!
+        */
+       if (!disable_hpd)
+               dc_link_enable_hpd(link);
+
+       prefer_link_settings.lane_count = link->verified_link_cap.lane_count;
+       prefer_link_settings.link_rate = link->verified_link_cap.link_rate;
+       prefer_link_settings.link_spread = link->verified_link_cap.link_spread;
+
+       cur_link_settings.lane_count = link->cur_link_settings.lane_count;
+       cur_link_settings.link_rate = link->cur_link_settings.link_rate;
+       cur_link_settings.link_spread = link->cur_link_settings.link_spread;
+
+       link_training_settings.link_settings = cur_link_settings;
+
+
+       if (test_pattern != DP_TEST_PATTERN_VIDEO_MODE) {
+               if (prefer_link_settings.lane_count != LANE_COUNT_UNKNOWN &&
+                       prefer_link_settings.link_rate !=  LINK_RATE_UNKNOWN &&
+                       (prefer_link_settings.lane_count != cur_link_settings.lane_count ||
+                       prefer_link_settings.link_rate != cur_link_settings.link_rate))
+                       link_training_settings.link_settings = prefer_link_settings;
+       }
+
+       for (i = 0; i < (unsigned int)(link_training_settings.link_settings.lane_count); i++)
+               link_training_settings.lane_settings[i] = link->cur_lane_setting;
+
+       dc_link_set_test_pattern(
+               link,
+               test_pattern,
+               &link_training_settings,
+               custom_pattern,
+               10);
+
+       /* Usage: Set DP physical test pattern using AMDDP with normal DP panel
+        * Then plug out DP panel and connect a scope to measure DP PHY signal.
+        * Need disable interrupt to avoid SW driver disable DP output. This is
+        * done after the test pattern is set.
+        */
+       if (valid_test_pattern && disable_hpd)
+               dc_link_disable_hpd(link);
+
+       kfree(wr_buf);
+
+       return bytes_from_user;
 }
 
 static const struct file_operations dp_link_settings_debugfs_fops = {
@@ -298,7 +499,6 @@ static const struct file_operations dp_pre_emphasis_fops = {
 
 static const struct file_operations dp_phy_test_pattern_fops = {
        .owner = THIS_MODULE,
-       .read = dp_phy_test_pattern_debugfs_read,
        .write = dp_phy_test_pattern_debugfs_write,
        .llseek = default_llseek
 };
@@ -310,7 +510,7 @@ static const struct {
                {"link_settings", &dp_link_settings_debugfs_fops},
                {"voltage_swing", &dp_voltage_swing_fops},
                {"pre_emphasis", &dp_pre_emphasis_fops},
-               {"phy_test_pattern", &dp_phy_test_pattern_fops}
+               {"test_pattern", &dp_phy_test_pattern_fops}
 };
 
 int connector_debugfs_init(struct amdgpu_dm_connector *connector)