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

Commit 2d14e35c authored by Francisco Jerez's avatar Francisco Jerez Committed by Ben Skeggs
Browse files

drm/nv30: Workaround dual TMDS brain damage.

parent bfe9dbcf
Loading
Loading
Loading
Loading
+35 −4
Original line number Diff line number Diff line
@@ -146,6 +146,36 @@ void nv04_dfp_update_fp_control(struct drm_encoder *encoder, int mode)
	}
}

static struct drm_encoder *get_tmds_slave(struct drm_encoder *encoder)
{
	struct drm_device *dev = encoder->dev;
	struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb;
	struct drm_encoder *slave;

	if (dcb->type != OUTPUT_TMDS || dcb->location == DCB_LOC_ON_CHIP)
		return NULL;

	/* Some BIOSes (e.g. the one in a Quadro FX1000) report several
	 * TMDS transmitters at the same I2C address, in the same I2C
	 * bus. This can still work because in that case one of them is
	 * always hard-wired to a reasonable configuration using straps,
	 * and the other one needs to be programmed.
	 *
	 * I don't think there's a way to know which is which, even the
	 * blob programs the one exposed via I2C for *both* heads, so
	 * let's do the same.
	 */
	list_for_each_entry(slave, &dev->mode_config.encoder_list, head) {
		struct dcb_entry *slave_dcb = nouveau_encoder(slave)->dcb;

		if (slave_dcb->type == OUTPUT_TMDS && get_slave_funcs(slave) &&
		    slave_dcb->tmdsconf.slave_addr == dcb->tmdsconf.slave_addr)
			return slave;
	}

	return NULL;
}

static bool nv04_dfp_mode_fixup(struct drm_encoder *encoder,
				struct drm_display_mode *mode,
				struct drm_display_mode *adjusted_mode)
@@ -432,9 +462,9 @@ static void nv04_dfp_commit(struct drm_encoder *encoder)
		NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + nv04_dac_output_offset(encoder), 0x00100000);

	/* Init external transmitters */
	if (get_slave_funcs(encoder))
		get_slave_funcs(encoder)->mode_set(encoder, &nv_encoder->mode,
						   &nv_encoder->mode);
	if (get_tmds_slave(encoder))
		get_slave_funcs(get_tmds_slave(encoder))->mode_set(
			encoder, &nv_encoder->mode, &nv_encoder->mode);

	helper->dpms(encoder, DRM_MODE_DPMS_ON);

@@ -581,7 +611,8 @@ static void nv04_tmds_slave_init(struct drm_encoder *encoder)
	};
	int type;

	if (!nv_gf4_disp_arch(dev) || !i2c)
	if (!nv_gf4_disp_arch(dev) || !i2c ||
	    get_tmds_slave(encoder))
		return;

	type = nouveau_i2c_identify(dev, "TMDS transmitter", info, 2);