From patchwork Tue Aug 14 04:34:46 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Keith Packard X-Patchwork-Id: 1317971 Return-Path: X-Original-To: patchwork-dri-devel@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by patchwork2.kernel.org (Postfix) with ESMTP id ADA6BDF266 for ; Tue, 14 Aug 2012 04:39:25 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id A1115A0879 for ; Mon, 13 Aug 2012 21:39:25 -0700 (PDT) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from keithp.com (home.keithp.com [63.227.221.253]) by gabe.freedesktop.org (Postfix) with ESMTP id AD14F9E77F; Mon, 13 Aug 2012 21:34:46 -0700 (PDT) Received: from localhost (localhost [127.0.0.1]) by keithp.com (Postfix) with ESMTP id 6BDAB76021F; Mon, 13 Aug 2012 21:34:46 -0700 (PDT) X-Virus-Scanned: Debian amavisd-new at keithp.com Received: from keithp.com ([127.0.0.1]) by localhost (keithp.com [127.0.0.1]) (amavisd-new, port 10024) with LMTP id kMBU-9ds9z6r; Mon, 13 Aug 2012 21:34:42 -0700 (PDT) Received: by keithp.com (Postfix, from userid 1033) id 047EABF4235; Mon, 13 Aug 2012 21:34:38 -0700 (PDT) Received: from miki.keithp.com (localhost [127.0.0.1]) by keithp.com (Postfix) with ESMTP id 4726CB80017; Mon, 13 Aug 2012 21:34:38 -0700 (PDT) Received: by miki.keithp.com (Postfix, from userid 1001) id 5C7EABA4; Mon, 13 Aug 2012 21:34:56 -0700 (PDT) From: Keith Packard To: intel-gfx@lists.freedesktop.org, Daniel Vetter Subject: [PATCH 2/7] drm/i915: FDI B/C share 4 lanes on Ivybridge Date: Mon, 13 Aug 2012 21:34:46 -0700 Message-Id: <1344918891-6283-3-git-send-email-keithp@keithp.com> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1344918891-6283-1-git-send-email-keithp@keithp.com> References: <1344918891-6283-1-git-send-email-keithp@keithp.com> Cc: linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: dri-devel-bounces+patchwork-dri-devel=patchwork.kernel.org@lists.freedesktop.org Errors-To: dri-devel-bounces+patchwork-dri-devel=patchwork.kernel.org@lists.freedesktop.org IVB shares 4 lanes between FDI B and FDI C. When sharing, compute the maximum BPC based on the available bandwidth. Signed-off-by: Keith Packard --- drivers/gpu/drm/i915/intel_display.c | 101 +++++++++++++++++++++++++++++++--- 1 file changed, 94 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 70d30fc..7106807 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3575,7 +3575,7 @@ void intel_encoder_destroy(struct drm_encoder *encoder) } static bool intel_crtc_mode_fixup(struct drm_crtc *crtc, - struct drm_display_mode *mode, + const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct drm_device *dev = crtc->dev; @@ -3728,7 +3728,8 @@ static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv) */ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc, unsigned int *pipe_bpp, - struct drm_display_mode *mode) + struct drm_display_mode *mode, + int max_fdi_bpp) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -3800,6 +3801,15 @@ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc, display_bpc = 6; } + if (display_bpc * 3 > max_fdi_bpp) { + if (max_fdi_bpp < 24) + display_bpc = 6; + else if (max_fdi_bpp < 30) + display_bpc = 8; + else if (max_fdi_bpp < 36) + display_bpc = 10; + DRM_DEBUG_KMS("Dithering FDI to %dbpc\n", display_bpc); + } /* * We could just drive the pipe at the highest bpc all the time and * enable dithering as needed, but that costs bandwidth. So choose @@ -4570,6 +4580,53 @@ static int ironlake_get_refclk(struct drm_crtc *crtc) return 120000; } +/* + * FDI C can only have 2 lanes, borrowed from FDI B + */ + +static int ivb_fdi_max_lanes(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + enum pipe other_pipe; + struct drm_crtc *other_crtc; + struct intel_crtc *other_intel_crtc; + int max_lanes; + + /* FDI links B and C share 4 lanes */ + switch (intel_crtc->pipe) { + case PIPE_B: + other_pipe = PIPE_C; + max_lanes = 4; + break; + case PIPE_C: + other_pipe = PIPE_B; + max_lanes = 2; + break; + default: + return 4; + } + other_crtc = dev_priv->pipe_to_crtc_mapping[other_pipe]; + other_intel_crtc = to_intel_crtc(other_crtc); + + /* If the other FDI link isn't running, we can use all of the + * available lanes + */ + if (!other_intel_crtc->active) + return max_lanes; + + /* If the other FDI link is using too many lanes, we can't have + * any + */ + if (other_intel_crtc->fdi_lanes > 2) + return 0; + + /* When both are running, we only get 2 lanes at most + */ + return 2; +} + static int ironlake_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, @@ -4595,6 +4652,8 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, unsigned int pipe_bpp; bool dither; bool is_cpu_edp = false, is_pch_edp = false; + int max_fdi_bpp; + int max_lane; for_each_encoder_on_crtc(dev, crtc, encoder) { switch (encoder->type) { @@ -4672,7 +4731,18 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, according to current link config */ if (is_cpu_edp) { intel_edp_link_config(edp_encoder, &lane, &link_bw); + max_fdi_bpp = 0; + max_lane = lane; } else { + u32 fdi_bw; + + /* [e]DP over FDI requires target mode clock + instead of link clock */ + if (is_dp) + target_clock = mode->clock; + else + target_clock = adjusted_mode->clock; + /* FDI is a binary signal running at ~2.7GHz, encoding * each output octet as 10 bits. The actual frequency * is stored as a divider into a 100MHz clock, and the @@ -4681,6 +4751,18 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, * is: */ link_bw = intel_fdi_link_freq(dev) * MHz(100)/KHz(1)/10; + + max_lane = 4; + if (IS_IVYBRIDGE(dev)) + max_lane = ivb_fdi_max_lanes(crtc); + + /* + * Compute the available FDI bandwidth, use that + * to compute the maximum supported BPP + */ + fdi_bw = link_bw * max_lane * 19 / 20; + max_fdi_bpp = fdi_bw / target_clock; + DRM_DEBUG_KMS("max lane %d yields max fdi bpp %d\n", max_lane, max_fdi_bpp); } /* [e]DP over FDI requires target mode clock instead of link clock. */ @@ -4694,7 +4776,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, mode); + dither = intel_choose_pipe_bpp_dither(crtc, &pipe_bpp, mode, max_fdi_bpp); switch (pipe_bpp) { case 18: temp |= PIPE_6BPC; @@ -4716,19 +4798,24 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, break; } - intel_crtc->bpp = pipe_bpp; - I915_WRITE(PIPECONF(pipe), temp); - if (!lane) { /* * Account for spread spectrum to avoid * oversubscribing the link. Max center spread * is 2.5%; use 5% for safety's sake. */ - u32 bps = target_clock * intel_crtc->bpp * 21 / 20; + u32 bps = target_clock * pipe_bpp * 21 / 20; lane = bps / (link_bw * 8) + 1; + if (lane > max_lane) { + DRM_ERROR("Not enough lanes available for mode! (want %d have %d)\n", + lane, max_lane); + return -EINVAL; + } } + intel_crtc->bpp = pipe_bpp; + I915_WRITE(PIPECONF(pipe), temp); + intel_crtc->fdi_lanes = lane; if (pixel_multiplier > 1)