Commit 6c22ea37 authored by Ben Skeggs's avatar Ben Skeggs
Browse files

drm/nouveau/disp: introduce acquire/release display path methods



These exist to give NVKM information on the set of display paths that
the DD needs to be active at any given time.

Previously, the supervisor attempted to determine this solely from OR
state, but there's a few configurations where this information on its
own isn't enough to determine the specific display paths in question:

- ANX9805, where the PIOR protocol for both DP and TMDS is TMDS.
- On a device using DCB Switched Outputs.
- On GM20x and newer, with a crossbar between the SOR and macro links.

After this commit, the DD tells NVKM *exactly* which display path it's
attempting a modeset on.

Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 3c66c87d
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -27,6 +27,8 @@ struct nv50_disp_scanoutpos_v0 {

struct nv50_disp_mthd_v1 {
	__u8  version;
#define NV50_DISP_MTHD_V1_ACQUIRE                                          0x01
#define NV50_DISP_MTHD_V1_RELEASE                                          0x02
#define NV50_DISP_MTHD_V1_DAC_LOAD                                         0x11
#define NV50_DISP_MTHD_V1_SOR_HDA_ELD                                      0x21
#define NV50_DISP_MTHD_V1_SOR_HDMI_PWR                                     0x22
@@ -39,6 +41,13 @@ struct nv50_disp_mthd_v1 {
	__u8  pad06[2];
};

struct nv50_disp_acquire_v0 {
	__u8  version;
	__u8  or;
	__u8  link;
	__u8  pad03[5];
};

struct nv50_disp_dac_load_v0 {
	__u8  version;
	__u8  load;
+2 −1
Original line number Diff line number Diff line
@@ -1533,7 +1533,8 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb,
	if (conf & 0x100000)
		entry->i2c_upper_default = true;

	entry->hasht = (entry->location << 4) | entry->type;
	entry->hasht = (entry->extdev << 8) | (entry->location << 4) |
			entry->type;
	entry->hashm = (entry->heads << 8) | (link << 6) | entry->or;
	return true;
}
+1 −0
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ struct nouveau_encoder {

	struct dcb_output *dcb;
	int or;
	int link;

	struct i2c_adapter *i2c;
	struct nvkm_i2c_aux *aux;
+69 −6
Original line number Diff line number Diff line
@@ -2403,6 +2403,51 @@ out:
/******************************************************************************
 * Output path helpers
 *****************************************************************************/
static void
nv50_outp_release(struct nouveau_encoder *nv_encoder)
{
	struct nv50_disp *disp = nv50_disp(nv_encoder->base.base.dev);
	struct {
		struct nv50_disp_mthd_v1 base;
	} args = {
		.base.version = 1,
		.base.method = NV50_DISP_MTHD_V1_RELEASE,
		.base.hasht  = nv_encoder->dcb->hasht,
		.base.hashm  = nv_encoder->dcb->hashm,
	};

	nvif_mthd(disp->disp, 0, &args, sizeof(args));
	nv_encoder->or = -1;
	nv_encoder->link = 0;
}

static int
nv50_outp_acquire(struct nouveau_encoder *nv_encoder)
{
	struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev);
	struct nv50_disp *disp = nv50_disp(drm->dev);
	struct {
		struct nv50_disp_mthd_v1 base;
		struct nv50_disp_acquire_v0 info;
	} args = {
		.base.version = 1,
		.base.method = NV50_DISP_MTHD_V1_ACQUIRE,
		.base.hasht  = nv_encoder->dcb->hasht,
		.base.hashm  = nv_encoder->dcb->hashm,
	};
	int ret;

	ret = nvif_mthd(disp->disp, 0, &args, sizeof(args));
	if (ret) {
		NV_ERROR(drm, "error acquiring output path: %d\n", ret);
		return ret;
	}

	nv_encoder->or = args.info.or;
	nv_encoder->link = args.info.link;
	return 0;
}

static int
nv50_outp_atomic_check_view(struct drm_encoder *encoder,
			    struct drm_crtc_state *crtc_state,
@@ -2482,6 +2527,7 @@ nv50_dac_disable(struct drm_encoder *encoder)
	}

	nv_encoder->crtc = NULL;
	nv50_outp_release(nv_encoder);
}

static void
@@ -2493,6 +2539,8 @@ nv50_dac_enable(struct drm_encoder *encoder)
	struct drm_display_mode *mode = &nv_crtc->base.state->adjusted_mode;
	u32 *push;

	nv50_outp_acquire(nv_encoder);

	push = evo_wait(mast, 8);
	if (push) {
		if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) {
@@ -2592,7 +2640,6 @@ nv50_dac_create(struct drm_connector *connector, struct dcb_output *dcbe)
	if (!nv_encoder)
		return -ENOMEM;
	nv_encoder->dcb = dcbe;
	nv_encoder->or = ffs(dcbe->or) - 1;

	bus = nvkm_i2c_bus_find(i2c, dcbe->i2c_index);
	if (bus)
@@ -2759,6 +2806,8 @@ struct nv50_mstm {
	struct nv50_msto *msto[4];

	bool modified;
	bool disabled;
	int links;
};

struct nv50_mstc {
@@ -2907,7 +2956,10 @@ nv50_msto_enable(struct drm_encoder *encoder)
	r = drm_dp_mst_allocate_vcpi(&mstm->mgr, mstc->port, mstc->pbn, slots);
	WARN_ON(!r);

	if (mstm->outp->dcb->sorconf.link & 1)
	if (!mstm->links++)
		nv50_outp_acquire(mstm->outp);

	if (mstm->outp->link & 1)
		proto = 0x8;
	else
		proto = 0x9;
@@ -2939,6 +2991,8 @@ nv50_msto_disable(struct drm_encoder *encoder)

	mstm->outp->update(mstm->outp, msto->head->base.index, NULL, 0, 0);
	mstm->modified = true;
	if (!--mstm->links)
		mstm->disabled = true;
	msto->disabled = true;
}

@@ -3154,6 +3208,12 @@ nv50_mstm_prepare(struct nv50_mstm *mstm)
				nv50_msto_prepare(msto);
		}
	}

	if (mstm->disabled) {
		if (!mstm->links)
			nv50_outp_release(mstm->outp);
		mstm->disabled = false;
	}
}

