aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2014-05-15 20:49:28 -0400
committerBen Skeggs <bskeggs@redhat.com>2014-06-11 02:09:13 -0400
commit1f86ca1a2e555abb11681f31c17d2fd1b11ac6cf (patch)
tree48b1e0420c34ebe47ecdca860d3ba05ac7900aae
parent04e7e92d53d83e3595373311ca21aad6a33ba2f6 (diff)
drm/nouveau/disp/dp: support training to highest rate, rather than a target
We really want this for, at least, MST devices. Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/dport.c57
1 files changed, 34 insertions, 23 deletions
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/dport.c b/drivers/gpu/drm/nouveau/core/engine/disp/dport.c
index 758d2eace928..3814c3d33812 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/dport.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/dport.c
@@ -293,20 +293,36 @@ dp_link_train_fini(struct dp_state *dp)
293 nvbios_exec(&init); 293 nvbios_exec(&init);
294} 294}
295 295
296static const struct dp_rates {
297 u32 rate;
298 u8 bw;
299 u8 nr;
300} nouveau_dp_rates[] = {
301 { 2160000, 0x14, 4 },
302 { 1080000, 0x0a, 4 },
303 { 1080000, 0x14, 2 },
304 { 648000, 0x06, 4 },
305 { 540000, 0x0a, 2 },
306 { 540000, 0x14, 1 },
307 { 324000, 0x06, 2 },
308 { 270000, 0x0a, 1 },
309 { 162000, 0x06, 1 },
310 {}
311};
312
296int 313int
297nouveau_dp_train(struct nouveau_disp *disp, const struct nouveau_dp_func *func, 314nouveau_dp_train(struct nouveau_disp *disp, const struct nouveau_dp_func *func,
298 struct dcb_output *outp, int head, u32 datarate) 315 struct dcb_output *outp, int head, u32 datarate)
299{ 316{
300 struct nouveau_bios *bios = nouveau_bios(disp); 317 struct nouveau_bios *bios = nouveau_bios(disp);
301 struct nouveau_i2c *i2c = nouveau_i2c(disp); 318 struct nouveau_i2c *i2c = nouveau_i2c(disp);
319 const struct dp_rates *cfg = nouveau_dp_rates;
302 struct dp_state _dp = { 320 struct dp_state _dp = {
303 .disp = disp, 321 .disp = disp,
304 .func = func, 322 .func = func,
305 .outp = outp, 323 .outp = outp,
306 .head = head, 324 .head = head,
307 }, *dp = &_dp; 325 }, *dp = &_dp;
308 const u32 bw_list[] = { 540000, 270000, 162000, 0 };
309 const u32 *link_bw = bw_list;
310 u8 hdr, cnt, len; 326 u8 hdr, cnt, len;
311 u32 data; 327 u32 data;
312 int ret; 328 int ret;
@@ -338,8 +354,8 @@ nouveau_dp_train(struct nouveau_disp *disp, const struct nouveau_dp_func *func,
338 * so results at best in an UPDATE hanging, and at worst 354 * so results at best in an UPDATE hanging, and at worst
339 * with PDISP running away to join the circus. 355 * with PDISP running away to join the circus.
340 */ 356 */
341 dp->dpcd[1] = link_bw[0] / 27000; 357 dp->dpcd[1] = dp->outp->dpconf.link_bw;
342 dp->dpcd[2] = 4; 358 dp->dpcd[2] = dp->outp->dpconf.link_nr;
343 dp->dpcd[3] = 0x00; 359 dp->dpcd[3] = 0x00;
344 ERR("failed to read DPCD\n"); 360 ERR("failed to read DPCD\n");
345 } 361 }
@@ -355,26 +371,24 @@ nouveau_dp_train(struct nouveau_disp *disp, const struct nouveau_dp_func *func,
355 dp->dpcd[1] = dp->outp->dpconf.link_bw; 371 dp->dpcd[1] = dp->outp->dpconf.link_bw;
356 dp->pc2 = dp->dpcd[2] & DPCD_RC02_TPS3_SUPPORTED; 372 dp->pc2 = dp->dpcd[2] & DPCD_RC02_TPS3_SUPPORTED;
357 373
358 /* adjust required bandwidth for 8B/10B coding overhead */ 374 /* restrict link config to the lowest required rate, if requested */
359 datarate = (datarate / 8) * 10; 375 if (datarate) {
376 datarate = (datarate / 8) * 10; /* 8B/10B coding overhead */
377 while (cfg[1].rate >= datarate)
378 cfg++;
379 }
380 cfg--;
360 381
361 /* enable down-spreading and execute pre-train script from vbios */ 382 /* enable down-spreading and execute pre-train script from vbios */
362 dp_link_train_init(dp, dp->dpcd[3] & 0x01); 383 dp_link_train_init(dp, dp->dpcd[3] & 0x01);
363 384
364 /* start off at highest link rate supported by encoder and display */ 385 while (ret = -EIO, (++cfg)->rate) {
365 while (*link_bw > (dp->dpcd[1] * 27000)) 386 /* select next configuration supported by encoder and sink */
366 link_bw++; 387 while (cfg->nr > (dp->dpcd[2] & DPCD_RC02_MAX_LANE_COUNT) ||
367 388 cfg->bw > (dp->dpcd[DPCD_RC01_MAX_LINK_RATE]))
368 while ((ret = -EIO) && link_bw[0]) { 389 cfg++;
369 /* find minimum required lane count at this link rate */ 390 dp->link_bw = cfg->bw * 27000;
370 dp->link_nr = dp->dpcd[2] & DPCD_RC02_MAX_LANE_COUNT; 391 dp->link_nr = cfg->nr;
371 while ((dp->link_nr >> 1) * link_bw[0] > datarate)
372 dp->link_nr >>= 1;
373
374 /* drop link rate to minimum with this lane count */
375 while ((link_bw[1] * dp->link_nr) > datarate)
376 link_bw++;
377 dp->link_bw = link_bw[0];
378 392
379 /* program selected link configuration */ 393 /* program selected link configuration */
380 ret = dp_set_link_config(dp); 394 ret = dp_set_link_config(dp);
@@ -391,9 +405,6 @@ nouveau_dp_train(struct nouveau_disp *disp, const struct nouveau_dp_func *func,
391 */ 405 */
392 break; 406 break;
393 } 407 }
394
395 /* retry at lower rate */
396 link_bw++;
397 } 408 }
398 409
399 /* finish link training */ 410 /* finish link training */