Merge branch 'drm-intel-fixes' of git://people.freedesktop.org/~keithp/linux into...
authorDave Airlie <airlied@redhat.com>
Tue, 22 Nov 2011 20:01:00 +0000 (20:01 +0000)
committerDave Airlie <airlied@redhat.com>
Tue, 22 Nov 2011 20:01:00 +0000 (20:01 +0000)
* 'drm-intel-fixes' of git://people.freedesktop.org/~keithp/linux: (25 commits)
  drm/i915: Fix inconsistent backlight level during disabled
  drm, i915: Fix memory leak in i915_gem_busy_ioctl().
  drm/i915: Use DPCD value for max DP lanes.
  drm/i915: Initiate DP link training only on the lanes we'll be using
  drm/i915: Remove trailing white space
  drm/i915: Try harder during dp pattern 1 link training
  drm/i915: Make DP prepare/commit consistent with DP dpms
  drm/i915: Let panel power sequencing hardware do its job
  drm/i915: Treat PCH eDP like DP in most places
  drm/i915: Remove link_status field from intel_dp structure
  drm/i915: Move common PCH_PP_CONTROL setup to ironlake_get_pp_control
  drm/i915: Module parameters using '-1' as default must be signed type
  drm/i915: Turn on another required clock gating bit on gen6.
  drm/i915: Turn on a required 3D clock gating bit on Sandybridge.
  drm/i915: enable cacheable objects on Ivybridge
  drm/i915: add constants to size fence arrays and fields
  drm/i915: Ivybridge still has fences!
  drm/i915: forcewake warning fixes in debugfs
  drm/i915: Fix object refcount leak on mmappable size limit error path.
  drm/i915: Use mode_config.mutex in ironlake_panel_vdd_work
  ...

1  2 
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/intel_dp.c

index 4f40f1ce1d8effd5ff1c5502cfcefcaaf49af751,f2e02075d51009705492d0bd52be108ea8532f95..d09a6e02dc95374caf456923cba25efa94aafa94
@@@ -29,7 -29,6 +29,7 @@@
  #include <linux/seq_file.h>
  #include <linux/debugfs.h>
  #include <linux/slab.h>
 +#include <linux/export.h>
  #include "drmP.h"
  #include "drm.h"
  #include "intel_drv.h"
@@@ -636,11 -635,16 +636,16 @@@ static int i915_ringbuffer_info(struct 
        struct drm_device *dev = node->minor->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct intel_ring_buffer *ring;
+       int ret;
  
        ring = &dev_priv->ring[(uintptr_t)node->info_ent->data];
        if (ring->size == 0)
                return 0;
  
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
        seq_printf(m, "Ring %s:\n", ring->name);
        seq_printf(m, "  Head :    %08x\n", I915_READ_HEAD(ring) & HEAD_ADDR);
        seq_printf(m, "  Tail :    %08x\n", I915_READ_TAIL(ring) & TAIL_ADDR);
        seq_printf(m, "  Control : %08x\n", I915_READ_CTL(ring));
        seq_printf(m, "  Start :   %08x\n", I915_READ_START(ring));
  
+       mutex_unlock(&dev->struct_mutex);
        return 0;
  }
  
@@@ -842,7 -848,16 +849,16 @@@ static int i915_rstdby_delays(struct se
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        struct drm_device *dev = node->minor->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       u16 crstanddelay = I915_READ16(CRSTANDVID);
+       u16 crstanddelay;
+       int ret;
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
+       crstanddelay = I915_READ16(CRSTANDVID);
+       mutex_unlock(&dev->struct_mutex);
  
        seq_printf(m, "w/ctx: %d, w/o ctx: %d\n", (crstanddelay >> 8) & 0x3f, (crstanddelay & 0x3f));
  
@@@ -940,7 -955,11 +956,11 @@@ static int i915_delayfreq_table(struct 
        struct drm_device *dev = node->minor->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
        u32 delayfreq;
-       int i;
+       int ret, i;
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
  
        for (i = 0; i < 16; i++) {
                delayfreq = I915_READ(PXVFREQ_BASE + i * 4);
                           (delayfreq & PXVFREQ_PX_MASK) >> PXVFREQ_PX_SHIFT);
        }
  
+       mutex_unlock(&dev->struct_mutex);
        return 0;
  }
  
@@@ -962,13 -983,19 +984,19 @@@ static int i915_inttoext_table(struct s
        struct drm_device *dev = node->minor->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
        u32 inttoext;
-       int i;
+       int ret, i;
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
  
        for (i = 1; i <= 32; i++) {
                inttoext = I915_READ(INTTOEXT_BASE_ILK + i * 4);
                seq_printf(m, "INTTOEXT%02d: 0x%08x\n", i, inttoext);
        }
  
+       mutex_unlock(&dev->struct_mutex);
        return 0;
  }
  
