[Intel-gfx] [PATCH 1/2] drm/i915: update reduced refresh rate support for ILK+

Jesse Barnes jbarnes at virtuousgeek.org
Tue Jan 11 00:38:55 CET 2011


We can support it on eDP as well, as long as we enable panel power
before trying to retrieve the EDID.
---
 drivers/gpu/drm/i915/i915_drv.c      |    4 +-
 drivers/gpu/drm/i915/i915_drv.h      |    8 ++--
 drivers/gpu/drm/i915/intel_bios.c    |   10 +++---
 drivers/gpu/drm/i915/intel_display.c |   51 +++++++++++----------------
 drivers/gpu/drm/i915/intel_dp.c      |   62 +++++++++++++++++++++++++++++++++-
 drivers/gpu/drm/i915/intel_lvds.c    |    6 ++--
 6 files changed, 96 insertions(+), 45 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 5ca0663..d603c68 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -46,8 +46,8 @@ module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400);
 unsigned int i915_powersave = 1;
 module_param_named(powersave, i915_powersave, int, 0600);
 
-unsigned int i915_lvds_downclock = 0;
-module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400);
+unsigned int i915_panel_downclock = 0;
+module_param_named(panel_downclock, i915_panel_downclock, int, 0400);
 
 bool i915_try_reset = true;
 module_param_named(reset, i915_try_reset, bool, 0600);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 0e167e4..76ab3c1 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -655,9 +655,9 @@ typedef struct drm_i915_private {
 
 	/* Reclocking support */
 	bool render_reclock_avail;
-	bool lvds_downclock_avail;
-	/* indicates the reduced downclock for LVDS*/
-	int lvds_downclock;
+	bool panel_downclock_avail;
+	/* indicates the reduced downclock for the panel */
+	int panel_downclock;
 	struct work_struct idle_work;
 	struct timer_list idle_timer;
 	bool busy;
@@ -950,7 +950,7 @@ extern struct drm_ioctl_desc i915_ioctls[];
 extern int i915_max_ioctl;
 extern unsigned int i915_fbpercrtc;
 extern unsigned int i915_powersave;
-extern unsigned int i915_lvds_downclock;
+extern unsigned int i915_panel_downclock;
 
 extern int i915_suspend(struct drm_device *dev, pm_message_t state);
 extern int i915_resume(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
index b0b1200..bd8e151 100644
--- a/drivers/gpu/drm/i915/intel_bios.c
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -211,11 +211,11 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
 	}
 	kfree(temp_mode);
 	if (temp_downclock < panel_fixed_mode->clock &&
-	    i915_lvds_downclock) {
-		dev_priv->lvds_downclock_avail = 1;
-		dev_priv->lvds_downclock = temp_downclock;
-		DRM_DEBUG_KMS("LVDS downclock is found in VBT. ",
-				"Normal Clock %dKHz, downclock %dKHz\n",
+	    i915_panel_downclock) {
+		dev_priv->panel_downclock_avail = 1;
+		dev_priv->panel_downclock = temp_downclock;
+		DRM_ERROR("LVDS downclock is found in VBT.  "
+			  "Normal Clock %dKHz, downclock %dKHz\n",
 				temp_downclock, panel_fixed_mode->clock);
 	}
 	return;
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 365b47c..aa1579b 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3906,9 +3906,9 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
 	/* Ensure that the cursor is valid for the new mode before changing... */
 	intel_crtc_update_cursor(crtc, true);
 
-	if (is_lvds && dev_priv->lvds_downclock_avail) {
+	if ((is_lvds || has_edp_encoder) && dev_priv->panel_downclock_avail) {
 		has_reduced_clock = limit->find_pll(limit, crtc,
-						    dev_priv->lvds_downclock,
+						    dev_priv->panel_downclock,
 						    refclk,
 						    &reduced_clock);
 		if (has_reduced_clock && (clock.p != reduced_clock.p)) {
@@ -3949,7 +3949,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
 		int lane = 0, link_bw, bpp;
 		/* CPU eDP doesn't require FDI link, so just set DP M/N
 		   according to current link config */
-		if (has_edp_encoder && !intel_encoder_is_pch_edp(&encoder->base)) {
+		if (has_edp_encoder && !intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
 			target_clock = mode->clock;
 			intel_edp_link_config(has_edp_encoder,
 					      &lane, &link_bw);
@@ -4349,17 +4349,17 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
 	}
 
 	intel_crtc->lowfreq_avail = false;
-	if (is_lvds && has_reduced_clock && i915_powersave) {
+	if ((is_lvds || has_edp_encoder) && has_reduced_clock && i915_powersave) {
 		I915_WRITE(fp_reg + 4, fp2);
 		intel_crtc->lowfreq_avail = true;
 		if (HAS_PIPE_CXSR(dev)) {
-			DRM_DEBUG_KMS("enabling CxSR downclocking\n");
+			DRM_ERROR("enabling CxSR downclocking\n");
 			pipeconf |= PIPECONF_CXSR_DOWNCLOCK;
 		}
 	} else {
 		I915_WRITE(fp_reg + 4, fp);
 		if (HAS_PIPE_CXSR(dev)) {
-			DRM_DEBUG_KMS("disabling CxSR downclocking\n");
+			DRM_ERROR("disabling CxSR downclocking\n");
 			pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK;
 		}
 	}
@@ -4414,6 +4414,11 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
 		I915_WRITE(PIPE_LINK_M1(pipe), m_n.link_m);
 		I915_WRITE(PIPE_LINK_N1(pipe), m_n.link_n);
 
+		I915_WRITE(PIPE_DATA_M2(pipe), TU_SIZE(m_n.tu) | m_n.gmch_m);
+		I915_WRITE(PIPE_DATA_N2(pipe), m_n.gmch_n);
+		I915_WRITE(PIPE_LINK_M2(pipe), m_n.link_m);
+		I915_WRITE(PIPE_LINK_N2(pipe), m_n.link_n);
+
 		if (has_edp_encoder && !intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
 			ironlake_set_pll_edp(crtc, adjusted_mode->clock);
 		}
@@ -5039,19 +5044,15 @@ static void intel_increase_pllclock(struct drm_crtc *crtc)
 	int dpll_reg = DPLL(pipe);
 	int dpll;
 
-	if (HAS_PCH_SPLIT(dev))
+	if (!dev_priv->panel_downclock_avail)
 		return;
 
-	if (!dev_priv->lvds_downclock_avail)
-		return;
+	if (HAS_PCH_SPLIT(dev))
+		dpll_reg = PCH_DPLL(pipe);
 
 	dpll = I915_READ(dpll_reg);
 	if (!HAS_PIPE_CXSR(dev) && (dpll & DISPLAY_RATE_SELECT_FPA1)) {
-		DRM_DEBUG_DRIVER("upclocking LVDS\n");
-
-		/* Unlock panel regs */
-		I915_WRITE(PP_CONTROL,
-			   I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS);
+		DRM_ERROR("upclocking LVDS\n");
 
 		dpll &= ~DISPLAY_RATE_SELECT_FPA1;
 		I915_WRITE(dpll_reg, dpll);
@@ -5060,10 +5061,7 @@ static void intel_increase_pllclock(struct drm_crtc *crtc)
 
 		dpll = I915_READ(dpll_reg);
 		if (dpll & DISPLAY_RATE_SELECT_FPA1)
-			DRM_DEBUG_DRIVER("failed to upclock LVDS!\n");
-
-		/* ...and lock them again */
-		I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) & 0x3);
+			DRM_ERROR("failed to upclock LVDS!\n");
 	}
 
 	/* Schedule downclock */
@@ -5080,22 +5078,18 @@ static void intel_decrease_pllclock(struct drm_crtc *crtc)
 	int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
 	int dpll = I915_READ(dpll_reg);
 
-	if (HAS_PCH_SPLIT(dev))
+	if (!dev_priv->panel_downclock_avail)
 		return;
 
-	if (!dev_priv->lvds_downclock_avail)
-		return;
+	if (HAS_PCH_SPLIT(dev))
+		dpll_reg = PCH_DPLL(pipe);
 
 	/*
 	 * Since this is called by a timer, we should never get here in
 	 * the manual case.
 	 */
 	if (!HAS_PIPE_CXSR(dev) && intel_crtc->lowfreq_avail) {
-		DRM_DEBUG_DRIVER("downclocking LVDS\n");
-
-		/* Unlock panel regs */
-		I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) |
-			   PANEL_UNLOCK_REGS);
+		DRM_ERROR("downclocking LVDS\n");
 
 		dpll |= DISPLAY_RATE_SELECT_FPA1;
 		I915_WRITE(dpll_reg, dpll);
@@ -5103,10 +5097,7 @@ static void intel_decrease_pllclock(struct drm_crtc *crtc)
 		intel_wait_for_vblank(dev, pipe);
 		dpll = I915_READ(dpll_reg);
 		if (!(dpll & DISPLAY_RATE_SELECT_FPA1))
-			DRM_DEBUG_DRIVER("failed to downclock LVDS!\n");
-
-		/* ...and lock them again */
-		I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) & 0x3);
+			DRM_ERROR("failed to downclock LVDS!\n");
 	}
 
 }
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 1dc6040..feb0c23 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1572,25 +1572,82 @@ intel_dp_detect(struct drm_connector *connector, bool force)
 	return connector_status_connected;
 }
 
