]> bbs.cooldavid.org Git - net-next-2.6.git/commitdiff
Merge remote branch 'airlied/drm-core-next' into tmp
authorChris Wilson <chris@chris-wilson.co.uk>
Tue, 19 Oct 2010 08:13:00 +0000 (09:13 +0100)
committerChris Wilson <chris@chris-wilson.co.uk>
Tue, 19 Oct 2010 08:14:50 +0000 (09:14 +0100)
14 files changed:
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_acpi.c [new file with mode: 0644]
drivers/gpu/drm/i915/intel_bios.c
drivers/gpu/drm/i915/intel_crt.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_fb.c
include/drm/drm_dp_helper.h

index f6e98dd416c9085d662042fd14655b66f03c4880..fdc833d5cc7b473eb2f69cb2e856aaf8811215ce 100644 (file)
@@ -35,6 +35,8 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \
 
 i915-$(CONFIG_COMPAT)   += i915_ioc32.o
 
+i915-$(CONFIG_ACPI)    += intel_acpi.o
+
 obj-$(CONFIG_DRM_I915)  += i915.o
 
 CFLAGS_i915_trace_points.o := -I$(src)
index 251987307ebebe4926dbc9224671f2df68137f16..a99fae33bdf6bd8fe7fe39ccf7f9b070fa11b43c 100644 (file)
@@ -1244,6 +1244,8 @@ static int i915_load_modeset_init(struct drm_device *dev,
        if (ret)
                goto cleanup_ringbuffer;
 
+       intel_register_dsm_handler();
+
        ret = vga_switcheroo_register_client(dev->pdev,
                                             i915_switcheroo_set_state,
                                             i915_switcheroo_can_switch);
@@ -2153,6 +2155,9 @@ int i915_driver_unload(struct drm_device *dev)
                drm_mm_takedown(&dev_priv->mm.vram);
 
                intel_cleanup_overlay(dev);
+
+               if (!I915_NEED_GFX_HWS(dev))
+                       i915_free_hws(dev);
        }
 
        intel_teardown_gmbus(dev);
index 73ad8bff2c2a7ab833dbad13156453e5d9c2569d..84e33aeececdc98b8cc4a1b835a492d710eb14b2 100644 (file)
@@ -339,17 +339,18 @@ typedef struct drm_i915_private {
        unsigned int int_crt_support:1;
        unsigned int lvds_use_ssc:1;
        int lvds_ssc_freq;
-
        struct {
-               u8 rate:4;
-               u8 lanes:4;
-               u8 preemphasis:4;
-               u8 vswing:4;
-
-               u8 initialized:1;
-               u8 support:1;
-               u8 bpp:6;
+               int rate;
+               int lanes;
+               int preemphasis;
+               int vswing;
+
+               bool initialized;
+               bool support;
+               int bpp;
+               struct edp_power_seq pps;
        } edp;
+       bool no_aux_handshake;
 
        struct notifier_block lid_notifier;
 
@@ -1136,6 +1137,15 @@ static inline void intel_opregion_gse_intr(struct drm_device *dev) { return; }
 static inline void intel_opregion_enable_asle(struct drm_device *dev) { return; }
 #endif
 
+/* intel_acpi.c */
+#ifdef CONFIG_ACPI
+extern void intel_register_dsm_handler(void);
+extern void intel_unregister_dsm_handler(void);
+#else
+static inline void intel_register_dsm_handler(void) { return; }
+static inline void intel_unregister_dsm_handler(void) { return; }
+#endif /* CONFIG_ACPI */
+
 /* modesetting */
 extern void intel_modeset_init(struct drm_device *dev);
 extern void intel_modeset_cleanup(struct drm_device *dev);
index 100a7537980e1c65eb4f4c2f4d0c89b3224d5451..72ab3032300ad6c0b6b10a2b4274d7f39ec814d5 100644 (file)
@@ -3646,41 +3646,6 @@ i915_gem_check_execbuffer (struct drm_i915_gem_execbuffer2 *exec,
        return 0;
 }
 
-static int
-i915_gem_wait_for_pending_flip(struct drm_device *dev,
-                              struct drm_gem_object **object_list,
-                              int count)
-{
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       struct drm_i915_gem_object *obj_priv;
-       DEFINE_WAIT(wait);
-       int i, ret = 0;
-
-       for (;;) {
-               prepare_to_wait(&dev_priv->pending_flip_queue,
-                               &wait, TASK_INTERRUPTIBLE);
-               for (i = 0; i < count; i++) {
-                       obj_priv = to_intel_bo(object_list[i]);
-                       if (atomic_read(&obj_priv->pending_flip) > 0)
-                               break;
-               }
-               if (i == count)
-                       break;
-
-               if (!signal_pending(current)) {
-                       mutex_unlock(&dev->struct_mutex);
-                       schedule();
-                       mutex_lock(&dev->struct_mutex);
-                       continue;
-               }
-               ret = -ERESTARTSYS;
-               break;
-       }
-       finish_wait(&dev_priv->pending_flip_queue, &wait);
-
-       return ret;
-}
-
 static int
 i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                       struct drm_file *file_priv,
@@ -3773,7 +3738,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
        }
 
        /* Look up object handles */
-       flips = 0;
        for (i = 0; i < args->buffer_count; i++) {
                object_list[i] = drm_gem_object_lookup(dev, file_priv,
                                                       exec_list[i].handle);
@@ -3796,14 +3760,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                        goto err;
                }
                obj_priv->in_execbuffer = true;
-               flips += atomic_read(&obj_priv->pending_flip);
-       }
-
-       if (flips > 0) {
-               ret = i915_gem_wait_for_pending_flip(dev, object_list,
-                                                    args->buffer_count);
-               if (ret)
-                       goto err;
        }
 
        /* Pin and relocate */
@@ -3943,9 +3899,38 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                              ~0);
 #endif
 
