drm/i915/dp: Extract drm_dp_read_dpcd_caps()
authorLyude Paul <lyude@redhat.com>
Wed, 26 Aug 2020 18:24:55 +0000 (14:24 -0400)
committerLyude Paul <lyude@redhat.com>
Mon, 31 Aug 2020 23:10:09 +0000 (19:10 -0400)
Since DP 1.3, it's been possible for DP receivers to specify an
additional set of DPCD capabilities, which can take precedence over the
capabilities reported at DP_DPCD_REV.

Basically any device supporting DP is going to need to read these in an
identical manner, in particular nouveau, so let's go ahead and just move
this code out of i915 into a shared DRM DP helper that we can use in
other drivers.

v2:
* Remove redundant dpcd[DP_DPCD_REV] == 0 check
* Fix drm_dp_dpcd_read() ret checks

Signed-off-by: Lyude Paul <lyude@redhat.com>
Reviewed-by: Sean Paul <sean@poorly.run>
Link: https://patchwork.freedesktop.org/patch/msgid/20200826182456.322681-20-lyude@redhat.com
drivers/gpu/drm/drm_dp_helper.c
drivers/gpu/drm/i915/display/intel_dp.c
drivers/gpu/drm/i915/display/intel_dp.h
drivers/gpu/drm/i915/display/intel_lspcon.c
include/drm/drm_dp_helper.h

index 46d88ef4f59ac996c4d1b870cf0b48632d768e5d..9ca88e6c78820fb9f446ea42af01575a554570ce 100644 (file)
@@ -433,6 +433,83 @@ static u8 drm_dp_downstream_port_count(const u8 dpcd[DP_RECEIVER_CAP_SIZE])
        return port_count;
 }
 