@@@ -977,9 -1004,19 +1005,19 @@@ static int i915_drpc_info(struct seq_fi
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        struct drm_device *dev = node->minor->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       u32 rgvmodectl = I915_READ(MEMMODECTL);
-       u32 rstdbyctl = I915_READ(RSTDBYCTL);
-       u16 crstandvid = I915_READ16(CRSTANDVID);
+       u32 rgvmodectl, rstdbyctl;
+       u16 crstandvid;
+       int ret;
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
+       rgvmodectl = I915_READ(MEMMODECTL);
+       rstdbyctl = I915_READ(RSTDBYCTL);
+       crstandvid = I915_READ16(CRSTANDVID);
+       mutex_unlock(&dev->struct_mutex);
  
        seq_printf(m, "HD boost: %s\n", (rgvmodectl & MEMMODE_BOOST_EN) ?
                   "yes" : "no");
@@@ -1167,9 -1204,16 +1205,16 @@@ static int i915_gfxec(struct seq_file *
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        struct drm_device *dev = node->minor->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
+       int ret;
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
  
        seq_printf(m, "GFXEC: %ld\n", (unsigned long)I915_READ(0x112f4));
  
+       mutex_unlock(&dev->struct_mutex);
        return 0;
  }
  
@@@ -1506,10 -1550,7 +1551,10 @@@ drm_add_fake_info_node(struct drm_mino
        node->minor = minor;
        node->dent = ent;
        node->info_ent = (void *) key;
 -      list_add(&node->list, &minor->debugfs_nodes.list);
 +
 +      mutex_lock(&minor->debugfs_lock);
 +      list_add(&node->list, &minor->debugfs_list);
 +      mutex_unlock(&minor->debugfs_lock);
  
        return 0;
  }
index cc531bb59c26f7ccc8b7de8721f1b94bce576be6,13488be4ae4b09143dacf5955c26736044d9462d..2fa96c817c2ac715d84f2a59203a94bc917c5af4
@@@ -35,7 -35,6 +35,7 @@@
  #include "intel_drv.h"
  
  #include <linux/console.h>
 +#include <linux/module.h>
  #include "drm_crtc_helper.h"
  
  static int i915_modeset __read_mostly = -1;
@@@ -68,7 -67,7 +68,7 @@@ module_param_named(i915_enable_rc6, i91
  MODULE_PARM_DESC(i915_enable_rc6,
                "Enable power-saving render C-state 6 (default: true)");
  
unsigned int i915_enable_fbc __read_mostly = -1;
+ int i915_enable_fbc __read_mostly = -1;
  module_param_named(i915_enable_fbc, i915_enable_fbc, int, 0600);
  MODULE_PARM_DESC(i915_enable_fbc,
                "Enable frame buffer compression for power savings "
@@@ -80,7 -79,7 +80,7 @@@ MODULE_PARM_DESC(lvds_downclock
                "Use panel (LVDS/eDP) downclocking for power savings "
                "(default: false)");
  
unsigned int i915_panel_use_ssc __read_mostly = -1;
+ int i915_panel_use_ssc __read_mostly = -1;
  module_param_named(lvds_use_ssc, i915_panel_use_ssc, int, 0600);
  MODULE_PARM_DESC(lvds_use_ssc,
                "Use Spread Spectrum Clock with panels [LVDS/eDP] "
@@@ -107,7 -106,7 +107,7 @@@ static struct drm_driver driver
  extern int intel_agp_enabled;
  
  #define INTEL_VGA_DEVICE(id, info) {          \
-       .class = PCI_CLASS_DISPLAY_VGA << 8,    \
+       .class = PCI_BASE_CLASS_DISPLAY << 16,  \
        .class_mask = 0xff0000,                 \
        .vendor = 0x8086,                       \
        .device = id,                           \
index 09b318b0227f3571402c479c06bb376c6aae7eda,ec28aebf5147c7b2f7ebb74dc919ac87581eb407..4d0358fad93795c31dd9d4229daa3c7c2ecedcc5
@@@ -27,7 -27,6 +27,7 @@@
  
  #include <linux/i2c.h>
  #include <linux/slab.h>
 +#include <linux/export.h>
  #include "drmP.h"
  #include "drm.h"
  #include "drm_crtc.h"
@@@ -59,7 -58,6 +59,6 @@@ struct intel_dp 
        struct i2c_algo_dp_aux_data algo;
        bool is_pch_edp;
        uint8_t train_set[4];
-       uint8_t link_status[DP_LINK_STATUS_SIZE];
        int panel_power_up_delay;
        int panel_power_down_delay;
        int panel_power_cycle_delay;
@@@ -68,7 -66,6 +67,6 @@@
        struct drm_display_mode *panel_fixed_mode;  /* for eDP */
        struct delayed_work panel_vdd_work;
        bool want_panel_vdd;
-       unsigned long panel_off_jiffies;
  };
  
  /**
@@@ -157,16 -154,12 +155,12 @@@ intel_edp_link_config(struct intel_enco
  static int
  intel_dp_max_lane_count(struct intel_dp *intel_dp)
  {
-       int max_lane_count = 4;
-       if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11) {
-               max_lane_count = intel_dp->dpcd[DP_MAX_LANE_COUNT] & 0x1f;
-               switch (max_lane_count) {
-               case 1: case 2: case 4:
-                       break;
-               default:
-                       max_lane_count = 4;
-               }
+       int max_lane_count = intel_dp->dpcd[DP_MAX_LANE_COUNT] & 0x1f;
+       switch (max_lane_count) {
+       case 1: case 2: case 4:
+               break;
+       default:
+               max_lane_count = 4;
        }
        return max_lane_count;
  }
@@@ -768,12 -761,11 +762,11 @@@ intel_dp_set_m_n(struct drm_crtc *crtc
                        continue;
  
                intel_dp = enc_to_intel_dp(encoder);
-               if (intel_dp->base.type == INTEL_OUTPUT_DISPLAYPORT) {
+               if (intel_dp->base.type == INTEL_OUTPUT_DISPLAYPORT ||
+                   intel_dp->base.type == INTEL_OUTPUT_EDP)
+               {
                        lane_count = intel_dp->lane_count;
                        break;
-               } else if (is_edp(intel_dp)) {
-                       lane_count = dev_priv->edp.lanes;
-                       break;
                }
        }
  
@@@ -810,6 -802,7 +803,7 @@@ intel_dp_mode_set(struct drm_encoder *e
                  struct drm_display_mode *adjusted_mode)
  {
        struct drm_device *dev = encoder->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
        struct drm_crtc *crtc = intel_dp->base.base.crtc;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
                        ironlake_edp_pll_off(encoder);
        }
  
-       intel_dp->DP = DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0;
-       intel_dp->DP |= intel_dp->color_range;
+       /*
+        * There are three kinds of DP registers:
+        *
+        *      IBX PCH
+        *      CPU
+        *      CPT PCH
+        *
+        * IBX PCH and CPU are the same for almost everything,
+        * except that the CPU DP PLL is configured in this
+        * register
+        *
+        * CPT PCH is quite different, having many bits moved
+        * to the TRANS_DP_CTL register instead. That
+        * configuration happens (oddly) in ironlake_pch_enable
+        */
  
-       if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
-               intel_dp->DP |= DP_SYNC_HS_HIGH;
-       if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
-               intel_dp->DP |= DP_SYNC_VS_HIGH;
+       /* Preserve the BIOS-computed detected bit. This is
+        * supposed to be read-only.
+        */
+       intel_dp->DP = I915_READ(intel_dp->output_reg) & DP_DETECTED;
+       intel_dp->DP |=  DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0;
  
-       if (HAS_PCH_CPT(dev) && !is_cpu_edp(intel_dp))
-               intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT;
-       else
-               intel_dp->DP |= DP_LINK_TRAIN_OFF;
+       /* Handle DP bits in common between all three register formats */
+       intel_dp->DP |= DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0;
  
        switch (intel_dp->lane_count) {
        case 1:
                intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE;
                intel_write_eld(encoder, adjusted_mode);
        }
        memset(intel_dp->link_configuration, 0, DP_LINK_CONFIGURATION_SIZE);
        intel_dp->link_configuration[0] = intel_dp->link_bw;
        intel_dp->link_configuration[1] = intel_dp->lane_count;
        intel_dp->link_configuration[8] = DP_SET_ANSI_8B10B;
        /*
         * Check for DPCD version > 1.1 and enhanced framing support
         */
        if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11 &&
            (intel_dp->dpcd[DP_MAX_LANE_COUNT] & DP_ENHANCED_FRAME_CAP)) {
                intel_dp->link_configuration[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
-               intel_dp->DP |= DP_ENHANCED_FRAMING;
        }
  
-       /* CPT DP's pipe select is decided in TRANS_DP_CTL */
-       if (intel_crtc->pipe == 1 && !HAS_PCH_CPT(dev))
-               intel_dp->DP |= DP_PIPEB_SELECT;
+       /* Split out the IBX/CPU vs CPT settings */
  
-       if (is_cpu_edp(intel_dp)) {
-               /* don't miss out required setting for eDP */
-               intel_dp->DP |= DP_PLL_ENABLE;
-               if (adjusted_mode->clock < 200000)
-                       intel_dp->DP |= DP_PLL_FREQ_160MHZ;
-               else
-                       intel_dp->DP |= DP_PLL_FREQ_270MHZ;
+       if (!HAS_PCH_CPT(dev) || is_cpu_edp(intel_dp)) {
+               intel_dp->DP |= intel_dp->color_range;
+               if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
+                       intel_dp->DP |= DP_SYNC_HS_HIGH;
+               if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
+                       intel_dp->DP |= DP_SYNC_VS_HIGH;
+               intel_dp->DP |= DP_LINK_TRAIN_OFF;
+               if (intel_dp->link_configuration[1] & DP_LANE_COUNT_ENHANCED_FRAME_EN)
+                       intel_dp->DP |= DP_ENHANCED_FRAMING;
+               if (intel_crtc->pipe == 1)
+                       intel_dp->DP |= DP_PIPEB_SELECT;
+               if (is_cpu_edp(intel_dp)) {
+                       /* don't miss out required setting for eDP */
+                       intel_dp->DP |= DP_PLL_ENABLE;
+                       if (adjusted_mode->clock < 200000)
+                               intel_dp->DP |= DP_PLL_FREQ_160MHZ;
+                       else
+                               intel_dp->DP |= DP_PLL_FREQ_270MHZ;
+               }
+       } else {
+               intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT;
        }
  }
  
- static void ironlake_wait_panel_off(struct intel_dp *intel_dp)
+ #define IDLE_ON_MASK          (PP_ON | 0        | PP_SEQUENCE_MASK | 0                     | PP_SEQUENCE_STATE_MASK)
+ #define IDLE_ON_VALUE         (PP_ON | 0        | PP_SEQUENCE_NONE | 0                     | PP_SEQUENCE_STATE_ON_IDLE)
+ #define IDLE_OFF_MASK         (PP_ON | 0        | PP_SEQUENCE_MASK | 0                     | PP_SEQUENCE_STATE_MASK)
+ #define IDLE_OFF_VALUE                (0     | 0        | PP_SEQUENCE_NONE | 0                     | PP_SEQUENCE_STATE_OFF_IDLE)
+ #define IDLE_CYCLE_MASK               (PP_ON | 0        | PP_SEQUENCE_MASK | PP_CYCLE_DELAY_ACTIVE | PP_SEQUENCE_STATE_MASK)
+ #define IDLE_CYCLE_VALUE      (0     | 0        | PP_SEQUENCE_NONE | 0                     | PP_SEQUENCE_STATE_OFF_IDLE)
+ static void ironlake_wait_panel_status(struct intel_dp *intel_dp,
+                                      u32 mask,
+                                      u32 value)
  {
-       unsigned long   off_time;
-       unsigned long   delay;
+       struct drm_device *dev = intel_dp->base.base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
  
-       DRM_DEBUG_KMS("Wait for panel power off time\n");
+       DRM_DEBUG_KMS("mask %08x value %08x status %08x control %08x\n",
+                     mask, value,
+                     I915_READ(PCH_PP_STATUS),
+                     I915_READ(PCH_PP_CONTROL));
  
-       if (ironlake_edp_have_panel_power(intel_dp) ||
-           ironlake_edp_have_panel_vdd(intel_dp))
-       {
-               DRM_DEBUG_KMS("Panel still on, no delay needed\n");
-               return;
+       if (_wait_for((I915_READ(PCH_PP_STATUS) & mask) == value, 5000, 10)) {
+               DRM_ERROR("Panel status timeout: status %08x control %08x\n",
+                         I915_READ(PCH_PP_STATUS),
+                         I915_READ(PCH_PP_CONTROL));
        }
+ }
  
-       off_time = intel_dp->panel_off_jiffies + msecs_to_jiffies(intel_dp->panel_power_down_delay);
-       if (time_after(jiffies, off_time)) {
-               DRM_DEBUG_KMS("Time already passed");
-               return;
-       }
-       delay = jiffies_to_msecs(off_time - jiffies);
-       if (delay > intel_dp->panel_power_down_delay)
-               delay = intel_dp->panel_power_down_delay;
-       DRM_DEBUG_KMS("Waiting an additional %ld ms\n", delay);
-       msleep(delay);
+ static void ironlake_wait_panel_on(struct intel_dp *intel_dp)
+ {
+       DRM_DEBUG_KMS("Wait for panel power on\n");
+       ironlake_wait_panel_status(intel_dp, IDLE_ON_MASK, IDLE_ON_VALUE);
+ }
+ static void ironlake_wait_panel_off(struct intel_dp *intel_dp)
+ {
+       DRM_DEBUG_KMS("Wait for panel power off time\n");
+       ironlake_wait_panel_status(intel_dp, IDLE_OFF_MASK, IDLE_OFF_VALUE);
+ }
+ static void ironlake_wait_panel_power_cycle(struct intel_dp *intel_dp)
+ {
+       DRM_DEBUG_KMS("Wait for panel power cycle\n");
+       ironlake_wait_panel_status(intel_dp, IDLE_CYCLE_MASK, IDLE_CYCLE_VALUE);
+ }
+ /* Read the current pp_control value, unlocking the register if it
+  * is locked
+  */
+ static  u32 ironlake_get_pp_control(struct drm_i915_private *dev_priv)
+ {
+       u32     control = I915_READ(PCH_PP_CONTROL);
+       control &= ~PANEL_UNLOCK_MASK;
+       control |= PANEL_UNLOCK_REGS;
+       return control;
  }
  
  static void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp)
             "eDP VDD already requested on\n");
  
        intel_dp->want_panel_vdd = true;
        if (ironlake_edp_have_panel_vdd(intel_dp)) {
                DRM_DEBUG_KMS("eDP VDD already on\n");
                return;
        }
  
-       ironlake_wait_panel_off(intel_dp);
-       pp = I915_READ(PCH_PP_CONTROL);
-       pp &= ~PANEL_UNLOCK_MASK;
-       pp |= PANEL_UNLOCK_REGS;
+       if (!ironlake_edp_have_panel_power(intel_dp))
+               ironlake_wait_panel_power_cycle(intel_dp);
+       pp = ironlake_get_pp_control(dev_priv);
        pp |= EDP_FORCE_VDD;
        I915_WRITE(PCH_PP_CONTROL, pp);
        POSTING_READ(PCH_PP_CONTROL);
@@@ -952,9 -1006,7 +1007,7 @@@ static void ironlake_panel_vdd_off_sync
        u32 pp;
  
        if (!intel_dp->want_panel_vdd && ironlake_edp_have_panel_vdd(intel_dp)) {
-               pp = I915_READ(PCH_PP_CONTROL);
-               pp &= ~PANEL_UNLOCK_MASK;
-               pp |= PANEL_UNLOCK_REGS;
+               pp = ironlake_get_pp_control(dev_priv);
                pp &= ~EDP_FORCE_VDD;
                I915_WRITE(PCH_PP_CONTROL, pp);
                POSTING_READ(PCH_PP_CONTROL);
                /* Make sure sequencer is idle before allowing subsequent activity */
                DRM_DEBUG_KMS("PCH_PP_STATUS: 0x%08x PCH_PP_CONTROL: 0x%08x\n",
                              I915_READ(PCH_PP_STATUS), I915_READ(PCH_PP_CONTROL));
-               intel_dp->panel_off_jiffies = jiffies;
+               msleep(intel_dp->panel_power_down_delay);
        }
  }
  
@@@ -972,9 -1025,9 +1026,9 @@@ static void ironlake_panel_vdd_work(str
                                                 struct intel_dp, panel_vdd_work);
        struct drm_device *dev = intel_dp->base.base.dev;
  
-       mutex_lock(&dev->struct_mutex);
+       mutex_lock(&dev->mode_config.mutex);
        ironlake_panel_vdd_off_sync(intel_dp);
-       mutex_unlock(&dev->struct_mutex);
+       mutex_unlock(&dev->mode_config.mutex);
  }
  
  static void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync)
  
        DRM_DEBUG_KMS("Turn eDP VDD off %d\n", intel_dp->want_panel_vdd);
        WARN(!intel_dp->want_panel_vdd, "eDP VDD not forced on");