+       /* Check for any pending flips. As we only maintain a flip queue depth
+        * of 1, we can simply insert a WAIT for the next display flip prior
+        * to executing the batch and avoid stalling the CPU.
+        */
+       flips = 0;
+       for (i = 0; i < args->buffer_count; i++) {
+               if (object_list[i]->write_domain)
+                       flips |= atomic_read(&to_intel_bo(object_list[i])->pending_flip);
+       }
+       if (flips) {
+               int plane, flip_mask;
+
+               for (plane = 0; flips >> plane; plane++) {
+                       if (((flips >> plane) & 1) == 0)
+                               continue;
+
+                       if (plane)
+                               flip_mask = MI_WAIT_FOR_PLANE_B_FLIP;
+                       else
+                               flip_mask = MI_WAIT_FOR_PLANE_A_FLIP;
+
+                       intel_ring_begin(dev, ring, 2);
+                       intel_ring_emit(dev, ring,
+                                       MI_WAIT_FOR_EVENT | flip_mask);
+                       intel_ring_emit(dev, ring, MI_NOOP);
+                       intel_ring_advance(dev, ring);
+               }
+       }
+
        /* Exec the batchbuffer */
        ret = ring->dispatch_gem_execbuffer(dev, ring, args,
-                       cliprects, exec_offset);
+                                           cliprects, exec_offset);
        if (ret) {
                DRM_ERROR("dispatch failed %d\n", ret);
                goto err;
index 64c07c24e3001af891f8ed659a2ecfc4aad7026b..0d051e7f670263648d4df6dbf7427f107c771313 100644 (file)
@@ -298,6 +298,7 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        int ret = IRQ_NONE;
        u32 de_iir, gt_iir, de_ier, pch_iir;
+       u32 hotplug_mask;
        struct drm_i915_master_private *master_priv;
        struct intel_ring_buffer *render_ring = &dev_priv->render_ring;
        u32 bsd_usr_interrupt = GT_BSD_USER_INTERRUPT;
@@ -317,6 +318,11 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
        if (de_iir == 0 && gt_iir == 0 && pch_iir == 0)
                goto done;
 
+       if (HAS_PCH_CPT(dev))
+               hotplug_mask = SDE_HOTPLUG_MASK_CPT;
+       else
+               hotplug_mask = SDE_HOTPLUG_MASK;
+
        ret = IRQ_HANDLED;
 
        if (dev->primary->master) {
@@ -358,10 +364,8 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
                drm_handle_vblank(dev, 1);
 
        /* check event from PCH */
-       if ((de_iir & DE_PCH_EVENT) &&
-           (pch_iir & SDE_HOTPLUG_MASK)) {
+       if ((de_iir & DE_PCH_EVENT) && (pch_iir & hotplug_mask))
                queue_work(dev_priv->wq, &dev_priv->hotplug_work);
-       }
 
        if (de_iir & DE_PCU_EVENT) {
                I915_WRITE16(MEMINTRSTS, I915_READ(MEMINTRSTS));
@@ -1431,8 +1435,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
        u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
                           DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE;
        u32 render_mask = GT_PIPE_NOTIFY | GT_BSD_USER_INTERRUPT;
-       u32 hotplug_mask = SDE_CRT_HOTPLUG | SDE_PORTB_HOTPLUG |
-                          SDE_PORTC_HOTPLUG | SDE_PORTD_HOTPLUG;
+       u32 hotplug_mask;
 
        dev_priv->irq_mask_reg = ~display_mask;
        dev_priv->de_irq_enable_reg = display_mask | DE_PIPEA_VBLANK | DE_PIPEB_VBLANK;
@@ -1459,6 +1462,14 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
        I915_WRITE(GTIER, dev_priv->gt_irq_enable_reg);
        (void) I915_READ(GTIER);
 
+       if (HAS_PCH_CPT(dev)) {
+               hotplug_mask = SDE_CRT_HOTPLUG_CPT | SDE_PORTB_HOTPLUG_CPT  |
+                              SDE_PORTC_HOTPLUG_CPT | SDE_PORTD_HOTPLUG_CPT ;
+       } else {
+               hotplug_mask = SDE_CRT_HOTPLUG | SDE_PORTB_HOTPLUG |
+                              SDE_PORTC_HOTPLUG | SDE_PORTD_HOTPLUG;
+       }
+
        dev_priv->pch_irq_mask_reg = ~hotplug_mask;
        dev_priv->pch_irq_enable_reg = hotplug_mask;
 
index d02de212e6ad217de1f09ddc589ea7949ae814f4..47032186a31ab60484dd890dcb2639054bdf6440 100644 (file)
 #define   PP_SEQUENCE_ON       (1 << 28)
 #define   PP_SEQUENCE_OFF      (2 << 28)
 #define   PP_SEQUENCE_MASK     0x30000000
+#define   PP_CYCLE_DELAY_ACTIVE        (1 << 27)
+#define   PP_SEQUENCE_STATE_ON_IDLE (1 << 3)
+#define   PP_SEQUENCE_STATE_MASK 0x0000000f
 #define PP_CONTROL     0x61204
 #define   POWER_TARGET_ON      (1 << 0)
 #define PP_ON_DELAYS   0x61208
 #define SDE_PORTD_HOTPLUG_CPT  (1 << 23)
 #define SDE_PORTC_HOTPLUG_CPT  (1 << 22)
 #define SDE_PORTB_HOTPLUG_CPT  (1 << 21)
+#define SDE_HOTPLUG_MASK_CPT   (SDE_CRT_HOTPLUG_CPT |          \
+                                SDE_PORTD_HOTPLUG_CPT |        \
+                                SDE_PORTC_HOTPLUG_CPT |        \
+                                SDE_PORTB_HOTPLUG_CPT)
 
 #define SDEISR  0xc4000
 #define SDEIMR  0xc4004
 #define FDI_RXA_CHICKEN         0xc200c
 #define FDI_RXB_CHICKEN         0xc2010
 #define  FDI_RX_PHASE_SYNC_POINTER_ENABLE       (1)
+#define FDI_RX_CHICKEN(pipe) _PIPE(pipe, FDI_RXA_CHICKEN, FDI_RXB_CHICKEN)
+
+#define SOUTH_DSPCLK_GATE_D    0xc2020
+#define  PCH_DPLSUNIT_CLOCK_GATE_DISABLE (1<<29)
 
 /* CPU: FDI_TX */
 #define FDI_TXA_CTL             0x60100
diff --git a/drivers/gpu/drm/i915/intel_acpi.c b/drivers/gpu/drm/i915/intel_acpi.c
new file mode 100644 (file)
index 0000000..65c88f9
--- /dev/null
@@ -0,0 +1,286 @@
+/*
+ * Intel ACPI functions
+ *
+ * _DSM related code stolen from nouveau_acpi.c.
+ */
+#include <linux/pci.h>
+#include <linux/acpi.h>
+#include <linux/vga_switcheroo.h>
+#include <acpi/acpi_drivers.h>
+
+#include "drmP.h"
+
+#define INTEL_DSM_REVISION_ID 1 /* For Calpella anyway... */
+
+#define INTEL_DSM_FN_SUPPORTED_FUNCTIONS 0 /* No args */
+#define INTEL_DSM_FN_PLATFORM_MUX_INFO 1 /* No args */
+
+static struct intel_dsm_priv {
+       acpi_handle dhandle;
+} intel_dsm_priv;
+
+static const u8 intel_dsm_guid[] = {
+       0xd3, 0x73, 0xd8, 0x7e,
+       0xd0, 0xc2,
+       0x4f, 0x4e,
+       0xa8, 0x54,
+       0x0f, 0x13, 0x17, 0xb0, 0x1c, 0x2c
+};
+
+static int intel_dsm(acpi_handle handle, int func, int arg)
+{
+       struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+       struct acpi_object_list input;
+       union acpi_object params[4];
+       union acpi_object *obj;
+       u32 result;
+       int ret = 0;
+
+       input.count = 4;
+       input.pointer = params;
+       params[0].type = ACPI_TYPE_BUFFER;
+       params[0].buffer.length = sizeof(intel_dsm_guid);
+       params[0].buffer.pointer = (char *)intel_dsm_guid;
+       params[1].type = ACPI_TYPE_INTEGER;
+       params[1].integer.value = INTEL_DSM_REVISION_ID;
+       params[2].type = ACPI_TYPE_INTEGER;
+       params[2].integer.value = func;
+       params[3].type = ACPI_TYPE_INTEGER;
+       params[3].integer.value = arg;
+
+       ret = acpi_evaluate_object(handle, "_DSM", &input, &output);
+       if (ret) {
+               DRM_DEBUG_DRIVER("failed to evaluate _DSM: %d\n", ret);
+               return ret;
+       }
+
+       obj = (union acpi_object *)output.pointer;
+
+       result = 0;
+       switch (obj->type) {
+       case ACPI_TYPE_INTEGER:
+               result = obj->integer.value;
+               break;
+
+       case ACPI_TYPE_BUFFER:
+               if (obj->buffer.length == 4) {
+                       result =(obj->buffer.pointer[0] |
+                               (obj->buffer.pointer[1] <<  8) |
+                               (obj->buffer.pointer[2] << 16) |
+                               (obj->buffer.pointer[3] << 24));
+                       break;
+               }
+       default:
+               ret = -EINVAL;
+               break;
+       }
+       if (result == 0x80000002)
+               ret = -ENODEV;
+
+       kfree(output.pointer);
+       return ret;
+}
+
+static char *intel_dsm_port_name(u8 id)
+{
+       switch (id) {
+       case 0:
+               return "Reserved";
+       case 1:
+               return "Analog VGA";
+       case 2:
+               return "LVDS";
+       case 3:
+               return "Reserved";
+       case 4:
+               return "HDMI/DVI_B";
+       case 5:
+               return "HDMI/DVI_C";
+       case 6:
+               return "HDMI/DVI_D";
+       case 7:
+               return "DisplayPort_A";
+       case 8:
+               return "DisplayPort_B";
+       case 9:
+               return "DisplayPort_C";
+       case 0xa:
+               return "DisplayPort_D";
+       case 0xb:
+       case 0xc:
+       case 0xd:
+               return "Reserved";
+       case 0xe:
+               return "WiDi";
+       default:
+               return "bad type";
+       }
+}
+
+static char *intel_dsm_mux_type(u8 type)
+{
+       switch (type) {
+       case 0:
+               return "unknown";
+       case 1:
+               return "No MUX, iGPU only";
+       case 2:
+               return "No MUX, dGPU only";
+       case 3:
+               return "MUXed between iGPU and dGPU";
+       default:
+               return "bad type";
+       }
+}
+
+static void intel_dsm_platform_mux_info(void)
+{
+       struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+       struct acpi_object_list input;
+       union acpi_object params[4];
+       union acpi_object *pkg;
+       int i, ret;
+
+       input.count = 4;
+       input.pointer = params;
+       params[0].type = ACPI_TYPE_BUFFER;
+       params[0].buffer.length = sizeof(intel_dsm_guid);
+       params[0].buffer.pointer = (char *)intel_dsm_guid;
+       params[1].type = ACPI_TYPE_INTEGER;
+       params[1].integer.value = INTEL_DSM_REVISION_ID;
+       params[2].type = ACPI_TYPE_INTEGER;
+       params[2].integer.value = INTEL_DSM_FN_PLATFORM_MUX_INFO;
+       params[3].type = ACPI_TYPE_INTEGER;
+       params[3].integer.value = 0;
+
+       ret = acpi_evaluate_object(intel_dsm_priv.dhandle, "_DSM", &input,
+                                  &output);
+       if (ret) {
+               DRM_DEBUG_DRIVER("failed to evaluate _DSM: %d\n", ret);
+               goto out;
+       }
+
+       pkg = (union acpi_object *)output.pointer;
+
+       if (pkg->type == ACPI_TYPE_PACKAGE) {
+               union acpi_object *connector_count = &pkg->package.elements[0];
+               DRM_DEBUG_DRIVER("MUX info connectors: %lld\n",
+                         (unsigned long long)connector_count->integer.value);
+               for (i = 1; i < pkg->package.count; i++) {
+                       union acpi_object *obj = &pkg->package.elements[i];
+                       union acpi_object *connector_id =
+                               &obj->package.elements[0];
+                       union acpi_object *info = &obj->package.elements[1];
+                       DRM_DEBUG_DRIVER("Connector id: 0x%016llx\n",
+                                 (unsigned long long)connector_id->integer.value);
+                       DRM_DEBUG_DRIVER("  port id: %s\n",
+                              intel_dsm_port_name(info->buffer.pointer[0]));
+                       DRM_DEBUG_DRIVER("  display mux info: %s\n",
+                              intel_dsm_mux_type(info->buffer.pointer[1]));
+                       DRM_DEBUG_DRIVER("  aux/dc mux info: %s\n",
+                              intel_dsm_mux_type(info->buffer.pointer[2]));
+                       DRM_DEBUG_DRIVER("  hpd mux info: %s\n",
+                              intel_dsm_mux_type(info->buffer.pointer[3]));
+               }
+       } else {
+               DRM_ERROR("MUX INFO call failed\n");
+       }
+
+out:
+       kfree(output.pointer);
+}
+
+static int intel_dsm_switchto(enum vga_switcheroo_client_id id)
+{
+       return 0;
+}
+
+static int intel_dsm_power_state(enum vga_switcheroo_client_id id,
+                                enum vga_switcheroo_state state)
+{
+       return 0;
+}
+
+static int intel_dsm_init(void)
+{
+       return 0;
+}
+
+static int intel_dsm_get_client_id(struct pci_dev *pdev)
+{
+       if (intel_dsm_priv.dhandle == DEVICE_ACPI_HANDLE(&pdev->dev))
+               return VGA_SWITCHEROO_IGD;
+       else
+               return VGA_SWITCHEROO_DIS;
+}
+
+static struct vga_switcheroo_handler intel_dsm_handler = {
+       .switchto = intel_dsm_switchto,
+       .power_state = intel_dsm_power_state,
+       .init = intel_dsm_init,
+       .get_client_id = intel_dsm_get_client_id,
+};
+
+static bool intel_dsm_pci_probe(struct pci_dev *pdev)
+{
+       acpi_handle dhandle, intel_handle;
+       acpi_status status;
+       int ret;
+
+       dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
+       if (!dhandle)
+               return false;
+
+       status = acpi_get_handle(dhandle, "_DSM", &intel_handle);
+       if (ACPI_FAILURE(status)) {
+               DRM_DEBUG_KMS("no _DSM method for intel device\n");
+               return false;
+       }
+
+       ret = intel_dsm(dhandle, INTEL_DSM_FN_SUPPORTED_FUNCTIONS, 0);
+       if (ret < 0) {
+               DRM_ERROR("failed to get supported _DSM functions\n");
+               return false;
+       }
+
+       intel_dsm_priv.dhandle = dhandle;
+
+       intel_dsm_platform_mux_info();
+       return true;
+}
+
+static bool intel_dsm_detect(void)
+{
+       char acpi_method_name[255] = { 0 };
+       struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
+       struct pci_dev *pdev = NULL;
+       bool has_dsm = false;
+       int vga_count = 0;
+
+       while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
+               vga_count++;
+               has_dsm |= intel_dsm_pci_probe(pdev);
+       }
+
+       if (vga_count == 2 && has_dsm) {
+               acpi_get_name(intel_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer);
+               DRM_DEBUG_DRIVER("VGA switcheroo: detected DSM switching method %s handle\n",
+                                acpi_method_name);
+               return true;
+       }
+
+       return false;
+}
+
+void intel_register_dsm_handler(void)
+{
+       if (!intel_dsm_detect())
+               return;
+
+       vga_switcheroo_register_handler(&intel_dsm_handler);
+}
+
+void intel_unregister_dsm_handler(void)
+{
+       vga_switcheroo_unregister_handler();
+}
index b1f73ac0f3fd310c7599383212091fff02c1c093..cc15447eff410ad8712357e69b2dc85f1f8acafb 100644 (file)
@@ -24,6 +24,7 @@
  *    Eric Anholt <eric@anholt.net>
  *
  */
+#include <drm/drm_dp_helper.h>
 #include "drmP.h"
 #include "drm.h"
 #include "i915_drm.h"
@@ -413,6 +414,8 @@ static void
 parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
 {
        struct bdb_edp *edp;
+       struct edp_power_seq *edp_pps;
+       struct edp_link_params *edp_link_params;
 
        edp = find_section(bdb, BDB_EDP);
        if (!edp) {
@@ -437,19 +440,54 @@ parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
                break;
        }
 
-       dev_priv->edp.rate = edp->link_params[panel_type].rate;
-       dev_priv->edp.lanes = edp->link_params[panel_type].lanes;
-       dev_priv->edp.preemphasis = edp->link_params[panel_type].preemphasis;
-       dev_priv->edp.vswing = edp->link_params[panel_type].vswing;
+       /* Get the eDP sequencing and link info */
+       edp_pps = &edp->power_seqs[panel_type];
+       edp_link_params = &edp->link_params[panel_type];
 
-       DRM_DEBUG_KMS("eDP vBIOS settings: bpp=%d, rate=%d, lanes=%d, preemphasis=%d, vswing=%d\n",
-                     dev_priv->edp.bpp,
-                     dev_priv->edp.rate,
-                     dev_priv->edp.lanes,
-                     dev_priv->edp.preemphasis,
-                     dev_priv->edp.vswing);
+       dev_priv->edp.pps = *edp_pps;
 
-       dev_priv->edp.initialized = true;
+       dev_priv->edp.rate = edp_link_params->rate ? DP_LINK_BW_2_7 :
+               DP_LINK_BW_1_62;
+       switch (edp_link_params->lanes) {
+       case 0:
+               dev_priv->edp.lanes = 1;
+               break;
+       case 1:
+               dev_priv->edp.lanes = 2;
+               break;
+       case 3:
+       default:
+               dev_priv->edp.lanes = 4;
+               break;
+       }
+       switch (edp_link_params->preemphasis) {
+       case 0:
+               dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_0;
+               break;
+       case 1:
+               dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_3_5;
+               break;
+       case 2:
+               dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_6;
+               break;
+       case 3:
+               dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_9_5;
+               break;
+       }
+       switch (edp_link_params->vswing) {
+       case 0:
+               dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_400;
+               break;
+       case 1:
+               dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_600;
+               break;
+       case 2:
+               dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_800;
+               break;
+       case 3:
+               dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_1200;
+               break;
+       }
 }
 
 static void
index 389fcd2aea1f0f7fe90ec6e0dbb152214b735b7b..c55c77043357cb0243a4b368a1e6d63b7a4af398 100644 (file)
@@ -191,7 +191,8 @@ static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector)
                DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER");
 
        if (turn_off_dac) {
-               I915_WRITE(PCH_ADPA, temp);
+               /* Make sure hotplug is enabled */
+               I915_WRITE(PCH_ADPA, temp | ADPA_CRT_HOTPLUG_ENABLE);
                (void)I915_READ(PCH_ADPA);
        }
 
