diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_dp.c')
-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 25ecb776c7b..de5efe71fef 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) switch (table[0]) { case 0x20: case 0x21: + case 0x30: break; default: 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) int or = dp->or, link = dp->link; u8 *entry, sink[2]; u32 dp_ctrl; + u16 script; NV_DEBUG_KMS(dev, "%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw); @@ -360,10 +362,17 @@ dp_set_link_config(struct drm_device *dev, struct dp_state *dp) */ entry = ROMPTR(&dev_priv->vbios, dp->entry[10]); if (entry) { - while (dp->link_bw < (ROM16(entry[0]) * 10)) - entry += 4; + if (dp->table[0] < 0x30) { + while (dp->link_bw < (ROM16(entry[0]) * 10)) + entry += 4; + script = ROM16(entry[2]); + } else { + while (dp->link_bw < (entry[0] * 27000)) + entry += 3; + script = ROM16(entry[1]); + } - nouveau_bios_run_init_table(dev, ROM16(entry[2]), dp->dcb, dp->crtc); + nouveau_bios_run_init_table(dev, script, dp->dcb, dp->crtc); } /* configure lane count on the source */ @@ -414,33 +423,50 @@ dp_link_train_commit(struct drm_device *dev, struct dp_state *dp) shifts = nvaf_lane_map; for (i = 0; i < dp->link_nr; i++) { - u8 lane = (dp->stat[4 + (i >> 1)] >> ((i & 1) * 4)) & 0xf; u8 *conf = dp->entry + dp->table[4]; - u8 *last = conf + (dp->entry[4] * dp->table[5]); - - while (conf < last) { - if ((lane & 3) == conf[0] && - (lane >> 2) == conf[1]) - break; - conf += 5; - } + u8 lane = (dp->stat[4 + (i >> 1)] >> ((i & 1) * 4)) & 0xf; + u8 lpre = (lane & 0x0c) >> 2; + u8 lvsw = (lane & 0x03) >> 0; - if (conf == last) - return -EINVAL; + mask |= 0xff << shifts[i]; + unk |= 1 << (shifts[i] >> 3); - dp->conf[i] = (conf[1] << 3) | conf[0]; - if (conf[0] == DP_TRAIN_VOLTAGE_SWING_1200) + dp->conf[i] = (lpre << 3) | lvsw; + if (lvsw == DP_TRAIN_VOLTAGE_SWING_1200) dp->conf[i] |= DP_TRAIN_MAX_SWING_REACHED; - if (conf[1] == DP_TRAIN_PRE_EMPHASIS_9_5) + if (lpre == DP_TRAIN_PRE_EMPHASIS_9_5) dp->conf[i] |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED; NV_DEBUG_KMS(dev, "config lane %d %02x\n", i, dp->conf[i]); - mask |= 0xff << shifts[i]; - drv |= conf[2] << shifts[i]; - pre |= conf[3] << shifts[i]; - unk = (unk & ~0x0000ff00) | (conf[4] << 8); - unk |= 1 << (shifts[i] >> 3); + if (dp->table[0] < 0x30) { + u8 *last = conf + (dp->entry[4] * dp->table[5]); + while (lvsw != conf[0] || lpre != conf[1]) { + conf += dp->table[5]; + if (conf >= last) + return -EINVAL; + } + + conf += 2; + } else { + /* no lookup table anymore, set entries for each + * combination of voltage swing and pre-emphasis + * level allowed by the DP spec. + */ + switch (lvsw) { + case 0: lpre += 0; break; + case 1: lpre += 4; break; + case 2: lpre += 7; break; + case 3: lpre += 9; break; + } + + conf = conf + (lpre * dp->table[5]); + conf++; + } + + drv |= conf[0] << shifts[i]; + pre |= conf[1] << shifts[i]; + unk = (unk & ~0x0000ff00) | (conf[2] << 8); } nv_mask(dev, NV50_SOR_DP_UNK118(or, link), mask, drv); |