Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8df1d0c0 authored by Ben Skeggs's avatar Ben Skeggs
Browse files

drm/nouveau/disp: semi-complete link training sequence even if display disappears



Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 4767fae8
Loading
Loading
Loading
Loading
+32 −16
Original line number Diff line number Diff line
@@ -70,17 +70,10 @@ dp_set_link_config(struct dp_state *dp)
	};
	u32 lnkcmp;
	u8 sink[2];
	int ret;

	DBG("%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw);

	/* set desired link configuration on the sink */
	sink[0] = dp->link_bw / 27000;
	sink[1] = dp->link_nr;
	if (dp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP)
		sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN;

	nv_wraux(dp->aux, DPCD_LC00, sink, 2);

	/* set desired link configuration on the source */
	if ((lnkcmp = dp->info.lnkcmp)) {
		if (dp->version < 0x30) {
@@ -96,10 +89,22 @@ dp_set_link_config(struct dp_state *dp)
		nvbios_exec(&init);
	}

	return dp->func->lnk_ctl(dp->disp, dp->outp, dp->head,
	ret = dp->func->lnk_ctl(dp->disp, dp->outp, dp->head,
				dp->link_nr, dp->link_bw / 27000,
				dp->dpcd[DPCD_RC02] &
					 DPCD_RC02_ENHANCED_FRAME_CAP);
	if (ret) {
		ERR("lnk_ctl failed with %d\n", ret);
		return ret;
	}

	/* set desired link configuration on the sink */
	sink[0] = dp->link_bw / 27000;
	sink[1] = dp->link_nr;
	if (dp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP)
		sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN;

	return nv_wraux(dp->aux, DPCD_LC00, sink, 2);
}

static void
@@ -294,8 +299,17 @@ nouveau_dp_train(struct nouveau_disp *disp, const struct nouveau_dp_func *func,

	ret = nv_rdaux(dp->aux, 0x00000, dp->dpcd, sizeof(dp->dpcd));
	if (ret) {
		/* it's possible the display has been unplugged before we
		 * get here.  we still need to execute the full set of
		 * vbios scripts, and program the OR at a high enough
		 * frequency to satisfy the target mode.  failure to do
		 * so results at best in an UPDATE hanging, and at worst
		 * with PDISP running away to join the circus.
		 */
		dp->dpcd[1] = link_bw[0] / 27000;
		dp->dpcd[2] = 4;
		dp->dpcd[3] = 0x00;
		ERR("failed to read DPCD\n");
		return ret;
	}

	/* adjust required bandwidth for 8B/10B coding overhead */
@@ -328,8 +342,10 @@ nouveau_dp_train(struct nouveau_disp *disp, const struct nouveau_dp_func *func,
			    !dp_link_train_eq(dp))
				break;
		} else
		if (ret >= 1) {
			/* dp_set_link_config() handled training */
		if (ret) {
			/* dp_set_link_config() handled training, or
			 * we failed to communicate with the sink.
			 */
			break;
		}

@@ -344,5 +360,5 @@ nouveau_dp_train(struct nouveau_disp *disp, const struct nouveau_dp_func *func,

	/* execute post-train script from vbios */
	dp_link_train_fini(dp);
	return true;
	return (ret < 0) ? false : true;
}