index 96d08a9f3aaaa8e9b8351ccad80f882fabc6e614..faacbbdbb270ac81729fed72d3c8f0be8ccf3286 100644 (file)
@@ -932,10 +932,6 @@ intel_find_pll_ironlake_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
        struct drm_device *dev = crtc->dev;
        intel_clock_t clock;
 
-       /* return directly when it is eDP */
-       if (HAS_eDP)
-               return true;
-
        if (target < 200000) {
                clock.n = 1;
                clock.p1 = 2;
@@ -1719,6 +1715,9 @@ static void ironlake_fdi_link_train(struct drm_crtc *crtc)
        POSTING_READ(reg);
        udelay(150);
 
+       /* Ironlake workaround, enable clock pointer after FDI enable*/
+       I915_WRITE(FDI_RX_CHICKEN(pipe), FDI_RX_PHASE_SYNC_POINTER_ENABLE);
+
        reg = FDI_RX_IIR(pipe);
        for (tries = 0; tries < 5; tries++) {
                temp = I915_READ(reg);
@@ -1764,6 +1763,28 @@ static void ironlake_fdi_link_train(struct drm_crtc *crtc)
                DRM_ERROR("FDI train 2 fail!\n");
 
        DRM_DEBUG_KMS("FDI train done\n");
+
+       /* enable normal train */
+       reg = FDI_TX_CTL(pipe);
+       temp = I915_READ(reg);
+       temp &= ~FDI_LINK_TRAIN_NONE;
+       temp |= FDI_LINK_TRAIN_NONE | FDI_TX_ENHANCE_FRAME_ENABLE;
+       I915_WRITE(reg, temp);
+
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(reg);
+       if (HAS_PCH_CPT(dev)) {
+               temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+               temp |= FDI_LINK_TRAIN_NORMAL_CPT;
+       } else {
+               temp &= ~FDI_LINK_TRAIN_NONE;
+               temp |= FDI_LINK_TRAIN_NONE;
+       }
+       I915_WRITE(reg, temp | FDI_RX_ENHANCE_FRAME_ENABLE);
+
+       /* wait one idle pattern time */
+       POSTING_READ(reg);
+       udelay(1000);
 }
 
 static const int const snb_b_fdi_train_param [] = {
@@ -2002,8 +2023,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
 
        /* Enable panel fitting for LVDS */
        if (dev_priv->pch_pf_size &&
-           (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)
-            || HAS_eDP || intel_pch_has_edp(crtc))) {
+           (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) || HAS_eDP)) {
                /* Force use of hard-coded filter coefficients
                 * as some pre-programmed values are broken,
                 * e.g. x201.
@@ -2022,7 +2042,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
        if ((temp & PIPECONF_ENABLE) == 0) {
                I915_WRITE(reg, temp | PIPECONF_ENABLE);
                POSTING_READ(reg);
-               udelay(100);
+               intel_wait_for_vblank(dev, intel_crtc->pipe);
        }
 
        /* configure and enable CPU plane */
@@ -2067,28 +2087,6 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
        I915_WRITE(TRANS_VBLANK(pipe), I915_READ(VBLANK(pipe)));
        I915_WRITE(TRANS_VSYNC(pipe),  I915_READ(VSYNC(pipe)));
 
-       /* enable normal train */
-       reg = FDI_TX_CTL(pipe);
-       temp = I915_READ(reg);
-       temp &= ~FDI_LINK_TRAIN_NONE;
-       temp |= FDI_LINK_TRAIN_NONE | FDI_TX_ENHANCE_FRAME_ENABLE;
-       I915_WRITE(reg, temp);
-
-       reg = FDI_RX_CTL(pipe);
-       temp = I915_READ(reg);
-       if (HAS_PCH_CPT(dev)) {
-               temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
-               temp |= FDI_LINK_TRAIN_NORMAL_CPT;
-       } else {
-               temp &= ~FDI_LINK_TRAIN_NONE;
-               temp |= FDI_LINK_TRAIN_NONE;
-       }
-       I915_WRITE(reg, temp | FDI_RX_ENHANCE_FRAME_ENABLE);
-
-       /* wait one idle pattern time */
-       POSTING_READ(reg);
-       udelay(100);
-
        /* For PCH DP, enable TRANS_DP_CTL */
        if (HAS_PCH_CPT(dev) &&
            intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) {
@@ -2134,7 +2132,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
        temp |= I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK;
        I915_WRITE(reg, temp | TRANS_ENABLE);
        if (wait_for(I915_READ(reg) & TRANS_STATE_ENABLE, 100))
-               DRM_ERROR("failed to enable transcoder\n");
+               DRM_ERROR("failed to enable transcoder %d\n", pipe);
 
        intel_crtc_load_lut(crtc);
        intel_update_fbc(dev);
@@ -2174,9 +2172,9 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
        temp = I915_READ(reg);
        if (temp & PIPECONF_ENABLE) {
                I915_WRITE(reg, temp & ~PIPECONF_ENABLE);
+               POSTING_READ(reg);
                /* wait for cpu pipe off, pipe state */
-               if (wait_for((I915_READ(reg) & I965_PIPECONF_ACTIVE) == 0, 50))
-                       DRM_ERROR("failed to turn off cpu pipe\n");
+               intel_wait_for_pipe_off(dev, intel_crtc->pipe);
        }
 
        /* Disable PF */
@@ -2198,6 +2196,11 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
        POSTING_READ(reg);
        udelay(100);
 
+       /* Ironlake workaround, disable clock pointer after downing FDI */
+       I915_WRITE(FDI_RX_CHICKEN(pipe),
+                  I915_READ(FDI_RX_CHICKEN(pipe) &
+                            ~FDI_RX_PHASE_SYNC_POINTER_ENABLE));
+
        /* still set train pattern 1 */
        reg = FDI_TX_CTL(pipe);
        temp = I915_READ(reg);
@@ -3623,7 +3626,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                              refclk / 1000);
        } else if (!IS_GEN2(dev)) {
                refclk = 96000;
-               if (HAS_PCH_SPLIT(dev))
+               if (HAS_PCH_SPLIT(dev) &&
+                   (!has_edp_encoder || intel_encoder_is_pch_edp(&has_edp_encoder->base)))
                        refclk = 120000; /* 120Mhz refclk */
        } else {
                refclk = 48000;
@@ -3685,16 +3689,16 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        /* FDI link */
        if (HAS_PCH_SPLIT(dev)) {
                int lane = 0, link_bw, bpp;
-               /* eDP doesn't require FDI link, so just set DP M/N
+               /* CPU eDP doesn't require FDI link, so just set DP M/N
                   according to current link config */
-               if (has_edp_encoder) {
+               if (has_edp_encoder && !intel_encoder_is_pch_edp(&encoder->base)) {
                        target_clock = mode->clock;
                        intel_edp_link_config(has_edp_encoder,
                                              &lane, &link_bw);
                } else {
-                       /* DP over FDI requires target mode clock
+                       /* [e]DP over FDI requires target mode clock
                           instead of link clock */
-                       if (is_dp)
+                       if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base))
                                target_clock = mode->clock;
                        else
                                target_clock = adjusted_mode->clock;
@@ -3718,7 +3722,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                                temp |= PIPE_8BPC;
                        else
                                temp |= PIPE_6BPC;
-               } else if (has_edp_encoder || (is_dp && intel_pch_has_edp(crtc))) {
+               } else if (has_edp_encoder) {
                        switch (dev_priv->edp.bpp/3) {
                        case 8:
                                temp |= PIPE_8BPC;
@@ -3794,13 +3798,25 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
 
                                POSTING_READ(PCH_DREF_CONTROL);
                                udelay(200);
+                       }
+                       temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
 
-                               temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
-                               temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
+                       /* Enable CPU source on CPU attached eDP */
+                       if (!intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
+                               if (dev_priv->lvds_use_ssc)
+                                       temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
+                               else
+                                       temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
                        } else {
-                               temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
+                               /* Enable SSC on PCH eDP if needed */
+                               if (dev_priv->lvds_use_ssc) {
+                                       DRM_ERROR("enabling SSC on PCH\n");
+                                       temp |= DREF_SUPERSPREAD_SOURCE_ENABLE;
+                               }
                        }
                        I915_WRITE(PCH_DREF_CONTROL, temp);
+                       POSTING_READ(PCH_DREF_CONTROL);
+                       udelay(200);
                }
        }
 