-       
        intel_dp->want_panel_vdd = false;
  
        if (sync) {
        }
  }
  
- /* Returns true if the panel was already on when called */
  static void ironlake_edp_panel_on(struct intel_dp *intel_dp)
  {
        struct drm_device *dev = intel_dp->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 pp, idle_on_mask = PP_ON | PP_SEQUENCE_STATE_ON_IDLE;
+       u32 pp;
  
        if (!is_edp(intel_dp))
                return;
-       if (ironlake_edp_have_panel_power(intel_dp))
+       DRM_DEBUG_KMS("Turn eDP power on\n");
+       if (ironlake_edp_have_panel_power(intel_dp)) {
+               DRM_DEBUG_KMS("eDP power already on\n");
                return;
+       }
  
-       ironlake_wait_panel_off(intel_dp);
-       pp = I915_READ(PCH_PP_CONTROL);
-       pp &= ~PANEL_UNLOCK_MASK;
-       pp |= PANEL_UNLOCK_REGS;
+       ironlake_wait_panel_power_cycle(intel_dp);
  
+       pp = ironlake_get_pp_control(dev_priv);
        if (IS_GEN5(dev)) {
                /* ILK workaround: disable reset around power sequence */
                pp &= ~PANEL_POWER_RESET;
        }
  
        pp |= POWER_TARGET_ON;
+       if (!IS_GEN5(dev))
+               pp |= PANEL_POWER_RESET;
        I915_WRITE(PCH_PP_CONTROL, pp);
        POSTING_READ(PCH_PP_CONTROL);
  
-       if (wait_for((I915_READ(PCH_PP_STATUS) & idle_on_mask) == idle_on_mask,
-                    5000))
-               DRM_ERROR("panel on wait timed out: 0x%08x\n",
-                         I915_READ(PCH_PP_STATUS));
+       ironlake_wait_panel_on(intel_dp);
  
        if (IS_GEN5(dev)) {
                pp |= PANEL_POWER_RESET; /* restore panel reset bit */
        }
  }
  
