From patchwork Sat Apr 16 09:17:34 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Wilson X-Patchwork-Id: 712131 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p3G9NSrr010812 for ; Sat, 16 Apr 2011 09:23:54 GMT Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 849E39EC09 for ; Sat, 16 Apr 2011 02:23:28 -0700 (PDT) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from fireflyinternet.com (server109-228-6-236.live-servers.net [109.228.6.236]) by gabe.freedesktop.org (Postfix) with ESMTP id D6C769EAFA for ; Sat, 16 Apr 2011 02:18:14 -0700 (PDT) X-Default-Received-SPF: pass (skip=forwardok (res=PASS)) x-ip-name=78.156.66.37; Received: from arrandale.alporthouse.com (unverified [78.156.66.37]) by fireflyinternet.com (Firefly Internet SMTP) with ESMTP id 32233672-1500050 for multiple; Sat, 16 Apr 2011 10:17:51 +0100 From: Chris Wilson To: intel-gfx@lists.freedesktop.org Date: Sat, 16 Apr 2011 10:17:34 +0100 Message-Id: <1302945465-32115-11-git-send-email-chris@chris-wilson.co.uk> X-Mailer: git-send-email 1.7.4.1 In-Reply-To: <1302945465-32115-1-git-send-email-chris@chris-wilson.co.uk> References: <1302945465-32115-1-git-send-email-chris@chris-wilson.co.uk> X-Originating-IP: 78.156.66.37 Subject: [Intel-gfx] [PATCH 10/21] drm/i915: Implement manual override of LVDS single/dual channel mode X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.11 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: intel-gfx-bounces+patchwork-intel-gfx=patchwork.kernel.org@lists.freedesktop.org Errors-To: intel-gfx-bounces+patchwork-intel-gfx=patchwork.kernel.org@lists.freedesktop.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Sat, 16 Apr 2011 09:23:54 +0000 (UTC) From: Mike Isely The logic for LVDS setup in the Intel driver needs to know whether the LVDS port should be in single or dual channel mode when calculating video timing. It had been answering this question by probing the current hardware configuration, under the assumption that the video BIOS would have already set it up. But the video BIOS would actually have to know how to set up the LVDS port for the connected device, which is a bad assumption if the display device is not integral to the processor board - a situation that can exist for embedded situation. This is yet one more case where the Intel driver had been implicitly relying on the video BIOS for display configuration. This changes creates a new kernel option, lvds_channels, which can be used to override the probe. Setting this allows the user to specify the number of channels in use, avoiding the possibly erroneous probe of the hardware. Almost nobody should ever need to touch this option, and its default value of zero is interpreted to preserve existing probe-the-hardware behavior. But if the video BIOS gets this "wrong", then it can be overridden by setting lvds_channels to 1 or 2, indicating single or dual channel LVDS mode, respectively. Signed-off-by: Mike Isely Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.c | 4 ++++ drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_display.c | 32 +++++++++++++++++--------------- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 49d38b0..0acc995 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -71,6 +71,10 @@ unsigned int i915_lvds_24bit = 0; module_param_named(lvds_24bit, i915_lvds_24bit, int, 0600); MODULE_PARM_DESC(lvds_24bit, "LVDS 24 bit pixel format: 0=leave untouched (default), 1=24 bit '2.0' format, 2=24 bit '2.1' format, 3=force older 18 bit format"); +unsigned int i915_lvds_channels = 0; +module_param_named(lvds_channels, i915_lvds_channels, int, 0600); +MODULE_PARM_DESC(lvds_channels, "LVDS channels in use: 0=(default) probe hardware 1=single 2=dual"); + static struct drm_driver driver; extern int intel_agp_enabled; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 7cd63bb..76e111c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -977,6 +977,7 @@ extern unsigned int i915_fbpercrtc; extern int i915_panel_ignore_lid; extern unsigned int i915_powersave; extern unsigned int i915_semaphores; +extern unsigned int i915_lvds_channels; extern unsigned int i915_lvds_downclock; extern unsigned int i915_panel_use_ssc; extern int i915_vbt_sdvo_panel_type; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a21d3666..29b292c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -354,6 +354,17 @@ static const intel_limit_t intel_limits_ironlake_display_port = { .find_pll = intel_find_pll_ironlake_dp, }; +static bool intel_lvds_is_dual_channel_mode(struct drm_i915_private *dev_priv, + int lvds_reg) +{ + /* Did the user specify the number of channels? */ + if (i915_lvds_channels) + return i915_lvds_channels == 2; + + /* No, let's probe the current status of the hardware instead. */ + return (I915_READ(lvds_reg) & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP; +} + static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc, int refclk) { @@ -362,8 +373,7 @@ static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc, const intel_limit_t *limit; if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { - if ((I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) == - LVDS_CLKB_POWER_UP) { + if (intel_lvds_is_dual_channel_mode(dev_priv, PCH_LVDS)) { /* LVDS dual channel */ if (refclk == 100000) limit = &intel_limits_ironlake_dual_lvds_100m; @@ -391,8 +401,7 @@ static const intel_limit_t *intel_g4x_limit(struct drm_crtc *crtc) const intel_limit_t *limit; if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { - if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) == - LVDS_CLKB_POWER_UP) + if (intel_lvds_is_dual_channel_mode(dev_priv, LVDS)) /* LVDS with dual channel */ limit = &intel_limits_g4x_dual_channel_lvds; else @@ -523,14 +532,7 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) && (I915_READ(LVDS)) != 0) { - /* - * For LVDS, if the panel is on, just rely on its current - * settings for dual-channel. We haven't figured out how to - * reliably set up different single/dual channel state, if we - * even can. - */ - if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) == - LVDS_CLKB_POWER_UP) + if (intel_lvds_is_dual_channel_mode(dev_priv, LVDS)) clock.p2 = limit->p2.p2_fast; else clock.p2 = limit->p2.p2_slow; @@ -594,8 +596,8 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, lvds_reg = PCH_LVDS; else lvds_reg = LVDS; - if ((I915_READ(lvds_reg) & LVDS_CLKB_POWER_MASK) == - LVDS_CLKB_POWER_UP) + + if (intel_lvds_is_dual_channel_mode(dev_priv, lvds_reg)) clock.p2 = limit->p2.p2_fast; else clock.p2 = limit->p2.p2_slow; @@ -4913,7 +4915,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, if (is_lvds) { if ((intel_panel_use_ssc(dev_priv) && dev_priv->lvds_ssc_freq == 100) || - (I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP) + intel_lvds_is_dual_channel_mode(dev_priv, PCH_LVDS)) factor = 25; } else if (is_sdvo && is_tv) factor = 20;