[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