+static int drm_dp_read_extended_dpcd_caps(struct drm_dp_aux *aux,
+                                         u8 dpcd[DP_RECEIVER_CAP_SIZE])
+{
+       u8 dpcd_ext[6];
+       int ret;
+
+       /*
+        * Prior to DP1.3 the bit represented by
+        * DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT was reserved.
+        * If it is set DP_DPCD_REV at 0000h could be at a value less than
+        * the true capability of the panel. The only way to check is to
+        * then compare 0000h and 2200h.
+        */
+       if (!(dpcd[DP_TRAINING_AUX_RD_INTERVAL] &
+             DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT))
+               return 0;
+
+       ret = drm_dp_dpcd_read(aux, DP_DP13_DPCD_REV, &dpcd_ext,
+                              sizeof(dpcd_ext));
+       if (ret < 0)
+               return ret;
+       if (ret != sizeof(dpcd_ext))
+               return -EIO;
+
+       if (dpcd[DP_DPCD_REV] > dpcd_ext[DP_DPCD_REV]) {
+               DRM_DEBUG_KMS("%s: Extended DPCD rev less than base DPCD rev (%d > %d)\n",
+                             aux->name, dpcd[DP_DPCD_REV],
+                             dpcd_ext[DP_DPCD_REV]);
+               return 0;
+       }
+
+       if (!memcmp(dpcd, dpcd_ext, sizeof(dpcd_ext)))
+               return 0;
+
+       DRM_DEBUG_KMS("%s: Base DPCD: %*ph\n",
+                     aux->name, DP_RECEIVER_CAP_SIZE, dpcd);
+
+       memcpy(dpcd, dpcd_ext, sizeof(dpcd_ext));
+
+       return 0;
+}
+
+/**
+ * drm_dp_read_dpcd_caps() - read DPCD caps and extended DPCD caps if
+ * available
+ * @aux: DisplayPort AUX channel
+ * @dpcd: Buffer to store the resulting DPCD in
+ *
+ * Attempts to read the base DPCD caps for @aux. Additionally, this function
+ * checks for and reads the extended DPRX caps (%DP_DP13_DPCD_REV) if
+ * present.
+ *
+ * Returns: %0 if the DPCD was read successfully, negative error code
+ * otherwise.
+ */
+int drm_dp_read_dpcd_caps(struct drm_dp_aux *aux,
+                         u8 dpcd[DP_RECEIVER_CAP_SIZE])
+{
+       int ret;
+
+       ret = drm_dp_dpcd_read(aux, DP_DPCD_REV, dpcd, DP_RECEIVER_CAP_SIZE);
+       if (ret < 0)
+               return ret;
+       if (ret != DP_RECEIVER_CAP_SIZE || dpcd[DP_DPCD_REV] == 0)
+               return -EIO;
+
+       ret = drm_dp_read_extended_dpcd_caps(aux, dpcd);
+       if (ret < 0)
+               return ret;
+
+       DRM_DEBUG_KMS("%s: DPCD: %*ph\n",
+                     aux->name, DP_RECEIVER_CAP_SIZE, dpcd);
+
+       return ret;
+}
+EXPORT_SYMBOL(drm_dp_read_dpcd_caps);
+
 /**
  * drm_dp_read_downstream_info() - read DPCD downstream port info if available
  * @aux: DisplayPort AUX channel
index 0de94fc6289be6d290fb52854c360343de60f18a..284b15f845926c6f54d1731ebe7047576b0be464 100644 (file)
@@ -4449,62 +4449,6 @@ intel_dp_link_down(struct intel_encoder *encoder,
        }
 }
 
-static void
-intel_dp_extended_receiver_capabilities(struct intel_dp *intel_dp)
-{
-       struct drm_i915_private *i915 = dp_to_i915(intel_dp);
-       u8 dpcd_ext[6];
-
-       /*
-        * Prior to DP1.3 the bit represented by
-        * DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT was reserved.
-        * if it is set DP_DPCD_REV at 0000h could be at a value less than
-        * the true capability of the panel. The only way to check is to
-        * then compare 0000h and 2200h.
-        */
-       if (!(intel_dp->dpcd[DP_TRAINING_AUX_RD_INTERVAL] &
-             DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT))
-               return;
-
-       if (drm_dp_dpcd_read(&intel_dp->aux, DP_DP13_DPCD_REV,
-                            &dpcd_ext, sizeof(dpcd_ext)) != sizeof(dpcd_ext)) {
-               drm_err(&i915->drm,
-                       "DPCD failed read at extended capabilities\n");
-               return;
-       }
-
-       if (intel_dp->dpcd[DP_DPCD_REV] > dpcd_ext[DP_DPCD_REV]) {
-               drm_dbg_kms(&i915->drm,
-                           "DPCD extended DPCD rev less than base DPCD rev\n");
-               return;
-       }
-
-       if (!memcmp(intel_dp->dpcd, dpcd_ext, sizeof(dpcd_ext)))
-               return;
-
-       drm_dbg_kms(&i915->drm, "Base DPCD: %*ph\n",
-                   (int)sizeof(intel_dp->dpcd), intel_dp->dpcd);
-
-       memcpy(intel_dp->dpcd, dpcd_ext, sizeof(dpcd_ext));
-}
-
-bool
-intel_dp_read_dpcd(struct intel_dp *intel_dp)
-{
-       struct drm_i915_private *i915 = dp_to_i915(intel_dp);
-
-       if (drm_dp_dpcd_read(&intel_dp->aux, 0x000, intel_dp->dpcd,
-                            sizeof(intel_dp->dpcd)) < 0)
-               return false; /* aux transfer failed */
-
-       intel_dp_extended_receiver_capabilities(intel_dp);
-
-       drm_dbg_kms(&i915->drm, "DPCD: %*ph\n", (int)sizeof(intel_dp->dpcd),
-                   intel_dp->dpcd);
-
-       return intel_dp->dpcd[DP_DPCD_REV] != 0;
-}
-
 bool intel_dp_get_colorimetry_status(struct intel_dp *intel_dp)
 {
        u8 dprx = 0;
@@ -4563,7 +4507,7 @@ intel_edp_init_dpcd(struct intel_dp *intel_dp)
        /* this function is meant to be called only once */
        drm_WARN_ON(&dev_priv->drm, intel_dp->dpcd[DP_DPCD_REV] != 0);
 
-       if (!intel_dp_read_dpcd(intel_dp))
+       if (drm_dp_read_dpcd_caps(&intel_dp->aux, intel_dp->dpcd) != 0)
                return false;
 
        drm_dp_read_desc(&intel_dp->aux, &intel_dp->desc,
@@ -4650,7 +4594,7 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
 {
        int ret;
 
-       if (!intel_dp_read_dpcd(intel_dp))
+       if (drm_dp_read_dpcd_caps(&intel_dp->aux, intel_dp->dpcd))
                return false;
 
        /*
index b901ab850cbd92cc0889bf8e89cacf4bf084aa88..0a3af3410d52e1fee205af8a2004e5d19507d446 100644 (file)
@@ -99,7 +99,6 @@ bool intel_dp_source_supports_hbr3(struct intel_dp *intel_dp);
 bool
 intel_dp_get_link_status(struct intel_dp *intel_dp, u8 *link_status);
 
-bool intel_dp_read_dpcd(struct intel_dp *intel_dp);
 bool intel_dp_get_colorimetry_status(struct intel_dp *intel_dp);
 int intel_dp_link_required(int pixel_clock, int bpp);
 int intel_dp_max_data_rate(int max_link_clock, int max_lanes);
index b781bf46964437179aff89226d4c30633e528546..dc1b35559afdf863669319c8a6f0e026c91757c0 100644 (file)
@@ -571,7 +571,7 @@ bool lspcon_init(struct intel_digital_port *dig_port)
                return false;
        }
 
-       if (!intel_dp_read_dpcd(dp)) {
+       if (drm_dp_read_dpcd_caps(&dp->aux, dp->dpcd) != 0) {
                DRM_ERROR("LSPCON DPCD read failed\n");
                return false;
        }
index bc5cb8c503fbc4578b4636bfbd07fb8d6fe9ab65..85513eeb2196682227e6c1377d2bf53ed7510ffa 100644 (file)
@@ -1607,6 +1607,9 @@ static inline ssize_t drm_dp_dpcd_writeb(struct drm_dp_aux *aux,
        return drm_dp_dpcd_write(aux, offset, &value, 1);
 }
 
+int drm_dp_read_dpcd_caps(struct drm_dp_aux *aux,
+                         u8 dpcd[DP_RECEIVER_CAP_SIZE]);
+
 int drm_dp_dpcd_read_link_status(struct drm_dp_aux *aux,
                                 u8 status[DP_LINK_STATUS_SIZE]);