@@ -3835,7 +3851,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        }
                        dpll |= DPLL_DVO_HIGH_SPEED;
                }
-               if (is_dp)
+               if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base))
                        dpll |= DPLL_DVO_HIGH_SPEED;
 
                /* compute bitmask from p1 value */
@@ -3934,7 +3950,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                dpll_reg = DPLL(pipe);
        }
 
-       if (!has_edp_encoder) {
+       /* PCH eDP needs FDI, but CPU eDP does not */
+       if (!has_edp_encoder || intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
                I915_WRITE(fp_reg, fp);
                I915_WRITE(dpll_reg, dpll & ~DPLL_VCO_ENABLE);
 
@@ -4011,9 +4028,9 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                }
        }
 
-       if (is_dp)
+       if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
                intel_dp_set_m_n(crtc, mode, adjusted_mode);
-       else if (HAS_PCH_SPLIT(dev)) {
+       else if (HAS_PCH_SPLIT(dev)) {
                /* For non-DP output, clear any trans DP clock recovery setting.*/
                if (pipe == 0) {
                        I915_WRITE(TRANSA_DATA_M1, 0);
@@ -4028,7 +4045,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                }
        }
 
-       if (!has_edp_encoder) {
+       if (!has_edp_encoder || intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
                I915_WRITE(fp_reg, fp);
                I915_WRITE(dpll_reg, dpll);
 
@@ -4122,29 +4139,8 @@ 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);
 
-               if (has_edp_encoder) {
+               if (has_edp_encoder && !intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
                        ironlake_set_pll_edp(crtc, adjusted_mode->clock);
-               } else {
-                       /* enable FDI RX PLL too */
-                       reg = FDI_RX_CTL(pipe);
-                       temp = I915_READ(reg);
-                       I915_WRITE(reg, temp | FDI_RX_PLL_ENABLE);
-
-                       POSTING_READ(reg);
-                       udelay(200);
-
-                       /* enable FDI TX PLL too */
-                       reg = FDI_TX_CTL(pipe);
-                       temp = I915_READ(reg);
-                       I915_WRITE(reg, temp | FDI_TX_PLL_ENABLE);
-
-                       /* enable FDI RX PCDCLK */
-                       reg = FDI_RX_CTL(pipe);
-                       temp = I915_READ(reg);
-                       I915_WRITE(reg, temp | FDI_PCDCLK);
-
-                       POSTING_READ(reg);
-                       udelay(200);
                }
        }
 
@@ -4995,8 +4991,9 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
        obj_priv = to_intel_bo(work->pending_flip_obj);
 
        /* Initial scanout buffer will have a 0 pending flip count */
-       if ((atomic_read(&obj_priv->pending_flip) == 0) ||
-           atomic_dec_and_test(&obj_priv->pending_flip))
+       atomic_clear_mask(1 << intel_crtc->plane,
+                         &obj_priv->pending_flip.counter);
+       if (atomic_read(&obj_priv->pending_flip) == 0)
                wake_up(&dev_priv->pending_flip_queue);
        schedule_work(&work->work);
 
@@ -5093,7 +5090,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
                goto cleanup_objs;
 
        obj_priv = to_intel_bo(obj);
-       atomic_inc(&obj_priv->pending_flip);
+       atomic_add(1 << intel_crtc->plane, &obj_priv->pending_flip);
        work->pending_flip_obj = obj;
 
        if (IS_GEN3(dev) || IS_GEN2(dev)) {
@@ -5749,6 +5746,13 @@ void intel_init_clock_gating(struct drm_device *dev)
 
                I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
 
+               /*
+                * On Ibex Peak and Cougar Point, we need to disable clock
+                * gating for the panel power sequencer or it will fail to
+                * start up when no ports are active.
+                */
+               I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE);
+
                /*
                 * According to the spec the following bits should be set in
                 * order to enable memory self-refresh
@@ -6131,6 +6135,9 @@ void intel_modeset_cleanup(struct drm_device *dev)
        drm_kms_helper_poll_fini(dev);
        mutex_lock(&dev->struct_mutex);
 
+       intel_unregister_dsm_handler();
+
+
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
                /* Skip inactive CRTCs */
                if (!crtc->fb)
index 152d94507b79170e651a35374d2238968c7a637d..128c2fefd541ab5fb255873751e5b5fdcf46ecf2 100644 (file)
@@ -42,9 +42,6 @@
 
 #define DP_LINK_CONFIGURATION_SIZE     9
 
-#define IS_eDP(i) ((i)->base.type == INTEL_OUTPUT_EDP)
-#define IS_PCH_eDP(i) ((i)->is_pch_edp)
-
 struct intel_dp {
        struct intel_encoder base;
        uint32_t output_reg;
@@ -62,6 +59,31 @@ struct intel_dp {
        uint8_t link_status[DP_LINK_STATUS_SIZE];
 };
 
+/**
+ * is_edp - is the given port attached to an eDP panel (either CPU or PCH)
+ * @intel_dp: DP struct
+ *
+ * If a CPU or PCH DP output is attached to an eDP panel, this function
+ * will return true, and false otherwise.
+ */
+static bool is_edp(struct intel_dp *intel_dp)
+{
+       return intel_dp->base.type == INTEL_OUTPUT_EDP;
+}
+
+/**
+ * is_pch_edp - is the port on the PCH and attached to an eDP panel?
+ * @intel_dp: DP struct
+ *
+ * Returns true if the given DP struct corresponds to a PCH DP port attached
+ * to an eDP panel, false otherwise.  Helpful for determining whether we
+ * may need FDI resources for a given DP output or not.
+ */
+static bool is_pch_edp(struct intel_dp *intel_dp)
+{
+       return intel_dp->is_pch_edp;
+}
+
 static struct intel_dp *enc_to_intel_dp(struct drm_encoder *encoder)
 {
        return container_of(encoder, struct intel_dp, base.base);
@@ -73,6 +95,25 @@ static struct intel_dp *intel_attached_dp(struct drm_connector *connector)
                            struct intel_dp, base);
 }
 
+/**
+ * intel_encoder_is_pch_edp - is the given encoder a PCH attached eDP?
+ * @encoder: DRM encoder
+ *
+ * Return true if @encoder corresponds to a PCH attached eDP panel.  Needed
+ * by intel_display.c.
+ */
+bool intel_encoder_is_pch_edp(struct drm_encoder *encoder)
+{
+       struct intel_dp *intel_dp;
+
+       if (!encoder)
+               return false;
+
+       intel_dp = enc_to_intel_dp(encoder);
+
+       return is_pch_edp(intel_dp);
+}
+
 static void intel_dp_start_link_train(struct intel_dp *intel_dp);
 static void intel_dp_complete_link_train(struct intel_dp *intel_dp);
 static void intel_dp_link_down(struct intel_dp *intel_dp);
@@ -138,7 +179,7 @@ intel_dp_link_required(struct drm_device *dev, struct intel_dp *intel_dp, int pi
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
+       if (is_edp(intel_dp))
                return (pixel_clock * dev_priv->edp.bpp + 7) / 8;
        else
                return pixel_clock * 3;
@@ -160,8 +201,7 @@ intel_dp_mode_valid(struct drm_connector *connector,
        int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_dp));
        int max_lanes = intel_dp_max_lane_count(intel_dp);
 
-       if ((IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) &&
-           dev_priv->panel_fixed_mode) {
+       if (is_edp(intel_dp) && dev_priv->panel_fixed_mode) {
                if (mode->hdisplay > dev_priv->panel_fixed_mode->hdisplay)
                        return MODE_PANEL;
 
@@ -171,7 +211,7 @@ intel_dp_mode_valid(struct drm_connector *connector,
 
        /* only refuse the mode on non eDP since we have seen some wierd eDP panels
           which are outside spec tolerances but somehow work by magic */
-       if (!IS_eDP(intel_dp) &&
+       if (!is_edp(intel_dp) &&
            (intel_dp_link_required(connector->dev, intel_dp, mode->clock)
             > intel_dp_max_data_rate(max_link_clock, max_lanes)))
                return MODE_CLOCK_HIGH;
@@ -258,7 +298,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
         * Note that PCH attached eDP panels should use a 125MHz input
         * clock divider.
         */
-       if (IS_eDP(intel_dp) && !IS_PCH_eDP(intel_dp)) {
+       if (is_edp(intel_dp) && !is_pch_edp(intel_dp)) {
                if (IS_GEN6(dev))
                        aux_clock_divider = 200; /* SNB eDP input clock at 400Mhz */
                else
@@ -530,8 +570,7 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
        int max_clock = intel_dp_max_link_bw(intel_dp) == DP_LINK_BW_2_7 ? 1 : 0;
        static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 };
 
-       if ((IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) &&
-           dev_priv->panel_fixed_mode) {
+       if (is_edp(intel_dp) && dev_priv->panel_fixed_mode) {
                intel_fixed_panel_mode(dev_priv->panel_fixed_mode, adjusted_mode);
                intel_pch_panel_fitting(dev, DRM_MODE_SCALE_FULLSCREEN,
                                        mode, adjusted_mode);
@@ -542,6 +581,17 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
                mode->clock = dev_priv->panel_fixed_mode->clock;
        }
 
+       /* Just use VBT values for eDP */
+       if (is_edp(intel_dp)) {
+               intel_dp->lane_count = dev_priv->edp.lanes;
+               intel_dp->link_bw = dev_priv->edp.rate;
+               adjusted_mode->clock = intel_dp_link_clock(intel_dp->link_bw);
+               DRM_DEBUG_KMS("eDP link bw %02x lane count %d clock %d\n",
+                             intel_dp->link_bw, intel_dp->lane_count,
+                             adjusted_mode->clock);
+               return true;
+       }
+
        for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) {
                for (clock = 0; clock <= max_clock; clock++) {
                        int link_avail = intel_dp_max_data_rate(intel_dp_link_clock(bws[clock]), lane_count);
@@ -560,19 +610,6 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
                }
        }
 
-       if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) {
-               /* okay we failed just pick the highest */
-               intel_dp->lane_count = max_lane_count;
-               intel_dp->link_bw = bws[max_clock];
-               adjusted_mode->clock = intel_dp_link_clock(intel_dp->link_bw);
-               DRM_DEBUG_KMS("Force picking display port link bw %02x lane "
-                             "count %d clock %d\n",
-                             intel_dp->link_bw, intel_dp->lane_count,
-                             adjusted_mode->clock);
-
-               return true;
-       }
-
        return false;
 }
 
@@ -609,25 +646,6 @@ intel_dp_compute_m_n(int bpp,
        intel_reduce_ratio(&m_n->link_m, &m_n->link_n);
 }
 
-bool intel_pch_has_edp(struct drm_crtc *crtc)
-{
-       struct drm_device *dev = crtc->dev;
-       struct drm_mode_config *mode_config = &dev->mode_config;
-       struct drm_encoder *encoder;
-
-       list_for_each_entry(encoder, &mode_config->encoder_list, head) {
-               struct intel_dp *intel_dp;
-
-               if (encoder->crtc != crtc)
-                       continue;
-
-               intel_dp = enc_to_intel_dp(encoder);
-               if (intel_dp->base.type == INTEL_OUTPUT_DISPLAYPORT)
-                       return intel_dp->is_pch_edp;
-       }
-       return false;
-}
-
 void
 intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
                 struct drm_display_mode *adjusted_mode)
@@ -652,8 +670,10 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
                intel_dp = enc_to_intel_dp(encoder);
                if (intel_dp->base.type == INTEL_OUTPUT_DISPLAYPORT) {
                        lane_count = intel_dp->lane_count;
-                       if (IS_PCH_eDP(intel_dp))
-                               bpp = dev_priv->edp.bpp;
+                       break;
+               } else if (is_edp(intel_dp)) {
+                       lane_count = dev_priv->edp.lanes;
+                       bpp = dev_priv->edp.bpp;
                        break;
                }
        }
@@ -720,7 +740,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
        if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
                intel_dp->DP |= DP_SYNC_VS_HIGH;
 
-       if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp))
+       if (HAS_PCH_CPT(dev) && !is_edp(intel_dp))
                intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT;
        else
                intel_dp->DP |= DP_LINK_TRAIN_OFF;
@@ -755,7 +775,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
        if (intel_crtc->pipe == 1 && !HAS_PCH_CPT(dev))
                intel_dp->DP |= DP_PIPEB_SELECT;
 
-       if (IS_eDP(intel_dp)) {
+       if (is_edp(intel_dp) && !is_pch_edp(intel_dp)) {
                /* don't miss out required setting for eDP */
                intel_dp->DP |= DP_PLL_ENABLE;
                if (adjusted_mode->clock < 200000)
@@ -766,10 +786,11 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
 }
 
 /* Returns true if the panel was already on when called */
-static bool ironlake_edp_panel_on (struct drm_device *dev)
+static bool 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;
+       u32 pp, idle_on_mask = PP_ON | PP_SEQUENCE_STATE_ON_IDLE;
 
        if (I915_READ(PCH_PP_STATUS) & PP_ON)
                return true;
@@ -781,19 +802,20 @@ static bool ironlake_edp_panel_on (struct drm_device *dev)
        I915_WRITE(PCH_PP_CONTROL, pp);
        POSTING_READ(PCH_PP_CONTROL);
 
-       pp |= POWER_TARGET_ON;
+       pp |= PANEL_UNLOCK_REGS | POWER_TARGET_ON;
        I915_WRITE(PCH_PP_CONTROL, pp);
+       POSTING_READ(PCH_PP_CONTROL);
 
        /* Ouch. We need to wait here for some panels, like Dell e6510
         * https://bugs.freedesktop.org/show_bug.cgi?id=29278i
         */
        msleep(300);
 
-       if (wait_for(I915_READ(PCH_PP_STATUS) & PP_ON, 5000))
+       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));
 