static void
@@ -3452,6 +3512,7 @@ nv50_sor_disable(struct drm_encoder *encoder)
		nv_encoder->update(nv_encoder, nv_crtc->index, NULL, 0, 0);
		nv50_audio_disable(encoder, nv_crtc);
		nv50_hdmi_disable(&nv_encoder->base.base, nv_crtc);
		nv50_outp_release(nv_encoder);
	}
}

@@ -3480,10 +3541,11 @@ nv50_sor_enable(struct drm_encoder *encoder)

	nv_connector = nouveau_encoder_connector_get(nv_encoder);
	nv_encoder->crtc = encoder->crtc;
	nv50_outp_acquire(nv_encoder);

	switch (nv_encoder->dcb->type) {
	case DCB_OUTPUT_TMDS:
		if (nv_encoder->dcb->sorconf.link & 1) {
		if (nv_encoder->link & 1) {
			proto = 0x1;
			/* Only enable dual-link if:
			 *  - Need to (i.e. rate > 165MHz)
@@ -3541,7 +3603,7 @@ nv50_sor_enable(struct drm_encoder *encoder)
		else
			depth = 0x6;

		if (nv_encoder->dcb->sorconf.link & 1)
		if (nv_encoder->link & 1)
			proto = 0x8;
		else
			proto = 0x9;
@@ -3600,7 +3662,6 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe)
	if (!nv_encoder)
		return -ENOMEM;
	nv_encoder->dcb = dcbe;
	nv_encoder->or = ffs(dcbe->or) - 1;
	nv_encoder->update = nv50_sor_update;

	encoder = to_drm_encoder(nv_encoder);
@@ -3673,6 +3734,7 @@ nv50_pior_disable(struct drm_encoder *encoder)
	}

	nv_encoder->crtc = NULL;
	nv50_outp_release(nv_encoder);
}

static void
@@ -3687,6 +3749,8 @@ nv50_pior_enable(struct drm_encoder *encoder)
	u8 proto, depth;
	u32 *push;

	nv50_outp_acquire(nv_encoder);

	nv_connector = nouveau_encoder_connector_get(nv_encoder);
	switch (nv_connector->base.display_info.bpc) {
	case 10: depth = 0x6; break;
@@ -3774,7 +3838,6 @@ nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe)
	if (!nv_encoder)
		return -ENOMEM;
	nv_encoder->dcb = dcbe;
	nv_encoder->or = ffs(dcbe->or) - 1;
	nv_encoder->i2c = ddc;
	nv_encoder->aux = aux;

+0 −5
Original line number Diff line number Diff line
@@ -24,7 +24,6 @@
#include "dp.h"
#include "conn.h"
#include "ior.h"
#include "nv50.h"

#include <subdev/bios.h>
#include <subdev/bios/init.h>
@@ -351,7 +350,6 @@ static const struct dp_rates {
static int
nvkm_dp_train(struct nvkm_dp *dp, u32 dataKBps)
{
	struct nv50_disp *disp = nv50_disp(dp->outp.disp);
	struct nvkm_ior *ior = dp->outp.ior;
	const u8 sink_nr = dp->dpcd[DPCD_RC02] & DPCD_RC02_MAX_LANE_COUNT;
	const u8 sink_bw = dp->dpcd[DPCD_RC01_MAX_LINK_RATE];
@@ -361,9 +359,6 @@ nvkm_dp_train(struct nvkm_dp *dp, u32 dataKBps)
	int ret = -EINVAL;
	u8  pwr;

	if (!dp->outp.info.location && disp->func->sor.magic)
		disp->func->sor.magic(&dp->outp);

	/* Find the lowest configuration of the OR that can support
	 * the required link rate.
	 *
Loading