Commit 63371650 authored by Ben Skeggs's avatar Ben Skeggs Committed by Lyude Paul
Browse files

drm/nouveau/disp: add dp train method



- passes DPCD information from DRM to NVKM
- removes NVKM's own sink caps handling
- link still trained from supervisor, more patches to come

Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
Reviewed-by: default avatarLyude Paul <lyude@redhat.com>
Acked-by: default avatarDanilo Krummrich <me@dakr.org>
Signed-off-by: default avatarLyude Paul <lyude@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20230919220442.202488-33-lyude@redhat.com
parent 75703380
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -1038,7 +1038,7 @@ nv50_msto_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *st

	if (!mstm->links++) {
		nvif_outp_acquire_sor(&mstm->outp->outp, false /*TODO: MST audio... */);
		nvif_outp_acquire_dp(&mstm->outp->outp, mstm->outp->dp.dpcd, 0, 0, false, true);
		nouveau_dp_train(mstm->outp, true, 0, 0);
	}

	if (mstm->outp->outp.or.link & 1)
@@ -1661,7 +1661,7 @@ nv50_sor_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *sta
		nvif_outp_lvds(&nv_encoder->outp, lvds_dual, lvds_8bpc);
		break;
	case DCB_OUTPUT_DP:
		nvif_outp_acquire_dp(&nv_encoder->outp, nv_encoder->dp.dpcd, 0, 0, hda, false);
		nouveau_dp_train(nv_encoder, false, mode->clock, asyh->or.bpc);
		depth = nv50_dp_bpc_to_depth(asyh->or.bpc);

		if (nv_encoder->outp.or.link & 1)
@@ -1852,7 +1852,7 @@ nv50_pior_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *st
		break;
	case DCB_OUTPUT_DP:
		ctrl |= NVDEF(NV507D, PIOR_SET_CONTROL, PROTOCOL, EXT_TMDS_ENC);
		nvif_outp_acquire_dp(&nv_encoder->outp, nv_encoder->dp.dpcd, 0, 0, false, false);
		nouveau_dp_train(nv_encoder, false, asyh->state.adjusted_mode.clock, 6);
		break;
	default:
		BUG();
+12 −13
Original line number Diff line number Diff line
@@ -34,7 +34,7 @@ union nvif_outp_args {
#define NVIF_OUTP_V0_DP_AUX_PWR    0x70
#define NVIF_OUTP_V0_DP_AUX_XFER   0x71
#define NVIF_OUTP_V0_DP_RATES      0x72
#define NVIF_OUTP_V0_DP_RETRAIN    0x73
#define NVIF_OUTP_V0_DP_TRAIN      0x73
#define NVIF_OUTP_V0_DP_MST_VCPI   0x78

union nvif_outp_detect_args {
@@ -71,7 +71,6 @@ union nvif_outp_acquire_args {
#define NVIF_OUTP_ACQUIRE_V0_DAC  0x00
#define NVIF_OUTP_ACQUIRE_V0_SOR  0x01
#define NVIF_OUTP_ACQUIRE_V0_PIOR 0x02
#define NVIF_OUTP_ACQUIRE_V0_DP      0x04
		__u8 type;
		__u8 or;
		__u8 link;
@@ -80,14 +79,6 @@ union nvif_outp_acquire_args {
			struct {
				__u8 hda;
			} sor;
			struct {
				__u8 link_nr; /* 0 = highest possible. */
				__u8 link_bw; /* 0 = highest possible, DP BW code otherwise. */
				__u8 hda;
				__u8 mst;
				__u8 pad04[4];
				__u8 dpcd[DP_RECEIVER_CAP_SIZE];
			} dp;
		};
	} v0;
};
@@ -207,9 +198,17 @@ union nvif_outp_dp_rates_args {
	} v0;
};