-       pp &= ~(PANEL_UNLOCK_REGS);
        pp |= PANEL_POWER_RESET; /* restore panel reset bit */
        I915_WRITE(PCH_PP_CONTROL, pp);
        POSTING_READ(PCH_PP_CONTROL);
@@ -804,7 +826,8 @@ static bool ironlake_edp_panel_on (struct drm_device *dev)
 static void ironlake_edp_panel_off (struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 pp;
+       u32 pp, idle_off_mask = PP_ON | PP_SEQUENCE_MASK |
+               PP_CYCLE_DELAY_ACTIVE | PP_SEQUENCE_STATE_MASK;
 
        pp = I915_READ(PCH_PP_CONTROL);
 
@@ -815,12 +838,12 @@ static void ironlake_edp_panel_off (struct drm_device *dev)
 
        pp &= ~POWER_TARGET_ON;
        I915_WRITE(PCH_PP_CONTROL, pp);
+       POSTING_READ(PCH_PP_CONTROL);
 
-       if (wait_for((I915_READ(PCH_PP_STATUS) & PP_ON) == 0, 5000))
+       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));
 
-       /* Make sure VDD is enabled so DP AUX will work */
        pp |= PANEL_POWER_RESET; /* restore panel reset bit */
        I915_WRITE(PCH_PP_CONTROL, pp);
        POSTING_READ(PCH_PP_CONTROL);
