aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2011-08-05 00:47:28 -0400
committerBen Skeggs <bskeggs@redhat.com>2011-09-20 02:11:21 -0400
commitc16a3a358b6460696b2dc275cbbab1adbbbd1f67 (patch)
tree506426a31390a624a7b4bfbb53dff6f62b774b5d /drivers/gpu
parent5f1800bd8a774f773e3be71702da7ec77188b283 (diff)
drm/nouveau/dp: add support for displayport table 0x30
Written from observations of my NVD9's vbios, completely untested due to my NVD9 lacking actual DisplayPort connectors.. Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dp.c70
1 files changed, 48 insertions, 22 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c
index 25ecb776c7bc..de5efe71fefd 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dp.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dp.c
@@ -298,6 +298,7 @@ nouveau_dp_bios_data(struct drm_device *dev, struct dcb_entry *dcb, u8 **entry)
298 switch (table[0]) { 298 switch (table[0]) {
299 case 0x20: 299 case 0x20:
300 case 0x21: 300 case 0x21:
301 case 0x30:
301 break; 302 break;
302 default: 303 default:
303 NV_ERROR(dev, "displayport table 0x%02x unknown\n", table[0]); 304 NV_ERROR(dev, "displayport table 0x%02x unknown\n", table[0]);
@@ -339,6 +340,7 @@ dp_set_link_config(struct drm_device *dev, struct dp_state *dp)
339 int or = dp->or, link = dp->link; 340 int or = dp->or, link = dp->link;
340 u8 *entry, sink[2]; 341 u8 *entry, sink[2];
341 u32 dp_ctrl; 342 u32 dp_ctrl;
343 u16 script;
342 344
343 NV_DEBUG_KMS(dev, "%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw); 345 NV_DEBUG_KMS(dev, "%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw);
344 346
@@ -360,10 +362,17 @@ dp_set_link_config(struct drm_device *dev, struct dp_state *dp)
360 */ 362 */
361 entry = ROMPTR(&dev_priv->vbios, dp->entry[10]); 363 entry = ROMPTR(&dev_priv->vbios, dp->entry[10]);
362 if (entry) { 364 if (entry) {
363 while (dp->link_bw < (ROM16(entry[0]) * 10)) 365 if (dp->table[0] < 0x30) {
364 entry += 4; 366 while (dp->link_bw < (ROM16(entry[0]) * 10))
367 entry += 4;
368 script = ROM16(entry[2]);
369 } else {
370 while (dp->link_bw < (entry[0] * 27000))
371 entry += 3;
372 script = ROM16(entry[1]);
373 }
365 374
366 nouveau_bios_run_init_table(dev, ROM16(entry[2]), dp->dcb, dp->crtc); 375 nouveau_bios_run_init_table(dev, script, dp->dcb, dp->crtc);
367 } 376 }
368 377
369 /* configure lane count on the source */ 378 /* configure lane count on the source */
@@ -414,33 +423,50 @@ dp_link_train_commit(struct drm_device *dev, struct dp_state *dp)
414 shifts = nvaf_lane_map; 423 shifts = nvaf_lane_map;
415 424
416 for (i = 0; i < dp->link_nr; i++) { 425 for (i = 0; i < dp->link_nr; i++) {
417 u8 lane = (dp->stat[4 + (i >> 1)] >> ((i & 1) * 4)) & 0xf;
418 u8 *conf = dp->entry + dp->table[4]; 426 u8 *conf = dp->entry + dp->table[4];
419 u8 *last = conf + (dp->entry[4] * dp->table[5]); 427 u8 lane = (dp->stat[4 + (i >> 1)] >> ((i & 1) * 4)) & 0xf;
420 428 u8 lpre = (lane & 0x0c) >> 2;
421 while (conf < last) { 429 u8 lvsw = (lane & 0x03) >> 0;
422 if ((lane & 3) == conf[0] &&
423 (lane >> 2) == conf[1])
424 break;
425 conf += 5;
426 }
427 430
428 if (conf == last) 431 mask |= 0xff << shifts[i];
429 return -EINVAL; 432 unk |= 1 << (shifts[i] >> 3);
430 433
431 dp->conf[i] = (conf[1] << 3) | conf[0]; 434 dp->conf[i] = (lpre << 3) | lvsw;
432 if (conf[0] == DP_TRAIN_VOLTAGE_SWING_1200) 435 if (lvsw == DP_TRAIN_VOLTAGE_SWING_1200)
433 dp->conf[i] |= DP_TRAIN_MAX_SWING_REACHED; 436 dp->conf[i] |= DP_TRAIN_MAX_SWING_REACHED;
434 if (conf[1] == DP_TRAIN_PRE_EMPHASIS_9_5) 437 if (lpre == DP_TRAIN_PRE_EMPHASIS_9_5)
435 dp->conf[i] |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED; 438 dp->conf[i] |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
436 439
437 NV_DEBUG_KMS(dev, "config lane %d %02x\n", i, dp->conf[i]); 440 NV_DEBUG_KMS(dev, "config lane %d %02x\n", i, dp->conf[i]);
438 441
439 mask |= 0xff << shifts[i]; 442 if (dp->table[0] < 0x30) {
440 drv |= conf[2] << shifts[i]; 443 u8 *last = conf + (dp->entry[4] * dp->table[5]);
441 pre |= conf[3] << shifts[i]; 444 while (lvsw != conf[0] || lpre != conf[1]) {
442 unk = (unk & ~0x0000ff00) | (conf[4] << 8); 445 conf += dp->table[5];
443 unk |= 1 << (shifts[i] >> 3); 446 if (conf >= last)
447 return -EINVAL;
448 }
449
450 conf += 2;
451 } else {
452 /* no lookup table anymore, set entries for each
453 * combination of voltage swing and pre-emphasis
454 * level allowed by the DP spec.
455 */
456 switch (lvsw) {
457 case 0: lpre += 0; break;
458 case 1: lpre += 4; break;
459 case 2: lpre += 7; break;
460 case 3: lpre += 9; break;
461 }
462
463 conf = conf + (lpre * dp->table[5]);
464 conf++;
465 }
466
467 drv |= conf[0] << shifts[i];
468 pre |= conf[1] << shifts[i];
469 unk = (unk & ~0x0000ff00) | (conf[2] << 8);
444 } 470 }
445 471
446 nv_mask(dev, NV50_SOR_DP_UNK118(or, link), mask, drv); 472 nv_mask(dev, NV50_SOR_DP_UNK118(or, link), mask, drv);