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 %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

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to