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

Commit 6c9547ff authored by Chris Wilson's avatar Chris Wilson
Browse files

drm/i915/sdvo: Preserve pixel-multiplier



Store the pixel-multiplier on the adjusted mode and avoid modifying the
requested mode.

Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
parent 57cd6508
Loading
Loading
Loading
Loading
+16 −9
Original line number Diff line number Diff line
@@ -3519,7 +3519,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
	int trans_dpll_sel = (pipe == 0) ? 0 : 1;
	int lvds_reg = LVDS;
	u32 temp;
	int sdvo_pixel_multiply;
	int target_clock;

	drm_vblank_pre_modeset(dev, pipe);
@@ -3770,12 +3769,14 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
		else
			dpll |= DPLLB_MODE_DAC_SERIAL;
		if (is_sdvo) {
			dpll |= DPLL_DVO_HIGH_SPEED;
			sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
			int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
			if (pixel_multiplier > 1) {
				if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
				dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
					dpll |= (pixel_multiplier - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
				else if (HAS_PCH_SPLIT(dev))
				dpll |= (sdvo_pixel_multiply - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
					dpll |= (pixel_multiplier - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
			}
			dpll |= DPLL_DVO_HIGH_SPEED;
		}
		if (is_dp)
			dpll |= DPLL_DVO_HIGH_SPEED;
@@ -3982,9 +3983,15 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,

		if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) {
			if (is_sdvo) {
				sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
				I915_WRITE(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) |
					((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT));
				int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
				if (pixel_multiplier > 1)
					pixel_multiplier = (pixel_multiplier - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
				else
					pixel_multiplier = 0;

				I915_WRITE(dpll_md_reg,
					   (0 << DPLL_MD_UDI_DIVIDER_SHIFT) |
					   pixel_multiplier);
			} else
				I915_WRITE(dpll_md_reg, 0);
		} else {
+18 −0
Original line number Diff line number Diff line
@@ -99,6 +99,24 @@
#define INTEL_DVO_CHIP_TMDS 2
#define INTEL_DVO_CHIP_TVOUT 4

/* drm_display_mode->private_flags */
#define INTEL_MODE_PIXEL_MULTIPLIER_SHIFT (0x0)
#define INTEL_MODE_PIXEL_MULTIPLIER_MASK (0xf << INTEL_MODE_PIXEL_MULTIPLIER_SHIFT)

static inline void
intel_mode_set_pixel_multiplier(struct drm_display_mode *mode,
				int multiplier)
{
	mode->clock *= multiplier;
	mode->private_flags |= multiplier;
}

static inline int
intel_mode_get_pixel_multiplier(const struct drm_display_mode *mode)
{
	return (mode->private_flags & INTEL_MODE_PIXEL_MULTIPLIER_MASK) >> INTEL_MODE_PIXEL_MULTIPLIER_SHIFT;
}

struct intel_i2c_chan {
	struct drm_device *drm_dev; /* for getting at dev. private (mmio etc.) */
	u32 reg; /* GPIO reg */
+41 −58
Original line number Diff line number Diff line
@@ -106,15 +106,11 @@ struct intel_sdvo {
	bool is_hdmi;

	/**
	 * This is set if we detect output of sdvo device as LVDS.
	 * This is set if we detect output of sdvo device as LVDS and
	 * have a valid fixed mode to use with the panel.
	 */
	bool is_lvds;

	/**
	 * This is sdvo flags for input timing.
	 */
	uint8_t sdvo_flags;

	/**
	 * This is sdvo fixed pannel mode pointer
	 */
@@ -132,6 +128,8 @@ struct intel_sdvo {
	/* Mac mini hack -- use the same DDC as the analog connector */
	struct i2c_adapter *analog_ddc_bus;

	/* Input timings for adjusted_mode */
	struct intel_sdvo_dtd input_dtd;
};

struct intel_sdvo_connector {
@@ -1022,8 +1020,6 @@ intel_sdvo_set_input_timings_for_mode(struct intel_sdvo *intel_sdvo,
					struct drm_display_mode *mode,
					struct drm_display_mode *adjusted_mode)
{
	struct intel_sdvo_dtd input_dtd;

	/* Reset the input timing to the screen. Assume always input 0. */
	if (!intel_sdvo_set_target_input(intel_sdvo))
		return false;
@@ -1035,14 +1031,12 @@ intel_sdvo_set_input_timings_for_mode(struct intel_sdvo *intel_sdvo,
		return false;

	if (!intel_sdvo_get_preferred_input_timing(intel_sdvo,
						   &input_dtd))
						   &intel_sdvo->input_dtd))
		return false;

	intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd);
	intel_sdvo->sdvo_flags = input_dtd.part2.sdvo_flags;
	intel_sdvo_get_mode_from_dtd(adjusted_mode, &intel_sdvo->input_dtd);

	drm_mode_set_crtcinfo(adjusted_mode, 0);
	mode->clock = adjusted_mode->clock;
	return true;
}

@@ -1051,6 +1045,7 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
				  struct drm_display_mode *adjusted_mode)
{
	struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
	int multiplier;

	/* We need to construct preferred input timings based on our
	 * output timings.  To do that, we have to set the output
@@ -1065,8 +1060,6 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
							     mode,
							     adjusted_mode);
	} else if (intel_sdvo->is_lvds) {
		drm_mode_set_crtcinfo(intel_sdvo->sdvo_lvds_fixed_mode, 0);

		if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo,
							     intel_sdvo->sdvo_lvds_fixed_mode))
			return false;
@@ -1077,9 +1070,10 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
	}

	/* Make the CRTC code factor in the SDVO pixel multiplier.  The
	 * SDVO device will be told of the multiplier during mode_set.
	 * SDVO device will factor out the multiplier during mode_set.
	 */
	adjusted_mode->clock *= intel_sdvo_get_pixel_multiplier(mode);
	multiplier = intel_sdvo_get_pixel_multiplier(adjusted_mode);
	intel_mode_set_pixel_multiplier(adjusted_mode, multiplier);

	return true;
}
@@ -1093,10 +1087,11 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
	struct drm_crtc *crtc = encoder->crtc;
	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
	struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
	u32 sdvox = 0;
	int sdvo_pixel_multiply, rate;
	u32 sdvox;
	struct intel_sdvo_in_out_map in_out;
	struct intel_sdvo_dtd input_dtd;
	int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
	int rate;

	if (!mode)
		return;
@@ -1114,28 +1109,23 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
			     SDVO_CMD_SET_IN_OUT_MAP,
			     &in_out, sizeof(in_out));

	if (intel_sdvo->is_hdmi) {
		if (!intel_sdvo_set_avi_infoframe(intel_sdvo, mode))
	/* Set the output timings to the screen */
	if (!intel_sdvo_set_target_output(intel_sdvo,
					  intel_sdvo->attached_output))
		return;

		sdvox |= SDVO_AUDIO_ENABLE;
	}

	/* We have tried to get input timing in mode_fixup, and filled into
	   adjusted_mode */
	intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode);
	if (intel_sdvo->is_tv || intel_sdvo->is_lvds)
		input_dtd.part2.sdvo_flags = intel_sdvo->sdvo_flags;

	/* If it's a TV, we already set the output timing in mode_fixup.
	 * Otherwise, the output timing is equal to the input timing.
	 * adjusted_mode.
	 */
	if (!intel_sdvo->is_tv && !intel_sdvo->is_lvds) {
	if (intel_sdvo->is_tv || intel_sdvo->is_lvds) {
		input_dtd = intel_sdvo->input_dtd;
	} else {
		/* Set the output timing to the screen */
		if (!intel_sdvo_set_target_output(intel_sdvo,
						  intel_sdvo->attached_output))
			return;

		intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode);
		(void) intel_sdvo_set_output_timing(intel_sdvo, &input_dtd);
	}

@@ -1143,31 +1133,18 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
	if (!intel_sdvo_set_target_input(intel_sdvo))
		return;

	if (intel_sdvo->is_tv) {
		if (!intel_sdvo_set_tv_format(intel_sdvo))
	if (intel_sdvo->is_hdmi &&
	    !intel_sdvo_set_avi_infoframe(intel_sdvo, mode))
		return;
	}

	/* We would like to use intel_sdvo_create_preferred_input_timing() to
	 * provide the device with a timing it can support, if it supports that
	 * feature.  However, presumably we would need to adjust the CRTC to
	 * output the preferred timing, and we don't support that currently.
	 */
#if 0
	success = intel_sdvo_create_preferred_input_timing(encoder, clock,
							   width, height);
	if (success) {
		struct intel_sdvo_dtd *input_dtd;
	if (intel_sdvo->is_tv &&
	    !intel_sdvo_set_tv_format(intel_sdvo))
		return;

		intel_sdvo_get_preferred_input_timing(encoder, &input_dtd);
		intel_sdvo_set_input_timing(encoder, &input_dtd);
	}
#else
	(void) intel_sdvo_set_input_timing(intel_sdvo, &input_dtd);
#endif

	sdvo_pixel_multiply = intel_sdvo_get_pixel_multiplier(mode);
	switch (sdvo_pixel_multiply) {
	switch (pixel_multiplier) {
	default:
	case 1: rate = SDVO_CLOCK_RATE_MULT_1X; break;
	case 2: rate = SDVO_CLOCK_RATE_MULT_2X; break;
	case 4: rate = SDVO_CLOCK_RATE_MULT_4X; break;
@@ -1177,13 +1154,13 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,

	/* Set the SDVO control regs. */
	if (IS_I965G(dev)) {
		sdvox |= SDVO_BORDER_ENABLE;
		sdvox = SDVO_BORDER_ENABLE;
		if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
			sdvox |= SDVO_VSYNC_ACTIVE_HIGH;
		if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
			sdvox |= SDVO_HSYNC_ACTIVE_HIGH;
	} else {
		sdvox |= I915_READ(intel_sdvo->sdvo_reg);
		sdvox = I915_READ(intel_sdvo->sdvo_reg);
		switch (intel_sdvo->sdvo_reg) {
		case SDVOB:
			sdvox &= SDVOB_PRESERVE_MASK;
@@ -1196,16 +1173,18 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
	}
	if (intel_crtc->pipe == 1)
		sdvox |= SDVO_PIPE_B_SELECT;
	if (intel_sdvo->is_hdmi)
		sdvox |= SDVO_AUDIO_ENABLE;

	if (IS_I965G(dev)) {
		/* done in crtc_mode_set as the dpll_md reg must be written early */
	} else if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) {
		/* done in crtc_mode_set as it lives inside the dpll register */
	} else {
		sdvox |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT;
		sdvox |= (pixel_multiplier - 1) << SDVO_PORT_MULTIPLY_SHIFT;
	}

	if (intel_sdvo->sdvo_flags & SDVO_NEED_TO_STALL)
	if (input_dtd.part2.sdvo_flags & SDVO_NEED_TO_STALL)
		sdvox |= SDVO_STALL_SELECT;
	intel_sdvo_write_sdvox(intel_sdvo, sdvox);
}
@@ -1692,6 +1671,10 @@ end:
		if (newmode->type & DRM_MODE_TYPE_PREFERRED) {
			intel_sdvo->sdvo_lvds_fixed_mode =
				drm_mode_duplicate(connector->dev, newmode);

			drm_mode_set_crtcinfo(intel_sdvo->sdvo_lvds_fixed_mode,
					      0);

			intel_sdvo->is_lvds = true;
			break;
		}