From 8df1d0c07f18bd84ea7d8c7bc2cff45ba2b09680 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 4 Nov 2013 13:40:36 +1000 Subject: [PATCH] drm/nouveau/disp: semi-complete link training sequence even if display disappears Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/core/engine/disp/dport.c | 48 ++++++++++++------- 1 file 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; } -- 2.34.1