Merge tag 'topic/phy-compliance-2020-04-08' of git://anongit.freedesktop.org/drm...
authorThomas Zimmermann <tzimmermann@suse.de>
Fri, 17 Apr 2020 06:52:37 +0000 (08:52 +0200)
committerThomas Zimmermann <tzimmermann@suse.de>
Fri, 17 Apr 2020 06:52:39 +0000 (08:52 +0200)
Topic pull request for topic/phy-compliance:
- Standardize DP_PHY_TEST_PATTERN name.
- Add support for setting/getting test pattern from sink.
- Implement DP PHY compliance to i915.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
# gpg: Signatur vom Mi 08 Apr 2020 14:46:42 CEST
# gpg:                mittels RSA-Schlüssel B97BD6A80CAC4981091AE547FE558C72A67013C3
# gpg: Signatur kann nicht geprüft werden: Kein öffentlicher Schlüssel
From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/efb3d0d9-2cf7-046b-3a9b-2548d086258e@linux.intel.com
1  2 
drivers/gpu/drm/i915/display/intel_display_debugfs.c
drivers/gpu/drm/i915/display/intel_display_types.h
drivers/gpu/drm/i915/display/intel_dp.c

index 9f736420d83f5f79cbbcac6e734bb7f01c7a25b5,ab20b7ea26f7fa270be0a05335baae063f53a816..bdeea2e026420fc011c42e251dcdedca3c7f4fe1
@@@ -631,9 -631,15 +631,9 @@@ static void intel_dp_info(struct seq_fi
  }
  
  static void intel_dp_mst_info(struct seq_file *m,
 -                        struct intel_connector *intel_connector)
 +                            struct intel_connector *intel_connector)
  {
 -      struct intel_encoder *intel_encoder = intel_attached_encoder(intel_connector);
 -      struct intel_dp_mst_encoder *intel_mst =
 -              enc_to_mst(intel_encoder);
 -      struct intel_digital_port *intel_dig_port = intel_mst->primary;
 -      struct intel_dp *intel_dp = &intel_dig_port->dp;
 -      bool has_audio = drm_dp_mst_port_has_audio(&intel_dp->mst_mgr,
 -                                      intel_connector->port);
 +      bool has_audio = intel_connector->port->has_audio;
  
        seq_printf(m, "\taudio support: %s\n", yesno(has_audio));
  }
@@@ -1320,6 -1326,16 +1320,16 @@@ static int i915_displayport_test_data_s
                                           intel_dp->compliance.test_data.vdisplay);
                                seq_printf(m, "bpc: %u\n",
                                           intel_dp->compliance.test_data.bpc);
+                       } else if (intel_dp->compliance.test_type ==
+                                  DP_TEST_LINK_PHY_TEST_PATTERN) {
+                               seq_printf(m, "pattern: %d\n",
+                                          intel_dp->compliance.test_data.phytest.phy_pattern);
+                               seq_printf(m, "Number of lanes: %d\n",
+                                          intel_dp->compliance.test_data.phytest.num_lanes);
+                               seq_printf(m, "Link Rate: %d\n",
+                                          intel_dp->compliance.test_data.phytest.link_rate);
+                               seq_printf(m, "level: %02x\n",
+                                          intel_dp->train_set[0]);
                        }
                } else
                        seq_puts(m, "0");
@@@ -1352,7 -1368,7 +1362,7 @@@ static int i915_displayport_test_type_s
  
                if (encoder && connector->status == connector_status_connected) {
                        intel_dp = enc_to_intel_dp(encoder);
-                       seq_printf(m, "%02lx", intel_dp->compliance.test_type);
+                       seq_printf(m, "%02lx\n", intel_dp->compliance.test_type);
                } else
                        seq_puts(m, "0");
        }
