drm/dp: Don't attempt AUX transfers when eDP panels are not powered
authorjsg <jsg@openbsd.org>
Sat, 15 Jun 2024 04:05:42 +0000 (04:05 +0000)
committerjsg <jsg@openbsd.org>
Sat, 15 Jun 2024 04:05:42 +0000 (04:05 +0000)
From Douglas Anderson
9429b12dfcbd7eca89795730305cd1400bf97ec9 in linux-6.6.y/6.6.33
8df1ddb5bf11ab820ad991e164dab82c0960add9 in mainline linux

sys/dev/pci/drm/display/drm_dp_helper.c
sys/dev/pci/drm/include/drm/display/drm_dp_helper.h

index cdcb062..c2926c2 100644 (file)
@@ -532,6 +532,15 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request,
 
        mutex_lock(&aux->hw_mutex);
 
+       /*
+        * If the device attached to the aux bus is powered down then there's
+        * no reason to attempt a transfer. Error out immediately.
+        */
+       if (aux->powered_down) {
+               ret = -EBUSY;
+               goto unlock;
+       }
+
        /*
         * The specification doesn't give any recommendation on how often to
         * retry native transactions. We used to retry 7 times like for
@@ -599,6 +608,29 @@ int drm_dp_dpcd_probe(struct drm_dp_aux *aux, unsigned int offset)
 }
 EXPORT_SYMBOL(drm_dp_dpcd_probe);
 
+/**
+ * drm_dp_dpcd_set_powered() - Set whether the DP device is powered
+ * @aux: DisplayPort AUX channel; for convenience it's OK to pass NULL here
+ *       and the function will be a no-op.
+ * @powered: true if powered; false if not
+ *
+ * If the endpoint device on the DP AUX bus is known to be powered down
+ * then this function can be called to make future transfers fail immediately
+ * instead of needing to time out.
+ *
+ * If this function is never called then a device defaults to being powered.
+ */
+void drm_dp_dpcd_set_powered(struct drm_dp_aux *aux, bool powered)
+{
+       if (!aux)
+               return;
+
+       mutex_lock(&aux->hw_mutex);
+       aux->powered_down = !powered;
+       mutex_unlock(&aux->hw_mutex);
+}
+EXPORT_SYMBOL(drm_dp_dpcd_set_powered);
+
 /**
  * drm_dp_dpcd_read() - read a series of bytes from the DPCD
  * @aux: DisplayPort AUX channel (SST or MST)
@@ -1855,6 +1887,9 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
        struct drm_dp_aux_msg msg;
        int err = 0;
 
+       if (aux->powered_down)
+               return -EBUSY;
+
        dp_aux_i2c_transfer_size = clamp(dp_aux_i2c_transfer_size, 1, DP_AUX_MAX_PAYLOAD_BYTES);
 
        memset(&msg, 0, sizeof(msg));
index 6aa750e..133d996 100644 (file)
@@ -449,9 +449,15 @@ struct drm_dp_aux {
         * @is_remote: Is this AUX CH actually using sideband messaging.
         */
        bool is_remote;
+
+       /**
+        * @powered_down: If true then the remote endpoint is powered down.
+        */
+       bool powered_down;
 };
 
 int drm_dp_dpcd_probe(struct drm_dp_aux *aux, unsigned int offset);
+void drm_dp_dpcd_set_powered(struct drm_dp_aux *aux, bool powered);
 ssize_t drm_dp_dpcd_read(struct drm_dp_aux *aux, unsigned int offset,
                         void *buffer, size_t size);
 ssize_t drm_dp_dpcd_write(struct drm_dp_aux *aux, unsigned int offset,