diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2013-11-03 22:40:36 -0500 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2013-11-08 00:39:57 -0500 |
commit | 8df1d0c07f18bd84ea7d8c7bc2cff45ba2b09680 (patch) | |
tree | 70e72b11046c63bb370b50220393a38c27c397c0 | |
parent | 4767fae8f8e28a3be8fbe7eedf7f843aab97cfba (diff) |
drm/nouveau/disp: semi-complete link training sequence even if display disappears
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r-- | drivers/gpu/drm/nouveau/core/engine/disp/dport.c | 48 |
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) | |||
70 | }; | 70 | }; |
71 | u32 lnkcmp; | 71 | u32 lnkcmp; |
72 | u8 sink[2]; | 72 | u8 sink[2]; |
73 | int ret; | ||
73 | 74 | ||
74 | DBG("%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw); | 75 | DBG("%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw); |
75 | 76 | ||
76 | /* set desired link configuration on the sink */ | ||
77 | sink[0] = dp->link_bw / 27000; | ||
78 | sink[1] = dp->link_nr; | ||
79 | if (dp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP) | ||
80 | sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN; | ||
81 | |||
82 | nv_wraux(dp->aux, DPCD_LC00, sink, 2); | ||
83 | |||
84 | /* set desired link configuration on the source */ | 77 | /* set desired link configuration on the source */ |
85 | if ((lnkcmp = dp->info.lnkcmp)) { | 78 | if ((lnkcmp = dp->info.lnkcmp)) { |
86 | if (dp->version < 0x30) { | 79 | if (dp->version < 0x30) { |
@@ -96,10 +89,22 @@ dp_set_link_config(struct dp_state *dp) | |||
96 | nvbios_exec(&init); | 89 | nvbios_exec(&init); |
97 | } | 90 | } |
98 | 91 | ||
99 | return dp->func->lnk_ctl(dp->disp, dp->outp, dp->head, | 92 | ret = dp->func->lnk_ctl(dp->disp, dp->outp, dp->head, |
100 | dp->link_nr, dp->link_bw / 27000, | 93 | dp->link_nr, dp->link_bw / 27000, |
101 | dp->dpcd[DPCD_RC02] & | 94 | dp->dpcd[DPCD_RC02] & |
102 | DPCD_RC02_ENHANCED_FRAME_CAP); | 95 | DPCD_RC02_ENHANCED_FRAME_CAP); |
96 | if (ret) { | ||
97 | ERR("lnk_ctl failed with %d\n", ret); | ||
98 | return ret; | ||
99 | } | ||
100 | |||
101 | /* set desired link configuration on the sink */ | ||
102 | sink[0] = dp->link_bw / 27000; | ||
103 | sink[1] = dp->link_nr; | ||
104 | if (dp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP) | ||
105 | sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN; | ||
106 | |||
107 | return nv_wraux(dp->aux, DPCD_LC00, sink, 2); | ||
103 | } | 108 | } |
104 | 109 | ||
105 | static void | 110 | static void |
@@ -294,8 +299,17 @@ nouveau_dp_train(struct nouveau_disp *disp, const struct nouveau_dp_func *func, | |||
294 | 299 | ||
295 | ret = nv_rdaux(dp->aux, 0x00000, dp->dpcd, sizeof(dp->dpcd)); | 300 | ret = nv_rdaux(dp->aux, 0x00000, dp->dpcd, sizeof(dp->dpcd)); |
296 | if (ret) { | 301 | if (ret) { |
302 | /* it's possible the display has been unplugged before we | ||
303 | * get here. we still need to execute the full set of | ||
304 | * vbios scripts, and program the OR at a high enough | ||
305 | * frequency to satisfy the target mode. failure to do | ||
306 | * so results at best in an UPDATE hanging, and at worst | ||
307 | * with PDISP running away to join the circus. | ||
308 | */ | ||
309 | dp->dpcd[1] = link_bw[0] / 27000; | ||
310 | dp->dpcd[2] = 4; | ||
311 | dp->dpcd[3] = 0x00; | ||
297 | ERR("failed to read DPCD\n"); | 312 | ERR("failed to read DPCD\n"); |
298 | return ret; | ||
299 | } | 313 | } |
300 | 314 | ||
301 | /* adjust required bandwidth for 8B/10B coding overhead */ | 315 | /* 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, | |||
328 | !dp_link_train_eq(dp)) | 342 | !dp_link_train_eq(dp)) |
329 | break; | 343 | break; |
330 | } else | 344 | } else |
331 | if (ret >= 1) { | 345 | if (ret) { |
332 | /* dp_set_link_config() handled training */ | 346 | /* dp_set_link_config() handled training, or |
347 | * we failed to communicate with the sink. | ||
348 | */ | ||
333 | break; | 349 | break; |
334 | } | 350 | } |
335 | 351 | ||
@@ -344,5 +360,5 @@ nouveau_dp_train(struct nouveau_disp *disp, const struct nouveau_dp_func *func, | |||
344 | 360 | ||
345 | /* execute post-train script from vbios */ | 361 | /* execute post-train script from vbios */ |
346 | dp_link_train_fini(dp); | 362 | dp_link_train_fini(dp); |
347 | return true; | 363 | return (ret < 0) ? false : true; |
348 | } | 364 | } |