union nvif_outp_dp_retrain_args {
	struct nvif_outp_dp_retrain_vn {
	} vn;
union nvif_outp_dp_train_args {
	struct nvif_outp_dp_train_v0 {
		__u8  version;
		__u8  retrain;
		__u8  mst;
		__u8  lttprs;
		__u8  post_lt_adj;
		__u8  link_nr;
		__u32 link_bw;
		__u8 dpcd[DP_RECEIVER_CAP_SIZE];
	} v0;
};

union nvif_outp_dp_mst_vcpi_args {
+3 −4
Original line number Diff line number Diff line
@@ -31,8 +31,6 @@ int nvif_outp_load_detect(struct nvif_outp *, u32 loadval);
int nvif_outp_acquire_dac(struct nvif_outp *);
int nvif_outp_acquire_sor(struct nvif_outp *, bool hda);
int nvif_outp_acquire_pior(struct nvif_outp *);
int nvif_outp_acquire_dp(struct nvif_outp *outp, u8 dpcd[DP_RECEIVER_CAP_SIZE],
			 int link_nr, int link_bw, bool hda, bool mst);
int nvif_outp_inherit_rgb_crt(struct nvif_outp *outp, u8 *proto_out);
int nvif_outp_inherit_lvds(struct nvif_outp *outp, u8 *proto_out);
int nvif_outp_inherit_tmds(struct nvif_outp *outp, u8 *proto_out);
@@ -66,8 +64,9 @@ struct nvif_outp_dp_rate {
};

int nvif_outp_dp_rates(struct nvif_outp *, struct nvif_outp_dp_rate *rate, int rate_nr);

int nvif_outp_dp_retrain(struct nvif_outp *);
int nvif_outp_dp_train(struct nvif_outp *, u8 dpcd[DP_RECEIVER_CAP_SIZE],
		       u8 lttprs, u8 link_nr, u32 link_bw, bool mst, bool post_lt_adj,
		       bool retrain);
int nvif_outp_dp_mst_vcpi(struct nvif_outp *, int head,
			  u8 start_slot, u8 num_slots, u16 pbn, u16 aligned_pbn);
#endif
+68 −7
Original line number Diff line number Diff line
@@ -79,9 +79,22 @@ nouveau_dp_probe_dpcd(struct nouveau_connector *nv_connector,
	    !drm_dp_read_lttpr_common_caps(aux, dpcd, outp->dp.lttpr.caps)) {
		int nr = drm_dp_lttpr_count(outp->dp.lttpr.caps);

		if (nr > 0)
		if (nr) {
			drm_dp_dpcd_writeb(aux, DP_PHY_REPEATER_MODE,
						DP_PHY_REPEATER_MODE_TRANSPARENT);

			if (nr > 0) {
				ret = drm_dp_dpcd_writeb(aux, DP_PHY_REPEATER_MODE,
							      DP_PHY_REPEATER_MODE_NON_TRANSPARENT);
				if (ret != 1) {
					drm_dp_dpcd_writeb(aux, DP_PHY_REPEATER_MODE,
								DP_PHY_REPEATER_MODE_TRANSPARENT);
				} else {
					outp->dp.lttpr.nr = nr;
				}
			}
		}
	}

	ret = drm_dp_read_dpcd_caps(aux, dpcd);
	if (ret < 0)
@@ -291,23 +304,71 @@ nouveau_dp_power_down(struct nouveau_encoder *outp)
	int ret;
	u8 pwr;

	mutex_lock(&outp->dp.hpd_irq_lock);

	ret = drm_dp_dpcd_readb(aux, DP_SET_POWER, &pwr);
	if (ret == 1) {
		pwr &= ~DP_SET_POWER_MASK;
		pwr |=  DP_SET_POWER_D3;
		drm_dp_dpcd_writeb(aux, DP_SET_POWER, pwr);
	}

	outp->dp.lt.nr = 0;
	mutex_unlock(&outp->dp.hpd_irq_lock);
}

static bool
nouveau_dp_train_link(struct nouveau_encoder *outp, bool retrain)
{
	int ret;

	ret = nvif_outp_dp_train(&outp->outp, outp->dp.dpcd,
					      outp->dp.lttpr.nr,
					      outp->dp.lt.nr,
					      outp->dp.lt.bw,
					      outp->dp.lt.mst,
					      false,
					      retrain);

	return ret == 0;
}

bool
nouveau_dp_train(struct nouveau_encoder *outp, bool mst, u32 khz, u8 bpc)
{
	bool ret;

	mutex_lock(&outp->dp.hpd_irq_lock);

	outp->dp.lt.nr = outp->dp.link_nr;
	outp->dp.lt.bw = 0;
	outp->dp.lt.mst = mst;
	ret = nouveau_dp_train_link(outp, false);

	mutex_unlock(&outp->dp.hpd_irq_lock);
	return ret;
}

static bool
nouveau_dp_link_check_locked(struct nouveau_encoder *outp)
{
	return nouveau_dp_train_link(outp, true);
}

bool
nouveau_dp_link_check(struct nouveau_connector *nv_connector)
{
	struct nouveau_encoder *nv_encoder = find_encoder(&nv_connector->base, DCB_OUTPUT_DP);
	struct nouveau_encoder *outp = nv_connector->dp_encoder;
	bool link_ok = true;

	if (!nv_encoder || nv_encoder->outp.or.id < 0)
		return true;
	if (outp) {
		mutex_lock(&outp->dp.hpd_irq_lock);
		if (outp->dp.lt.nr)
			link_ok = nouveau_dp_link_check_locked(outp);
		mutex_unlock(&outp->dp.hpd_irq_lock);
	}

	return nvif_outp_dp_retrain(&nv_encoder->outp) == 0;
	return link_ok;
}

void
+7 −0
Original line number Diff line number Diff line
@@ -89,6 +89,12 @@ struct nouveau_encoder {
			int link_nr;
			int link_bw;

			struct {
				bool mst;
				u8   nr;
				u32  bw;
			} lt;

			/* Protects DP state that needs to be accessed outside
			 * connector reprobing contexts
			 */
@@ -155,6 +161,7 @@ enum nouveau_dp_status {
};

int nouveau_dp_detect(struct nouveau_connector *, struct nouveau_encoder *);
bool nouveau_dp_train(struct nouveau_encoder *, bool mst, u32 khz, u8 bpc);
void nouveau_dp_power_down(struct nouveau_encoder *);
bool nouveau_dp_link_check(struct nouveau_connector *);
void nouveau_dp_irq(struct work_struct *);
Loading