Commit 3b5c78a35cf7511c15e09a9b0ffab290a42d9bcf
Committed by
Keith Packard
1 parent
f45b55575c
Exists in
master
and in
6 other branches
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 dc22ee6fc18ce0f15424e753e8473c306ece95c1. 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: Adam Jackson <ajax@redhat.com> Signed-off-by: Eric Anholt <eric@anholt.net> Tested-by: Eric Anholt <eric@anholt.net> Tested-by: Dirk Hohndel <hohndel@infradead.org> Signed-off-by: Keith Packard <keithp@keithp.com>
Showing 3 changed files with 39 additions and 8 deletions Side-by-side Diff
drivers/gpu/drm/i915/intel_display.c
... | ... | @@ -4670,6 +4670,7 @@ |
4670 | 4670 | /** |
4671 | 4671 | * intel_choose_pipe_bpp_dither - figure out what color depth the pipe should send |
4672 | 4672 | * @crtc: CRTC structure |
4673 | + * @mode: requested mode | |
4673 | 4674 | * |
4674 | 4675 | * A pipe may be connected to one or more outputs. Based on the depth of the |
4675 | 4676 | * attached framebuffer, choose a good color depth to use on the pipe. |
4676 | 4677 | |
... | ... | @@ -4681,13 +4682,15 @@ |
4681 | 4682 | * HDMI supports only 8bpc or 12bpc, so clamp to 8bpc with dither for 10bpc |
4682 | 4683 | * Displays may support a restricted set as well, check EDID and clamp as |
4683 | 4684 | * appropriate. |
4685 | + * DP may want to dither down to 6bpc to fit larger modes | |
4684 | 4686 | * |
4685 | 4687 | * RETURNS: |
4686 | 4688 | * Dithering requirement (i.e. false if display bpc and pipe bpc match, |
4687 | 4689 | * true if they don't match). |
4688 | 4690 | */ |
4689 | 4691 | static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc, |
4690 | - unsigned int *pipe_bpp) | |
4692 | + unsigned int *pipe_bpp, | |
4693 | + struct drm_display_mode *mode) | |
4691 | 4694 | { |
4692 | 4695 | struct drm_device *dev = crtc->dev; |
4693 | 4696 | struct drm_i915_private *dev_priv = dev->dev_private; |
... | ... | @@ -4758,6 +4761,11 @@ |
4758 | 4761 | } |
4759 | 4762 | } |
4760 | 4763 | |
4764 | + if (mode->private_flags & INTEL_MODE_DP_FORCE_6BPC) { | |
4765 | + DRM_DEBUG_KMS("Dithering DP to 6bpc\n"); | |
4766 | + display_bpc = 6; | |
4767 | + } | |
4768 | + | |
4761 | 4769 | /* |
4762 | 4770 | * We could just drive the pipe at the highest bpc all the time and |
4763 | 4771 | * enable dithering as needed, but that costs bandwidth. So choose |
... | ... | @@ -5019,6 +5027,16 @@ |
5019 | 5027 | pipeconf &= ~PIPECONF_DOUBLE_WIDE; |
5020 | 5028 | } |
5021 | 5029 | |
5030 | + /* default to 8bpc */ | |
5031 | + pipeconf &= ~(PIPECONF_BPP_MASK | PIPECONF_DITHER_EN); | |
5032 | + if (is_dp) { | |
5033 | + if (mode->private_flags & INTEL_MODE_DP_FORCE_6BPC) { | |
5034 | + pipeconf |= PIPECONF_BPP_6 | | |
5035 | + PIPECONF_DITHER_EN | | |
5036 | + PIPECONF_DITHER_TYPE_SP; | |
5037 | + } | |
5038 | + } | |
5039 | + | |
5022 | 5040 | dpll |= DPLL_VCO_ENABLE; |
5023 | 5041 | |
5024 | 5042 | DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B'); |
... | ... | @@ -5480,7 +5498,7 @@ |
5480 | 5498 | /* determine panel color depth */ |
5481 | 5499 | temp = I915_READ(PIPECONF(pipe)); |
5482 | 5500 | temp &= ~PIPE_BPC_MASK; |
5483 | - dither = intel_choose_pipe_bpp_dither(crtc, &pipe_bpp); | |
5501 | + dither = intel_choose_pipe_bpp_dither(crtc, &pipe_bpp, mode); | |
5484 | 5502 | switch (pipe_bpp) { |
5485 | 5503 | case 18: |
5486 | 5504 | temp |= PIPE_6BPC; |
drivers/gpu/drm/i915/intel_dp.c
... | ... | @@ -208,13 +208,15 @@ |
208 | 208 | */ |
209 | 209 | |
210 | 210 | static int |
211 | -intel_dp_link_required(struct intel_dp *intel_dp, int pixel_clock) | |
211 | +intel_dp_link_required(struct intel_dp *intel_dp, int pixel_clock, int check_bpp) | |
212 | 212 | { |
213 | 213 | struct drm_crtc *crtc = intel_dp->base.base.crtc; |
214 | 214 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
215 | 215 | int bpp = 24; |
216 | 216 | |
217 | - if (intel_crtc) | |
217 | + if (check_bpp) | |
218 | + bpp = check_bpp; | |
219 | + else if (intel_crtc) | |
218 | 220 | bpp = intel_crtc->bpp; |
219 | 221 | |
220 | 222 | return (pixel_clock * bpp + 9) / 10; |
... | ... | @@ -233,6 +235,7 @@ |
233 | 235 | struct intel_dp *intel_dp = intel_attached_dp(connector); |
234 | 236 | int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_dp)); |
235 | 237 | int max_lanes = intel_dp_max_lane_count(intel_dp); |
238 | + int max_rate, mode_rate; | |
236 | 239 | |
237 | 240 | if (is_edp(intel_dp) && intel_dp->panel_fixed_mode) { |
238 | 241 | if (mode->hdisplay > intel_dp->panel_fixed_mode->hdisplay) |
239 | 242 | |
... | ... | @@ -242,10 +245,18 @@ |
242 | 245 | return MODE_PANEL; |
243 | 246 | } |
244 | 247 | |
245 | - if (intel_dp_link_required(intel_dp, mode->clock) | |
246 | - > intel_dp_max_data_rate(max_link_clock, max_lanes)) | |
247 | - return MODE_CLOCK_HIGH; | |
248 | + mode_rate = intel_dp_link_required(intel_dp, mode->clock, 0); | |
249 | + max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes); | |
248 | 250 | |
251 | + if (mode_rate > max_rate) { | |
252 | + mode_rate = intel_dp_link_required(intel_dp, | |
253 | + mode->clock, 18); | |
254 | + if (mode_rate > max_rate) | |
255 | + return MODE_CLOCK_HIGH; | |
256 | + else | |
257 | + mode->private_flags |= INTEL_MODE_DP_FORCE_6BPC; | |
258 | + } | |
259 | + | |
249 | 260 | if (mode->clock < 10000) |
250 | 261 | return MODE_CLOCK_LOW; |
251 | 262 | |
... | ... | @@ -672,6 +683,7 @@ |
672 | 683 | int lane_count, clock; |
673 | 684 | int max_lane_count = intel_dp_max_lane_count(intel_dp); |
674 | 685 | int max_clock = intel_dp_max_link_bw(intel_dp) == DP_LINK_BW_2_7 ? 1 : 0; |
686 | + int bpp = mode->private_flags & INTEL_MODE_DP_FORCE_6BPC ? 18 : 0; | |
675 | 687 | static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 }; |
676 | 688 | |
677 | 689 | if (is_edp(intel_dp) && intel_dp->panel_fixed_mode) { |
... | ... | @@ -689,7 +701,7 @@ |
689 | 701 | for (clock = 0; clock <= max_clock; clock++) { |
690 | 702 | int link_avail = intel_dp_max_data_rate(intel_dp_link_clock(bws[clock]), lane_count); |
691 | 703 | |
692 | - if (intel_dp_link_required(intel_dp, mode->clock) | |
704 | + if (intel_dp_link_required(intel_dp, mode->clock, bpp) | |
693 | 705 | <= link_avail) { |
694 | 706 | intel_dp->link_bw = bws[clock]; |
695 | 707 | intel_dp->lane_count = lane_count; |
drivers/gpu/drm/i915/intel_drv.h
... | ... | @@ -110,6 +110,7 @@ |
110 | 110 | /* drm_display_mode->private_flags */ |
111 | 111 | #define INTEL_MODE_PIXEL_MULTIPLIER_SHIFT (0x0) |
112 | 112 | #define INTEL_MODE_PIXEL_MULTIPLIER_MASK (0xf << INTEL_MODE_PIXEL_MULTIPLIER_SHIFT) |
113 | +#define INTEL_MODE_DP_FORCE_6BPC (0x10) | |
113 | 114 | |
114 | 115 | static inline void |
115 | 116 | intel_mode_set_pixel_multiplier(struct drm_display_mode *mode, |