@@ -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;
};
@@ -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) {
@@ -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;
}
@@ -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);
}
@@ -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;
@@ -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
@@ -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) {