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

Commit 3b5c78a3 authored by Adam Jackson's avatar Adam Jackson Committed by Keith Packard
Browse files

drm/i915/dp: Dither down to 6bpc if it makes the mode fit



Some active adaptors (VGA usually) only have two lanes at 2.7GHz.
That's a maximum pixel clock of 144MHz at 8bpc, but 192MHz at 6bpc.

Fixes Asus UX31 panel being black at startup due to no valid modes since
dc22ee6f.

v2: Rebased to current code, resulting in the fix applying to EDP panels as
    well.  Also changed from spatio-temporal to just spatial dithering on
    pre-ironlake, to be conssitent (and less visual flicker)

Signed-off-by: default avatarAdam Jackson <ajax@redhat.com>
Signed-off-by: default avatarEric Anholt <eric@anholt.net>
Tested-by: default avatarEric Anholt <eric@anholt.net>
Tested-by: default avatarDirk Hohndel <hohndel@infradead.org>
Signed-off-by: default avatarKeith Packard <keithp@keithp.com>
parent f45b5557
Loading
Loading
Loading
Loading
+20 −2
Original line number Diff line number Diff line
@@ -4670,6 +4670,7 @@ static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
/**
 * intel_choose_pipe_bpp_dither - figure out what color depth the pipe should send
 * @crtc: CRTC structure
 * @mode: requested mode
 *
 * A pipe may be connected to one or more outputs.  Based on the depth of the
 * attached framebuffer, choose a good color depth to use on the pipe.
@@ -4681,13 +4682,15 @@ static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
 *    HDMI supports only 8bpc or 12bpc, so clamp to 8bpc with dither for 10bpc
 *    Displays may support a restricted set as well, check EDID and clamp as
 *      appropriate.
 *    DP may want to dither down to 6bpc to fit larger modes
 *
 * RETURNS:
 * Dithering requirement (i.e. false if display bpc and pipe bpc match,
 * true if they don't match).
 */
static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc,
					 unsigned int *pipe_bpp)
					 unsigned int *pipe_bpp,
					 struct drm_display_mode *mode)
{
	struct drm_device *dev = crtc->dev;
	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -4758,6 +4761,11 @@ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc,
		}
	}

	if (mode->private_flags & INTEL_MODE_DP_FORCE_6BPC) {
		DRM_DEBUG_KMS("Dithering DP to 6bpc\n");
		display_bpc = 6;
	}

	/*
	 * We could just drive the pipe at the highest bpc all the time and
	 * enable dithering as needed, but that costs bandwidth.  So choose
@@ -5019,6 +5027,16 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
			pipeconf &= ~PIPECONF_DOUBLE_WIDE;
	}

	/* default to 8bpc */
	pipeconf &= ~(PIPECONF_BPP_MASK | PIPECONF_DITHER_EN);
	if (is_dp) {
		if (mode->private_flags & INTEL_MODE_DP_FORCE_6BPC) {
			pipeconf |= PIPECONF_BPP_6 |
				    PIPECONF_DITHER_EN |
				    PIPECONF_DITHER_TYPE_SP;
		}
	}

	dpll |= DPLL_VCO_ENABLE;

	DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
@@ -5480,7 +5498,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
	/* determine panel color depth */
	temp = I915_READ(PIPECONF(pipe));
	temp &= ~PIPE_BPC_MASK;
	dither = intel_choose_pipe_bpp_dither(crtc, &pipe_bpp);
	dither = intel_choose_pipe_bpp_dither(crtc, &pipe_bpp, mode);
	switch (pipe_bpp) {
	case 18:
		temp |= PIPE_6BPC;
+18 −6
Original line number Diff line number Diff line
@@ -208,13 +208,15 @@ intel_dp_link_clock(uint8_t link_bw)
 */

static int
intel_dp_link_required(struct intel_dp *intel_dp, int pixel_clock)
intel_dp_link_required(struct intel_dp *intel_dp, int pixel_clock, int check_bpp)
{
	struct drm_crtc *crtc = intel_dp->base.base.crtc;
	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
	int bpp = 24;

	if (intel_crtc)
	if (check_bpp)
		bpp = check_bpp;
	else if (intel_crtc)
		bpp = intel_crtc->bpp;

	return (pixel_clock * bpp + 9) / 10;
@@ -233,6 +235,7 @@ intel_dp_mode_valid(struct drm_connector *connector,
	struct intel_dp *intel_dp = intel_attached_dp(connector);
	int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_dp));
	int max_lanes = intel_dp_max_lane_count(intel_dp);
	int max_rate, mode_rate;

	if (is_edp(intel_dp) && intel_dp->panel_fixed_mode) {
		if (mode->hdisplay > intel_dp->panel_fixed_mode->hdisplay)
@@ -242,9 +245,17 @@ intel_dp_mode_valid(struct drm_connector *connector,
			return MODE_PANEL;
	}

	if (intel_dp_link_required(intel_dp, mode->clock)
	    > intel_dp_max_data_rate(max_link_clock, max_lanes))
	mode_rate = intel_dp_link_required(intel_dp, mode->clock, 0);
	max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes);

	if (mode_rate > max_rate) {
			mode_rate = intel_dp_link_required(intel_dp,
							   mode->clock, 18);
			if (mode_rate > max_rate)
				return MODE_CLOCK_HIGH;
			else
				mode->private_flags |= INTEL_MODE_DP_FORCE_6BPC;
	}

	if (mode->clock < 10000)
		return MODE_CLOCK_LOW;
@@ -672,6 +683,7 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
	int lane_count, clock;
	int max_lane_count = intel_dp_max_lane_count(intel_dp);
	int max_clock = intel_dp_max_link_bw(intel_dp) == DP_LINK_BW_2_7 ? 1 : 0;
	int bpp = mode->private_flags & INTEL_MODE_DP_FORCE_6BPC ? 18 : 0;
	static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 };

	if (is_edp(intel_dp) && intel_dp->panel_fixed_mode) {
@@ -689,7 +701,7 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
		for (clock = 0; clock <= max_clock; clock++) {
			int link_avail = intel_dp_max_data_rate(intel_dp_link_clock(bws[clock]), lane_count);

			if (intel_dp_link_required(intel_dp, mode->clock)
			if (intel_dp_link_required(intel_dp, mode->clock, bpp)
					<= link_avail) {
				intel_dp->link_bw = bws[clock];
				intel_dp->lane_count = lane_count;
+1 −0
Original line number Diff line number Diff line
@@ -110,6 +110,7 @@
/* drm_display_mode->private_flags */
#define INTEL_MODE_PIXEL_MULTIPLIER_SHIFT (0x0)
#define INTEL_MODE_PIXEL_MULTIPLIER_MASK (0xf << INTEL_MODE_PIXEL_MULTIPLIER_SHIFT)
#define INTEL_MODE_DP_FORCE_6BPC (0x10)

static inline void
intel_mode_set_pixel_multiplier(struct drm_display_mode *mode,