diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h
index a2e3373..9fa95fb 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h
@@ -37,6 +37,7 @@ struct nvkm_i2c_port {
 	struct list_head head;
 	u8  index;
 	int aux;
+	void *drm_dp_aux;
 
 	const struct nvkm_i2c_func *func;
 };
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index 1e5224f..159df7f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -144,8 +144,8 @@ nouveau_connector_ddc_detect(struct drm_connector *connector)
 		nv_encoder = nouveau_encoder(encoder);
 
 		if (nv_encoder->dcb->type == DCB_OUTPUT_DP) {
-			int ret = nouveau_dp_detect(nv_encoder);
-			if (ret == 0)
+			nv_encoder->i2c->drm_dp_aux = &nv_connector->aux;
+			if (nouveau_dp_detect(nv_encoder) == 0)
 				break;
 		} else
 		if (nv_encoder->i2c) {
diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c
index c3ef30b..317d6b1 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dp.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dp.c
@@ -30,6 +30,25 @@
 #include "nouveau_encoder.h"
 #include "nouveau_crtc.h"
 
+#include <engine/disp.h>
+#include <engine/disp/outpdp.h>
+
+static void
+nouveau_dp_check_link_training(struct nouveau_encoder *nv_encoder)
+{
+	struct nvkm_disp *disp = nvkm_disp(nv_encoder->i2c);
+	struct nvkm_output *outp;
+	struct nvkm_output_dp *outpdp;
+
+	list_for_each_entry(outp, &disp->outp, head)
+		if (outp->info.index == nv_encoder->dcb->index)
+			break;
+
+	outpdp = (struct nvkm_output_dp *)outp;
+	if (!atomic_read(&outpdp->lt.done))
+		nvkm_output_dp_detect(outpdp);
+}
+
 static void
 nouveau_dp_probe_oui(struct drm_device *dev, struct nvkm_i2c_port *auxch,
 		     u8 *dpcd)
@@ -85,5 +104,6 @@ nouveau_dp_detect(struct nouveau_encoder *nv_encoder)
 		     nv_encoder->dp.link_nr, nv_encoder->dp.link_bw);
 
 	nouveau_dp_probe_oui(dev, auxch, dpcd);
+	nouveau_dp_check_link_training(nv_encoder);
 	return 0;
 }
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c
index 6834766..5257e4c 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c
@@ -61,7 +61,7 @@ dp_set_link_config(struct dp_state *dp)
 		.execute = 1,
 	};
 	u32 lnkcmp;
-	u8 sink[2];
+	u8 sink[2], sink_rd[2];
 	int ret;
 
 	DBG("%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw);
@@ -98,6 +98,10 @@ dp_set_link_config(struct dp_state *dp)
 	if (outp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP)
 		sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN;
 
+	if (nv_rdaux(outp->base.edid, DPCD_LC00_LINK_BW_SET, sink_rd, 2) == 0 &&
+	    memcmp(sink, sink_rd, 2) == 0)
+		return 0;
+
 	return nv_wraux(outp->base.edid, DPCD_LC00_LINK_BW_SET, sink, 2);
 }
 
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c
index 0bde0fa..b95373b 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c
@@ -122,7 +122,7 @@ nvkm_output_dp_enable(struct nvkm_output_dp *outp, bool present)
 	}
 }
 
-static void
+void
 nvkm_output_dp_detect(struct nvkm_output_dp *outp)
 {
 	struct nvkm_i2c_port *port = outp->base.edid;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h
index 70c77ae..0bd4dcb 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h
@@ -58,4 +58,5 @@ struct nvkm_output_dp_impl {
 };
 
 int nvkm_output_dp_train(struct nvkm_output *, u32 rate, bool wait);
+void nvkm_output_dp_detect(struct nvkm_output_dp *);
 #endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c
index 1c18860..16ec3cc 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c
@@ -23,10 +23,34 @@
  */
 #include "priv.h"
 
+#if IS_ENABLED(CONFIG_DRM_KMS_HELPER)
+#include <drm/drm_dp_helper.h>
+#endif
+
+static int
+drm_rdaux(struct nvkm_i2c_port *port, u32 addr, u8 *data, u8 size)
+{
+#if IS_ENABLED(CONFIG_DRM_KMS_HELPER)
+	if (port->drm_dp_aux) {
+		nv_debug(port, "Try reading DPCD with KMS helper: addr=0x%x size=%d\n",
+			 addr, size);
+		return !(drm_dp_dpcd_read(port->drm_dp_aux, addr, data, size)
+			 == size);
+	}
+#endif
+	return -ENODEV;
+}
+
 int
 nv_rdaux(struct nvkm_i2c_port *port, u32 addr, u8 *data, u8 size)
 {
 	struct nvkm_i2c *i2c = nvkm_i2c(port);
+
+	if (drm_rdaux(port, addr, data, size) == 0)
+		return 0;
+
+	nv_debug(port, "Try reading DPCD directly:        addr=0x%x size=%d\n",
+		 addr, size);
 	if (port->func->aux) {
 		int ret = i2c->acquire(port, 0);
 		if (ret == 0) {
