aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/core/engine/disp/dport.c
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2013-11-04 13:40:36 +1000
committerBen Skeggs <bskeggs@redhat.com>2013-11-08 15:39:57 +1000
commit8df1d0c07f18bd84ea7d8c7bc2cff45ba2b09680 (patch)
tree70e72b11046c63bb370b50220393a38c27c397c0 /drivers/gpu/drm/nouveau/core/engine/disp/dport.c
parentdrm/nouveau/bios: some older boards have shorter displayport tables (diff)
downloadlinux-dev-8df1d0c07f18bd84ea7d8c7bc2cff45ba2b09680.tar.xz
linux-dev-8df1d0c07f18bd84ea7d8c7bc2cff45ba2b09680.zip
drm/nouveau/disp: semi-complete link training sequence even if display disappears
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/core/engine/disp/dport.c')
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/dport.c48
1 files changed, 32 insertions, 16 deletions
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/dport.c b/drivers/gpu/drm/nouveau/core/engine/disp/dport.c
index 15448b9abac8..1bd4c63369c1 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/dport.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/dport.c
@@ -70,17 +70,10 @@ dp_set_link_config(struct dp_state *dp)
};
u32 lnkcmp;
u8 sink[2];
+ int ret;
DBG("%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw);
- /* set desired link configuration on the sink */
- sink[0] = dp->link_bw / 27000;
- sink[1] = dp->link_nr;
- if (dp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP)
- sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN;
-
- nv_wraux(dp->aux, DPCD_LC00, sink, 2);
-
/* set desired link configuration on the source */
if ((lnkcmp = dp->info.lnkcmp)) {
if (dp->version < 0x30) {
@@ -96,10 +89,22 @@ dp_set_link_config(struct dp_state *dp)
nvbios_exec(&init);
}
- return dp->func->lnk_ctl(dp->disp, dp->outp, dp->head,
- dp->link_nr, dp->link_bw / 27000,
- dp->dpcd[DPCD_RC02] &
- DPCD_RC02_ENHANCED_FRAME_CAP);
+ ret = dp->func->lnk_ctl(dp->disp, dp->outp, dp->head,
+ dp->link_nr, dp->link_bw / 27000,
+ dp->dpcd[DPCD_RC02] &
+ DPCD_RC02_ENHANCED_FRAME_CAP);
+ if (ret) {
+ ERR("lnk_ctl failed with %d\n", ret);
+ return ret;
+ }
+
+ /* set desired link configuration on the sink */
+ sink[0] = dp->link_bw / 27000;
+ sink[1] = dp->link_nr;
+ if (dp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP)
+ sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN;
+
+ return nv_wraux(dp->aux, DPCD_LC00, sink, 2);
}
static void
@@ -294,8 +299,17 @@ nouveau_dp_train(struct nouveau_disp *disp, const struct nouveau_dp_func *func,
ret = nv_rdaux(dp->aux, 0x00000, dp->dpcd, sizeof(dp->dpcd));
if (ret) {
+ /* it's possible the display has been unplugged before we
+ * get here. we still need to execute the full set of
+ * vbios scripts, and program the OR at a high enough
+ * frequency to satisfy the target mode. failure to do
+ * so results at best in an UPDATE hanging, and at worst
+ * with PDISP running away to join the circus.
+ */
+ dp->dpcd[1] = link_bw[0] / 27000;
+ dp->dpcd[2] = 4;
+ dp->dpcd[3] = 0x00;
ERR("failed to read DPCD\n");
- return ret;
}
/* adjust required bandwidth for 8B/10B coding overhead */
@@ -328,8 +342,10 @@ nouveau_dp_train(struct nouveau_disp *disp, const struct nouveau_dp_func *func,
!dp_link_train_eq(dp))
break;
} else
- if (ret >= 1) {
- /* dp_set_link_config() handled training */
+ if (ret) {
+ /* dp_set_link_config() handled training, or
+ * we failed to communicate with the sink.
+ */
break;
}
@@ -344,5 +360,5 @@ nouveau_dp_train(struct nouveau_disp *disp, const struct nouveau_dp_func *func,
/* execute post-train script from vbios */
dp_link_train_fini(dp);
- return true;
+ return (ret < 0) ? false : true;
}