txbuf[3] = msg->size - 1;
 }
 
+static u32 intel_dp_aux_xfer_flags(const struct drm_dp_aux_msg *msg)
+{
+       /*
+        * If we're trying to send the HDCP Aksv, we need to set a the Aksv
+        * select bit to inform the hardware to send the Aksv after our header
+        * since we can't access that data from software.
+        */
+       if ((msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_NATIVE_WRITE &&
+           msg->address == DP_AUX_HDCP_AKSV)
+               return DP_AUX_CH_CTL_AUX_AKSV_SELECT;
+
+       return 0;
+}
+
 static ssize_t
 intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
 {
        struct drm_i915_private *i915 = dp_to_i915(intel_dp);
        u8 txbuf[20], rxbuf[20];
        size_t txsize, rxsize;
+       u32 flags = intel_dp_aux_xfer_flags(msg);
        int ret;
 
        intel_dp_aux_header(txbuf, msg);
                        memcpy(txbuf + HEADER_SIZE, msg->buffer, msg->size);
 
                ret = intel_dp_aux_xfer(intel_dp, txbuf, txsize,
-                                       rxbuf, rxsize, 0);
+                                       rxbuf, rxsize, flags);
                if (ret > 0) {
                        msg->reply = rxbuf[0] >> 4;
 
                        return -E2BIG;
 
                ret = intel_dp_aux_xfer(intel_dp, txbuf, txsize,
-                                       rxbuf, rxsize, 0);
+                                       rxbuf, rxsize, flags);
                if (ret > 0) {
                        msg->reply = rxbuf[0] >> 4;
                        /*
                                u8 *an)
 {
        struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
-       struct intel_dp *intel_dp = enc_to_intel_dp(to_intel_encoder(&dig_port->base.base));
-       static const struct drm_dp_aux_msg msg = {
-               .request = DP_AUX_NATIVE_WRITE,
-               .address = DP_AUX_HDCP_AKSV,
-               .size = DRM_HDCP_KSV_LEN,
-       };
-       u8 txbuf[HEADER_SIZE + DRM_HDCP_KSV_LEN] = {}, rxbuf[2], reply = 0;
+       u8 aksv[DRM_HDCP_KSV_LEN] = {};
        ssize_t dpcd_ret;
-       int ret;
 
        /* Output An first, that's easy */
        dpcd_ret = drm_dp_dpcd_write(&dig_port->dp.aux, DP_AUX_HDCP_AN,
        }
 
        /*
-        * Since Aksv is Oh-So-Secret, we can't access it in software. So in
-        * order to get it on the wire, we need to create the AUX header as if
-        * we were writing the data, and then tickle the hardware to output the
-        * data once the header is sent out.
+        * Since Aksv is Oh-So-Secret, we can't access it in software. So we
+        * send an empty buffer of the correct length through the DP helpers. On
+        * the other side, in the transfer hook, we'll generate a flag based on
+        * the destination address which will tickle the hardware to output the
+        * Aksv on our behalf after the header is sent.
         */
-       intel_dp_aux_header(txbuf, &msg);
-
-       ret = intel_dp_aux_xfer(intel_dp, txbuf, HEADER_SIZE + msg.size,
-                               rxbuf, sizeof(rxbuf),
-                               DP_AUX_CH_CTL_AUX_AKSV_SELECT);
-       if (ret < 0) {
-               drm_dbg_kms(&i915->drm,
-                           "Write Aksv over DP/AUX failed (%d)\n", ret);
-               return ret;
-       } else if (ret == 0) {
-               drm_dbg_kms(&i915->drm, "Aksv write over DP/AUX was empty\n");
-               return -EIO;
-       }
-
-       reply = (rxbuf[0] >> 4) & DP_AUX_NATIVE_REPLY_MASK;
-       if (reply != DP_AUX_NATIVE_REPLY_ACK) {
+       dpcd_ret = drm_dp_dpcd_write(&dig_port->dp.aux, DP_AUX_HDCP_AKSV,
+                                    aksv, DRM_HDCP_KSV_LEN);
+       if (dpcd_ret != DRM_HDCP_KSV_LEN) {
                drm_dbg_kms(&i915->drm,
-                           "Aksv write: no DP_AUX_NATIVE_REPLY_ACK %x\n",
-                           reply);
-               return -EIO;
+                           "Failed to write Aksv over DP/AUX (%zd)\n",
+                           dpcd_ret);
+               return dpcd_ret >= 0 ? -EIO : dpcd_ret;
        }
        return 0;
 }