@@ -1714,6 +1714,9 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe)
struct nv50_disp *disp = nv50_disp(encoder->dev);
struct nvkm_i2c_aux *aux =
nvkm_i2c_aux_find(i2c, dcbe->i2c_index);
+ u32 caps = nvif_rd32(&disp->disp->object,
+ 0x00640144 + (nv_encoder->or * 8));
+
if (aux) {
if (disp->disp->object.oclass < GF110_DISP) {
/* HW has no support for address-only
@@ -1727,13 +1730,17 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe)
nv_encoder->aux = aux;
}
- if (nv_connector->type != DCB_CONNECTOR_eDP &&
- nv50_has_mst(drm)) {
- ret = nv50_mstm_new(nv_encoder, &nv_connector->aux,
- 16, nv_connector->base.base.id,
- &nv_encoder->dp.mstm);
- if (ret)
- return ret;
+ if (nv_connector->type != DCB_CONNECTOR_eDP) {
+ if (nv50_has_mst(drm)) {
+ ret = nv50_mstm_new(nv_encoder,
+ &nv_connector->aux,
+ 16,
+ connector->base.id,
+ &nv_encoder->dp.mstm);
+ if (ret)
+ return ret;
+ }
+ nv_encoder->dp.caps.interlace = !!(caps & 0x04000000);
}
} else {
struct nvkm_i2c_bus *bus =
@@ -509,7 +509,11 @@ nouveau_connector_set_encoder(struct drm_connector *connector,
nv_connector->detected_encoder = nv_encoder;
if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) {
- connector->interlace_allowed = true;
+ if (nv_encoder->dcb->type == DCB_OUTPUT_DP)
+ connector->interlace_allowed =
+ nv_encoder->dp.caps.interlace;
+ else
+ connector->interlace_allowed = true;
connector->doublescan_allowed = true;
} else
if (nv_encoder->dcb->type == DCB_OUTPUT_LVDS ||
@@ -1060,6 +1064,10 @@ nouveau_connector_mode_valid(struct drm_connector *connector,
case DCB_OUTPUT_TV:
return get_slave_funcs(encoder)->mode_valid(encoder, mode);
case DCB_OUTPUT_DP:
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE &&
+ !nv_encoder->dp.caps.interlace)
+ return MODE_NO_INTERLACE;
+
max_clock = nv_encoder->dp.link_nr;
max_clock *= nv_encoder->dp.link_bw;
clock = clock * (connector->display_info.bpc * 3) / 10;
@@ -63,6 +63,9 @@ struct nouveau_encoder {
struct nv50_mstm *mstm;
int link_nr;
int link_bw;
+ struct {
+ bool interlace : 1;
+ } caps;
} dp;
};
Right now, we make the mistake of allowing interlacing on all connectors. Nvidia hardware does not always support interlacing with DP though, so we need to make sure that we don't allow interlaced modes to be set in such situations as otherwise we'll end up accidentally hanging the display HW. This fixes some hangs with Turing, which would be caused by attempting to set an interlaced mode on hardware that doesn't support it. This patch likely fixes other hardware hanging in the same way as well. Signed-off-by: Lyude Paul <lyude@redhat.com> Cc: stable@vger.kernel.org --- drivers/gpu/drm/nouveau/dispnv50/disp.c | 21 ++++++++++++++------- drivers/gpu/drm/nouveau/nouveau_connector.c | 10 +++++++++- drivers/gpu/drm/nouveau/nouveau_encoder.h | 3 +++ 3 files changed, 26 insertions(+), 8 deletions(-)