[Intel-gfx] [PATCH 1/2] drm/i915: Use the software DRRS to select the alternative frequency for LVDS

yakui.zhao at intel.com yakui.zhao at intel.com
Thu Nov 5 04:27:16 CET 2009


From: Zhao Yakui <yakui.zhao at intel.com>

According to the spec the DRRS bit in DPLL control register can be used to
select dynamically between low and high frequency.  If more than one mode with
the same resolution defined in EDID has the different refresh rate, it is
thought that the downclock is found for LVDS. We will program the different
FPx0/1 register. Then we can use the DRRS feature to select dynamically between
the low and high frequency.

Signed-off-by: Zhao Yakui <yakui.zhao at intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h      |    2 +
 drivers/gpu/drm/i915/intel_display.c |   30 ++++++++++++------------
 drivers/gpu/drm/i915/intel_lvds.c    |   43 ++++++++++++++++++++++++++++++++++
 3 files changed, 60 insertions(+), 15 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 9f35883..5aeae1f 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -506,6 +506,8 @@ typedef struct drm_i915_private {
 	/* Reclocking support */
 	bool render_reclock_avail;
 	bool lvds_downclock_avail;
+	/* indicates the reduced downclock for LVDS*/
+	int	lvds_downclock;
 	struct work_struct idle_work;
 	struct timer_list idle_timer;
 	bool busy;
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 1a40b9a..6912a3f 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -360,7 +360,7 @@ static const intel_limit_t intel_limits_g4x_sdvo = {
 		 .p2_fast = G4X_P2_SDVO_FAST
 	},
 	.find_pll = intel_g4x_find_best_PLL,
-	.find_reduced_pll = intel_g4x_find_best_PLL,
+	.find_reduced_pll = intel_find_best_reduced_PLL,
 };
 
 static const intel_limit_t intel_limits_g4x_hdmi = {
@@ -377,7 +377,7 @@ static const intel_limit_t intel_limits_g4x_hdmi = {
 		 .p2_fast = G4X_P2_HDMI_DAC_FAST
 	},
 	.find_pll = intel_g4x_find_best_PLL,
-	.find_reduced_pll = intel_g4x_find_best_PLL,
+	.find_reduced_pll = intel_find_best_reduced_PLL,
 };
 
 static const intel_limit_t intel_limits_g4x_single_channel_lvds = {
@@ -402,7 +402,7 @@ static const intel_limit_t intel_limits_g4x_single_channel_lvds = {
 		 .p2_fast = G4X_P2_SINGLE_CHANNEL_LVDS_FAST
 	},
 	.find_pll = intel_g4x_find_best_PLL,
-	.find_reduced_pll = intel_g4x_find_best_PLL,
+	.find_reduced_pll = intel_find_best_reduced_PLL,
 };
 
 static const intel_limit_t intel_limits_g4x_dual_channel_lvds = {
@@ -427,7 +427,7 @@ static const intel_limit_t intel_limits_g4x_dual_channel_lvds = {
 		 .p2_fast = G4X_P2_DUAL_CHANNEL_LVDS_FAST
 	},
 	.find_pll = intel_g4x_find_best_PLL,
-	.find_reduced_pll = intel_g4x_find_best_PLL,
+	.find_reduced_pll = intel_find_best_reduced_PLL,
 };
 
 static const intel_limit_t intel_limits_g4x_display_port = {
@@ -2781,7 +2781,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
 	if (limit->find_reduced_pll && dev_priv->lvds_downclock_avail) {
 		memcpy(&reduced_clock, &clock, sizeof(intel_clock_t));
 		has_reduced_clock = limit->find_reduced_pll(limit, crtc,
-							    (adjusted_mode->clock*3/4),
+						dev_priv->lvds_downclock,
 							    refclk,
 							    &reduced_clock);
 	}
@@ -3047,20 +3047,20 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
 		udelay(150);
 	}
 