- static void ironlake_edp_panel_off(struct drm_encoder *encoder)
+ static void ironlake_edp_panel_off(struct intel_dp *intel_dp)
  {
-       struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-       struct drm_device *dev = encoder->dev;
+       struct drm_device *dev = intel_dp->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 pp, idle_off_mask = PP_ON | PP_SEQUENCE_MASK |
-               PP_CYCLE_DELAY_ACTIVE | PP_SEQUENCE_STATE_MASK;
+       u32 pp;
  
        if (!is_edp(intel_dp))
                return;
-       pp = I915_READ(PCH_PP_CONTROL);
-       pp &= ~PANEL_UNLOCK_MASK;
-       pp |= PANEL_UNLOCK_REGS;
  
-       if (IS_GEN5(dev)) {
-               /* ILK workaround: disable reset around power sequence */
-               pp &= ~PANEL_POWER_RESET;
-               I915_WRITE(PCH_PP_CONTROL, pp);
-               POSTING_READ(PCH_PP_CONTROL);
-       }
+       DRM_DEBUG_KMS("Turn eDP power off\n");
  
-       intel_dp->panel_off_jiffies = jiffies;
+       WARN(intel_dp->want_panel_vdd, "Cannot turn power off while VDD is on\n");
  
-       if (IS_GEN5(dev)) {
-               pp &= ~POWER_TARGET_ON;
-               I915_WRITE(PCH_PP_CONTROL, pp);
-               POSTING_READ(PCH_PP_CONTROL);
-               pp &= ~POWER_TARGET_ON;
-               I915_WRITE(PCH_PP_CONTROL, pp);
-               POSTING_READ(PCH_PP_CONTROL);
-               msleep(intel_dp->panel_power_cycle_delay);
-               if (wait_for((I915_READ(PCH_PP_STATUS) & idle_off_mask) == 0, 5000))
-                       DRM_ERROR("panel off wait timed out: 0x%08x\n",
-                                 I915_READ(PCH_PP_STATUS));
+       pp = ironlake_get_pp_control(dev_priv);
+       pp &= ~(POWER_TARGET_ON | EDP_FORCE_VDD | PANEL_POWER_RESET | EDP_BLC_ENABLE);
+       I915_WRITE(PCH_PP_CONTROL, pp);
+       POSTING_READ(PCH_PP_CONTROL);
  
-               pp |= PANEL_POWER_RESET; /* restore panel reset bit */
-               I915_WRITE(PCH_PP_CONTROL, pp);
-               POSTING_READ(PCH_PP_CONTROL);
-       }
+       ironlake_wait_panel_off(intel_dp);
  }
  
  static void ironlake_edp_backlight_on(struct intel_dp *intel_dp)
         * allowing it to appear.
         */
        msleep(intel_dp->backlight_on_delay);
