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

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

drm/nv50: fix suspend/resume with DP outputs



Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 17b96cc3
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -48,6 +48,8 @@ struct nouveau_encoder {
	union {
		struct {
			int mc_unknown;
			uint32_t unk0;
			uint32_t unk1;
			int dpcd_version;
			int link_nr;
			int link_bw;
+1 −0
Original line number Diff line number Diff line
@@ -826,6 +826,7 @@
#define NV50_SOR_DP_CTRL_TRAINING_PATTERN_2                          0x02000000
#define NV50_SOR_DP_UNK118(i,l)          (0x0061c118 + (i) * 0x800 + (l) * 0x80)
#define NV50_SOR_DP_UNK120(i,l)          (0x0061c120 + (i) * 0x800 + (l) * 0x80)
#define NV50_SOR_DP_UNK128(i,l)          (0x0061c128 + (i) * 0x800 + (l) * 0x80)
#define NV50_SOR_DP_UNK130(i,l)          (0x0061c130 + (i) * 0x800 + (l) * 0x80)

#define NV50_PDISPLAY_USER(i)                        ((i) * 0x1000 + 0x00640000)
+33 −0
Original line number Diff line number Diff line
@@ -783,6 +783,37 @@ nv50_display_unk10_handler(struct drm_device *dev)
	nv_wr32(dev, 0x610030, 0x80000000);
}

static void
nv50_display_unk20_dp_hack(struct drm_device *dev, struct dcb_entry *dcb)
{
	int or = ffs(dcb->or) - 1, link = !(dcb->dpconf.sor.link & 1);
	struct drm_encoder *encoder;
	uint32_t tmp, unk0 = 0, unk1 = 0;

	if (dcb->type != OUTPUT_DP)
		return;

	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
		struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);

		if (nv_encoder->dcb == dcb) {
			unk0 = nv_encoder->dp.unk0;
			unk1 = nv_encoder->dp.unk1;
			break;
		}
	}

	if (unk0 || unk1) {
		tmp  = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link));
		tmp &= 0xfffffe03;
		nv_wr32(dev, NV50_SOR_DP_CTRL(or, link), tmp | unk0);

		tmp  = nv_rd32(dev, NV50_SOR_DP_UNK128(or, link));
		tmp &= 0xfef080c0;
		nv_wr32(dev, NV50_SOR_DP_UNK128(or, link), tmp | unk1);
	}
}

static void
nv50_display_unk20_handler(struct drm_device *dev)
{
@@ -806,6 +837,8 @@ nv50_display_unk20_handler(struct drm_device *dev)

	nouveau_bios_run_display_table(dev, dcbent, script, pclk);

	nv50_display_unk20_dp_hack(dev, dcbent);

	tmp = nv_rd32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(head));
	tmp &= ~0x000000f;
	nv_wr32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(head), tmp);
+10 −5
Original line number Diff line number Diff line
@@ -321,18 +321,23 @@ nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry)
	encoder->possible_clones = 0;

	if (nv_encoder->dcb->type == OUTPUT_DP) {
		uint32_t mc, or = nv_encoder->or;
		int or = nv_encoder->or, link = !(entry->dpconf.sor.link & 1);
		uint32_t tmp;

		if (dev_priv->chipset < 0x90 ||
		    dev_priv->chipset == 0x92 || dev_priv->chipset == 0xa0)
			mc = nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_C(or));
			tmp = nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_C(or));
		else
			mc = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_C(or));
			tmp = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_C(or));

		switch ((mc & 0x00000f00) >> 8) {
		switch ((tmp & 0x00000f00) >> 8) {
		case 8:
		case 9:
			nv_encoder->dp.mc_unknown = (mc & 0x000f0000) >> 16;
			nv_encoder->dp.mc_unknown = (tmp & 0x000f0000) >> 16;
			tmp = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link));
			nv_encoder->dp.unk0 = tmp & 0x000001fc;
			tmp = nv_rd32(dev, NV50_SOR_DP_UNK128(or, link));
			nv_encoder->dp.unk1 = tmp & 0x010f7f3f;
			break;
		default:
			break;