From patchwork Tue Apr 12 23:01:00 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Wilson X-Patchwork-Id: 702301 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 p3CN2rU0015174 for ; Tue, 12 Apr 2011 23:03:13 GMT Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 17D259F050 for ; Tue, 12 Apr 2011 16:02:53 -0700 (PDT) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by gabe.freedesktop.org (Postfix) with ESMTP id 86B7A9EEEF for ; Tue, 12 Apr 2011 16:01:39 -0700 (PDT) Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by fmsmga101.fm.intel.com with ESMTP; 12 Apr 2011 16:01:38 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.64,200,1301900400"; d="scan'208";a="678255322" Received: from unknown (HELO cantiga.alporthouse.com) ([10.255.16.172]) by fmsmga002.fm.intel.com with ESMTP; 12 Apr 2011 16:01:10 -0700 From: Chris Wilson To: Mike Isely Date: Wed, 13 Apr 2011 00:01:00 +0100 Message-Id: <1302649260-11996-3-git-send-email-chris@chris-wilson.co.uk> X-Mailer: git-send-email 1.7.4.1 In-Reply-To: <1302649260-11996-1-git-send-email-chris@chris-wilson.co.uk> References: <1302649260-11996-1-git-send-email-chris@chris-wilson.co.uk> Cc: intel-gfx@lists.freedesktop.org Subject: [Intel-gfx] [PATCH 2/2] 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]); Tue, 12 Apr 2011 23:03:13 +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 29ee1e3..16a2532 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 97153f0..2112af3 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 f84dd21..7734d1e 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; @@ -4914,7 +4916,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;