-       pp = I915_READ(PCH_PP_CONTROL);
-       pp &= ~PANEL_UNLOCK_MASK;
-       pp |= PANEL_UNLOCK_REGS;
+       pp = ironlake_get_pp_control(dev_priv);
        pp |= EDP_BLC_ENABLE;
        I915_WRITE(PCH_PP_CONTROL, pp);
        POSTING_READ(PCH_PP_CONTROL);
@@@ -1117,9 -1149,7 +1150,7 @@@ static void ironlake_edp_backlight_off(
                return;
  
        DRM_DEBUG_KMS("\n");
-       pp = I915_READ(PCH_PP_CONTROL);
-       pp &= ~PANEL_UNLOCK_MASK;
-       pp |= PANEL_UNLOCK_REGS;
+       pp = ironlake_get_pp_control(dev_priv);
        pp &= ~EDP_BLC_ENABLE;
        I915_WRITE(PCH_PP_CONTROL, pp);
        POSTING_READ(PCH_PP_CONTROL);
@@@ -1187,17 -1217,18 +1218,18 @@@ static void intel_dp_prepare(struct drm
  {
        struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
  
+       ironlake_edp_backlight_off(intel_dp);
+       ironlake_edp_panel_off(intel_dp);
        /* Wake up the sink first */
        ironlake_edp_panel_vdd_on(intel_dp);
        intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
+       intel_dp_link_down(intel_dp);
        ironlake_edp_panel_vdd_off(intel_dp, false);
  
        /* Make sure the panel is off before trying to
         * change the mode
         */
-       ironlake_edp_backlight_off(intel_dp);
-       intel_dp_link_down(intel_dp);
-       ironlake_edp_panel_off(encoder);
  }
  
  static void intel_dp_commit(struct drm_encoder *encoder)
        intel_dp_start_link_train(intel_dp);
        ironlake_edp_panel_on(intel_dp);
        ironlake_edp_panel_vdd_off(intel_dp, true);
        intel_dp_complete_link_train(intel_dp);
        ironlake_edp_backlight_on(intel_dp);
  
@@@ -1230,16 -1260,20 +1261,20 @@@ intel_dp_dpms(struct drm_encoder *encod
        uint32_t dp_reg = I915_READ(intel_dp->output_reg);
  
        if (mode != DRM_MODE_DPMS_ON) {
+               ironlake_edp_backlight_off(intel_dp);
+               ironlake_edp_panel_off(intel_dp);
                ironlake_edp_panel_vdd_on(intel_dp);
-               if (is_edp(intel_dp))
-                       ironlake_edp_backlight_off(intel_dp);
                intel_dp_sink_dpms(intel_dp, mode);
                intel_dp_link_down(intel_dp);
-               ironlake_edp_panel_off(encoder);
-               if (is_edp(intel_dp) && !is_pch_edp(intel_dp))
-                       ironlake_edp_pll_off(encoder);
                ironlake_edp_panel_vdd_off(intel_dp, false);
+               if (is_cpu_edp(intel_dp))
+                       ironlake_edp_pll_off(encoder);
        } else {
+               if (is_cpu_edp(intel_dp))
+                       ironlake_edp_pll_on(encoder);
                ironlake_edp_panel_vdd_on(intel_dp);
                intel_dp_sink_dpms(intel_dp, mode);
                if (!(dp_reg & DP_PORT_EN)) {
                        ironlake_edp_panel_on(intel_dp);
                        ironlake_edp_panel_vdd_off(intel_dp, true);
                        intel_dp_complete_link_train(intel_dp);
-                       ironlake_edp_backlight_on(intel_dp);
                } else
                        ironlake_edp_panel_vdd_off(intel_dp, false);
                ironlake_edp_backlight_on(intel_dp);
@@@ -1285,11 -1318,11 +1319,11 @@@ intel_dp_aux_native_read_retry(struct i
   * link status information
   */
  static bool
- intel_dp_get_link_status(struct intel_dp *intel_dp)
+ intel_dp_get_link_status(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_STATUS_SIZE])
  {
        return intel_dp_aux_native_read_retry(intel_dp,
                                              DP_LANE0_1_STATUS,
-                                             intel_dp->link_status,
+                                             link_status,
                                              DP_LINK_STATUS_SIZE);
  }
  
@@@ -1301,27 -1334,25 +1335,25 @@@ intel_dp_link_status(uint8_t link_statu
  }
  
  static uint8_t
- intel_get_adjust_request_voltage(uint8_t link_status[DP_LINK_STATUS_SIZE],
+ intel_get_adjust_request_voltage(uint8_t adjust_request[2],
                                 int lane)
  {
-       int         i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1);
        int         s = ((lane & 1) ?
                         DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT :
                         DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT);
-       uint8_t l = intel_dp_link_status(link_status, i);
+       uint8_t l = adjust_request[lane>>1];
  
        return ((l >> s) & 3) << DP_TRAIN_VOLTAGE_SWING_SHIFT;
  }
  
  static uint8_t
- intel_get_adjust_request_pre_emphasis(uint8_t link_status[DP_LINK_STATUS_SIZE],
+ intel_get_adjust_request_pre_emphasis(uint8_t adjust_request[2],
                                      int lane)
  {
-       int         i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1);
        int         s = ((lane & 1) ?
                         DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT :
                         DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT);
-       uint8_t l = intel_dp_link_status(link_status, i);
+       uint8_t l = adjust_request[lane>>1];
  
        return ((l >> s) & 3) << DP_TRAIN_PRE_EMPHASIS_SHIFT;
  }
@@@ -1344,6 -1375,7 +1376,7 @@@ static char     *link_train_names[] = 
   * a maximum voltage of 800mV and a maximum pre-emphasis of 6dB
   */
  #define I830_DP_VOLTAGE_MAX       DP_TRAIN_VOLTAGE_SWING_800
+ #define I830_DP_VOLTAGE_MAX_CPT           DP_TRAIN_VOLTAGE_SWING_1200
  
  static uint8_t
  intel_dp_pre_emphasis_max(uint8_t voltage_swing)
  }
  
  static void
- intel_get_adjust_train(struct intel_dp *intel_dp)
+ intel_get_adjust_train(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_STATUS_SIZE])
  {
+       struct drm_device *dev = intel_dp->base.base.dev;
        uint8_t v = 0;
        uint8_t p = 0;
        int lane;
+       uint8_t *adjust_request = link_status + (DP_ADJUST_REQUEST_LANE0_1 - DP_LANE0_1_STATUS);
+       int voltage_max;
  
        for (lane = 0; lane < intel_dp->lane_count; lane++) {
-               uint8_t this_v = intel_get_adjust_request_voltage(intel_dp->link_status, lane);
-               uint8_t this_p = intel_get_adjust_request_pre_emphasis(intel_dp->link_status, lane);
+               uint8_t this_v = intel_get_adjust_request_voltage(adjust_request, lane);
+               uint8_t this_p = intel_get_adjust_request_pre_emphasis(adjust_request, lane);
  
                if (this_v > v)
                        v = this_v;
                        p = this_p;
        }
  
-       if (v >= I830_DP_VOLTAGE_MAX)
-               v = I830_DP_VOLTAGE_MAX | DP_TRAIN_MAX_SWING_REACHED;
+       if (HAS_PCH_CPT(dev) && !is_cpu_edp(intel_dp))
+               voltage_max = I830_DP_VOLTAGE_MAX_CPT;
+       else
+               voltage_max = I830_DP_VOLTAGE_MAX;
+       if (v >= voltage_max)
+               v = voltage_max | DP_TRAIN_MAX_SWING_REACHED;
  
        if (p >= intel_dp_pre_emphasis_max(v))
                p = intel_dp_pre_emphasis_max(v) | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
  }
  
  static uint32_t
- intel_dp_signal_levels(uint8_t train_set, int lane_count)
+ intel_dp_signal_levels(uint8_t train_set)
  {
        uint32_t        signal_levels = 0;
  
@@@ -1458,9 -1497,8 +1498,8 @@@ static uint8_
  intel_get_lane_status(uint8_t link_status[DP_LINK_STATUS_SIZE],
                      int lane)
  {
-       int i = DP_LANE0_1_STATUS + (lane >> 1);
        int s = (lane & 1) * 4;
-       uint8_t l = intel_dp_link_status(link_status, i);
+       uint8_t l = link_status[lane>>1];
  
        return (l >> s) & 0xf;
  }
@@@ -1485,18 -1523,18 +1524,18 @@@ intel_clock_recovery_ok(uint8_t link_st
                         DP_LANE_CHANNEL_EQ_DONE|\
                         DP_LANE_SYMBOL_LOCKED)
  static bool
- intel_channel_eq_ok(struct intel_dp *intel_dp)
+ intel_channel_eq_ok(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_STATUS_SIZE])
  {
        uint8_t lane_align;
        uint8_t lane_status;
        int lane;
  
-       lane_align = intel_dp_link_status(intel_dp->link_status,
+       lane_align = intel_dp_link_status(link_status,
                                          DP_LANE_ALIGN_STATUS_UPDATED);
        if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0)
                return false;
        for (lane = 0; lane < intel_dp->lane_count; lane++) {
-               lane_status = intel_get_lane_status(intel_dp->link_status, lane);
+               lane_status = intel_get_lane_status(link_status, lane);
                if ((lane_status & CHANNEL_EQ_BITS) != CHANNEL_EQ_BITS)
                        return false;
        }
@@@ -1521,8 -1559,9 +1560,9 @@@ intel_dp_set_link_train(struct intel_d
  
        ret = intel_dp_aux_native_write(intel_dp,
                                        DP_TRAINING_LANE0_SET,
-                                       intel_dp->train_set, 4);
-       if (ret != 4)
+                                       intel_dp->train_set,
+                                       intel_dp->lane_count);
+       if (ret != intel_dp->lane_count)
                return false;
  
        return true;
@@@ -1538,7 -1577,7 +1578,7 @@@ intel_dp_start_link_train(struct intel_
        int i;
        uint8_t voltage;
        bool clock_recovery = false;
-       int tries;
+       int voltage_tries, loop_tries;
        u32 reg;
        uint32_t DP = intel_dp->DP;
  
                DP &= ~DP_LINK_TRAIN_MASK;
        memset(intel_dp->train_set, 0, 4);
        voltage = 0xff;
-       tries = 0;
+       voltage_tries = 0;
+       loop_tries = 0;
        clock_recovery = false;
        for (;;) {
                /* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */
+               uint8_t     link_status[DP_LINK_STATUS_SIZE];
                uint32_t    signal_levels;
-               if (IS_GEN6(dev) && is_edp(intel_dp)) {
+               if (IS_GEN6(dev) && is_cpu_edp(intel_dp)) {
                        signal_levels = intel_gen6_edp_signal_levels(intel_dp->train_set[0]);
                        DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels;
                } else {
-                       signal_levels = intel_dp_signal_levels(intel_dp->train_set[0], intel_dp->lane_count);
+                       signal_levels = intel_dp_signal_levels(intel_dp->train_set[0]);
+                       DRM_DEBUG_KMS("training pattern 1 signal levels %08x\n", signal_levels);
                        DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
                }
  
                /* Set training pattern 1 */
  
                udelay(100);
-               if (!intel_dp_get_link_status(intel_dp))
+               if (!intel_dp_get_link_status(intel_dp, link_status)) {
+                       DRM_ERROR("failed to get link status\n");
                        break;
+               }
  
-               if (intel_clock_recovery_ok(intel_dp->link_status, intel_dp->lane_count)) {
+               if (intel_clock_recovery_ok(link_status, intel_dp->lane_count)) {
+                       DRM_DEBUG_KMS("clock recovery OK\n");
                        clock_recovery = true;
                        break;
                }
                for (i = 0; i < intel_dp->lane_count; i++)
                        if ((intel_dp->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
                                break;
-               if (i == intel_dp->lane_count)
-                       break;
+               if (i == intel_dp->lane_count) {
+                       ++loop_tries;
+                       if (loop_tries == 5) {
+                               DRM_DEBUG_KMS("too many full retries, give up\n");
+                               break;
+                       }
+                       memset(intel_dp->train_set, 0, 4);
+                       voltage_tries = 0;
+                       continue;
+               }
  
                /* Check to see if we've tried the same voltage 5 times */
                if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
-                       ++tries;
-                       if (tries == 5)
+                       ++voltage_tries;
+                       if (voltage_tries == 5) {
+                               DRM_DEBUG_KMS("too many voltage retries, give up\n");
                                break;
+                       }
                } else
-                       tries = 0;
+                       voltage_tries = 0;
                voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
  
                /* Compute new intel_dp->train_set as requested by target */
-               intel_get_adjust_train(intel_dp);
+               intel_get_adjust_train(intel_dp, link_status);
        }
  
        intel_dp->DP = DP;
@@@ -1638,6 -1694,7 +1695,7 @@@ intel_dp_complete_link_train(struct int
        for (;;) {
                /* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */
                uint32_t    signal_levels;
+               uint8_t     link_status[DP_LINK_STATUS_SIZE];
  
                if (cr_tries > 5) {
                        DRM_ERROR("failed to train DP, aborting\n");
                        break;
                }
  
-               if (IS_GEN6(dev) && is_edp(intel_dp)) {
+               if (IS_GEN6(dev) && is_cpu_edp(intel_dp)) {
                        signal_levels = intel_gen6_edp_signal_levels(intel_dp->train_set[0]);
                        DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels;
                } else {
-                       signal_levels = intel_dp_signal_levels(intel_dp->train_set[0], intel_dp->lane_count);
+                       signal_levels = intel_dp_signal_levels(intel_dp->train_set[0]);
                        DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
                }
  
                        break;
  
                udelay(400);
-               if (!intel_dp_get_link_status(intel_dp))
+               if (!intel_dp_get_link_status(intel_dp, link_status))
                        break;
  
                /* Make sure clock is still ok */
-               if (!intel_clock_recovery_ok(intel_dp->link_status, intel_dp->lane_count)) {
+               if (!intel_clock_recovery_ok(link_status, intel_dp->lane_count)) {
                        intel_dp_start_link_train(intel_dp);
                        cr_tries++;
                        continue;
                }
  
-               if (intel_channel_eq_ok(intel_dp)) {
+               if (intel_channel_eq_ok(intel_dp, link_status)) {
                        channel_eq = true;
                        break;
                }
                }
  
                /* Compute new intel_dp->train_set as requested by target */
-               intel_get_adjust_train(intel_dp);
+               intel_get_adjust_train(intel_dp, link_status);
                ++tries;
        }
  
@@@ -1735,8 -1792,12 +1793,12 @@@ intel_dp_link_down(struct intel_dp *int
  
        msleep(17);
  
-       if (is_edp(intel_dp))
-               DP |= DP_LINK_TRAIN_OFF;
+       if (is_edp(intel_dp)) {
+               if (HAS_PCH_CPT(dev) && !is_cpu_edp(intel_dp))
+                       DP |= DP_LINK_TRAIN_OFF_CPT;
+               else
+                       DP |= DP_LINK_TRAIN_OFF;
+       }
  
        if (!HAS_PCH_CPT(dev) &&
            I915_READ(intel_dp->output_reg) & DP_PIPEB_SELECT) {
@@@ -1822,6 -1883,7 +1884,7 @@@ static voi
  intel_dp_check_link_status(struct intel_dp *intel_dp)
  {
        u8 sink_irq_vector;
+       u8 link_status[DP_LINK_STATUS_SIZE];
  
        if (intel_dp->dpms_mode != DRM_MODE_DPMS_ON)
                return;
                return;
  
        /* Try to read receiver status if the link appears to be up */
-       if (!intel_dp_get_link_status(intel_dp)) {
+       if (!intel_dp_get_link_status(intel_dp, link_status)) {
                intel_dp_link_down(intel_dp);
                return;
        }
                        DRM_DEBUG_DRIVER("CP or sink specific irq unhandled\n");
        }
  
-       if (!intel_channel_eq_ok(intel_dp)) {
+       if (!intel_channel_eq_ok(intel_dp, link_status)) {
                DRM_DEBUG_KMS("%s: channel EQ not ok, retraining\n",
                              drm_get_encoder_name(&intel_dp->base.base));
                intel_dp_start_link_train(intel_dp);
@@@ -2179,7 -2241,8 +2242,8 @@@ intel_trans_dp_port_sel(struct drm_crt
                        continue;
  
                intel_dp = enc_to_intel_dp(encoder);
-               if (intel_dp->base.type == INTEL_OUTPUT_DISPLAYPORT)
+               if (intel_dp->base.type == INTEL_OUTPUT_DISPLAYPORT ||
+                   intel_dp->base.type == INTEL_OUTPUT_EDP)
                        return intel_dp->output_reg;
        }
  
@@@ -2321,7 -2384,7 +2385,7 @@@ intel_dp_init(struct drm_device *dev, i
  
                cur.t8 = (pp_on & PANEL_LIGHT_ON_DELAY_MASK) >>
                        PANEL_LIGHT_ON_DELAY_SHIFT;
-               
                cur.t9 = (pp_off & PANEL_LIGHT_OFF_DELAY_MASK) >>
                        PANEL_LIGHT_OFF_DELAY_SHIFT;
  
                DRM_DEBUG_KMS("backlight on delay %d, off delay %d\n",
                              intel_dp->backlight_on_delay, intel_dp->backlight_off_delay);
  
-               intel_dp->panel_off_jiffies = jiffies - intel_dp->panel_power_down_delay;
                ironlake_edp_panel_vdd_on(intel_dp);
                ret = intel_dp_get_dpcd(intel_dp);
                ironlake_edp_panel_vdd_off(intel_dp, false);
                if (ret) {
                        if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11)
                                dev_priv->no_aux_handshake =