@@ -831,36 +854,19 @@ static void ironlake_edp_panel_off (struct drm_device *dev)
        msleep(300);
 }
 
-static void ironlake_edp_panel_vdd_on(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 pp;
-
-       pp = I915_READ(PCH_PP_CONTROL);
-       pp |= EDP_FORCE_VDD;
-       I915_WRITE(PCH_PP_CONTROL, pp);
-       POSTING_READ(PCH_PP_CONTROL);
-       msleep(300);
-}
-
-static void ironlake_edp_panel_vdd_off(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 pp;
-
-       pp = I915_READ(PCH_PP_CONTROL);
-       pp &= ~EDP_FORCE_VDD;
-       I915_WRITE(PCH_PP_CONTROL, pp);
-       POSTING_READ(PCH_PP_CONTROL);
-       msleep(300);
-}
-
 static void ironlake_edp_backlight_on (struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 pp;
 
        DRM_DEBUG_KMS("\n");
+       /*
+        * If we enable the backlight right away following a panel power
+        * on, we may see slight flicker as the panel syncs with the eDP
+        * link.  So delay a bit to make sure the image is solid before
+        * allowing it to appear.
+        */
+       msleep(300);
        pp = I915_READ(PCH_PP_CONTROL);
        pp |= EDP_BLC_ENABLE;
        I915_WRITE(PCH_PP_CONTROL, pp);
@@ -885,8 +891,10 @@ static void ironlake_edp_pll_on(struct drm_encoder *encoder)
 
        DRM_DEBUG_KMS("\n");
        dpa_ctl = I915_READ(DP_A);
-       dpa_ctl &= ~DP_PLL_ENABLE;
+       dpa_ctl |= DP_PLL_ENABLE;
        I915_WRITE(DP_A, dpa_ctl);
+       POSTING_READ(DP_A);
+       udelay(200);
 }
 
 static void ironlake_edp_pll_off(struct drm_encoder *encoder)