+	/*
+	 * According to the spec We can select between two alternative
+	 * frequency by using DRRS bit only when the CxSR bit in PIPECONF
+	 * register is zero. So it will clear the CxSR bit of PIPECONF
+	 * register.
+	 */
 	if (is_lvds && 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");
-			pipeconf |= PIPECONF_CXSR_DOWNCLOCK;
-		}
+		pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK;
 	} else {
 		I915_WRITE(fp_reg + 4, fp);
 		intel_crtc->lowfreq_avail = false;
-		if (HAS_PIPE_CXSR(dev)) {
-			DRM_DEBUG_KMS("disabling CxSR downclocking\n");
-			pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK;
-		}
+		pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK;
 	}
 
 	I915_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) |
@@ -3750,7 +3750,7 @@ static void intel_increase_pllclock(struct drm_crtc *crtc, bool schedule)
 	if (!dev_priv->lvds_downclock_avail)
 		return;
 
-	if (!HAS_PIPE_CXSR(dev) && (dpll & DISPLAY_RATE_SELECT_FPA1)) {
+	if (HAS_PIPE_CXSR(dev) && (dpll & DISPLAY_RATE_SELECT_FPA1)) {
 		DRM_DEBUG_DRIVER("upclocking LVDS\n");
 
 		/* Unlock panel regs */
@@ -3793,7 +3793,7 @@ static void intel_decrease_pllclock(struct drm_crtc *crtc)
 	 * 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) {
+	if (HAS_PIPE_CXSR(dev) && intel_crtc->lowfreq_avail) {
 		DRM_DEBUG_DRIVER("downclocking LVDS\n");
 
 		/* Unlock panel regs */
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index ac71696..e1aa9cd 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -899,6 +899,48 @@ static int intel_lid_present(void)
 #endif
 
 /**
+ * intel_find_lvds_downclock - find the reduced downclock for LVDS in EDID
+ * @dev: drm device
+ * @connector: LVDS connector
+ *
+ * Find the reduced downclock for LVDS in EDID.
+ */
+static void intel_find_lvds_downclock(struct drm_device *dev,
+				struct drm_connector *connector)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_display_mode *scan, *panel_fixed_mode;
+
+	panel_fixed_mode = dev_priv->panel_fixed_mode;
+	list_for_each_entry(scan, &connector->probed_modes, head) {
+		mutex_lock(&dev->mode_config.mutex);
+		/*
+		 * 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 == panel_fixed_mode->hdisplay &&
+			scan->hsync_start == panel_fixed_mode->hsync_start &&
+			scan->hsync_end == panel_fixed_mode->hsync_end &&
+			scan->htotal == panel_fixed_mode->htotal &&
+			scan->vdisplay == panel_fixed_mode->vdisplay &&
+			scan->vsync_start == panel_fixed_mode->vsync_start &&
+			scan->vsync_end == panel_fixed_mode->vsync_end &&
+			scan->vtotal == panel_fixed_mode->vtotal) {
+			if (scan->clock < panel_fixed_mode->clock) {
+				DRM_DEBUG_KMS("Reduced downclock is found\n");
+				dev_priv->lvds_downclock_avail = 1;
+				dev_priv->lvds_downclock = scan->clock;
+			}
+		}
+		mutex_unlock(&dev->mode_config.mutex);
+	}
+	return;
+}
+
+/**
  * intel_lvds_init - setup LVDS connectors on this device
  * @dev: drm device
  *
@@ -1008,6 +1050,7 @@ void intel_lvds_init(struct drm_device *dev)
 			dev_priv->panel_fixed_mode =
 				drm_mode_duplicate(dev, scan);
 			mutex_unlock(&dev->mode_config.mutex);
+			intel_find_lvds_downclock(dev, connector);
 			goto out;
 		}
 		mutex_unlock(&dev->mode_config.mutex);
-- 
1.5.4.5




More information about the Intel-gfx mailing list