diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2011-08-05 00:47:28 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2011-09-20 02:11:21 -0400 |
commit | c16a3a358b6460696b2dc275cbbab1adbbbd1f67 (patch) | |
tree | 506426a31390a624a7b4bfbb53dff6f62b774b5d /drivers/gpu | |
parent | 5f1800bd8a774f773e3be71702da7ec77188b283 (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.c | 70 |
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); |