@@@ -1921,7 -1937,7 +1931,7 @@@ static const struct 
        {"i915_edp_psr_debug", &i915_edp_psr_debug_fops},
  };
  
 -int intel_display_debugfs_register(struct drm_i915_private *i915)
 +void intel_display_debugfs_register(struct drm_i915_private *i915)
  {
        struct drm_minor *minor = i915->drm.primary;
        int i;
                                    intel_display_debugfs_files[i].fops);
        }
  
 -      return drm_debugfs_create_files(intel_display_debugfs_list,
 -                                      ARRAY_SIZE(intel_display_debugfs_list),
 -                                      minor->debugfs_root, minor);
 +      drm_debugfs_create_files(intel_display_debugfs_list,
 +                               ARRAY_SIZE(intel_display_debugfs_list),
 +                               minor->debugfs_root, minor);
  }
  
  static int i915_panel_show(struct seq_file *m, void *data)
index e67474a717617d99875d1041015ad2bfb0d22e78,42d0b102c2cf2eff5ed26c194d40c7932dc559ad..1170a1ce4b5698d219526f031764cb8ff97d4bd8
@@@ -429,7 -429,7 +429,7 @@@ struct intel_connector 
           state of connector->polled in case hotplug storm detection changes it */
        u8 polled;
  
 -      void *port; /* store this opaque as its illegal to dereference it */
 +      struct drm_dp_mst_port *port;
  
        struct intel_dp *mst_port;
  
@@@ -1238,6 -1238,7 +1238,7 @@@ struct intel_dp_compliance_data 
        u8 video_pattern;
        u16 hdisplay, vdisplay;
        u8 bpc;