@@ -896,7 +904,7 @@ static void ironlake_edp_pll_off(struct drm_encoder *encoder)
        u32 dpa_ctl;
 
        dpa_ctl = I915_READ(DP_A);
-       dpa_ctl |= DP_PLL_ENABLE;
+       dpa_ctl &= ~DP_PLL_ENABLE;
        I915_WRITE(DP_A, dpa_ctl);
        POSTING_READ(DP_A);
        udelay(200);
@@ -909,11 +917,13 @@ static void intel_dp_prepare(struct drm_encoder *encoder)
        struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t dp_reg = I915_READ(intel_dp->output_reg);
 
-       if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) {
-               ironlake_edp_panel_off(dev);
+       if (is_edp(intel_dp)) {
                ironlake_edp_backlight_off(dev);
-               ironlake_edp_panel_vdd_on(dev);
-               ironlake_edp_pll_on(encoder);
+               ironlake_edp_panel_on(intel_dp);
+               if (!is_pch_edp(intel_dp))
+                       ironlake_edp_pll_on(encoder);
+               else
+                       ironlake_edp_pll_off(encoder);
        }
        if (dp_reg & DP_PORT_EN)
                intel_dp_link_down(intel_dp);
@@ -926,14 +936,13 @@ static void intel_dp_commit(struct drm_encoder *encoder)
 
        intel_dp_start_link_train(intel_dp);
 
-       if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
-               ironlake_edp_panel_on(dev);
+       if (is_edp(intel_dp))
+               ironlake_edp_panel_on(intel_dp);
 
        intel_dp_complete_link_train(intel_dp);
 
-       if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
+       if (is_edp(intel_dp))
                ironlake_edp_backlight_on(dev);
-       intel_dp->dpms_mode = DRM_MODE_DPMS_ON;
 }
 
 static void
@@ -945,21 +954,21 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
        uint32_t dp_reg = I915_READ(intel_dp->output_reg);
 
        if (mode != DRM_MODE_DPMS_ON) {
-               if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) {
+               if (is_edp(intel_dp))
                        ironlake_edp_backlight_off(dev);
-                       ironlake_edp_panel_off(dev);
-               }
                if (dp_reg & DP_PORT_EN)
                        intel_dp_link_down(intel_dp);
-               if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
+               if (is_edp(intel_dp))
+                       ironlake_edp_panel_off(dev);
+               if (is_edp(intel_dp) && !is_pch_edp(intel_dp))
                        ironlake_edp_pll_off(encoder);
        } else {
                if (!(dp_reg & DP_PORT_EN)) {
+                       if (is_edp(intel_dp))
+                               ironlake_edp_panel_on(intel_dp);
                        intel_dp_start_link_train(intel_dp);
-                       if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
-                               ironlake_edp_panel_on(dev);
                        intel_dp_complete_link_train(intel_dp);
-                       if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
+                       if (is_edp(intel_dp))
                                ironlake_edp_backlight_on(dev);
                }
        }
@@ -1079,11 +1088,21 @@ intel_get_adjust_train(struct intel_dp *intel_dp)
 }
 
 static uint32_t
-intel_dp_signal_levels(uint8_t train_set, int lane_count)
+intel_dp_signal_levels(struct intel_dp *intel_dp)
 {
-       uint32_t        signal_levels = 0;
+       struct drm_device *dev = intel_dp->base.base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t signal_levels = 0;
+       u8 train_set = intel_dp->train_set[0];
+       u32 vswing = train_set & DP_TRAIN_VOLTAGE_SWING_MASK;
+       u32 preemphasis = train_set & DP_TRAIN_PRE_EMPHASIS_MASK;
+
+       if (is_edp(intel_dp)) {
+               vswing = dev_priv->edp.vswing;
+               preemphasis = dev_priv->edp.preemphasis;
+       }
 
-       switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
+       switch (vswing) {
        case DP_TRAIN_VOLTAGE_SWING_400:
        default:
                signal_levels |= DP_VOLTAGE_0_4;
@@ -1098,7 +1117,7 @@ intel_dp_signal_levels(uint8_t train_set, int lane_count)
                signal_levels |= DP_VOLTAGE_1_2;
                break;
        }
-       switch (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) {
+       switch (preemphasis) {
        case DP_TRAIN_PRE_EMPHASIS_0:
        default:
                signal_levels |= DP_PRE_EMPHASIS_0;
@@ -1184,6 +1203,18 @@ intel_channel_eq_ok(struct intel_dp *intel_dp)
        return true;
 }
 
+static bool
+intel_dp_aux_handshake_required(struct intel_dp *intel_dp)
+{
+       struct drm_device *dev = intel_dp->base.base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (is_edp(intel_dp) && dev_priv->no_aux_handshake)
+               return false;
+
+       return true;
+}
+
 static bool
 intel_dp_set_link_train(struct intel_dp *intel_dp,
                        uint32_t dp_reg_value,
@@ -1196,6 +1227,9 @@ intel_dp_set_link_train(struct intel_dp *intel_dp,
        I915_WRITE(intel_dp->output_reg, dp_reg_value);
        POSTING_READ(intel_dp->output_reg);
 
+       if (!intel_dp_aux_handshake_required(intel_dp))
+               return true;
+
        intel_dp_aux_native_write_1(intel_dp,
                                    DP_TRAINING_PATTERN_SET,
                                    dp_train_pat);
@@ -1228,13 +1262,14 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
        POSTING_READ(intel_dp->output_reg);
        intel_wait_for_vblank(dev, intel_crtc->pipe);
 
-       /* Write the link configuration data */
-       intel_dp_aux_native_write(intel_dp, DP_LINK_BW_SET,
-                                 intel_dp->link_configuration,
-                                 DP_LINK_CONFIGURATION_SIZE);
+       if (intel_dp_aux_handshake_required(intel_dp))
+               /* Write the link configuration data */
+               intel_dp_aux_native_write(intel_dp, DP_LINK_BW_SET,
+                                         intel_dp->link_configuration,
+                                         DP_LINK_CONFIGURATION_SIZE);
 
        DP |= DP_PORT_EN;
-       if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp))
+       if (HAS_PCH_CPT(dev) && !is_edp(intel_dp))
                DP &= ~DP_LINK_TRAIN_MASK_CPT;
        else
                DP &= ~DP_LINK_TRAIN_MASK;
@@ -1245,15 +1280,15 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
        for (;;) {
                /* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */
                uint32_t    signal_levels;
-               if (IS_GEN6(dev) && IS_eDP(intel_dp)) {
+               if (IS_GEN6(dev) && is_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);
                        DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
                }
 
-               if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp))
+               if (HAS_PCH_CPT(dev) && !is_edp(intel_dp))
                        reg = DP | DP_LINK_TRAIN_PAT_1_CPT;
                else
                        reg = DP | DP_LINK_TRAIN_PAT_1;
@@ -1263,33 +1298,37 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
                        break;
                /* Set training pattern 1 */
 
-               udelay(100);
-               if (!intel_dp_get_link_status(intel_dp))
+               udelay(500);
+               if (intel_dp_aux_handshake_required(intel_dp)) {
                        break;
+               } else {
+                       if (!intel_dp_get_link_status(intel_dp))
+                               break;
 
-               if (intel_clock_recovery_ok(intel_dp->link_status, intel_dp->lane_count)) {
-                       clock_recovery = true;
-                       break;
-               }
-
-               /* Check to see if we've tried the max voltage */
-               for (i = 0; i < intel_dp->lane_count; i++)
-                       if ((intel_dp->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
+                       if (intel_clock_recovery_ok(intel_dp->link_status, intel_dp->lane_count)) {
+                               clock_recovery = true;
                                break;
-               if (i == intel_dp->lane_count)
-                       break;
+                       }
 
-               /* 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)
+                       /* Check to see if we've tried the max voltage */
+                       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;
-               } else
-                       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);
+                       /* 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)
+                                       break;
+                       } else
+                               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_dp->DP = DP;
@@ -1312,15 +1351,15 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
                /* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */
                uint32_t    signal_levels;
 
-               if (IS_GEN6(dev) && IS_eDP(intel_dp)) {
+               if (IS_GEN6(dev) && is_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);
                        DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
                }
 
-               if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp))
+               if (HAS_PCH_CPT(dev) && !is_edp(intel_dp))
                        reg = DP | DP_LINK_TRAIN_PAT_2_CPT;
                else
                        reg = DP | DP_LINK_TRAIN_PAT_2;
