diff mbox

[3/3,drm/i915] - Implement manual override of LVDS single/dual channel mode

Message ID alpine.DEB.1.10.1103161533050.13431@cnc.isely.net (mailing list archive)
State New, archived
Headers show

Commit Message

Mike Isely March 17, 2011, 1:58 p.m. UTC
None

Comments

meta tech May 1, 2011, 6:51 a.m. UTC | #1
Mike Isely <isely <at> isely.net> writes:

> This is yet one more case where the Intel driver had been implicitly
> relying on the video BIOS for display configuration.
> 
> Almost nobody should ever need to touch this option,
> and its default value of zero is interpreted to preserve existing
> probe-the-hardware behavior.  

Hello,

Just for information, this patch is very useful for Mac machines 
(MacBook Pro 2010 or higher with Intel integrated graphics) 
booting Linux in EFI mode, because in this mode the BIOS 
does not initializes the graphic card, and therefore it is 
required to force dual channel mode with this parameter.

Regards,

metatech
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 004880aa3a948669b8b4e23d9ad73d132cff81d0..1d88f059a27321ecb681e2b7927bb69029fcb49a 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -49,6 +49,10 @@  module_param_named(powersave, i915_powersave, int, 0600);
 unsigned int i915_lvds_fixed = 1;
 module_param_named(lvds_fixed, i915_lvds_fixed, int, 0600);
 
+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");
+
 unsigned int i915_lvds_downclock = 0;
 module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400);
 
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 3fa8681459aa596e12e885568e5b48f0c9a60719..a6aab43e5f39f2d5b92a69a284bf8f72a254ea7c 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -886,6 +886,7 @@  extern int i915_max_ioctl;
 extern unsigned int i915_fbpercrtc;
 extern unsigned int i915_powersave;
 extern unsigned int i915_lvds_fixed;
+extern unsigned int i915_lvds_channels;
 extern unsigned int i915_lvds_downclock;
 extern unsigned int i915_lvds_24bit;
 
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 09f57f29c30c371c213944be473090a780a287db..4dc91400edd8935be45a229cf91292339bca0ce8 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -642,6 +642,20 @@  static const intel_limit_t intel_limits_ironlake_display_port = {
         .find_pll = intel_find_pll_ironlake_dp,
 };
 
+static int intel_is_dual_channel_mode(struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	if (i915_lvds_channels) {
+		/* User has specified desired channel mode */
+		return (i915_lvds_channels == 2);
+	}
+
+	/* User has not specified mode so let's see
+	   what the hardware is doing. */
+	return ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP);
+}
+
 static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc)
 {
 	struct drm_device *dev = crtc->dev;
@@ -653,8 +667,7 @@  static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc)
 		if (dev_priv->lvds_use_ssc && dev_priv->lvds_ssc_freq == 100)
 			refclk = 100;
 
-		if ((I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) ==
-		    LVDS_CLKB_POWER_UP) {
+		if (intel_is_dual_channel_mode(crtc)) {
 			/* LVDS dual channel */
 			if (refclk == 100)
 				limit = &intel_limits_ironlake_dual_lvds_100m;
@@ -677,18 +690,16 @@  static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc)
 
 static const intel_limit_t *intel_g4x_limit(struct drm_crtc *crtc)
 {
-	struct drm_device *dev = crtc->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
 	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_is_dual_channel_mode(crtc)) {
 			/* LVDS with dual channel */
 			limit = &intel_limits_g4x_dual_channel_lvds;
-		else
-			/* LVDS with dual channel */
+		} else {
+			/* LVDS with single channel */
 			limit = &intel_limits_g4x_single_channel_lvds;
+		}
 	} else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI) ||
 		   intel_pipe_has_type(crtc, INTEL_OUTPUT_ANALOG)) {
 		limit = &intel_limits_g4x_hdmi;
@@ -821,8 +832,7 @@  intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
 		 * 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_is_dual_channel_mode(crtc))
 			clock.p2 = limit->p2.p2_fast;
 		else
 			clock.p2 = limit->p2.p2_slow;
@@ -871,7 +881,6 @@  intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
 			int target, int refclk, intel_clock_t *best_clock)
 {
 	struct drm_device *dev = crtc->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
 	intel_clock_t clock;
 	int max_n;
 	bool found;
@@ -886,8 +895,7 @@  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_is_dual_channel_mode(crtc))
 			clock.p2 = limit->p2.p2_fast;
 		else
 			clock.p2 = limit->p2.p2_slow;