+       struct drm_dp_phy_test_params phytest;
  };
  
  struct intel_dp_compliance {
index 804b1d966f66424ebd5fa5601bbb357feec1c0cb,8846471a49b897123aab7bf659a3494725a8771c..f2ee2a0f286a2c93ea473dc26896b6cbd58fd0d0
@@@ -1374,7 -1374,7 +1374,7 @@@ intel_dp_aux_xfer(struct intel_dp *inte
         * lowest possible wakeup latency and so prevent the cpu from going into
         * deep sleep states.
         */
 -      pm_qos_update_request(&i915->pm_qos, 0);
 +      cpu_latency_qos_update_request(&i915->pm_qos, 0);
  
        intel_dp_check_edp(intel_dp);
  
@@@ -1507,7 -1507,7 +1507,7 @@@ done
  
        ret = recv_bytes;
  out:
 -      pm_qos_update_request(&i915->pm_qos, PM_QOS_DEFAULT_VALUE);
 +      cpu_latency_qos_update_request(&i915->pm_qos, PM_QOS_DEFAULT_VALUE);
  
        if (vdd)
                edp_panel_vdd_off(intel_dp, false);
@@@ -5001,9 -5001,180 +5001,180 @@@ static u8 intel_dp_autotest_edid(struc
        return test_result;
  }
  
+ static u8 intel_dp_prepare_phytest(struct intel_dp *intel_dp)
+ {
+       struct drm_dp_phy_test_params *data =
+               &intel_dp->compliance.test_data.phytest;
+       if (drm_dp_get_phy_test_pattern(&intel_dp->aux, data)) {
+               DRM_DEBUG_KMS("DP Phy Test pattern AUX read failure\n");
+               return DP_TEST_NAK;
+       }
+       /*
+        * link_mst is set to false to avoid executing mst related code
+        * during compliance testing.
+        */
+       intel_dp->link_mst = false;
+       return DP_TEST_ACK;
+ }
+ static void intel_dp_phy_pattern_update(struct intel_dp *intel_dp)
+ {
+       struct drm_i915_private *dev_priv =
+                       to_i915(dp_to_dig_port(intel_dp)->base.base.dev);
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       struct drm_dp_phy_test_params *data =
+                       &intel_dp->compliance.test_data.phytest;
+       struct intel_crtc *crtc = to_intel_crtc(intel_dig_port->base.base.crtc);
+       enum pipe pipe = crtc->pipe;
+       u32 pattern_val;
+       switch (data->phy_pattern) {
+       case DP_PHY_TEST_PATTERN_NONE:
+               DRM_DEBUG_KMS("Disable Phy Test Pattern\n");
+               intel_de_write(dev_priv, DDI_DP_COMP_CTL(pipe), 0x0);
+               break;
+       case DP_PHY_TEST_PATTERN_D10_2:
+               DRM_DEBUG_KMS("Set D10.2 Phy Test Pattern\n");
+               intel_de_write(dev_priv, DDI_DP_COMP_CTL(pipe),
+                              DDI_DP_COMP_CTL_ENABLE | DDI_DP_COMP_CTL_D10_2);
+               break;
+       case DP_PHY_TEST_PATTERN_ERROR_COUNT:
+               DRM_DEBUG_KMS("Set Error Count Phy Test Pattern\n");
+               intel_de_write(dev_priv, DDI_DP_COMP_CTL(pipe),
+                              DDI_DP_COMP_CTL_ENABLE |
+                              DDI_DP_COMP_CTL_SCRAMBLED_0);
+               break;
+       case DP_PHY_TEST_PATTERN_PRBS7:
+               DRM_DEBUG_KMS("Set PRBS7 Phy Test Pattern\n");
+               intel_de_write(dev_priv, DDI_DP_COMP_CTL(pipe),
+                              DDI_DP_COMP_CTL_ENABLE | DDI_DP_COMP_CTL_PRBS7);
+               break;
+       case DP_PHY_TEST_PATTERN_80BIT_CUSTOM:
+               /*
+                * FIXME: Ideally pattern should come from DPCD 0x250. As
+                * current firmware of DPR-100 could not set it, so hardcoding
+                * now for complaince test.
+                */
+               DRM_DEBUG_KMS("Set 80Bit Custom Phy Test Pattern 0x3e0f83e0 0x0f83e0f8 0x0000f83e\n");
+               pattern_val = 0x3e0f83e0;
+               intel_de_write(dev_priv, DDI_DP_COMP_PAT(pipe, 0), pattern_val);
+               pattern_val = 0x0f83e0f8;
+               intel_de_write(dev_priv, DDI_DP_COMP_PAT(pipe, 1), pattern_val);
+               pattern_val = 0x0000f83e;
+               intel_de_write(dev_priv, DDI_DP_COMP_PAT(pipe, 2), pattern_val);
+               intel_de_write(dev_priv, DDI_DP_COMP_CTL(pipe),
+                              DDI_DP_COMP_CTL_ENABLE |
+                              DDI_DP_COMP_CTL_CUSTOM80);
+               break;
+       case DP_PHY_TEST_PATTERN_CP2520:
+               /*
+                * FIXME: Ideally pattern should come from DPCD 0x24A. As
+                * current firmware of DPR-100 could not set it, so hardcoding
+                * now for complaince test.
+                */
+               DRM_DEBUG_KMS("Set HBR2 compliance Phy Test Pattern\n");
+               pattern_val = 0xFB;
+               intel_de_write(dev_priv, DDI_DP_COMP_CTL(pipe),
+                              DDI_DP_COMP_CTL_ENABLE | DDI_DP_COMP_CTL_HBR2 |
+                              pattern_val);
+               break;
+       default:
+               WARN(1, "Invalid Phy Test Pattern\n");
+       }
+ }
+ static void
+ intel_dp_autotest_phy_ddi_disable(struct intel_dp *intel_dp)
+ {
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       struct drm_device *dev = intel_dig_port->base.base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_crtc *crtc = to_intel_crtc(intel_dig_port->base.base.crtc);
+       enum pipe pipe = crtc->pipe;
+       u32 trans_ddi_func_ctl_value, trans_conf_value, dp_tp_ctl_value;
+       trans_ddi_func_ctl_value = intel_de_read(dev_priv,
+                                                TRANS_DDI_FUNC_CTL(pipe));
+       trans_conf_value = intel_de_read(dev_priv, PIPECONF(pipe));
+       dp_tp_ctl_value = intel_de_read(dev_priv, TGL_DP_TP_CTL(pipe));
+       trans_ddi_func_ctl_value &= ~(TRANS_DDI_FUNC_ENABLE |
+                                     TGL_TRANS_DDI_PORT_MASK);
+       trans_conf_value &= ~PIPECONF_ENABLE;
+       dp_tp_ctl_value &= ~DP_TP_CTL_ENABLE;
+       intel_de_write(dev_priv, PIPECONF(pipe), trans_conf_value);
+       intel_de_write(dev_priv, TRANS_DDI_FUNC_CTL(pipe),
+                      trans_ddi_func_ctl_value);
+       intel_de_write(dev_priv, TGL_DP_TP_CTL(pipe), dp_tp_ctl_value);
+ }
+ static void
+ intel_dp_autotest_phy_ddi_enable(struct intel_dp *intel_dp, uint8_t lane_cnt)
+ {
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       struct drm_device *dev = intel_dig_port->base.base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       enum port port = intel_dig_port->base.port;
+       struct intel_crtc *crtc = to_intel_crtc(intel_dig_port->base.base.crtc);
+       enum pipe pipe = crtc->pipe;
+       u32 trans_ddi_func_ctl_value, trans_conf_value, dp_tp_ctl_value;
+       trans_ddi_func_ctl_value = intel_de_read(dev_priv,
+                                                TRANS_DDI_FUNC_CTL(pipe));
+       trans_conf_value = intel_de_read(dev_priv, PIPECONF(pipe));
+       dp_tp_ctl_value = intel_de_read(dev_priv, TGL_DP_TP_CTL(pipe));
+       trans_ddi_func_ctl_value |= TRANS_DDI_FUNC_ENABLE |
+                                   TGL_TRANS_DDI_SELECT_PORT(port);
+       trans_conf_value |= PIPECONF_ENABLE;
+       dp_tp_ctl_value |= DP_TP_CTL_ENABLE;
+       intel_de_write(dev_priv, PIPECONF(pipe), trans_conf_value);
+       intel_de_write(dev_priv, TGL_DP_TP_CTL(pipe), dp_tp_ctl_value);
+       intel_de_write(dev_priv, TRANS_DDI_FUNC_CTL(pipe),
+                      trans_ddi_func_ctl_value);
+ }
+ void intel_dp_process_phy_request(struct intel_dp *intel_dp)
+ {
+       struct drm_dp_phy_test_params *data =
+               &intel_dp->compliance.test_data.phytest;
+       u8 link_status[DP_LINK_STATUS_SIZE];
+       if (!intel_dp_get_link_status(intel_dp, link_status)) {
+               DRM_DEBUG_KMS("failed to get link status\n");
+               return;
+       }
+       /* retrieve vswing & pre-emphasis setting */
+       intel_dp_get_adjust_train(intel_dp, link_status);
+       intel_dp_autotest_phy_ddi_disable(intel_dp);
+       intel_dp_set_signal_levels(intel_dp);
+       intel_dp_phy_pattern_update(intel_dp);
+       intel_dp_autotest_phy_ddi_enable(intel_dp, data->num_lanes);
+       drm_dp_set_phy_test_pattern(&intel_dp->aux, data,
+                                   link_status[DP_DPCD_REV]);
+ }
  static u8 intel_dp_autotest_phy_pattern(struct intel_dp *intel_dp)
  {
        u8 test_result = DP_TEST_NAK;
+       test_result = intel_dp_prepare_phytest(intel_dp);
+       if (test_result != DP_TEST_ACK)
+               DRM_ERROR("Phy test preparation failed\n");
+       intel_dp_process_phy_request(intel_dp);
        return test_result;
  }