+/**
+ * intel_find_panel_downclock - find the reduced downclock for the panel in EDID
+ * @dev: drm device
+ * @connector: eDP connector
+ *
+ * Find the reduced downclock for the panel in EDID.
+ */
+static void intel_find_panel_downclock(struct drm_device *dev,
+				       struct drm_display_mode *fixed_mode,
+				       struct drm_connector *connector)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_display_mode *scan;
+	int temp_downclock;
+
+	DRM_ERROR("looking for reduced panel refresh\n");
+
+	temp_downclock = fixed_mode->clock;
+	list_for_each_entry(scan, &connector->probed_modes, head) {
+		DRM_ERROR("checking %dx%d@%d\n", scan->hdisplay,
+			  scan->vdisplay, scan->clock);
+		/*
+		 * If one mode has the same resolution with the fixed_panel
+		 * mode while they have the different refresh rate, it means
+		 * that the reduced downclock is found for the LVDS. In such
+		 * case we can set the different FPx0/1 to dynamically select
+		 * between low and high frequency.
+		 */
+		if (scan->hdisplay == fixed_mode->hdisplay &&
+		    scan->vdisplay == fixed_mode->vdisplay) {
+			if (scan->clock < temp_downclock) {
+				/*
+				 * The downclock is already found. But we
+				 * expect to find the lower downclock.
+				 */
+				temp_downclock = scan->clock;
+			}
+		}
+	}
+	if (temp_downclock < fixed_mode->clock && i915_panel_downclock) {
+		/* We found the downclock for LVDS. */
+		dev_priv->panel_downclock_avail = 1;
+		dev_priv->panel_downclock = temp_downclock;
+		DRM_ERROR("Panel downclock is found in EDID. "
+			  "Normal clock %dKhz, downclock %dKhz\n",
+			  fixed_mode->clock, temp_downclock);
+	}
+}
+
 static int intel_dp_get_modes(struct drm_connector *connector)
 {
 	struct intel_dp *intel_dp = intel_attached_dp(connector);
 	struct drm_device *dev = intel_dp->base.base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	int ret;
+	bool was_on;
 
 	/* We should parse the EDID data and find out if it has an audio sink
 	 */
 
+	was_on = ironlake_edp_panel_on(intel_dp);
 	ret = intel_ddc_get_modes(connector, &intel_dp->adapter);
+	if (!was_on)
+		ironlake_edp_panel_off(dev);
 	if (ret) {
-		if (is_edp(intel_dp) && !dev_priv->panel_fixed_mode) {
+		if (is_edp(intel_dp) && (!dev_priv->panel_fixed_mode ||
+					 !dev_priv->panel_downclock)) {
 			struct drm_display_mode *newmode;
 			list_for_each_entry(newmode, &connector->probed_modes,
 					    head) {
 				if (newmode->type & DRM_MODE_TYPE_PREFERRED) {
 					dev_priv->panel_fixed_mode =
 						drm_mode_duplicate(dev, newmode);
+					intel_find_panel_downclock(dev,
+								   dev_priv->panel_fixed_mode,
+								   connector);
 					break;
 				}
 			}
@@ -1605,6 +1662,9 @@ static int intel_dp_get_modes(struct drm_connector *connector)
 			struct drm_display_mode *mode;
 			mode = drm_mode_duplicate(dev, dev_priv->panel_fixed_mode);
 			drm_mode_probed_add(connector, mode);
+			intel_find_panel_downclock(dev,
+						   dev_priv->panel_fixed_mode,
+						   connector);
 			return 1;
 		}
 	}
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index aa23070..3f81bd7 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -764,10 +764,10 @@ static void intel_find_lvds_downclock(struct drm_device *dev,
 			}
 		}
 	}
-	if (temp_downclock < fixed_mode->clock && i915_lvds_downclock) {
+	if (temp_downclock < fixed_mode->clock && i915_panel_downclock) {
 		/* We found the downclock for LVDS. */
-		dev_priv->lvds_downclock_avail = 1;
-		dev_priv->lvds_downclock = temp_downclock;
+		dev_priv->panel_downclock_avail = 1;
+		dev_priv->panel_downclock = temp_downclock;
 		DRM_DEBUG_KMS("LVDS downclock is found in EDID. "
 			      "Normal clock %dKhz, downclock %dKhz\n",
 			      fixed_mode->clock, temp_downclock);
-- 
1.7.0.4




More information about the Intel-gfx mailing list