Commit c16a3a35 authored by Ben Skeggs's avatar Ben Skeggs
Browse files

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: default avatarBen Skeggs <bskeggs@redhat.com>
parent 5f1800bd
Loading
Loading
Loading
Loading
+48 −22
Original line number Diff line number Diff line
@@ -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) {
		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);