@@ -1330,25 +1369,29 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
                                             DP_TRAINING_PATTERN_2))
                        break;
 
-               udelay(400);
-               if (!intel_dp_get_link_status(intel_dp))
-                       break;
+               udelay(500);
 
-               if (intel_channel_eq_ok(intel_dp)) {
-                       channel_eq = true;
+               if (!intel_dp_aux_handshake_required(intel_dp)) {
                        break;
-               }
+               } else {
+                       if (!intel_dp_get_link_status(intel_dp))
+                               break;
 
-               /* Try 5 times */
-               if (tries > 5)
-                       break;
+                       if (intel_channel_eq_ok(intel_dp)) {
+                               channel_eq = true;
+                               break;
+                       }
 
-               /* Compute new intel_dp->train_set as requested by target */
-               intel_get_adjust_train(intel_dp);
-               ++tries;
-       }
+                       /* Try 5 times */
+                       if (tries > 5)
+                               break;
 
-       if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp))
+                       /* Compute new intel_dp->train_set as requested by target */
+                       intel_get_adjust_train(intel_dp);
+                       ++tries;
+               }
+       }
+       if (HAS_PCH_CPT(dev) && !is_edp(intel_dp))
                reg = DP | DP_LINK_TRAIN_OFF_CPT;
        else
                reg = DP | DP_LINK_TRAIN_OFF;
@@ -1368,14 +1411,14 @@ intel_dp_link_down(struct intel_dp *intel_dp)
 
        DRM_DEBUG_KMS("\n");
 
-       if (IS_eDP(intel_dp)) {
+       if (is_edp(intel_dp)) {
                DP &= ~DP_PLL_ENABLE;
                I915_WRITE(intel_dp->output_reg, DP);
                POSTING_READ(intel_dp->output_reg);
                udelay(100);
        }
 
-       if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp)) {
+       if (HAS_PCH_CPT(dev) && !is_edp(intel_dp)) {
                DP &= ~DP_LINK_TRAIN_MASK_CPT;
                I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE_CPT);
        } else {
@@ -1386,7 +1429,7 @@ intel_dp_link_down(struct intel_dp *intel_dp)
 
        msleep(17);
 
-       if (IS_eDP(intel_dp))
+       if (is_edp(intel_dp))
                DP |= DP_LINK_TRAIN_OFF;
        I915_WRITE(intel_dp->output_reg, DP & ~DP_PORT_EN);
        POSTING_READ(intel_dp->output_reg);
@@ -1424,9 +1467,10 @@ ironlake_dp_detect(struct drm_connector *connector)
        struct intel_dp *intel_dp = intel_attached_dp(connector);
        enum drm_connector_status status;
 
-       /* Panel needs power for AUX to work */
-       if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
-               ironlake_edp_panel_vdd_on(connector->dev);
+       /* Can't disconnect eDP */
+       if (is_edp(intel_dp))
+               return connector_status_connected;
+
        status = connector_status_disconnected;
        if (intel_dp_aux_native_read(intel_dp,
                                     0x000, intel_dp->dpcd,
@@ -1437,8 +1481,6 @@ ironlake_dp_detect(struct drm_connector *connector)
        }
        DRM_DEBUG_KMS("DPCD: %hx%hx%hx%hx\n", intel_dp->dpcd[0],
                      intel_dp->dpcd[1], intel_dp->dpcd[2], intel_dp->dpcd[3]);
-       if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
-               ironlake_edp_panel_vdd_off(connector->dev);
        return status;
 }
 
@@ -1504,8 +1546,7 @@ static int intel_dp_get_modes(struct drm_connector *connector)
 
        ret = intel_ddc_get_modes(connector, &intel_dp->adapter);
        if (ret) {
-               if ((IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) &&
-                   !dev_priv->panel_fixed_mode) {
+               if (is_edp(intel_dp) && !dev_priv->panel_fixed_mode) {
                        struct drm_display_mode *newmode;
                        list_for_each_entry(newmode, &connector->probed_modes,
                                            head) {
@@ -1521,7 +1562,7 @@ static int intel_dp_get_modes(struct drm_connector *connector)
        }
 
        /* if eDP has no EDID, try to use fixed panel mode from VBT */
-       if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) {
+       if (is_edp(intel_dp)) {
                if (dev_priv->panel_fixed_mode != NULL) {
                        struct drm_display_mode *mode;
                        mode = drm_mode_duplicate(dev, dev_priv->panel_fixed_mode);
@@ -1651,7 +1692,7 @@ intel_dp_init(struct drm_device *dev, int output_reg)
                if (intel_dpd_is_edp(dev))
                        intel_dp->is_pch_edp = true;
 
-       if (output_reg == DP_A || IS_PCH_eDP(intel_dp)) {
+       if (output_reg == DP_A || is_pch_edp(intel_dp)) {
                type = DRM_MODE_CONNECTOR_eDP;
                intel_encoder->type = INTEL_OUTPUT_EDP;
        } else {
@@ -1672,7 +1713,7 @@ intel_dp_init(struct drm_device *dev, int output_reg)
        else if (output_reg == DP_D || output_reg == PCH_DP_D)
                intel_encoder->clone_mask = (1 << INTEL_DP_D_CLONE_BIT);
 
-       if (IS_eDP(intel_dp))
+       if (is_edp(intel_dp))
                intel_encoder->clone_mask = (1 << INTEL_EDP_CLONE_BIT);
 
        intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
@@ -1717,9 +1758,29 @@ intel_dp_init(struct drm_device *dev, int output_reg)
 
        intel_dp_i2c_init(intel_dp, intel_connector, name);
 
+       /* Cache some DPCD data in the eDP case */
+       if (is_edp(intel_dp)) {
+               int ret;
+               bool was_on;
+
+               was_on = ironlake_edp_panel_on(intel_dp);
+               ret = intel_dp_aux_native_read(intel_dp, DP_DPCD_REV,
+                                              intel_dp->dpcd,
+                                              sizeof(intel_dp->dpcd));
+               if (ret == sizeof(intel_dp->dpcd)) {
+                       if (intel_dp->dpcd[0] >= 0x11)
+                               dev_priv->no_aux_handshake = intel_dp->dpcd[3] &
+                                       DP_NO_AUX_HANDSHAKE_LINK_TRAINING;
+               } else {
+                       DRM_ERROR("failed to retrieve link info\n");
+               }
+               if (!was_on)
+                       ironlake_edp_panel_off(dev);
+       }
+
        intel_encoder->hot_plug = intel_dp_hot_plug;
 
-       if (output_reg == DP_A || IS_PCH_eDP(intel_dp)) {
+       if (is_edp(intel_dp)) {
                /* initialize panel mode from VBT if available for eDP */
                if (dev_priv->lfp_lvds_vbt_mode) {
                        dev_priv->panel_fixed_mode =
index 40e99bf27ff7e23a59a838d37ce5cbd85783dff2..0581e5e5ac558882597ef5806fb4b28165f09616 100644 (file)
@@ -209,9 +209,9 @@ extern void intel_dp_init(struct drm_device *dev, int dp_reg);
 void
 intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
                 struct drm_display_mode *adjusted_mode);
-extern bool intel_pch_has_edp(struct drm_crtc *crtc);
 extern bool intel_dpd_is_edp(struct drm_device *dev);
 extern void intel_edp_link_config (struct intel_encoder *, int *, int *);
+extern bool intel_encoder_is_pch_edp(struct drm_encoder *encoder);
 
 /* intel_panel.c */
 extern void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
index 521622b9be7a7fa9ddebdd79813c5530c1d06425..af2a1dddc28e2e908529db44a24cea44ff10d387 100644 (file)
@@ -225,7 +225,7 @@ static void intel_fbdev_destroy(struct drm_device *dev,
 
        drm_framebuffer_cleanup(&ifb->base);
        if (ifb->obj) {
-               drm_gem_object_unreference(ifb->obj);
+               drm_gem_object_unreference_unlocked(ifb->obj);
                ifb->obj = NULL;
        }
 }
index a49e791db0b0308f284a17408a7051559102ca1d..83a389e44543f19911efe7726ad48d4dd602f967 100644 (file)
@@ -23,6 +23,9 @@
 #ifndef _DRM_DP_HELPER_H_
 #define _DRM_DP_HELPER_H_
 
+#include <linux/types.h>
+#include <linux/i2c.h>
+
 /* From the VESA DisplayPort spec */
 
 #define AUX_NATIVE_WRITE       0x8