Merge branch 'drm-intel-fixes' into drm-intel-next
authorChris Wilson <chris@chris-wilson.co.uk>
Wed, 16 Feb 2011 09:36:05 +0000 (09:36 +0000)
committerChris Wilson <chris@chris-wilson.co.uk>
Wed, 16 Feb 2011 09:44:30 +0000 (09:44 +0000)
Grab the latest stabilisation bits from -fixes and some suspend and
resume fixes from linus.

Conflicts:
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_irq.c

1  2 
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_reg.h
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_lvds.c
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/i915/intel_sdvo.c
drivers/gpu/drm/i915/intel_tv.c

@@@ -46,16 -46,16 +46,19 @@@ module_param_named(fbpercrtc, i915_fbpe
  unsigned int i915_powersave = 1;
  module_param_named(powersave, i915_powersave, int, 0600);
  
+ unsigned int i915_enable_rc6 = 0;
+ module_param_named(i915_enable_rc6, i915_enable_rc6, int, 0600);
  unsigned int i915_lvds_downclock = 0;
  module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400);
  
  unsigned int i915_panel_use_ssc = 1;
  module_param_named(lvds_use_ssc, i915_panel_use_ssc, int, 0600);
  
 -bool i915_try_reset = true;
 +int i915_vbt_sdvo_panel_type = -1;
 +module_param_named(vbt_sdvo_panel_type, i915_vbt_sdvo_panel_type, int, 0600);
 +
 +static bool i915_try_reset = true;
  module_param_named(reset, i915_try_reset, bool, 0600);
  
  static struct drm_driver driver;
@@@ -363,7 -363,7 +366,7 @@@ static int i915_drm_thaw(struct drm_dev
                /* Resume the modeset for every activated CRTC */
                drm_helper_resume_force_mode(dev);
  
-               if (dev_priv->renderctx && dev_priv->pwrctx)
+               if (IS_IRONLAKE_M(dev))
                        ironlake_enable_rc6(dev);
        }
  
@@@ -571,6 -571,14 +574,14 @@@ int i915_reset(struct drm_device *dev, 
  static int __devinit
  i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  {
+       /* Only bind to function 0 of the device. Early generations
+        * used function 1 as a placeholder for multi-head. This causes
+        * us confusion instead, especially on the systems where both
+        * functions have the same PCI-ID!
+        */
+       if (PCI_FUNC(pdev->devfn))
+               return -ENODEV;
        return drm_get_pci_dev(pdev, ent, &driver);
  }
  
@@@ -35,7 -35,6 +35,7 @@@
  #include "intel_ringbuffer.h"
  #include <linux/io-mapping.h>
  #include <linux/i2c.h>
 +#include <linux/pm_qos_params.h>
  #include <drm/intel-gtt.h>
  
  /* General customization:
  enum pipe {
        PIPE_A = 0,
        PIPE_B,
 +      PIPE_C,
 +      I915_MAX_PIPES
  };
 +#define pipe_name(p) ((p) + 'A')
  
  enum plane {
        PLANE_A = 0,
        PLANE_B,
 +      PLANE_C,
  };
 -
 -#define I915_NUM_PIPE 2
 +#define plane_name(p) ((p) + 'A')
  
  #define I915_GEM_GPU_DOMAINS  (~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT))
  
 +#define for_each_pipe(p) for ((p) = 0; (p) < dev_priv->num_pipe; (p)++)
 +
  /* Interface history:
   *
   * 1.1: Original.
  #define DRIVER_PATCHLEVEL     0
  
  #define WATCH_COHERENCY       0
 -#define WATCH_EXEC    0
 -#define WATCH_RELOC   0
  #define WATCH_LISTS   0
 -#define WATCH_PWRITE  0
  
  #define I915_GEM_PHYS_CURSOR_0 1
  #define I915_GEM_PHYS_CURSOR_1 2
@@@ -114,7 -111,6 +114,7 @@@ struct intel_opregion 
        struct opregion_swsci *swsci;
        struct opregion_asle *asle;
        void *vbt;
 +      u32 __iomem *lid_state;
  };
  #define OPREGION_SIZE            (8*1024)
  
@@@ -148,7 -144,8 +148,7 @@@ struct intel_display_error_state
  struct drm_i915_error_state {
        u32 eir;
        u32 pgtbl_er;
 -      u32 pipeastat;
 -      u32 pipebstat;
 +      u32 pipestat[I915_MAX_PIPES];
        u32 ipeir;
        u32 ipehr;
        u32 instdone;
                int page_count;
                u32 gtt_offset;
                u32 *pages[0];
 -      } *ringbuffer, *batchbuffer[I915_NUM_RINGS];
 +      } *ringbuffer[I915_NUM_RINGS], *batchbuffer[I915_NUM_RINGS];
        struct drm_i915_error_buffer {
                u32 size;
                u32 name;
@@@ -203,7 -200,9 +203,7 @@@ struct drm_i915_display_funcs 
        void (*disable_fbc)(struct drm_device *dev);
        int (*get_display_clock_speed)(struct drm_device *dev);
        int (*get_fifo_size)(struct drm_device *dev, int plane);
 -      void (*update_wm)(struct drm_device *dev, int planea_clock,
 -                        int planeb_clock, int sr_hdisplay, int sr_htotal,
 -                        int pixel_size);
 +      void (*update_wm)(struct drm_device *dev);
        /* clock updates for mode set */
        /* cursor updates */
        /* render clock increase/decrease */
@@@ -290,6 -289,7 +290,6 @@@ typedef struct drm_i915_private 
        int page_flipping;
  
        atomic_t irq_received;
 -      u32 trace_irq_seqno;
  
        /* protects the irq masks */
        spinlock_t irq_lock;
        int vblank_pipe;
        int num_pipe;
  
 +      atomic_t vblank_enabled;
 +      struct pm_qos_request_list vblank_pm_qos;
 +      struct work_struct vblank_work;
 +
        /* For hangcheck timer */
  #define DRM_I915_HANGCHECK_PERIOD 1500 /* in ms */
        struct timer_list hangcheck_timer;
        int cfb_plane;
        int cfb_y;
  
 -      int irq_enabled;
 -
        struct intel_opregion opregion;
  
        /* overlay */
        unsigned int lvds_vbt:1;
        unsigned int int_crt_support:1;
        unsigned int lvds_use_ssc:1;
 +      unsigned int display_clock_mode:1;
        int lvds_ssc_freq;
        struct {
                int rate;
        unsigned int lvds_border_bits;
        /* Panel fitter placement and size for Ironlake+ */
        u32 pch_pf_pos, pch_pf_size;
 +      int panel_t3, panel_t12;
  
        struct drm_crtc *plane_to_crtc_mapping[2];
        struct drm_crtc *pipe_to_crtc_mapping[2];
@@@ -962,7 -958,7 +962,8 @@@ extern unsigned int i915_fbpercrtc
  extern unsigned int i915_powersave;
  extern unsigned int i915_lvds_downclock;
  extern unsigned int i915_panel_use_ssc;
 +extern int i915_vbt_sdvo_panel_type;
+ extern unsigned int i915_enable_rc6;
  
  extern int i915_suspend(struct drm_device *dev, pm_message_t state);
  extern int i915_resume(struct drm_device *dev);
@@@ -1001,6 -997,8 +1002,6 @@@ extern int i915_irq_emit(struct drm_dev
                         struct drm_file *file_priv);
  extern int i915_irq_wait(struct drm_device *dev, void *data,
                         struct drm_file *file_priv);
 -void i915_trace_irq_get(struct drm_device *dev, u32 seqno);
 -extern void i915_enable_interrupt (struct drm_device *dev);
  
  extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS);
  extern void i915_driver_irq_preinstall(struct drm_device * dev);
@@@ -1052,6 -1050,7 +1053,6 @@@ extern void i915_mem_takedown(struct me
  extern void i915_mem_release(struct drm_device * dev,
                             struct drm_file *file_priv, struct mem_block *heap);
  /* i915_gem.c */
 -int i915_gem_check_is_wedged(struct drm_device *dev);
  int i915_gem_init_ioctl(struct drm_device *dev, void *data,
                        struct drm_file *file_priv);
  int i915_gem_create_ioctl(struct drm_device *dev, void *data,
@@@ -1094,7 -1093,8 +1095,7 @@@ int i915_gem_get_aperture_ioctl(struct 
                                struct drm_file *file_priv);
  void i915_gem_load(struct drm_device *dev);
  int i915_gem_init_object(struct drm_gem_object *obj);
 -int __must_check i915_gem_flush_ring(struct drm_device *dev,
 -                                   struct intel_ring_buffer *ring,
 +int __must_check i915_gem_flush_ring(struct intel_ring_buffer *ring,
                                     uint32_t invalidate_domains,
                                     uint32_t flush_domains);
  struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev,
@@@ -1125,9 -1125,10 +1126,9 @@@ i915_seqno_passed(uint32_t seq1, uint32
  }
  
  static inline u32
 -i915_gem_next_request_seqno(struct drm_device *dev,
 -                          struct intel_ring_buffer *ring)
 +i915_gem_next_request_seqno(struct intel_ring_buffer *ring)
  {
 -      drm_i915_private_t *dev_priv = dev->dev_private;
 +      drm_i915_private_t *dev_priv = ring->dev->dev_private;
        return ring->outstanding_lazy_request = dev_priv->next_seqno;
  }
  
@@@ -1152,12 -1153,14 +1153,12 @@@ void i915_gem_do_init(struct drm_devic
                      unsigned long end);
  int __must_check i915_gpu_idle(struct drm_device *dev);
  int __must_check i915_gem_idle(struct drm_device *dev);
 -int __must_check i915_add_request(struct drm_device *dev,
 -                                struct drm_file *file_priv,
 -                                struct drm_i915_gem_request *request,
 -                                struct intel_ring_buffer *ring);
 -int __must_check i915_do_wait_request(struct drm_device *dev,
 -                                    uint32_t seqno,
 -                                    bool interruptible,
 -                                    struct intel_ring_buffer *ring);
 +int __must_check i915_add_request(struct intel_ring_buffer *ring,
 +                                struct drm_file *file,
 +                                struct drm_i915_gem_request *request);
 +int __must_check i915_wait_request(struct intel_ring_buffer *ring,
 +                                 uint32_t seqno,
 +                                 bool interruptible);
  int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
  int __must_check
  i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj,
@@@ -1306,7 -1309,7 +1307,7 @@@ extern void intel_display_print_error_s
  #define __i915_read(x, y) \
  static inline u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \
        u##x val = read##y(dev_priv->regs + reg); \
 -      trace_i915_reg_rw('R', reg, val, sizeof(val)); \
 +      trace_i915_reg_rw(false, reg, val, sizeof(val)); \
        return val; \
  }
  __i915_read(8, b)
@@@ -1317,7 -1320,7 +1318,7 @@@ __i915_read(64, q
  
  #define __i915_write(x, y) \
  static inline void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val) { \
 -      trace_i915_reg_rw('W', reg, val, sizeof(val)); \
 +      trace_i915_reg_rw(true, reg, val, sizeof(val)); \
        write##y(val, dev_priv->regs + reg); \
  }
  __i915_write(8, b)
@@@ -1366,4 -1369,46 +1367,4 @@@ static inline u32 i915_safe_read(struc
        return val;
  }
  
 -static inline void
 -i915_write(struct drm_i915_private *dev_priv, u32 reg, u64 val, int len)
 -{
 -       /* Trace down the write operation before the real write */
 -       trace_i915_reg_rw('W', reg, val, len);
 -       switch (len) {
 -       case 8:
 -               writeq(val, dev_priv->regs + reg);
 -               break;
 -       case 4:
 -               writel(val, dev_priv->regs + reg);
 -               break;
 -       case 2:
 -               writew(val, dev_priv->regs + reg);
 -               break;
 -       case 1:
 -               writeb(val, dev_priv->regs + reg);
 -               break;
 -       }
 -}
 -
 -/**
 - * Reads a dword out of the status page, which is written to from the command
 - * queue by automatic updates, MI_REPORT_HEAD, MI_STORE_DATA_INDEX, or
 - * MI_STORE_DATA_IMM.
 - *
 - * The following dwords have a reserved meaning:
 - * 0x00: ISR copy, updated when an ISR bit not set in the HWSTAM changes.
 - * 0x04: ring 0 head pointer
 - * 0x05: ring 1 head pointer (915-class)
 - * 0x06: ring 2 head pointer (915-class)
 - * 0x10-0x1b: Context status DWords (GM45)
 - * 0x1f: Last written status offset. (GM45)
 - *
 - * The area from dword 0x20 to 0x3ff is available for driver usage.
 - */
 -#define READ_HWSP(dev_priv, reg)  (((volatile u32 *)\
 -                      (LP_RING(dev_priv)->status_page.page_addr))[reg])
 -#define READ_BREADCRUMB(dev_priv) READ_HWSP(dev_priv, I915_BREADCRUMB_INDEX)
 -#define I915_GEM_HWS_INDEX            0x20
 -#define I915_BREADCRUMB_INDEX         0x21
 -
  #endif
@@@ -85,11 -85,21 +85,11 @@@ ironlake_disable_display_irq(drm_i915_p
        }
  }
  
 -static inline u32
 -i915_pipestat(int pipe)
 -{
 -      if (pipe == 0)
 -              return PIPEASTAT;
 -      if (pipe == 1)
 -              return PIPEBSTAT;
 -      BUG();
 -}
 -
  void
  i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
  {
        if ((dev_priv->pipestat[pipe] & mask) != mask) {
 -              u32 reg = i915_pipestat(pipe);
 +              u32 reg = PIPESTAT(pipe);
  
                dev_priv->pipestat[pipe] |= mask;
                /* Enable the interrupt, clear any pending status */
@@@ -102,7 -112,7 +102,7 @@@ voi
  i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
  {
        if ((dev_priv->pipestat[pipe] & mask) != 0) {
 -              u32 reg = i915_pipestat(pipe);
 +              u32 reg = PIPESTAT(pipe);
  
                dev_priv->pipestat[pipe] &= ~mask;
                I915_WRITE(reg, dev_priv->pipestat[pipe]);
@@@ -161,12 -171,12 +161,12 @@@ u32 i915_get_vblank_counter(struct drm_
  
        if (!i915_pipe_enabled(dev, pipe)) {
                DRM_DEBUG_DRIVER("trying to get vblank count for disabled "
 -                              "pipe %d\n", pipe);
 +                              "pipe %c\n", pipe_name(pipe));
                return 0;
        }
  
 -      high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH;
 -      low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL;
 +      high_frame = PIPEFRAME(pipe);
 +      low_frame = PIPEFRAMEPIXEL(pipe);
  
        /*
         * High & low register fields aren't synchronized, so make sure
  u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
  {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 -      int reg = pipe ? PIPEB_FRMCOUNT_GM45 : PIPEA_FRMCOUNT_GM45;
 +      int reg = PIPE_FRMCOUNT_GM45(pipe);
  
        if (!i915_pipe_enabled(dev, pipe)) {
                DRM_DEBUG_DRIVER("trying to get vblank count for disabled "
 -                                      "pipe %d\n", pipe);
 +                               "pipe %c\n", pipe_name(pipe));
                return 0;
        }
  
@@@ -209,7 -219,7 +209,7 @@@ int i915_get_crtc_scanoutpos(struct drm
  
        if (!i915_pipe_enabled(dev, pipe)) {
                DRM_DEBUG_DRIVER("trying to get scanoutpos for disabled "
 -                                      "pipe %d\n", pipe);
 +                               "pipe %c\n", pipe_name(pipe));
                return 0;
        }
  
@@@ -306,6 -316,8 +306,8 @@@ static void i915_hotplug_work_func(stru
        struct drm_mode_config *mode_config = &dev->mode_config;
        struct intel_encoder *encoder;
  
+       DRM_DEBUG_KMS("running encoder hotplug functions\n");
        list_for_each_entry(encoder, &mode_config->encoder_list, base.head)
                if (encoder->hot_plug)
                        encoder->hot_plug(encoder);
@@@ -355,7 -367,7 +357,7 @@@ static void notify_ring(struct drm_devi
                return;
  
        seqno = ring->get_seqno(ring);
 -      trace_i915_gem_request_complete(dev, seqno);
 +      trace_i915_gem_request_complete(ring, seqno);
  
        ring->irq_seqno = seqno;
        wake_up_all(&ring->irq_queue);
@@@ -407,7 -419,6 +409,7 @@@ static void pch_irq_handler(struct drm_
  {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        u32 pch_iir;
 +      int pipe;
  
        pch_iir = I915_READ(SDEIIR);
  
        if (pch_iir & SDE_POISON)
                DRM_ERROR("PCH poison interrupt\n");
  
 -      if (pch_iir & SDE_FDI_MASK) {
 -              u32 fdia, fdib;
 -
 -              fdia = I915_READ(FDI_RXA_IIR);
 -              fdib = I915_READ(FDI_RXB_IIR);
 -              DRM_DEBUG_DRIVER("PCH FDI RX interrupt; FDI RXA IIR: 0x%08x, FDI RXB IIR: 0x%08x\n", fdia, fdib);
 -      }
 +      if (pch_iir & SDE_FDI_MASK)
 +              for_each_pipe(pipe)
 +                      DRM_DEBUG_DRIVER("  pipe %c FDI IIR: 0x%08x\n",
 +                                       pipe_name(pipe),
 +                                       I915_READ(FDI_RX_IIR(pipe)));
  
        if (pch_iir & (SDE_TRANSB_CRC_DONE | SDE_TRANSA_CRC_DONE))
                DRM_DEBUG_DRIVER("PCH transcoder CRC done interrupt\n");
@@@ -637,14 -650,9 +639,14 @@@ static voi
  i915_error_state_free(struct drm_device *dev,
                      struct drm_i915_error_state *error)
  {
 -      i915_error_object_free(error->batchbuffer[0]);
 -      i915_error_object_free(error->batchbuffer[1]);
 -      i915_error_object_free(error->ringbuffer);
 +      int i;
 +
 +      for (i = 0; i < ARRAY_SIZE(error->batchbuffer); i++)
 +              i915_error_object_free(error->batchbuffer[i]);
 +
 +      for (i = 0; i < ARRAY_SIZE(error->ringbuffer); i++)
 +              i915_error_object_free(error->ringbuffer[i]);
 +
        kfree(error->active_bo);
        kfree(error->overlay);
        kfree(error);
@@@ -759,7 -767,7 +761,7 @@@ static void i915_capture_error_state(st
        struct drm_i915_gem_object *obj;
        struct drm_i915_error_state *error;
        unsigned long flags;
 -      int i;
 +      int i, pipe;
  
        spin_lock_irqsave(&dev_priv->error_lock, flags);
        error = dev_priv->first_error;
        if (error)
                return;
  
 +      /* Account for pipe specific data like PIPE*STAT */
        error = kmalloc(sizeof(*error), GFP_ATOMIC);
        if (!error) {
                DRM_DEBUG_DRIVER("out of memory, not capturing error state\n");
                return;
        }
  
 -      DRM_DEBUG_DRIVER("generating error event\n");
 +      DRM_INFO("capturing error event; look for more information in /debug/dri/%d/i915_error_state\n",
 +               dev->primary->index);
  
        error->seqno = dev_priv->ring[RCS].get_seqno(&dev_priv->ring[RCS]);
        error->eir = I915_READ(EIR);
        error->pgtbl_er = I915_READ(PGTBL_ER);
 -      error->pipeastat = I915_READ(PIPEASTAT);
 -      error->pipebstat = I915_READ(PIPEBSTAT);
 +      for_each_pipe(pipe)
 +              error->pipestat[pipe] = I915_READ(PIPESTAT(pipe));
        error->instpm = I915_READ(INSTPM);
        error->error = 0;
        if (INTEL_INFO(dev)->gen >= 6) {
        }
        i915_gem_record_fences(dev, error);
  
 -      /* Record the active batchbuffers */
 -      for (i = 0; i < I915_NUM_RINGS; i++)
 +      /* Record the active batch and ring buffers */
 +      for (i = 0; i < I915_NUM_RINGS; i++) {
                error->batchbuffer[i] =
                        i915_error_first_batchbuffer(dev_priv,
                                                     &dev_priv->ring[i]);
  
 -      /* Record the ringbuffer */
 -      error->ringbuffer = i915_error_object_create(dev_priv,
 -                                                   dev_priv->ring[RCS].obj);
 +              error->ringbuffer[i] =
 +                      i915_error_object_create(dev_priv,
 +                                               dev_priv->ring[i].obj);
 +      }
  
        /* Record buffers on the active and pinned lists. */
        error->active_bo = NULL;
@@@ -902,7 -907,6 +904,7 @@@ static void i915_report_and_clear_eir(s
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 eir = I915_READ(EIR);
 +      int pipe;
  
        if (!eir)
                return;
        }
  
        if (eir & I915_ERROR_MEMORY_REFRESH) {
 -              u32 pipea_stats = I915_READ(PIPEASTAT);
 -              u32 pipeb_stats = I915_READ(PIPEBSTAT);
 -
 -              printk(KERN_ERR "memory refresh error\n");
 -              printk(KERN_ERR "PIPEASTAT: 0x%08x\n",
 -                     pipea_stats);
 -              printk(KERN_ERR "PIPEBSTAT: 0x%08x\n",
 -                     pipeb_stats);
 +              printk(KERN_ERR "memory refresh error:\n");
 +              for_each_pipe(pipe)
 +                      printk(KERN_ERR "pipe %c stat: 0x%08x\n",
 +                             pipe_name(pipe), I915_READ(PIPESTAT(pipe)));
                /* pipestat has already been acked */
        }
        if (eir & I915_ERROR_INSTRUCTION) {
@@@ -1068,10 -1076,10 +1070,10 @@@ static void i915_pageflip_stall_check(s
        /* Potential stall - if we see that the flip has happened, assume a missed interrupt */
        obj = work->pending_flip_obj;
        if (INTEL_INFO(dev)->gen >= 4) {
 -              int dspsurf = intel_crtc->plane == 0 ? DSPASURF : DSPBSURF;
 +              int dspsurf = DSPSURF(intel_crtc->plane);
                stall_detected = I915_READ(dspsurf) == obj->gtt_offset;
        } else {
 -              int dspaddr = intel_crtc->plane == 0 ? DSPAADDR : DSPBADDR;
 +              int dspaddr = DSPADDR(intel_crtc->plane);
                stall_detected = I915_READ(dspaddr) == (obj->gtt_offset +
                                                        crtc->y * crtc->fb->pitch +
                                                        crtc->x * crtc->fb->bits_per_pixel/8);
@@@ -1091,13 -1099,12 +1093,13 @@@ irqreturn_t i915_driver_irq_handler(DRM
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        struct drm_i915_master_private *master_priv;
        u32 iir, new_iir;
 -      u32 pipea_stats, pipeb_stats;
 +      u32 pipe_stats[I915_MAX_PIPES];
        u32 vblank_status;
        int vblank = 0;
        unsigned long irqflags;
        int irq_received;
 -      int ret = IRQ_NONE;
 +      int ret = IRQ_NONE, pipe;
 +      bool blc_event = false;
  
        atomic_inc(&dev_priv->irq_received);
  
                 * interrupts (for non-MSI).
                 */
                spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
 -              pipea_stats = I915_READ(PIPEASTAT);
 -              pipeb_stats = I915_READ(PIPEBSTAT);
 -
                if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
                        i915_handle_error(dev, false);
  
 -              /*
 -               * Clear the PIPE(A|B)STAT regs before the IIR
 -               */
 -              if (pipea_stats & 0x8000ffff) {
 -                      if (pipea_stats &  PIPE_FIFO_UNDERRUN_STATUS)
 -                              DRM_DEBUG_DRIVER("pipe a underrun\n");
 -                      I915_WRITE(PIPEASTAT, pipea_stats);
 -                      irq_received = 1;
 -              }
 -
 -              if (pipeb_stats & 0x8000ffff) {
 -                      if (pipeb_stats &  PIPE_FIFO_UNDERRUN_STATUS)
 -                              DRM_DEBUG_DRIVER("pipe b underrun\n");
 -                      I915_WRITE(PIPEBSTAT, pipeb_stats);
 -                      irq_received = 1;
 +              for_each_pipe(pipe) {
 +                      int reg = PIPESTAT(pipe);
 +                      pipe_stats[pipe] = I915_READ(reg);
 +
 +                      /*
 +                       * Clear the PIPE*STAT regs before the IIR
 +                       */
 +                      if (pipe_stats[pipe] & 0x8000ffff) {
 +                              if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
 +                                      DRM_DEBUG_DRIVER("pipe %c underrun\n",
 +                                                       pipe_name(pipe));
 +                              I915_WRITE(reg, pipe_stats[pipe]);
 +                              irq_received = 1;
 +                      }
                }
                spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
  
                                intel_finish_page_flip_plane(dev, 1);
                }
  
 -              if (pipea_stats & vblank_status &&
 -                  drm_handle_vblank(dev, 0)) {
 -                      vblank++;
 -                      if (!dev_priv->flip_pending_is_done) {
 -                              i915_pageflip_stall_check(dev, 0);
 -                              intel_finish_page_flip(dev, 0);
 +              for_each_pipe(pipe) {
 +                      if (pipe_stats[pipe] & vblank_status &&
 +                          drm_handle_vblank(dev, pipe)) {
 +                              vblank++;
 +                              if (!dev_priv->flip_pending_is_done) {
 +                                      i915_pageflip_stall_check(dev, pipe);
 +                                      intel_finish_page_flip(dev, pipe);
 +                              }
                        }
 -              }
  
 -              if (pipeb_stats & vblank_status &&
 -                  drm_handle_vblank(dev, 1)) {
 -                      vblank++;
 -                      if (!dev_priv->flip_pending_is_done) {
 -                              i915_pageflip_stall_check(dev, 1);
 -                              intel_finish_page_flip(dev, 1);
 -                      }
 +                      if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
 +                              blc_event = true;
                }
  
 -              if ((pipea_stats & PIPE_LEGACY_BLC_EVENT_STATUS) ||
 -                  (pipeb_stats & PIPE_LEGACY_BLC_EVENT_STATUS) ||
 -                  (iir & I915_ASLE_INTERRUPT))
 +
 +              if (blc_event || (iir & I915_ASLE_INTERRUPT))
                        intel_opregion_asle_intr(dev);
  
                /* With MSI, interrupts are only generated when iir
@@@ -1252,6 -1268,16 +1254,6 @@@ static int i915_emit_irq(struct drm_dev
        return dev_priv->counter;
  }
  
 -void i915_trace_irq_get(struct drm_device *dev, u32 seqno)
 -{
 -      drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 -      struct intel_ring_buffer *ring = LP_RING(dev_priv);
 -
 -      if (dev_priv->trace_irq_seqno == 0 &&
 -          ring->irq_get(ring))
 -              dev_priv->trace_irq_seqno = seqno;
 -}
 -
  static int i915_wait_irq(struct drm_device * dev, int irq_nr)
  {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@@ -1330,22 -1356,6 +1332,22 @@@ int i915_irq_wait(struct drm_device *de
        return i915_wait_irq(dev, irqwait->irq_seq);
  }
  
 +static void i915_vblank_work_func(struct work_struct *work)
 +{
 +      drm_i915_private_t *dev_priv =
 +              container_of(work, drm_i915_private_t, vblank_work);
 +
 +      if (atomic_read(&dev_priv->vblank_enabled)) {
 +              if (!dev_priv->vblank_pm_qos.pm_qos_class)
 +                      pm_qos_add_request(&dev_priv->vblank_pm_qos,
 +                                         PM_QOS_CPU_DMA_LATENCY,
 +                                         15); //>=20 won't work
 +      } else {
 +              if (dev_priv->vblank_pm_qos.pm_qos_class)
 +                      pm_qos_remove_request(&dev_priv->vblank_pm_qos);
 +      }
 +}
 +
  /* Called from drm generic code, passed 'crtc' which
   * we use as a pipe index
   */
@@@ -1368,16 -1378,6 +1370,16 @@@ int i915_enable_vblank(struct drm_devic
                i915_enable_pipestat(dev_priv, pipe,
                                     PIPE_VBLANK_INTERRUPT_ENABLE);
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 +
 +      /* gen3 platforms have an issue with vsync interrupts not reaching
 +       * cpu during deep c-state sleep (>C1), so we need to install a
 +       * PM QoS handle to prevent C-state starvation of the GPU.
 +       */
 +      if (dev_priv->info->gen == 3 && !dev_priv->info->is_g33) {
 +              atomic_inc(&dev_priv->vblank_enabled);
 +              queue_work(dev_priv->wq, &dev_priv->vblank_work);
 +      }
 +
        return 0;
  }
  
@@@ -1389,11 -1389,6 +1391,11 @@@ void i915_disable_vblank(struct drm_dev
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        unsigned long irqflags;
  
 +      if (dev_priv->info->gen == 3 && !dev_priv->info->is_g33) {
 +              atomic_dec(&dev_priv->vblank_enabled);
 +              queue_work(dev_priv->wq, &dev_priv->vblank_work);
 +      }
 +
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
        if (HAS_PCH_SPLIT(dev))
                ironlake_disable_display_irq(dev_priv, (pipe == 0) ?
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
  }
  
 -void i915_enable_interrupt (struct drm_device *dev)
 -{
 -      struct drm_i915_private *dev_priv = dev->dev_private;
 -
 -      if (!HAS_PCH_SPLIT(dev))
 -              intel_opregion_enable_asle(dev);
 -      dev_priv->irq_enabled = 1;
 -}
 -
 -
  /* Set the vblank monitor pipe
   */
  int i915_vblank_pipe_set(struct drm_device *dev, void *data,
@@@ -1613,7 -1618,6 +1615,7 @@@ static int ironlake_irq_postinstall(str
                           DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE;
        u32 render_irqs;
        u32 hotplug_mask;
 +      int pipe;
  
        dev_priv->irq_mask = ~display_mask;
  
        POSTING_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 ;
++              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;
-               hotplug_mask |= SDE_AUX_MASK | SDE_FDI_MASK | SDE_TRANS_MASK;
-               for_each_pipe(pipe)
-                       I915_WRITE(FDI_RX_IMR(pipe), 0);
 -              hotplug_mask |= SDE_AUX_MASK;
++              hotplug_mask = (SDE_CRT_HOTPLUG |
++                              SDE_PORTB_HOTPLUG |
++                              SDE_PORTC_HOTPLUG |
++                              SDE_PORTD_HOTPLUG |
++                              SDE_AUX_MASK);
        }
  
        dev_priv->pch_irq_mask = ~hotplug_mask;
  void i915_driver_irq_preinstall(struct drm_device * dev)
  {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 +      int pipe;
  
        atomic_set(&dev_priv->irq_received, 0);
 +      atomic_set(&dev_priv->vblank_enabled, 0);
  
        INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
        INIT_WORK(&dev_priv->error_work, i915_error_work_func);
 +      INIT_WORK(&dev_priv->vblank_work, i915_vblank_work_func);
  
        if (HAS_PCH_SPLIT(dev)) {
                ironlake_irq_preinstall(dev);
        }
  
        I915_WRITE(HWSTAM, 0xeffe);
 -      I915_WRITE(PIPEASTAT, 0);
 -      I915_WRITE(PIPEBSTAT, 0);
 +      for_each_pipe(pipe)
 +              I915_WRITE(PIPESTAT(pipe), 0);
        I915_WRITE(IMR, 0xffffffff);
        I915_WRITE(IER, 0x0);
        POSTING_READ(IER);
@@@ -1805,7 -1804,6 +1809,7 @@@ static void ironlake_irq_uninstall(stru
  void i915_driver_irq_uninstall(struct drm_device * dev)
  {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 +      int pipe;
  
        if (!dev_priv)
                return;
        }
  
        I915_WRITE(HWSTAM, 0xffffffff);
 -      I915_WRITE(PIPEASTAT, 0);
 -      I915_WRITE(PIPEBSTAT, 0);
 +      for_each_pipe(pipe)
 +              I915_WRITE(PIPESTAT(pipe), 0);
        I915_WRITE(IMR, 0xffffffff);
        I915_WRITE(IER, 0x0);
  
 -      I915_WRITE(PIPEASTAT, I915_READ(PIPEASTAT) & 0x8000ffff);
 -      I915_WRITE(PIPEBSTAT, I915_READ(PIPEBSTAT) & 0x8000ffff);
 +      for_each_pipe(pipe)
 +              I915_WRITE(PIPESTAT(pipe),
 +                         I915_READ(PIPESTAT(pipe)) & 0x8000ffff);
        I915_WRITE(IIR, I915_READ(IIR));
  }
   *   address/value pairs. Don't overdue it, though, x <= 2^4 must hold!
   */
  #define MI_LOAD_REGISTER_IMM(x)       MI_INSTR(0x22, 2*x-1)
- #define MI_FLUSH_DW           MI_INSTR(0x26, 2) /* for GEN6 */
+ #define MI_FLUSH_DW           MI_INSTR(0x26, 1) /* for GEN6 */
+ #define   MI_INVALIDATE_TLB   (1<<18)
+ #define   MI_INVALIDATE_BSD   (1<<7)
  #define MI_BATCH_BUFFER               MI_INSTR(0x30, 1)
  #define   MI_BATCH_NON_SECURE (1)
  #define   MI_BATCH_NON_SECURE_I965 (1<<8)
  #define   VGA1_PD_P1_DIV_2    (1 << 13)
  #define   VGA1_PD_P1_SHIFT    8
  #define   VGA1_PD_P1_MASK     (0x1f << 8)
 -#define DPLL_A        0x06014
 -#define DPLL_B        0x06018
 -#define DPLL(pipe) _PIPE(pipe, DPLL_A, DPLL_B)
 +#define _DPLL_A       0x06014
 +#define _DPLL_B       0x06018
 +#define DPLL(pipe) _PIPE(pipe, _DPLL_A, _DPLL_B)
  #define   DPLL_VCO_ENABLE             (1 << 31)
  #define   DPLL_DVO_HIGH_SPEED         (1 << 30)
  #define   DPLL_SYNCLOCK_ENABLE                (1 << 29)
  #define   SDVO_MULTIPLIER_MASK                        0x000000ff
  #define   SDVO_MULTIPLIER_SHIFT_HIRES         4
  #define   SDVO_MULTIPLIER_SHIFT_VGA           0
 -#define DPLL_A_MD 0x0601c /* 965+ only */
 +#define _DPLL_A_MD 0x0601c /* 965+ only */
  /*
   * UDI pixel divider, controlling how many pixels are stuffed into a packet.
   *
   */
  #define   DPLL_MD_VGA_UDI_MULTIPLIER_MASK     0x0000003f
  #define   DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT    0
 -#define DPLL_B_MD 0x06020 /* 965+ only */
 -#define DPLL_MD(pipe) _PIPE(pipe, DPLL_A_MD, DPLL_B_MD)
 -#define FPA0  0x06040
 -#define FPA1  0x06044
 -#define FPB0  0x06048
 -#define FPB1  0x0604c
 -#define FP0(pipe) _PIPE(pipe, FPA0, FPB0)
 -#define FP1(pipe) _PIPE(pipe, FPA1, FPB1)
 +#define _DPLL_B_MD 0x06020 /* 965+ only */
 +#define DPLL_MD(pipe) _PIPE(pipe, _DPLL_A_MD, _DPLL_B_MD)
 +#define _FPA0 0x06040
 +#define _FPA1 0x06044
 +#define _FPB0 0x06048
 +#define _FPB1 0x0604c
 +#define FP0(pipe) _PIPE(pipe, _FPA0, _FPB0)
 +#define FP1(pipe) _PIPE(pipe, _FPA1, _FPB1)
  #define   FP_N_DIV_MASK               0x003f0000
  #define   FP_N_PINEVIEW_DIV_MASK      0x00ff0000
  #define   FP_N_DIV_SHIFT              16
   * Palette regs
   */
  
 -#define PALETTE_A             0x0a000
 -#define PALETTE_B             0x0a800
 +#define _PALETTE_A            0x0a000
 +#define _PALETTE_B            0x0a800
 +#define PALETTE(pipe) _PIPE(pipe, _PALETTE_A, _PALETTE_B)
  
  /* MCH MMIO space */
  
   */
  
  /* Pipe A timing regs */
 -#define HTOTAL_A      0x60000
 -#define HBLANK_A      0x60004
 -#define HSYNC_A               0x60008
 -#define VTOTAL_A      0x6000c
 -#define VBLANK_A      0x60010
 -#define VSYNC_A               0x60014
 -#define PIPEASRC      0x6001c
 -#define BCLRPAT_A     0x60020
 +#define _HTOTAL_A     0x60000
 +#define _HBLANK_A     0x60004
 +#define _HSYNC_A              0x60008
 +#define _VTOTAL_A     0x6000c
 +#define _VBLANK_A     0x60010
 +#define _VSYNC_A              0x60014
 +#define _PIPEASRC     0x6001c
 +#define _BCLRPAT_A    0x60020
  
  /* Pipe B timing regs */
 -#define HTOTAL_B      0x61000
 -#define HBLANK_B      0x61004
 -#define HSYNC_B               0x61008
 -#define VTOTAL_B      0x6100c
 -#define VBLANK_B      0x61010
 -#define VSYNC_B               0x61014
 -#define PIPEBSRC      0x6101c
 -#define BCLRPAT_B     0x61020
 -
 -#define HTOTAL(pipe) _PIPE(pipe, HTOTAL_A, HTOTAL_B)
 -#define HBLANK(pipe) _PIPE(pipe, HBLANK_A, HBLANK_B)
 -#define HSYNC(pipe) _PIPE(pipe, HSYNC_A, HSYNC_B)
 -#define VTOTAL(pipe) _PIPE(pipe, VTOTAL_A, VTOTAL_B)
 -#define VBLANK(pipe) _PIPE(pipe, VBLANK_A, VBLANK_B)
 -#define VSYNC(pipe) _PIPE(pipe, VSYNC_A, VSYNC_B)
 -#define BCLRPAT(pipe) _PIPE(pipe, BCLRPAT_A, BCLRPAT_B)
 +#define _HTOTAL_B     0x61000
 +#define _HBLANK_B     0x61004
 +#define _HSYNC_B              0x61008
 +#define _VTOTAL_B     0x6100c
 +#define _VBLANK_B     0x61010
 +#define _VSYNC_B              0x61014
 +#define _PIPEBSRC     0x6101c
 +#define _BCLRPAT_B    0x61020
 +
 +#define HTOTAL(pipe) _PIPE(pipe, _HTOTAL_A, _HTOTAL_B)
 +#define HBLANK(pipe) _PIPE(pipe, _HBLANK_A, _HBLANK_B)
 +#define HSYNC(pipe) _PIPE(pipe, _HSYNC_A, _HSYNC_B)
 +#define VTOTAL(pipe) _PIPE(pipe, _VTOTAL_A, _VTOTAL_B)
 +#define VBLANK(pipe) _PIPE(pipe, _VBLANK_A, _VBLANK_B)
 +#define VSYNC(pipe) _PIPE(pipe, _VSYNC_A, _VSYNC_B)
 +#define BCLRPAT(pipe) _PIPE(pipe, _BCLRPAT_A, _BCLRPAT_B)
  
  /* VGA port control */
  #define ADPA                  0x61100
  #define   LVDS_PORT_EN                        (1 << 31)
  /* Selects pipe B for LVDS data.  Must be set on pre-965. */
  #define   LVDS_PIPEB_SELECT           (1 << 30)
 +#define   LVDS_PIPE_MASK              (1 << 30)
  /* LVDS dithering flag on 965/g4x platform */
  #define   LVDS_ENABLE_DITHER          (1 << 25)
 +/* LVDS sync polarity flags. Set to invert (i.e. negative) */
 +#define   LVDS_VSYNC_POLARITY         (1 << 21)
 +#define   LVDS_HSYNC_POLARITY         (1 << 20)
 +
  /* Enable border for unscaled (or aspect-scaled) display */
  #define   LVDS_BORDER_ENABLE          (1 << 15)
  /*
  #define   LVDS_B0B3_POWER_DOWN                (0 << 2)
  #define   LVDS_B0B3_POWER_UP          (3 << 2)
  
 +#define LVDS_PIPE_ENABLED(V, P) \
 +      (((V) & (LVDS_PIPE_MASK | LVDS_PORT_EN)) == ((P) << 30 | LVDS_PORT_EN))
 +
  /* Video Data Island Packet control */
  #define VIDEO_DIP_DATA                0x61178
  #define VIDEO_DIP_CTL         0x61170
  
  #define   DP_PORT_EN                  (1 << 31)
  #define   DP_PIPEB_SELECT             (1 << 30)
 +#define   DP_PIPE_MASK                        (1 << 30)
 +
 +#define DP_PIPE_ENABLED(V, P) \
 +      (((V) & (DP_PIPE_MASK | DP_PORT_EN)) == ((P) << 30 | DP_PORT_EN))
  
  /* Link training mode - select a suitable mode for each stage */
  #define   DP_LINK_TRAIN_PAT_1         (0 << 28)
   * which is after the LUTs, so we want the bytes for our color format.
   * For our current usage, this is always 3, one byte for R, G and B.
   */
 -#define PIPEA_GMCH_DATA_M                     0x70050
 -#define PIPEB_GMCH_DATA_M                     0x71050
 +#define _PIPEA_GMCH_DATA_M                    0x70050
 +#define _PIPEB_GMCH_DATA_M                    0x71050
  
  /* Transfer unit size for display port - 1, default is 0x3f (for TU size 64) */
  #define   PIPE_GMCH_DATA_M_TU_SIZE_MASK               (0x3f << 25)
  
  #define   PIPE_GMCH_DATA_M_MASK                       (0xffffff)
  
 -#define PIPEA_GMCH_DATA_N                     0x70054
 -#define PIPEB_GMCH_DATA_N                     0x71054
 +#define _PIPEA_GMCH_DATA_N                    0x70054
 +#define _PIPEB_GMCH_DATA_N                    0x71054
  #define   PIPE_GMCH_DATA_N_MASK                       (0xffffff)
  
  /*
   * Attributes and VB-ID.
   */
  
 -#define PIPEA_DP_LINK_M                               0x70060
 -#define PIPEB_DP_LINK_M                               0x71060
 +#define _PIPEA_DP_LINK_M                              0x70060
 +#define _PIPEB_DP_LINK_M                              0x71060
  #define   PIPEA_DP_LINK_M_MASK                        (0xffffff)
  
 -#define PIPEA_DP_LINK_N                               0x70064
 -#define PIPEB_DP_LINK_N                               0x71064
 +#define _PIPEA_DP_LINK_N                              0x70064
 +#define _PIPEB_DP_LINK_N                              0x71064
  #define   PIPEA_DP_LINK_N_MASK                        (0xffffff)
  
 +#define PIPE_GMCH_DATA_M(pipe) _PIPE(pipe, _PIPEA_GMCH_DATA_M, _PIPEB_GMCH_DATA_M)
 +#define PIPE_GMCH_DATA_N(pipe) _PIPE(pipe, _PIPEA_GMCH_DATA_N, _PIPEB_GMCH_DATA_N)
 +#define PIPE_DP_LINK_M(pipe) _PIPE(pipe, _PIPEA_DP_LINK_M, _PIPEB_DP_LINK_M)
 +#define PIPE_DP_LINK_N(pipe) _PIPE(pipe, _PIPEA_DP_LINK_N, _PIPEB_DP_LINK_N)
 +
  /* Display & cursor control */
  
  /* Pipe A */
 -#define PIPEADSL              0x70000
 +#define _PIPEADSL             0x70000
  #define   DSL_LINEMASK                0x00000fff
 -#define PIPEACONF             0x70008
 +#define _PIPEACONF            0x70008
  #define   PIPECONF_ENABLE     (1<<31)
  #define   PIPECONF_DISABLE    0
  #define   PIPECONF_DOUBLE_WIDE        (1<<30)
  #define   PIPECONF_DITHER_TYPE_ST1 (1<<2)
  #define   PIPECONF_DITHER_TYPE_ST2 (2<<2)
  #define   PIPECONF_DITHER_TYPE_TEMP (3<<2)
 -#define PIPEASTAT             0x70024
 +#define _PIPEASTAT            0x70024
  #define   PIPE_FIFO_UNDERRUN_STATUS           (1UL<<31)
  #define   PIPE_CRC_ERROR_ENABLE                       (1UL<<29)
  #define   PIPE_CRC_DONE_ENABLE                        (1UL<<28)
  #define   PIPE_6BPC                           (2 << 5)
  #define   PIPE_12BPC                          (3 << 5)
  
 -#define PIPESRC(pipe) _PIPE(pipe, PIPEASRC, PIPEBSRC)
 -#define PIPECONF(pipe) _PIPE(pipe, PIPEACONF, PIPEBCONF)
 -#define PIPEDSL(pipe)  _PIPE(pipe, PIPEADSL, PIPEBDSL)
 -#define PIPEFRAMEPIXEL(pipe)  _PIPE(pipe, PIPEAFRAMEPIXEL, PIPEBFRAMEPIXEL)
 +#define PIPESRC(pipe) _PIPE(pipe, _PIPEASRC, _PIPEBSRC)
 +#define PIPECONF(pipe) _PIPE(pipe, _PIPEACONF, _PIPEBCONF)
 +#define PIPEDSL(pipe)  _PIPE(pipe, _PIPEADSL, _PIPEBDSL)
 +#define PIPEFRAME(pipe) _PIPE(pipe, _PIPEAFRAMEHIGH, _PIPEBFRAMEHIGH)
 +#define PIPEFRAMEPIXEL(pipe)  _PIPE(pipe, _PIPEAFRAMEPIXEL, _PIPEBFRAMEPIXEL)
 +#define PIPESTAT(pipe) _PIPE(pipe, _PIPEASTAT, _PIPEBSTAT)
  
  #define DSPARB                        0x70030
  #define   DSPARB_CSTART_MASK  (0x7f << 7)
   *  } while (high1 != high2);
   *  frame = (high1 << 8) | low1;
   */
 -#define PIPEAFRAMEHIGH          0x70040
 +#define _PIPEAFRAMEHIGH          0x70040
  #define   PIPE_FRAME_HIGH_MASK    0x0000ffff
  #define   PIPE_FRAME_HIGH_SHIFT   0
 -#define PIPEAFRAMEPIXEL         0x70044
 +#define _PIPEAFRAMEPIXEL         0x70044
  #define   PIPE_FRAME_LOW_MASK     0xff000000
  #define   PIPE_FRAME_LOW_SHIFT    24
  #define   PIPE_PIXEL_MASK         0x00ffffff
  #define   PIPE_PIXEL_SHIFT        0
  /* GM45+ just has to be different */
 -#define PIPEA_FRMCOUNT_GM45   0x70040
 -#define PIPEA_FLIPCOUNT_GM45  0x70044
 +#define _PIPEA_FRMCOUNT_GM45  0x70040
 +#define _PIPEA_FLIPCOUNT_GM45 0x70044
 +#define PIPE_FRMCOUNT_GM45(pipe) _PIPE(pipe, _PIPEA_FRMCOUNT_GM45, _PIPEB_FRMCOUNT_GM45)
  
  /* Cursor A & B regs */
 -#define CURACNTR              0x70080
 +#define _CURACNTR             0x70080
  /* Old style CUR*CNTR flags (desktop 8xx) */
  #define   CURSOR_ENABLE               0x80000000
  #define   CURSOR_GAMMA_ENABLE 0x40000000
  #define   MCURSOR_PIPE_A      0x00
  #define   MCURSOR_PIPE_B      (1 << 28)
  #define   MCURSOR_GAMMA_ENABLE  (1 << 26)
 -#define CURABASE              0x70084
 -#define CURAPOS                       0x70088
 +#define _CURABASE             0x70084
 +#define _CURAPOS                      0x70088
  #define   CURSOR_POS_MASK       0x007FF
  #define   CURSOR_POS_SIGN       0x8000
  #define   CURSOR_X_SHIFT        0
  #define   CURSOR_Y_SHIFT        16
  #define CURSIZE                       0x700a0
 -#define CURBCNTR              0x700c0
 -#define CURBBASE              0x700c4
 -#define CURBPOS                       0x700c8
 +#define _CURBCNTR             0x700c0
 +#define _CURBBASE             0x700c4
 +#define _CURBPOS                      0x700c8
  
 -#define CURCNTR(pipe) _PIPE(pipe, CURACNTR, CURBCNTR)
 -#define CURBASE(pipe) _PIPE(pipe, CURABASE, CURBBASE)
 -#define CURPOS(pipe) _PIPE(pipe, CURAPOS, CURBPOS)
 +#define CURCNTR(pipe) _PIPE(pipe, _CURACNTR, _CURBCNTR)
 +#define CURBASE(pipe) _PIPE(pipe, _CURABASE, _CURBBASE)
 +#define CURPOS(pipe) _PIPE(pipe, _CURAPOS, _CURBPOS)
  
  /* Display A control */
 -#define DSPACNTR                0x70180
 +#define _DSPACNTR                0x70180
  #define   DISPLAY_PLANE_ENABLE                        (1<<31)
  #define   DISPLAY_PLANE_DISABLE                       0
  #define   DISPPLANE_GAMMA_ENABLE              (1<<30)
  #define   DISPPLANE_32BPP_30BIT_NO_ALPHA      (0xa<<26)
  #define   DISPPLANE_STEREO_ENABLE             (1<<25)
  #define   DISPPLANE_STEREO_DISABLE            0
 -#define   DISPPLANE_SEL_PIPE_MASK             (1<<24)
 +#define   DISPPLANE_SEL_PIPE_SHIFT            24
 +#define   DISPPLANE_SEL_PIPE_MASK             (3<<DISPPLANE_SEL_PIPE_SHIFT)
  #define   DISPPLANE_SEL_PIPE_A                        0
 -#define   DISPPLANE_SEL_PIPE_B                        (1<<24)
 +#define   DISPPLANE_SEL_PIPE_B                        (1<<DISPPLANE_SEL_PIPE_SHIFT)
  #define   DISPPLANE_SRC_KEY_ENABLE            (1<<22)
  #define   DISPPLANE_SRC_KEY_DISABLE           0
  #define   DISPPLANE_LINE_DOUBLE                       (1<<20)
  #define   DISPPLANE_STEREO_POLARITY_SECOND    (1<<18)
  #define   DISPPLANE_TRICKLE_FEED_DISABLE      (1<<14) /* Ironlake */
  #define   DISPPLANE_TILED                     (1<<10)
 -#define DSPAADDR              0x70184
 -#define DSPASTRIDE            0x70188
 -#define DSPAPOS                       0x7018C /* reserved */
 -#define DSPASIZE              0x70190
 -#define DSPASURF              0x7019C /* 965+ only */
 -#define DSPATILEOFF           0x701A4 /* 965+ only */
 -
 -#define DSPCNTR(plane) _PIPE(plane, DSPACNTR, DSPBCNTR)
 -#define DSPADDR(plane) _PIPE(plane, DSPAADDR, DSPBADDR)
 -#define DSPSTRIDE(plane) _PIPE(plane, DSPASTRIDE, DSPBSTRIDE)
 -#define DSPPOS(plane) _PIPE(plane, DSPAPOS, DSPBPOS)
 -#define DSPSIZE(plane) _PIPE(plane, DSPASIZE, DSPBSIZE)
 -#define DSPSURF(plane) _PIPE(plane, DSPASURF, DSPBSURF)
 -#define DSPTILEOFF(plane) _PIPE(plane, DSPATILEOFF, DSPBTILEOFF)
 +#define _DSPAADDR             0x70184
 +#define _DSPASTRIDE           0x70188
 +#define _DSPAPOS                      0x7018C /* reserved */
 +#define _DSPASIZE             0x70190
 +#define _DSPASURF             0x7019C /* 965+ only */
 +#define _DSPATILEOFF          0x701A4 /* 965+ only */
 +
 +#define DSPCNTR(plane) _PIPE(plane, _DSPACNTR, _DSPBCNTR)
 +#define DSPADDR(plane) _PIPE(plane, _DSPAADDR, _DSPBADDR)
 +#define DSPSTRIDE(plane) _PIPE(plane, _DSPASTRIDE, _DSPBSTRIDE)
 +#define DSPPOS(plane) _PIPE(plane, _DSPAPOS, _DSPBPOS)
 +#define DSPSIZE(plane) _PIPE(plane, _DSPASIZE, _DSPBSIZE)
 +#define DSPSURF(plane) _PIPE(plane, _DSPASURF, _DSPBSURF)
 +#define DSPTILEOFF(plane) _PIPE(plane, _DSPATILEOFF, _DSPBTILEOFF)
  
  /* VBIOS flags */
  #define SWF00                 0x71410
  #define SWF32                 0x7241c
  
  /* Pipe B */
 -#define PIPEBDSL              0x71000
 -#define PIPEBCONF             0x71008
 -#define PIPEBSTAT             0x71024
 -#define PIPEBFRAMEHIGH                0x71040
 -#define PIPEBFRAMEPIXEL               0x71044
 -#define PIPEB_FRMCOUNT_GM45   0x71040
 -#define PIPEB_FLIPCOUNT_GM45  0x71044
 +#define _PIPEBDSL             0x71000
 +#define _PIPEBCONF            0x71008
 +#define _PIPEBSTAT            0x71024
 +#define _PIPEBFRAMEHIGH               0x71040
 +#define _PIPEBFRAMEPIXEL              0x71044
 +#define _PIPEB_FRMCOUNT_GM45  0x71040
 +#define _PIPEB_FLIPCOUNT_GM45 0x71044
  
  
  /* Display B control */
 -#define DSPBCNTR              0x71180
 +#define _DSPBCNTR             0x71180
  #define   DISPPLANE_ALPHA_TRANS_ENABLE                (1<<15)
  #define   DISPPLANE_ALPHA_TRANS_DISABLE               0
  #define   DISPPLANE_SPRITE_ABOVE_DISPLAY      0
  #define   DISPPLANE_SPRITE_ABOVE_OVERLAY      (1)
 -#define DSPBADDR              0x71184
 -#define DSPBSTRIDE            0x71188
 -#define DSPBPOS                       0x7118C
 -#define DSPBSIZE              0x71190
 -#define DSPBSURF              0x7119C
 -#define DSPBTILEOFF           0x711A4
 +#define _DSPBADDR             0x71184
 +#define _DSPBSTRIDE           0x71188
 +#define _DSPBPOS                      0x7118C
 +#define _DSPBSIZE             0x71190
 +#define _DSPBSURF             0x7119C
 +#define _DSPBTILEOFF          0x711A4
  
  /* VBIOS regs */
  #define VGACNTRL              0x71400
  #define  FDI_PLL_FREQ_DISABLE_COUNT_LIMIT_MASK  0xff
  
  
 -#define PIPEA_DATA_M1           0x60030
 +#define _PIPEA_DATA_M1           0x60030
  #define  TU_SIZE(x)             (((x)-1) << 25) /* default size 64 */
  #define  TU_SIZE_MASK           0x7e000000
  #define  PIPE_DATA_M1_OFFSET    0
 -#define PIPEA_DATA_N1           0x60034
 +#define _PIPEA_DATA_N1           0x60034
  #define  PIPE_DATA_N1_OFFSET    0
  
 -#define PIPEA_DATA_M2           0x60038
 +#define _PIPEA_DATA_M2           0x60038
  #define  PIPE_DATA_M2_OFFSET    0
 -#define PIPEA_DATA_N2           0x6003c
 +#define _PIPEA_DATA_N2           0x6003c
  #define  PIPE_DATA_N2_OFFSET    0
  
 -#define PIPEA_LINK_M1           0x60040
 +#define _PIPEA_LINK_M1           0x60040
  #define  PIPE_LINK_M1_OFFSET    0
 -#define PIPEA_LINK_N1           0x60044
 +#define _PIPEA_LINK_N1           0x60044
  #define  PIPE_LINK_N1_OFFSET    0
  
 -#define PIPEA_LINK_M2           0x60048
 +#define _PIPEA_LINK_M2           0x60048
  #define  PIPE_LINK_M2_OFFSET    0
 -#define PIPEA_LINK_N2           0x6004c
 +#define _PIPEA_LINK_N2           0x6004c
  #define  PIPE_LINK_N2_OFFSET    0
  
  /* PIPEB timing regs are same start from 0x61000 */
  
 -#define PIPEB_DATA_M1           0x61030
 -#define PIPEB_DATA_N1           0x61034
 +#define _PIPEB_DATA_M1           0x61030
 +#define _PIPEB_DATA_N1           0x61034
  
 -#define PIPEB_DATA_M2           0x61038
 -#define PIPEB_DATA_N2           0x6103c
 +#define _PIPEB_DATA_M2           0x61038
 +#define _PIPEB_DATA_N2           0x6103c
  
 -#define PIPEB_LINK_M1           0x61040
 -#define PIPEB_LINK_N1           0x61044
 +#define _PIPEB_LINK_M1           0x61040
 +#define _PIPEB_LINK_N1           0x61044
  
 -#define PIPEB_LINK_M2           0x61048
 -#define PIPEB_LINK_N2           0x6104c
 +#define _PIPEB_LINK_M2           0x61048
 +#define _PIPEB_LINK_N2           0x6104c
  
 -#define PIPE_DATA_M1(pipe) _PIPE(pipe, PIPEA_DATA_M1, PIPEB_DATA_M1)
 -#define PIPE_DATA_N1(pipe) _PIPE(pipe, PIPEA_DATA_N1, PIPEB_DATA_N1)
 -#define PIPE_DATA_M2(pipe) _PIPE(pipe, PIPEA_DATA_M2, PIPEB_DATA_M2)
 -#define PIPE_DATA_N2(pipe) _PIPE(pipe, PIPEA_DATA_N2, PIPEB_DATA_N2)
 -#define PIPE_LINK_M1(pipe) _PIPE(pipe, PIPEA_LINK_M1, PIPEB_LINK_M1)
 -#define PIPE_LINK_N1(pipe) _PIPE(pipe, PIPEA_LINK_N1, PIPEB_LINK_N1)
 -#define PIPE_LINK_M2(pipe) _PIPE(pipe, PIPEA_LINK_M2, PIPEB_LINK_M2)
 -#define PIPE_LINK_N2(pipe) _PIPE(pipe, PIPEA_LINK_N2, PIPEB_LINK_N2)
 +#define PIPE_DATA_M1(pipe) _PIPE(pipe, _PIPEA_DATA_M1, _PIPEB_DATA_M1)
 +#define PIPE_DATA_N1(pipe) _PIPE(pipe, _PIPEA_DATA_N1, _PIPEB_DATA_N1)
 +#define PIPE_DATA_M2(pipe) _PIPE(pipe, _PIPEA_DATA_M2, _PIPEB_DATA_M2)
 +#define PIPE_DATA_N2(pipe) _PIPE(pipe, _PIPEA_DATA_N2, _PIPEB_DATA_N2)
 +#define PIPE_LINK_M1(pipe) _PIPE(pipe, _PIPEA_LINK_M1, _PIPEB_LINK_M1)
 +#define PIPE_LINK_N1(pipe) _PIPE(pipe, _PIPEA_LINK_N1, _PIPEB_LINK_N1)
 +#define PIPE_LINK_M2(pipe) _PIPE(pipe, _PIPEA_LINK_M2, _PIPEB_LINK_M2)
 +#define PIPE_LINK_N2(pipe) _PIPE(pipe, _PIPEA_LINK_N2, _PIPEB_LINK_N2)
  
  /* CPU panel fitter */
 -#define PFA_CTL_1               0x68080
 -#define PFB_CTL_1               0x68880
 +/* IVB+ has 3 fitters, 0 is 7x5 capable, the other two only 3x3 */
 +#define _PFA_CTL_1               0x68080
 +#define _PFB_CTL_1               0x68880
  #define  PF_ENABLE              (1<<31)
  #define  PF_FILTER_MASK               (3<<23)
  #define  PF_FILTER_PROGRAMMED (0<<23)
  #define  PF_FILTER_MED_3x3    (1<<23)
  #define  PF_FILTER_EDGE_ENHANCE       (2<<23)
  #define  PF_FILTER_EDGE_SOFTEN        (3<<23)
 -#define PFA_WIN_SZ            0x68074
 -#define PFB_WIN_SZ            0x68874
 -#define PFA_WIN_POS           0x68070
 -#define PFB_WIN_POS           0x68870
 +#define _PFA_WIN_SZ           0x68074
 +#define _PFB_WIN_SZ           0x68874
 +#define _PFA_WIN_POS          0x68070
 +#define _PFB_WIN_POS          0x68870
 +#define _PFA_VSCALE           0x68084
 +#define _PFB_VSCALE           0x68884
 +#define _PFA_HSCALE           0x68090
 +#define _PFB_HSCALE           0x68890
 +
 +#define PF_CTL(pipe)          _PIPE(pipe, _PFA_CTL_1, _PFB_CTL_1)
 +#define PF_WIN_SZ(pipe)               _PIPE(pipe, _PFA_WIN_SZ, _PFB_WIN_SZ)
 +#define PF_WIN_POS(pipe)      _PIPE(pipe, _PFA_WIN_POS, _PFB_WIN_POS)
 +#define PF_VSCALE(pipe)               _PIPE(pipe, _PFA_VSCALE, _PFB_VSCALE)
 +#define PF_HSCALE(pipe)               _PIPE(pipe, _PFA_HSCALE, _PFB_HSCALE)
  
  /* legacy palette */
 -#define LGC_PALETTE_A           0x4a000
 -#define LGC_PALETTE_B           0x4a800
 +#define _LGC_PALETTE_A           0x4a000
 +#define _LGC_PALETTE_B           0x4a800
 +#define LGC_PALETTE(pipe) _PIPE(pipe, _LGC_PALETTE_A, _LGC_PALETTE_B)
  
  /* interrupts */
  #define DE_MASTER_IRQ_CONTROL   (1 << 31)
  #define PCH_GMBUS4            0xc5110
  #define PCH_GMBUS5            0xc5120
  
 -#define PCH_DPLL_A              0xc6014
 -#define PCH_DPLL_B              0xc6018
 -#define PCH_DPLL(pipe) _PIPE(pipe, PCH_DPLL_A, PCH_DPLL_B)
 +#define _PCH_DPLL_A              0xc6014
 +#define _PCH_DPLL_B              0xc6018
 +#define PCH_DPLL(pipe) _PIPE(pipe, _PCH_DPLL_A, _PCH_DPLL_B)
  
 -#define PCH_FPA0                0xc6040
 +#define _PCH_FPA0                0xc6040
  #define  FP_CB_TUNE           (0x3<<22)
 -#define PCH_FPA1                0xc6044
 -#define PCH_FPB0                0xc6048
 -#define PCH_FPB1                0xc604c
 -#define PCH_FP0(pipe) _PIPE(pipe, PCH_FPA0, PCH_FPB0)
 -#define PCH_FP1(pipe) _PIPE(pipe, PCH_FPA1, PCH_FPB1)
 +#define _PCH_FPA1                0xc6044
 +#define _PCH_FPB0                0xc6048
 +#define _PCH_FPB1                0xc604c
 +#define PCH_FP0(pipe) _PIPE(pipe, _PCH_FPA0, _PCH_FPB0)
 +#define PCH_FP1(pipe) _PIPE(pipe, _PCH_FPA1, _PCH_FPB1)
  
  #define PCH_DPLL_TEST           0xc606c
  
  #define  DREF_NONSPREAD_SOURCE_MASK           (3<<9)
  #define  DREF_SUPERSPREAD_SOURCE_DISABLE        (0<<7)
  #define  DREF_SUPERSPREAD_SOURCE_ENABLE         (2<<7)
 +#define  DREF_SUPERSPREAD_SOURCE_MASK         (3<<7)
  #define  DREF_SSC4_DOWNSPREAD                   (0<<6)
  #define  DREF_SSC4_CENTERSPREAD                 (1<<6)
  #define  DREF_SSC1_DISABLE                      (0<<1)
  
  /* transcoder */
  
 -#define TRANS_HTOTAL_A          0xe0000
 +#define _TRANS_HTOTAL_A          0xe0000
  #define  TRANS_HTOTAL_SHIFT     16
  #define  TRANS_HACTIVE_SHIFT    0
 -#define TRANS_HBLANK_A          0xe0004
 +#define _TRANS_HBLANK_A          0xe0004
  #define  TRANS_HBLANK_END_SHIFT 16
  #define  TRANS_HBLANK_START_SHIFT 0
 -#define TRANS_HSYNC_A           0xe0008
 +#define _TRANS_HSYNC_A           0xe0008
  #define  TRANS_HSYNC_END_SHIFT  16
  #define  TRANS_HSYNC_START_SHIFT 0
 -#define TRANS_VTOTAL_A          0xe000c
 +#define _TRANS_VTOTAL_A          0xe000c
  #define  TRANS_VTOTAL_SHIFT     16
  #define  TRANS_VACTIVE_SHIFT    0
 -#define TRANS_VBLANK_A          0xe0010
 +#define _TRANS_VBLANK_A          0xe0010
  #define  TRANS_VBLANK_END_SHIFT 16
  #define  TRANS_VBLANK_START_SHIFT 0
 -#define TRANS_VSYNC_A           0xe0014
 +#define _TRANS_VSYNC_A           0xe0014
  #define  TRANS_VSYNC_END_SHIFT  16
  #define  TRANS_VSYNC_START_SHIFT 0
  
 -#define TRANSA_DATA_M1          0xe0030
 -#define TRANSA_DATA_N1          0xe0034
 -#define TRANSA_DATA_M2          0xe0038
 -#define TRANSA_DATA_N2          0xe003c
 -#define TRANSA_DP_LINK_M1       0xe0040
 -#define TRANSA_DP_LINK_N1       0xe0044
 -#define TRANSA_DP_LINK_M2       0xe0048
 -#define TRANSA_DP_LINK_N2       0xe004c
 -
 -#define TRANS_HTOTAL_B          0xe1000
 -#define TRANS_HBLANK_B          0xe1004
 -#define TRANS_HSYNC_B           0xe1008
 -#define TRANS_VTOTAL_B          0xe100c
 -#define TRANS_VBLANK_B          0xe1010
 -#define TRANS_VSYNC_B           0xe1014
 -
 -#define TRANS_HTOTAL(pipe) _PIPE(pipe, TRANS_HTOTAL_A, TRANS_HTOTAL_B)
 -#define TRANS_HBLANK(pipe) _PIPE(pipe, TRANS_HBLANK_A, TRANS_HBLANK_B)
 -#define TRANS_HSYNC(pipe) _PIPE(pipe, TRANS_HSYNC_A, TRANS_HSYNC_B)
 -#define TRANS_VTOTAL(pipe) _PIPE(pipe, TRANS_VTOTAL_A, TRANS_VTOTAL_B)
 -#define TRANS_VBLANK(pipe) _PIPE(pipe, TRANS_VBLANK_A, TRANS_VBLANK_B)
 -#define TRANS_VSYNC(pipe) _PIPE(pipe, TRANS_VSYNC_A, TRANS_VSYNC_B)
 -
 -#define TRANSB_DATA_M1          0xe1030
 -#define TRANSB_DATA_N1          0xe1034
 -#define TRANSB_DATA_M2          0xe1038
 -#define TRANSB_DATA_N2          0xe103c
 -#define TRANSB_DP_LINK_M1       0xe1040
 -#define TRANSB_DP_LINK_N1       0xe1044
 -#define TRANSB_DP_LINK_M2       0xe1048
 -#define TRANSB_DP_LINK_N2       0xe104c
 -
 -#define TRANSACONF              0xf0008
 -#define TRANSBCONF              0xf1008
 -#define TRANSCONF(plane) _PIPE(plane, TRANSACONF, TRANSBCONF)
 +#define _TRANSA_DATA_M1          0xe0030
 +#define _TRANSA_DATA_N1          0xe0034
 +#define _TRANSA_DATA_M2          0xe0038
 +#define _TRANSA_DATA_N2          0xe003c
 +#define _TRANSA_DP_LINK_M1       0xe0040
 +#define _TRANSA_DP_LINK_N1       0xe0044
 +#define _TRANSA_DP_LINK_M2       0xe0048
 +#define _TRANSA_DP_LINK_N2       0xe004c
 +
 +#define _TRANS_HTOTAL_B          0xe1000
 +#define _TRANS_HBLANK_B          0xe1004
 +#define _TRANS_HSYNC_B           0xe1008
 +#define _TRANS_VTOTAL_B          0xe100c
 +#define _TRANS_VBLANK_B          0xe1010
 +#define _TRANS_VSYNC_B           0xe1014
 +
 +#define TRANS_HTOTAL(pipe) _PIPE(pipe, _TRANS_HTOTAL_A, _TRANS_HTOTAL_B)
 +#define TRANS_HBLANK(pipe) _PIPE(pipe, _TRANS_HBLANK_A, _TRANS_HBLANK_B)
 +#define TRANS_HSYNC(pipe) _PIPE(pipe, _TRANS_HSYNC_A, _TRANS_HSYNC_B)
 +#define TRANS_VTOTAL(pipe) _PIPE(pipe, _TRANS_VTOTAL_A, _TRANS_VTOTAL_B)
 +#define TRANS_VBLANK(pipe) _PIPE(pipe, _TRANS_VBLANK_A, _TRANS_VBLANK_B)
 +#define TRANS_VSYNC(pipe) _PIPE(pipe, _TRANS_VSYNC_A, _TRANS_VSYNC_B)
 +
 +#define _TRANSB_DATA_M1          0xe1030
 +#define _TRANSB_DATA_N1          0xe1034
 +#define _TRANSB_DATA_M2          0xe1038
 +#define _TRANSB_DATA_N2          0xe103c
 +#define _TRANSB_DP_LINK_M1       0xe1040
 +#define _TRANSB_DP_LINK_N1       0xe1044
 +#define _TRANSB_DP_LINK_M2       0xe1048
 +#define _TRANSB_DP_LINK_N2       0xe104c
 +
 +#define TRANSDATA_M1(pipe) _PIPE(pipe, _TRANSA_DATA_M1, _TRANSB_DATA_M1)
 +#define TRANSDATA_N1(pipe) _PIPE(pipe, _TRANSA_DATA_N1, _TRANSB_DATA_N1)
 +#define TRANSDATA_M2(pipe) _PIPE(pipe, _TRANSA_DATA_M2, _TRANSB_DATA_M2)
 +#define TRANSDATA_N2(pipe) _PIPE(pipe, _TRANSA_DATA_N2, _TRANSB_DATA_N2)
 +#define TRANSDPLINK_M1(pipe) _PIPE(pipe, _TRANSA_DP_LINK_M1, _TRANSB_DP_LINK_M1)
 +#define TRANSDPLINK_N1(pipe) _PIPE(pipe, _TRANSA_DP_LINK_N1, _TRANSB_DP_LINK_N1)
 +#define TRANSDPLINK_M2(pipe) _PIPE(pipe, _TRANSA_DP_LINK_M2, _TRANSB_DP_LINK_M2)
 +#define TRANSDPLINK_N2(pipe) _PIPE(pipe, _TRANSA_DP_LINK_N2, _TRANSB_DP_LINK_N2)
 +
 +#define _TRANSACONF              0xf0008
 +#define _TRANSBCONF              0xf1008
 +#define TRANSCONF(plane) _PIPE(plane, _TRANSACONF, _TRANSBCONF)
  #define  TRANS_DISABLE          (0<<31)
  #define  TRANS_ENABLE           (1<<31)
  #define  TRANS_STATE_MASK       (1<<30)
  #define  TRANS_6BPC             (2<<5)
  #define  TRANS_12BPC            (3<<5)
  
 -#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 _FDI_RXA_CHICKEN         0xc200c
 +#define _FDI_RXB_CHICKEN         0xc2010
 +#define  FDI_RX_PHASE_SYNC_POINTER_OVR        (1<<1)
 +#define  FDI_RX_PHASE_SYNC_POINTER_EN (1<<0)
 +#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
 -#define FDI_TXB_CTL             0x61100
 -#define FDI_TX_CTL(pipe) _PIPE(pipe, FDI_TXA_CTL, FDI_TXB_CTL)
 +#define _FDI_TXA_CTL             0x60100
 +#define _FDI_TXB_CTL             0x61100
 +#define FDI_TX_CTL(pipe) _PIPE(pipe, _FDI_TXA_CTL, _FDI_TXB_CTL)
  #define  FDI_TX_DISABLE         (0<<31)
  #define  FDI_TX_ENABLE          (1<<31)
  #define  FDI_LINK_TRAIN_PATTERN_1       (0<<28)
  #define  FDI_SCRAMBLING_DISABLE         (1<<7)
  
  /* FDI_RX, FDI_X is hard-wired to Transcoder_X */
 -#define FDI_RXA_CTL             0xf000c
 -#define FDI_RXB_CTL             0xf100c
 -#define FDI_RX_CTL(pipe) _PIPE(pipe, FDI_RXA_CTL, FDI_RXB_CTL)
 +#define _FDI_RXA_CTL             0xf000c
 +#define _FDI_RXB_CTL             0xf100c
 +#define FDI_RX_CTL(pipe) _PIPE(pipe, _FDI_RXA_CTL, _FDI_RXB_CTL)
  #define  FDI_RX_ENABLE          (1<<31)
  /* train, dp width same as FDI_TX */
  #define  FDI_DP_PORT_WIDTH_X8           (7<<19)
  #define  FDI_LINK_TRAIN_NORMAL_CPT            (3<<8)
  #define  FDI_LINK_TRAIN_PATTERN_MASK_CPT      (3<<8)
  
 -#define FDI_RXA_MISC            0xf0010
 -#define FDI_RXB_MISC            0xf1010
 -#define FDI_RXA_TUSIZE1         0xf0030
 -#define FDI_RXA_TUSIZE2         0xf0038
 -#define FDI_RXB_TUSIZE1         0xf1030
 -#define FDI_RXB_TUSIZE2         0xf1038
 -#define FDI_RX_MISC(pipe) _PIPE(pipe, FDI_RXA_MISC, FDI_RXB_MISC)
 -#define FDI_RX_TUSIZE1(pipe) _PIPE(pipe, FDI_RXA_TUSIZE1, FDI_RXB_TUSIZE1)
 -#define FDI_RX_TUSIZE2(pipe) _PIPE(pipe, FDI_RXA_TUSIZE2, FDI_RXB_TUSIZE2)
 +#define _FDI_RXA_MISC            0xf0010
 +#define _FDI_RXB_MISC            0xf1010
 +#define _FDI_RXA_TUSIZE1         0xf0030
 +#define _FDI_RXA_TUSIZE2         0xf0038
 +#define _FDI_RXB_TUSIZE1         0xf1030
 +#define _FDI_RXB_TUSIZE2         0xf1038
 +#define FDI_RX_MISC(pipe) _PIPE(pipe, _FDI_RXA_MISC, _FDI_RXB_MISC)
 +#define FDI_RX_TUSIZE1(pipe) _PIPE(pipe, _FDI_RXA_TUSIZE1, _FDI_RXB_TUSIZE1)
 +#define FDI_RX_TUSIZE2(pipe) _PIPE(pipe, _FDI_RXA_TUSIZE2, _FDI_RXB_TUSIZE2)
  
  /* FDI_RX interrupt register format */
  #define FDI_RX_INTER_LANE_ALIGN         (1<<10)
  #define FDI_RX_CROSS_CLOCK_OVERFLOW     (1<<1)
  #define FDI_RX_SYMBOL_QUEUE_OVERFLOW    (1<<0)
  
 -#define FDI_RXA_IIR             0xf0014
 -#define FDI_RXA_IMR             0xf0018
 -#define FDI_RXB_IIR             0xf1014
 -#define FDI_RXB_IMR             0xf1018
 -#define FDI_RX_IIR(pipe) _PIPE(pipe, FDI_RXA_IIR, FDI_RXB_IIR)
 -#define FDI_RX_IMR(pipe) _PIPE(pipe, FDI_RXA_IMR, FDI_RXB_IMR)
 +#define _FDI_RXA_IIR             0xf0014
 +#define _FDI_RXA_IMR             0xf0018
 +#define _FDI_RXB_IIR             0xf1014
 +#define _FDI_RXB_IMR             0xf1018
 +#define FDI_RX_IIR(pipe) _PIPE(pipe, _FDI_RXA_IIR, _FDI_RXB_IIR)
 +#define FDI_RX_IMR(pipe) _PIPE(pipe, _FDI_RXA_IMR, _FDI_RXB_IMR)
  
  #define FDI_PLL_CTL_1           0xfe000
  #define FDI_PLL_CTL_2           0xfe004
  #define  ADPA_CRT_HOTPLUG_VOLREF_475MV  (1<<17)
  #define  ADPA_CRT_HOTPLUG_FORCE_TRIGGER (1<<16)
  
 +#define ADPA_PIPE_ENABLED(V, P) \
 +      (((V) & (ADPA_TRANS_SELECT_MASK | ADPA_DAC_ENABLE)) == ((P) << 30 | ADPA_DAC_ENABLE))
 +
  /* or SDVOB */
  #define HDMIB   0xe1140
  #define  PORT_ENABLE    (1 << 31)
  #define  TRANSCODER_A   (0)
  #define  TRANSCODER_B   (1 << 30)
 +#define  TRANSCODER_MASK   (1 << 30)
  #define  COLOR_FORMAT_8bpc      (0)
  #define  COLOR_FORMAT_12bpc     (3 << 26)
  #define  SDVOB_HOTPLUG_ENABLE   (1 << 23)
  #define  HSYNC_ACTIVE_HIGH      (1 << 3)
  #define  PORT_DETECTED          (1 << 2)
  
 +#define HDMI_PIPE_ENABLED(V, P) \
 +      (((V) & (TRANSCODER_MASK | PORT_ENABLE)) == ((P) << 30 | PORT_ENABLE))
 +
  /* PCH SDVOB multiplex with HDMIB */
  #define PCH_SDVOB     HDMIB
  
  #define  TRANS_DP_PORT_SEL_B  (0<<29)
  #define  TRANS_DP_PORT_SEL_C  (1<<29)
  #define  TRANS_DP_PORT_SEL_D  (2<<29)
 +#define  TRANS_DP_PORT_SEL_NONE       (3<<29)
  #define  TRANS_DP_PORT_SEL_MASK       (3<<29)
  #define  TRANS_DP_AUDIO_ONLY  (1<<26)
  #define  TRANS_DP_ENH_FRAMING (1<<18)
  #define GEN6_RP_DOWN_TIMEOUT                  0xA010
  #define GEN6_RP_INTERRUPT_LIMITS              0xA014
  #define GEN6_RPSTAT1                          0xA01C
 +#define   GEN6_CAGF_SHIFT                     8
 +#define   GEN6_CAGF_MASK                      (0x7f << GEN6_CAGF_SHIFT)
  #define GEN6_RP_CONTROL                               0xA024
  #define   GEN6_RP_MEDIA_TURBO                 (1<<11)
  #define   GEN6_RP_USE_NORMAL_FREQ             (1<<9)
  #define   GEN6_RP_MEDIA_IS_GFX                        (1<<8)
  #define   GEN6_RP_ENABLE                      (1<<7)
 -#define   GEN6_RP_UP_BUSY_MAX                 (0x2<<3)
 -#define   GEN6_RP_DOWN_BUSY_MIN                       (0x2<<0)
 +#define   GEN6_RP_UP_IDLE_MIN                 (0x1<<3)
 +#define   GEN6_RP_UP_BUSY_AVG                 (0x2<<3)
 +#define   GEN6_RP_UP_BUSY_CONT                        (0x4<<3)
 +#define   GEN6_RP_DOWN_IDLE_CONT              (0x1<<0)
  #define GEN6_RP_UP_THRESHOLD                  0xA02C
  #define GEN6_RP_DOWN_THRESHOLD                        0xA030
 +#define GEN6_RP_CUR_UP_EI                     0xA050
 +#define   GEN6_CURICONT_MASK                  0xffffff
 +#define GEN6_RP_CUR_UP                                0xA054
 +#define   GEN6_CURBSYTAVG_MASK                        0xffffff
 +#define GEN6_RP_PREV_UP                               0xA058
 +#define GEN6_RP_CUR_DOWN_EI                   0xA05C
 +#define   GEN6_CURIAVG_MASK                   0xffffff
 +#define GEN6_RP_CUR_DOWN                      0xA060
 +#define GEN6_RP_PREV_DOWN                     0xA064
  #define GEN6_RP_UP_EI                         0xA068
  #define GEN6_RP_DOWN_EI                               0xA06C
  #define GEN6_RP_IDLE_HYSTERSIS                        0xA070
@@@ -989,7 -989,7 +989,7 @@@ intel_find_pll_g4x_dp(const intel_limit
  void intel_wait_for_vblank(struct drm_device *dev, int pipe)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
 -      int pipestat_reg = (pipe == 0 ? PIPEASTAT : PIPEBSTAT);
 +      int pipestat_reg = PIPESTAT(pipe);
  
        /* Clear existing vblank status. Note this will clear any other
         * sticky status fields as well.
@@@ -1058,612 -1058,6 +1058,612 @@@ void intel_wait_for_pipe_off(struct drm
        }
  }
  
 +static const char *state_string(bool enabled)
 +{
 +      return enabled ? "on" : "off";
 +}
 +
 +/* Only for pre-ILK configs */
 +static void assert_pll(struct drm_i915_private *dev_priv,
 +                     enum pipe pipe, bool state)
 +{
 +      int reg;
 +      u32 val;
 +      bool cur_state;
 +
 +      reg = DPLL(pipe);
 +      val = I915_READ(reg);
 +      cur_state = !!(val & DPLL_VCO_ENABLE);
 +      WARN(cur_state != state,
 +           "PLL state assertion failure (expected %s, current %s)\n",
 +           state_string(state), state_string(cur_state));
 +}
 +#define assert_pll_enabled(d, p) assert_pll(d, p, true)
 +#define assert_pll_disabled(d, p) assert_pll(d, p, false)
 +
 +/* For ILK+ */
 +static void assert_pch_pll(struct drm_i915_private *dev_priv,
 +                         enum pipe pipe, bool state)
 +{
 +      int reg;
 +      u32 val;
 +      bool cur_state;
 +
 +      reg = PCH_DPLL(pipe);
 +      val = I915_READ(reg);
 +      cur_state = !!(val & DPLL_VCO_ENABLE);
 +      WARN(cur_state != state,
 +           "PCH PLL state assertion failure (expected %s, current %s)\n",
 +           state_string(state), state_string(cur_state));
 +}
 +#define assert_pch_pll_enabled(d, p) assert_pch_pll(d, p, true)
 +#define assert_pch_pll_disabled(d, p) assert_pch_pll(d, p, false)
 +
 +static void assert_fdi_tx(struct drm_i915_private *dev_priv,
 +                        enum pipe pipe, bool state)
 +{
 +      int reg;
 +      u32 val;
 +      bool cur_state;
 +
 +      reg = FDI_TX_CTL(pipe);
 +      val = I915_READ(reg);
 +      cur_state = !!(val & FDI_TX_ENABLE);
 +      WARN(cur_state != state,
 +           "FDI TX state assertion failure (expected %s, current %s)\n",
 +           state_string(state), state_string(cur_state));
 +}
 +#define assert_fdi_tx_enabled(d, p) assert_fdi_tx(d, p, true)
 +#define assert_fdi_tx_disabled(d, p) assert_fdi_tx(d, p, false)
 +
 +static void assert_fdi_rx(struct drm_i915_private *dev_priv,
 +                        enum pipe pipe, bool state)
 +{
 +      int reg;
 +      u32 val;
 +      bool cur_state;
 +
 +      reg = FDI_RX_CTL(pipe);
 +      val = I915_READ(reg);
 +      cur_state = !!(val & FDI_RX_ENABLE);
 +      WARN(cur_state != state,
 +           "FDI RX state assertion failure (expected %s, current %s)\n",
 +           state_string(state), state_string(cur_state));
 +}
 +#define assert_fdi_rx_enabled(d, p) assert_fdi_rx(d, p, true)
 +#define assert_fdi_rx_disabled(d, p) assert_fdi_rx(d, p, false)
 +
 +static void assert_fdi_tx_pll_enabled(struct drm_i915_private *dev_priv,
 +                                    enum pipe pipe)
 +{
 +      int reg;
 +      u32 val;
 +
 +      /* ILK FDI PLL is always enabled */
 +      if (dev_priv->info->gen == 5)
 +              return;
 +
 +      reg = FDI_TX_CTL(pipe);
 +      val = I915_READ(reg);
 +      WARN(!(val & FDI_TX_PLL_ENABLE), "FDI TX PLL assertion failure, should be active but is disabled\n");
 +}
 +
 +static void assert_fdi_rx_pll_enabled(struct drm_i915_private *dev_priv,
 +                                    enum pipe pipe)
 +{
 +      int reg;
 +      u32 val;
 +
 +      reg = FDI_RX_CTL(pipe);
 +      val = I915_READ(reg);
 +      WARN(!(val & FDI_RX_PLL_ENABLE), "FDI RX PLL assertion failure, should be active but is disabled\n");
 +}
 +
 +static void assert_panel_unlocked(struct drm_i915_private *dev_priv,
 +                                enum pipe pipe)
 +{
 +      int pp_reg, lvds_reg;
 +      u32 val;
 +      enum pipe panel_pipe = PIPE_A;
 +      bool locked = locked;
 +
 +      if (HAS_PCH_SPLIT(dev_priv->dev)) {
 +              pp_reg = PCH_PP_CONTROL;
 +              lvds_reg = PCH_LVDS;
 +      } else {
 +              pp_reg = PP_CONTROL;
 +              lvds_reg = LVDS;
 +      }
 +
 +      val = I915_READ(pp_reg);
 +      if (!(val & PANEL_POWER_ON) ||
 +          ((val & PANEL_UNLOCK_REGS) == PANEL_UNLOCK_REGS))
 +              locked = false;
 +
 +      if (I915_READ(lvds_reg) & LVDS_PIPEB_SELECT)
 +              panel_pipe = PIPE_B;
 +
 +      WARN(panel_pipe == pipe && locked,
 +           "panel assertion failure, pipe %c regs locked\n",
 +           pipe_name(pipe));
 +}
 +
 +static void assert_pipe(struct drm_i915_private *dev_priv,
 +                      enum pipe pipe, bool state)
 +{
 +      int reg;
 +      u32 val;
 +      bool cur_state;
 +
 +      reg = PIPECONF(pipe);
 +      val = I915_READ(reg);
 +      cur_state = !!(val & PIPECONF_ENABLE);
 +      WARN(cur_state != state,
 +           "pipe %c assertion failure (expected %s, current %s)\n",
 +           pipe_name(pipe), state_string(state), state_string(cur_state));
 +}
 +#define assert_pipe_enabled(d, p) assert_pipe(d, p, true)
 +#define assert_pipe_disabled(d, p) assert_pipe(d, p, false)
 +
 +static void assert_plane_enabled(struct drm_i915_private *dev_priv,
 +                               enum plane plane)
 +{
 +      int reg;
 +      u32 val;
 +
 +      reg = DSPCNTR(plane);
 +      val = I915_READ(reg);
 +      WARN(!(val & DISPLAY_PLANE_ENABLE),
 +           "plane %c assertion failure, should be active but is disabled\n",
 +           plane_name(plane));
 +}
 +
 +static void assert_planes_disabled(struct drm_i915_private *dev_priv,
 +                                 enum pipe pipe)
 +{
 +      int reg, i;
 +      u32 val;
 +      int cur_pipe;
 +
 +      /* Planes are fixed to pipes on ILK+ */
 +      if (HAS_PCH_SPLIT(dev_priv->dev))
 +              return;
 +
 +      /* Need to check both planes against the pipe */
 +      for (i = 0; i < 2; i++) {
 +              reg = DSPCNTR(i);
 +              val = I915_READ(reg);
 +              cur_pipe = (val & DISPPLANE_SEL_PIPE_MASK) >>
 +                      DISPPLANE_SEL_PIPE_SHIFT;
 +              WARN((val & DISPLAY_PLANE_ENABLE) && pipe == cur_pipe,
 +                   "plane %c assertion failure, should be off on pipe %c but is still active\n",
 +                   plane_name(i), pipe_name(pipe));
 +      }
 +}
 +
 +static void assert_pch_refclk_enabled(struct drm_i915_private *dev_priv)
 +{
 +      u32 val;
 +      bool enabled;
 +
 +      val = I915_READ(PCH_DREF_CONTROL);
 +      enabled = !!(val & (DREF_SSC_SOURCE_MASK | DREF_NONSPREAD_SOURCE_MASK |
 +                          DREF_SUPERSPREAD_SOURCE_MASK));
 +      WARN(!enabled, "PCH refclk assertion failure, should be active but is disabled\n");
 +}
 +
 +static void assert_transcoder_disabled(struct drm_i915_private *dev_priv,
 +                                     enum pipe pipe)
 +{
 +      int reg;
 +      u32 val;
 +      bool enabled;
 +
 +      reg = TRANSCONF(pipe);
 +      val = I915_READ(reg);
 +      enabled = !!(val & TRANS_ENABLE);
 +      WARN(enabled,
 +           "transcoder assertion failed, should be off on pipe %c but is still active\n",
 +           pipe_name(pipe));
 +}
 +
 +static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv,
 +                                 enum pipe pipe, int reg)
 +{
 +      u32 val = I915_READ(reg);
 +      WARN(DP_PIPE_ENABLED(val, pipe),
 +           "PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n",
 +           reg, pipe_name(pipe));
 +}
 +
 +static void assert_pch_hdmi_disabled(struct drm_i915_private *dev_priv,
 +                                   enum pipe pipe, int reg)
 +{
 +      u32 val = I915_READ(reg);
 +      WARN(HDMI_PIPE_ENABLED(val, pipe),
 +           "PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n",
 +           reg, pipe_name(pipe));
 +}
 +
 +static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv,
 +                                    enum pipe pipe)
 +{
 +      int reg;
 +      u32 val;
 +
 +      assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_B);
 +      assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_C);
 +      assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_D);
 +
 +      reg = PCH_ADPA;
 +      val = I915_READ(reg);
 +      WARN(ADPA_PIPE_ENABLED(val, pipe),
 +           "PCH VGA enabled on transcoder %c, should be disabled\n",
 +           pipe_name(pipe));
 +
 +      reg = PCH_LVDS;
 +      val = I915_READ(reg);
 +      WARN(LVDS_PIPE_ENABLED(val, pipe),
 +           "PCH LVDS enabled on transcoder %c, should be disabled\n",
 +           pipe_name(pipe));
 +
 +      assert_pch_hdmi_disabled(dev_priv, pipe, HDMIB);
 +      assert_pch_hdmi_disabled(dev_priv, pipe, HDMIC);
 +      assert_pch_hdmi_disabled(dev_priv, pipe, HDMID);
 +}
 +
 +/**
 + * intel_enable_pll - enable a PLL
 + * @dev_priv: i915 private structure
 + * @pipe: pipe PLL to enable
 + *
 + * Enable @pipe's PLL so we can start pumping pixels from a plane.  Check to
 + * make sure the PLL reg is writable first though, since the panel write
 + * protect mechanism may be enabled.
 + *
 + * Note!  This is for pre-ILK only.
 + */
 +static void intel_enable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)
 +{
 +      int reg;
 +      u32 val;
 +
 +      /* No really, not for ILK+ */
 +      BUG_ON(dev_priv->info->gen >= 5);
 +
 +      /* PLL is protected by panel, make sure we can write it */
 +      if (IS_MOBILE(dev_priv->dev) && !IS_I830(dev_priv->dev))
 +              assert_panel_unlocked(dev_priv, pipe);
 +
 +      reg = DPLL(pipe);
 +      val = I915_READ(reg);
 +      val |= DPLL_VCO_ENABLE;
 +
 +      /* We do this three times for luck */
 +      I915_WRITE(reg, val);
 +      POSTING_READ(reg);
 +      udelay(150); /* wait for warmup */
 +      I915_WRITE(reg, val);
 +      POSTING_READ(reg);
 +      udelay(150); /* wait for warmup */
 +      I915_WRITE(reg, val);
 +      POSTING_READ(reg);
 +      udelay(150); /* wait for warmup */
 +}
 +
 +/**
 + * intel_disable_pll - disable a PLL
 + * @dev_priv: i915 private structure
 + * @pipe: pipe PLL to disable
 + *
 + * Disable the PLL for @pipe, making sure the pipe is off first.
 + *
 + * Note!  This is for pre-ILK only.
 + */
 +static void intel_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)
 +{
 +      int reg;
 +      u32 val;
 +
 +      /* Don't disable pipe A or pipe A PLLs if needed */
 +      if (pipe == PIPE_A && (dev_priv->quirks & QUIRK_PIPEA_FORCE))
 +              return;
 +
 +      /* Make sure the pipe isn't still relying on us */
 +      assert_pipe_disabled(dev_priv, pipe);
 +
 +      reg = DPLL(pipe);
 +      val = I915_READ(reg);
 +      val &= ~DPLL_VCO_ENABLE;
 +      I915_WRITE(reg, val);
 +      POSTING_READ(reg);
 +}
 +
 +/**
 + * intel_enable_pch_pll - enable PCH PLL
 + * @dev_priv: i915 private structure
 + * @pipe: pipe PLL to enable
 + *
 + * The PCH PLL needs to be enabled before the PCH transcoder, since it
 + * drives the transcoder clock.
 + */
 +static void intel_enable_pch_pll(struct drm_i915_private *dev_priv,
 +                               enum pipe pipe)
 +{
 +      int reg;
 +      u32 val;
 +
 +      /* PCH only available on ILK+ */
 +      BUG_ON(dev_priv->info->gen < 5);
 +
 +      /* PCH refclock must be enabled first */
 +      assert_pch_refclk_enabled(dev_priv);
 +
 +      reg = PCH_DPLL(pipe);
 +      val = I915_READ(reg);
 +      val |= DPLL_VCO_ENABLE;
 +      I915_WRITE(reg, val);
 +      POSTING_READ(reg);
 +      udelay(200);
 +}
 +
 +static void intel_disable_pch_pll(struct drm_i915_private *dev_priv,
 +                                enum pipe pipe)
 +{
 +      int reg;
 +      u32 val;
 +
 +      /* PCH only available on ILK+ */
 +      BUG_ON(dev_priv->info->gen < 5);
 +
 +      /* Make sure transcoder isn't still depending on us */
 +      assert_transcoder_disabled(dev_priv, pipe);
 +
 +      reg = PCH_DPLL(pipe);
 +      val = I915_READ(reg);
 +      val &= ~DPLL_VCO_ENABLE;
 +      I915_WRITE(reg, val);
 +      POSTING_READ(reg);
 +      udelay(200);
 +}
 +
 +static void intel_enable_transcoder(struct drm_i915_private *dev_priv,
 +                                  enum pipe pipe)
 +{
 +      int reg;
 +      u32 val;
 +
 +      /* PCH only available on ILK+ */
 +      BUG_ON(dev_priv->info->gen < 5);
 +
 +      /* Make sure PCH DPLL is enabled */
 +      assert_pch_pll_enabled(dev_priv, pipe);
 +
 +      /* FDI must be feeding us bits for PCH ports */
 +      assert_fdi_tx_enabled(dev_priv, pipe);
 +      assert_fdi_rx_enabled(dev_priv, pipe);
 +
 +      reg = TRANSCONF(pipe);
 +      val = I915_READ(reg);
 +      /*
 +       * make the BPC in transcoder be consistent with
 +       * that in pipeconf reg.
 +       */
 +      val &= ~PIPE_BPC_MASK;
 +      val |= I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK;
 +      I915_WRITE(reg, val | TRANS_ENABLE);
 +      if (wait_for(I915_READ(reg) & TRANS_STATE_ENABLE, 100))
 +              DRM_ERROR("failed to enable transcoder %d\n", pipe);
 +}
 +
 +static void intel_disable_transcoder(struct drm_i915_private *dev_priv,
 +                                   enum pipe pipe)
 +{
 +      int reg;
 +      u32 val;
 +
 +      /* FDI relies on the transcoder */
 +      assert_fdi_tx_disabled(dev_priv, pipe);
 +      assert_fdi_rx_disabled(dev_priv, pipe);
 +
 +      /* Ports must be off as well */
 +      assert_pch_ports_disabled(dev_priv, pipe);
 +
 +      reg = TRANSCONF(pipe);
 +      val = I915_READ(reg);
 +      val &= ~TRANS_ENABLE;
 +      I915_WRITE(reg, val);
 +      /* wait for PCH transcoder off, transcoder state */
 +      if (wait_for((I915_READ(reg) & TRANS_STATE_ENABLE) == 0, 50))
 +              DRM_ERROR("failed to disable transcoder\n");
 +}
 +
 +/**
 + * intel_enable_pipe - enable a pipe, asserting requirements
 + * @dev_priv: i915 private structure
 + * @pipe: pipe to enable
 + * @pch_port: on ILK+, is this pipe driving a PCH port or not
 + *
 + * Enable @pipe, making sure that various hardware specific requirements
 + * are met, if applicable, e.g. PLL enabled, LVDS pairs enabled, etc.
 + *
 + * @pipe should be %PIPE_A or %PIPE_B.
 + *
 + * Will wait until the pipe is actually running (i.e. first vblank) before
 + * returning.
 + */
 +static void intel_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe,
 +                            bool pch_port)
 +{
 +      int reg;
 +      u32 val;
 +
 +      /*
 +       * A pipe without a PLL won't actually be able to drive bits from
 +       * a plane.  On ILK+ the pipe PLLs are integrated, so we don't
 +       * need the check.
 +       */
 +      if (!HAS_PCH_SPLIT(dev_priv->dev))
 +              assert_pll_enabled(dev_priv, pipe);
 +      else {
 +              if (pch_port) {
 +                      /* if driving the PCH, we need FDI enabled */
 +                      assert_fdi_rx_pll_enabled(dev_priv, pipe);
 +                      assert_fdi_tx_pll_enabled(dev_priv, pipe);
 +              }
 +              /* FIXME: assert CPU port conditions for SNB+ */
 +      }
 +
 +      reg = PIPECONF(pipe);
 +      val = I915_READ(reg);
 +      val |= PIPECONF_ENABLE;
 +      I915_WRITE(reg, val);
 +      POSTING_READ(reg);
 +      intel_wait_for_vblank(dev_priv->dev, pipe);
 +}
 +
 +/**
 + * intel_disable_pipe - disable a pipe, asserting requirements
 + * @dev_priv: i915 private structure
 + * @pipe: pipe to disable
 + *
 + * Disable @pipe, making sure that various hardware specific requirements
 + * are met, if applicable, e.g. plane disabled, panel fitter off, etc.
 + *
 + * @pipe should be %PIPE_A or %PIPE_B.
 + *
 + * Will wait until the pipe has shut down before returning.
 + */
 +static void intel_disable_pipe(struct drm_i915_private *dev_priv,
 +                             enum pipe pipe)
 +{
 +      int reg;
 +      u32 val;
 +
 +      /*
 +       * Make sure planes won't keep trying to pump pixels to us,
 +       * or we might hang the display.
 +       */
 +      assert_planes_disabled(dev_priv, pipe);
 +
 +      /* Don't disable pipe A or pipe A PLLs if needed */
 +      if (pipe == PIPE_A && (dev_priv->quirks & QUIRK_PIPEA_FORCE))
 +              return;
 +
 +      reg = PIPECONF(pipe);
 +      val = I915_READ(reg);
 +      val &= ~PIPECONF_ENABLE;
 +      I915_WRITE(reg, val);
 +      POSTING_READ(reg);
 +      intel_wait_for_pipe_off(dev_priv->dev, pipe);
 +}
 +
 +/**
 + * intel_enable_plane - enable a display plane on a given pipe
 + * @dev_priv: i915 private structure
 + * @plane: plane to enable
 + * @pipe: pipe being fed
 + *
 + * Enable @plane on @pipe, making sure that @pipe is running first.
 + */
 +static void intel_enable_plane(struct drm_i915_private *dev_priv,
 +                             enum plane plane, enum pipe pipe)
 +{
 +      int reg;
 +      u32 val;
 +
 +      /* If the pipe isn't enabled, we can't pump pixels and may hang */
 +      assert_pipe_enabled(dev_priv, pipe);
 +
 +      reg = DSPCNTR(plane);
 +      val = I915_READ(reg);
 +      val |= DISPLAY_PLANE_ENABLE;
 +      I915_WRITE(reg, val);
 +      POSTING_READ(reg);
 +      intel_wait_for_vblank(dev_priv->dev, pipe);
 +}
 +
 +/*
 + * Plane regs are double buffered, going from enabled->disabled needs a
 + * trigger in order to latch.  The display address reg provides this.
 + */
 +static void intel_flush_display_plane(struct drm_i915_private *dev_priv,
 +                                    enum plane plane)
 +{
 +      u32 reg = DSPADDR(plane);
 +      I915_WRITE(reg, I915_READ(reg));
 +}
 +
 +/**
 + * intel_disable_plane - disable a display plane
 + * @dev_priv: i915 private structure
 + * @plane: plane to disable
 + * @pipe: pipe consuming the data
 + *
 + * Disable @plane; should be an independent operation.
 + */
 +static void intel_disable_plane(struct drm_i915_private *dev_priv,
 +                              enum plane plane, enum pipe pipe)
 +{
 +      int reg;
 +      u32 val;
 +
 +      reg = DSPCNTR(plane);
 +      val = I915_READ(reg);
 +      val &= ~DISPLAY_PLANE_ENABLE;
 +      I915_WRITE(reg, val);
 +      POSTING_READ(reg);
 +      intel_flush_display_plane(dev_priv, plane);
 +      intel_wait_for_vblank(dev_priv->dev, pipe);
 +}
 +
 +static void disable_pch_dp(struct drm_i915_private *dev_priv,
 +                         enum pipe pipe, int reg)
 +{
 +      u32 val = I915_READ(reg);
 +      if (DP_PIPE_ENABLED(val, pipe))
 +              I915_WRITE(reg, val & ~DP_PORT_EN);
 +}
 +
 +static void disable_pch_hdmi(struct drm_i915_private *dev_priv,
 +                           enum pipe pipe, int reg)
 +{
 +      u32 val = I915_READ(reg);
 +      if (HDMI_PIPE_ENABLED(val, pipe))
 +              I915_WRITE(reg, val & ~PORT_ENABLE);
 +}
 +
 +/* Disable any ports connected to this transcoder */
 +static void intel_disable_pch_ports(struct drm_i915_private *dev_priv,
 +                                  enum pipe pipe)
 +{
 +      u32 reg, val;
 +
 +      val = I915_READ(PCH_PP_CONTROL);
 +      I915_WRITE(PCH_PP_CONTROL, val | PANEL_UNLOCK_REGS);
 +
 +      disable_pch_dp(dev_priv, pipe, PCH_DP_B);
 +      disable_pch_dp(dev_priv, pipe, PCH_DP_C);
 +      disable_pch_dp(dev_priv, pipe, PCH_DP_D);
 +
 +      reg = PCH_ADPA;
 +      val = I915_READ(reg);
 +      if (ADPA_PIPE_ENABLED(val, pipe))
 +              I915_WRITE(reg, val & ~ADPA_DAC_ENABLE);
 +
 +      reg = PCH_LVDS;
 +      val = I915_READ(reg);
 +      if (LVDS_PIPE_ENABLED(val, pipe)) {
 +              I915_WRITE(reg, val & ~LVDS_PORT_EN);
 +              POSTING_READ(reg);
 +              udelay(100);
 +      }
 +
 +      disable_pch_hdmi(dev_priv, pipe, HDMIB);
 +      disable_pch_hdmi(dev_priv, pipe, HDMIC);
 +      disable_pch_hdmi(dev_priv, pipe, HDMID);
 +}
 +
  static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
  {
        struct drm_device *dev = crtc->dev;
@@@ -1996,7 -1390,7 +1996,7 @@@ static void intel_update_fbc(struct drm
         *   - going to an unsupported config (interlace, pixel multiply, etc.)
         */
        list_for_each_entry(tmp_crtc, &dev->mode_config.crtc_list, head) {
 -              if (tmp_crtc->enabled) {
 +              if (tmp_crtc->enabled && tmp_crtc->fb) {
                        if (crtc) {
                                DRM_DEBUG_KMS("more than one pipe active, disabling compression\n");
                                dev_priv->no_fbc_reason = FBC_MULTIPLE_PIPES;
@@@ -2236,19 -1630,19 +2236,19 @@@ intel_pipe_set_base(struct drm_crtc *cr
                struct drm_i915_gem_object *obj = to_intel_framebuffer(old_fb)->obj;
  
                wait_event(dev_priv->pending_flip_queue,
+                          atomic_read(&dev_priv->mm.wedged) ||
                           atomic_read(&obj->pending_flip) == 0);
  
                /* Big Hammer, we also need to ensure that any pending
                 * MI_WAIT_FOR_EVENT inside a user batch buffer on the
                 * current scanout is retired before unpinning the old
                 * framebuffer.
+                *
+                * This should only fail upon a hung GPU, in which case we
+                * can safely continue.
                 */
                ret = i915_gem_object_flush_gpu(obj, false);
-               if (ret) {
-                       i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj);
-                       mutex_unlock(&dev->struct_mutex);
-                       return ret;
-               }
+               (void) ret;
        }
  
        ret = intel_pipe_set_base_atomic(crtc, crtc->fb, x, y,
@@@ -2359,13 -1753,8 +2359,13 @@@ static void ironlake_fdi_link_train(str
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe;
 +      int plane = intel_crtc->plane;
        u32 reg, temp, tries;
  
 +      /* FDI needs bits from pipe & plane first */
 +      assert_pipe_enabled(dev_priv, pipe);
 +      assert_plane_enabled(dev_priv, plane);
 +
        /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
           for train result */
        reg = FDI_RX_IMR(pipe);
        udelay(150);
  
        /* Ironlake workaround, enable clock pointer after FDI enable*/
 -      I915_WRITE(FDI_RX_CHICKEN(pipe), FDI_RX_PHASE_SYNC_POINTER_ENABLE);
 +      if (HAS_PCH_IBX(dev)) {
 +              I915_WRITE(FDI_RX_CHICKEN(pipe), FDI_RX_PHASE_SYNC_POINTER_OVR);
 +              I915_WRITE(FDI_RX_CHICKEN(pipe), FDI_RX_PHASE_SYNC_POINTER_OVR |
 +                         FDI_RX_PHASE_SYNC_POINTER_EN);
 +      }
  
        reg = FDI_RX_IIR(pipe);
        for (tries = 0; tries < 5; tries++) {
  
  }
  
 -static const int const snb_b_fdi_train_param [] = {
 +static const int snb_b_fdi_train_param [] = {
        FDI_LINK_TRAIN_400MV_0DB_SNB_B,
        FDI_LINK_TRAIN_400MV_6DB_SNB_B,
        FDI_LINK_TRAIN_600MV_3_5DB_SNB_B,
@@@ -2598,80 -1983,32 +2598,80 @@@ static void ironlake_fdi_enable(struct 
        I915_WRITE(reg, temp | FDI_RX_PLL_ENABLE);
  
        POSTING_READ(reg);
 -      udelay(200);
 +      udelay(200);
 +
 +      /* Switch from Rawclk to PCDclk */
 +      temp = I915_READ(reg);
 +      I915_WRITE(reg, temp | FDI_PCDCLK);
 +
 +      POSTING_READ(reg);
 +      udelay(200);
 +
 +      /* Enable CPU FDI TX PLL, always on for Ironlake */
 +      reg = FDI_TX_CTL(pipe);
 +      temp = I915_READ(reg);
 +      if ((temp & FDI_TX_PLL_ENABLE) == 0) {
 +              I915_WRITE(reg, temp | FDI_TX_PLL_ENABLE);
 +
 +              POSTING_READ(reg);
 +              udelay(100);
 +      }
 +}
 +
 +static void ironlake_fdi_disable(struct drm_crtc *crtc)
 +{
 +      struct drm_device *dev = crtc->dev;
 +      struct drm_i915_private *dev_priv = dev->dev_private;
 +      struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 +      int pipe = intel_crtc->pipe;
 +      u32 reg, temp;
 +
 +      /* disable CPU FDI tx and PCH FDI rx */
 +      reg = FDI_TX_CTL(pipe);
 +      temp = I915_READ(reg);
 +      I915_WRITE(reg, temp & ~FDI_TX_ENABLE);
 +      POSTING_READ(reg);
  
 -      /* Switch from Rawclk to PCDclk */
 +      reg = FDI_RX_CTL(pipe);
        temp = I915_READ(reg);
 -      I915_WRITE(reg, temp | FDI_PCDCLK);
 +      temp &= ~(0x7 << 16);
 +      temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11;
 +      I915_WRITE(reg, temp & ~FDI_RX_ENABLE);
  
        POSTING_READ(reg);
 -      udelay(200);
 +      udelay(100);
  
 -      /* Enable CPU FDI TX PLL, always on for Ironlake */
 +      /* Ironlake workaround, disable clock pointer after downing FDI */
 +      if (HAS_PCH_IBX(dev)) {
 +              I915_WRITE(FDI_RX_CHICKEN(pipe), FDI_RX_PHASE_SYNC_POINTER_OVR);
 +              I915_WRITE(FDI_RX_CHICKEN(pipe),
 +                         I915_READ(FDI_RX_CHICKEN(pipe) &
 +                                   ~FDI_RX_PHASE_SYNC_POINTER_EN));
 +      }
 +
 +      /* still set train pattern 1 */
        reg = FDI_TX_CTL(pipe);
        temp = I915_READ(reg);
 -      if ((temp & FDI_TX_PLL_ENABLE) == 0) {
 -              I915_WRITE(reg, temp | FDI_TX_PLL_ENABLE);
 +      temp &= ~FDI_LINK_TRAIN_NONE;
 +      temp |= FDI_LINK_TRAIN_PATTERN_1;
 +      I915_WRITE(reg, temp);
  
 -              POSTING_READ(reg);
 -              udelay(100);
 +      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_PATTERN_1_CPT;
 +      } else {
 +              temp &= ~FDI_LINK_TRAIN_NONE;
 +              temp |= FDI_LINK_TRAIN_PATTERN_1;
        }
 -}
 +      /* BPC in FDI rx is consistent with that in PIPECONF */
 +      temp &= ~(0x07 << 16);
 +      temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11;
 +      I915_WRITE(reg, temp);
  
 -static void intel_flush_display_plane(struct drm_device *dev,
 -                                    int plane)
 -{
 -      struct drm_i915_private *dev_priv = dev->dev_private;
 -      u32 reg = DSPADDR(plane);
 -      I915_WRITE(reg, I915_READ(reg));
 +      POSTING_READ(reg);
 +      udelay(100);
  }
  
  /*
@@@ -2708,46 -2045,60 +2708,46 @@@ static void intel_crtc_wait_for_pending
                   atomic_read(&obj->pending_flip) == 0);
  }
  
 -static void ironlake_crtc_enable(struct drm_crtc *crtc)
 +static bool intel_crtc_driving_pch(struct drm_crtc *crtc)
  {
        struct drm_device *dev = crtc->dev;
 -      struct drm_i915_private *dev_priv = dev->dev_private;
 -      struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 -      int pipe = intel_crtc->pipe;
 -      int plane = intel_crtc->plane;
 -      u32 reg, temp;
 -
 -      if (intel_crtc->active)
 -              return;
 -
 -      intel_crtc->active = true;
 -      intel_update_watermarks(dev);
 -
 -      if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
 -              temp = I915_READ(PCH_LVDS);
 -              if ((temp & LVDS_PORT_EN) == 0)
 -                      I915_WRITE(PCH_LVDS, temp | LVDS_PORT_EN);
 -      }
 +      struct drm_mode_config *mode_config = &dev->mode_config;
 +      struct intel_encoder *encoder;
  
 -      ironlake_fdi_enable(crtc);
 +      /*
 +       * If there's a non-PCH eDP on this crtc, it must be DP_A, and that
 +       * must be driven by its own crtc; no sharing is possible.
 +       */
 +      list_for_each_entry(encoder, &mode_config->encoder_list, base.head) {
 +              if (encoder->base.crtc != crtc)
 +                      continue;
  
 -      /* Enable panel fitting for LVDS */
 -      if (dev_priv->pch_pf_size &&
 -          (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.
 -               */
 -              I915_WRITE(pipe ? PFB_CTL_1 : PFA_CTL_1,
 -                         PF_ENABLE | PF_FILTER_MED_3x3);
 -              I915_WRITE(pipe ? PFB_WIN_POS : PFA_WIN_POS,
 -                         dev_priv->pch_pf_pos);
 -              I915_WRITE(pipe ? PFB_WIN_SZ : PFA_WIN_SZ,
 -                         dev_priv->pch_pf_size);
 +              switch (encoder->type) {
 +              case INTEL_OUTPUT_EDP:
 +                      if (!intel_encoder_is_pch_edp(&encoder->base))
 +                              return false;
 +                      continue;
 +              }
        }
  
 -      /* Enable CPU pipe */
 -      reg = PIPECONF(pipe);
 -      temp = I915_READ(reg);
 -      if ((temp & PIPECONF_ENABLE) == 0) {
 -              I915_WRITE(reg, temp | PIPECONF_ENABLE);
 -              POSTING_READ(reg);
 -              intel_wait_for_vblank(dev, intel_crtc->pipe);
 -      }
 +      return true;
 +}
  
 -      /* configure and enable CPU plane */
 -      reg = DSPCNTR(plane);
 -      temp = I915_READ(reg);
 -      if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
 -              I915_WRITE(reg, temp | DISPLAY_PLANE_ENABLE);
 -              intel_flush_display_plane(dev, plane);
 -      }
 +/*
 + * Enable PCH resources required for PCH ports:
 + *   - PCH PLLs
 + *   - FDI training & RX/TX
 + *   - update transcoder timings
 + *   - DP transcoding bits
 + *   - transcoder
 + */
 +static void ironlake_pch_enable(struct drm_crtc *crtc)
 +{
 +      struct drm_device *dev = crtc->dev;
 +      struct drm_i915_private *dev_priv = dev->dev_private;
 +      struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 +      int pipe = intel_crtc->pipe;
 +      u32 reg, temp;
  
        /* For PCH output, training FDI link */
        if (IS_GEN6(dev))
        else
                ironlake_fdi_link_train(crtc);
  
 -      /* enable PCH DPLL */
 -      reg = PCH_DPLL(pipe);
 -      temp = I915_READ(reg);
 -      if ((temp & DPLL_VCO_ENABLE) == 0) {
 -              I915_WRITE(reg, temp | DPLL_VCO_ENABLE);
 -              POSTING_READ(reg);
 -              udelay(200);
 -      }
 +      intel_enable_pch_pll(dev_priv, pipe);
  
        if (HAS_PCH_CPT(dev)) {
                /* Be sure PCH DPLL SEL is set */
                I915_WRITE(PCH_DPLL_SEL, temp);
        }
  
 -      /* set transcoder timing */
 +      /* set transcoder timing, panel must allow it */
 +      assert_panel_unlocked(dev_priv, pipe);
        I915_WRITE(TRANS_HTOTAL(pipe), I915_READ(HTOTAL(pipe)));
        I915_WRITE(TRANS_HBLANK(pipe), I915_READ(HBLANK(pipe)));
        I915_WRITE(TRANS_HSYNC(pipe),  I915_READ(HSYNC(pipe)));
                I915_WRITE(reg, temp);
        }
  
 -      /* enable PCH transcoder */
 -      reg = TRANSCONF(pipe);
 -      temp = I915_READ(reg);
 -      /*
 -       * make the BPC in transcoder be consistent with
 -       * that in pipeconf reg.
 -       */
 -      temp &= ~PIPE_BPC_MASK;
 -      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 %d\n", pipe);
 +      intel_enable_transcoder(dev_priv, pipe);
 +}
 +
 +static void ironlake_crtc_enable(struct drm_crtc *crtc)
 +{
 +      struct drm_device *dev = crtc->dev;
 +      struct drm_i915_private *dev_priv = dev->dev_private;
 +      struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 +      int pipe = intel_crtc->pipe;
 +      int plane = intel_crtc->plane;
 +      u32 temp;
 +      bool is_pch_port;
 +
 +      if (intel_crtc->active)
 +              return;
 +
 +      intel_crtc->active = true;
 +      intel_update_watermarks(dev);
 +
 +      if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
 +              temp = I915_READ(PCH_LVDS);
 +              if ((temp & LVDS_PORT_EN) == 0)
 +                      I915_WRITE(PCH_LVDS, temp | LVDS_PORT_EN);
 +      }
 +
 +      is_pch_port = intel_crtc_driving_pch(crtc);
 +
 +      if (is_pch_port)
 +              ironlake_fdi_enable(crtc);
 +      else
 +              ironlake_fdi_disable(crtc);
 +
 +      /* Enable panel fitting for LVDS */
 +      if (dev_priv->pch_pf_size &&
 +          (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.
 +               */
 +              I915_WRITE(PF_CTL(pipe), PF_ENABLE | PF_FILTER_MED_3x3);
 +              I915_WRITE(PF_WIN_POS(pipe), dev_priv->pch_pf_pos);
 +              I915_WRITE(PF_WIN_SZ(pipe), dev_priv->pch_pf_size);
 +      }
 +
 +      intel_enable_pipe(dev_priv, pipe, is_pch_port);
 +      intel_enable_plane(dev_priv, plane, pipe);
 +
 +      if (is_pch_port)
 +              ironlake_pch_enable(crtc);
  
        intel_crtc_load_lut(crtc);
        intel_update_fbc(dev);
@@@ -2886,58 -2206,116 +2886,58 @@@ static void ironlake_crtc_disable(struc
        drm_vblank_off(dev, pipe);
        intel_crtc_update_cursor(crtc, false);
  
 -      /* Disable display plane */
 -      reg = DSPCNTR(plane);
 -      temp = I915_READ(reg);
 -      if (temp & DISPLAY_PLANE_ENABLE) {
 -              I915_WRITE(reg, temp & ~DISPLAY_PLANE_ENABLE);
 -              intel_flush_display_plane(dev, plane);
 -      }
 +      intel_disable_plane(dev_priv, plane, pipe);
  
        if (dev_priv->cfb_plane == plane &&
            dev_priv->display.disable_fbc)
                dev_priv->display.disable_fbc(dev);
  
 -      /* disable cpu pipe, disable after all planes disabled */
 -      reg = PIPECONF(pipe);
 -      temp = I915_READ(reg);
 -      if (temp & PIPECONF_ENABLE) {
 -              I915_WRITE(reg, temp & ~PIPECONF_ENABLE);
 -              POSTING_READ(reg);
 -              /* wait for cpu pipe off, pipe state */
 -              intel_wait_for_pipe_off(dev, intel_crtc->pipe);
 -      }
 +      intel_disable_pipe(dev_priv, pipe);
  
        /* Disable PF */
 -      I915_WRITE(pipe ? PFB_CTL_1 : PFA_CTL_1, 0);
 -      I915_WRITE(pipe ? PFB_WIN_SZ : PFA_WIN_SZ, 0);
 -
 -      /* disable CPU FDI tx and PCH FDI rx */
 -      reg = FDI_TX_CTL(pipe);
 -      temp = I915_READ(reg);
 -      I915_WRITE(reg, temp & ~FDI_TX_ENABLE);
 -      POSTING_READ(reg);
 -
 -      reg = FDI_RX_CTL(pipe);
 -      temp = I915_READ(reg);
 -      temp &= ~(0x7 << 16);
 -      temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11;
 -      I915_WRITE(reg, temp & ~FDI_RX_ENABLE);
 -
 -      POSTING_READ(reg);
 -      udelay(100);
 -
 -      /* Ironlake workaround, disable clock pointer after downing FDI */
 -      if (HAS_PCH_IBX(dev))
 -              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);
 -      temp &= ~FDI_LINK_TRAIN_NONE;
 -      temp |= FDI_LINK_TRAIN_PATTERN_1;
 -      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_PATTERN_1_CPT;
 -      } else {
 -              temp &= ~FDI_LINK_TRAIN_NONE;
 -              temp |= FDI_LINK_TRAIN_PATTERN_1;
 -      }
 -      /* BPC in FDI rx is consistent with that in PIPECONF */
 -      temp &= ~(0x07 << 16);
 -      temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11;
 -      I915_WRITE(reg, temp);
 +      I915_WRITE(PF_CTL(pipe), 0);
 +      I915_WRITE(PF_WIN_SZ(pipe), 0);
  
 -      POSTING_READ(reg);
 -      udelay(100);
 +      ironlake_fdi_disable(crtc);
  
 -      if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
 -              temp = I915_READ(PCH_LVDS);
 -              if (temp & LVDS_PORT_EN) {
 -                      I915_WRITE(PCH_LVDS, temp & ~LVDS_PORT_EN);
 -                      POSTING_READ(PCH_LVDS);
 -                      udelay(100);
 -              }
 -      }
 +      /* This is a horrible layering violation; we should be doing this in
 +       * the connector/encoder ->prepare instead, but we don't always have
 +       * enough information there about the config to know whether it will
 +       * actually be necessary or just cause undesired flicker.
 +       */
 +      intel_disable_pch_ports(dev_priv, pipe);
  
 -      /* disable PCH transcoder */
 -      reg = TRANSCONF(plane);
 -      temp = I915_READ(reg);
 -      if (temp & TRANS_ENABLE) {
 -              I915_WRITE(reg, temp & ~TRANS_ENABLE);
 -              /* wait for PCH transcoder off, transcoder state */
 -              if (wait_for((I915_READ(reg) & TRANS_STATE_ENABLE) == 0, 50))
 -                      DRM_ERROR("failed to disable transcoder\n");
 -      }
 +      intel_disable_transcoder(dev_priv, pipe);
  
        if (HAS_PCH_CPT(dev)) {
                /* disable TRANS_DP_CTL */
                reg = TRANS_DP_CTL(pipe);
                temp = I915_READ(reg);
                temp &= ~(TRANS_DP_OUTPUT_ENABLE | TRANS_DP_PORT_SEL_MASK);
 +              temp |= TRANS_DP_PORT_SEL_NONE;
                I915_WRITE(reg, temp);
  
                /* disable DPLL_SEL */
                temp = I915_READ(PCH_DPLL_SEL);
 -              if (pipe == 0)
 -                      temp &= ~(TRANSA_DPLL_ENABLE | TRANSA_DPLLB_SEL);
 -              else
 +              switch (pipe) {
 +              case 0:
 +                      temp &= ~(TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL);
 +                      break;
 +              case 1:
                        temp &= ~(TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
 +                      break;
 +              case 2:
 +                      /* FIXME: manage transcoder PLLs? */
 +                      temp &= ~(TRANSC_DPLL_ENABLE | TRANSC_DPLLB_SEL);
 +                      break;
 +              default:
 +                      BUG(); /* wtf */
 +              }
                I915_WRITE(PCH_DPLL_SEL, temp);
        }
  
        /* disable PCH DPLL */
 -      reg = PCH_DPLL(pipe);
 -      temp = I915_READ(reg);
 -      I915_WRITE(reg, temp & ~DPLL_VCO_ENABLE);
 +      intel_disable_pch_pll(dev_priv, pipe);
  
        /* Switch from PCDclk to Rawclk */
        reg = FDI_RX_CTL(pipe);
@@@ -3012,6 -2390,7 +3012,6 @@@ static void i9xx_crtc_enable(struct drm
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe;
        int plane = intel_crtc->plane;
 -      u32 reg, temp;
  
        if (intel_crtc->active)
                return;
        intel_crtc->active = true;
        intel_update_watermarks(dev);
  
 -      /* Enable the DPLL */
 -      reg = DPLL(pipe);
 -      temp = I915_READ(reg);
 -      if ((temp & DPLL_VCO_ENABLE) == 0) {
 -              I915_WRITE(reg, temp);
 -
 -              /* Wait for the clocks to stabilize. */
 -              POSTING_READ(reg);
 -              udelay(150);
 -
 -              I915_WRITE(reg, temp | DPLL_VCO_ENABLE);
 -
 -              /* Wait for the clocks to stabilize. */
 -              POSTING_READ(reg);
 -              udelay(150);
 -
 -              I915_WRITE(reg, temp | DPLL_VCO_ENABLE);
 -
 -              /* Wait for the clocks to stabilize. */
 -              POSTING_READ(reg);
 -              udelay(150);
 -      }
 -
 -      /* Enable the pipe */
 -      reg = PIPECONF(pipe);
 -      temp = I915_READ(reg);
 -      if ((temp & PIPECONF_ENABLE) == 0)
 -              I915_WRITE(reg, temp | PIPECONF_ENABLE);
 -
 -      /* Enable the plane */
 -      reg = DSPCNTR(plane);
 -      temp = I915_READ(reg);
 -      if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
 -              I915_WRITE(reg, temp | DISPLAY_PLANE_ENABLE);
 -              intel_flush_display_plane(dev, plane);
 -      }
 +      intel_enable_pll(dev_priv, pipe);
 +      intel_enable_pipe(dev_priv, pipe, false);
 +      intel_enable_plane(dev_priv, plane, pipe);
  
        intel_crtc_load_lut(crtc);
        intel_update_fbc(dev);
@@@ -3038,6 -2450,7 +3038,6 @@@ static void i9xx_crtc_disable(struct dr
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe;
        int plane = intel_crtc->plane;
 -      u32 reg, temp;
  
        if (!intel_crtc->active)
                return;
        intel_crtc_dpms_overlay(intel_crtc, false);
        intel_crtc_update_cursor(crtc, false);
  
 -      if (dev_priv->cfb_plane == plane &&
 -          dev_priv->display.disable_fbc)
 -              dev_priv->display.disable_fbc(dev);
 -
 -      /* Disable display plane */
 -      reg = DSPCNTR(plane);
 -      temp = I915_READ(reg);
 -      if (temp & DISPLAY_PLANE_ENABLE) {
 -              I915_WRITE(reg, temp & ~DISPLAY_PLANE_ENABLE);
 -              /* Flush the plane changes */
 -              intel_flush_display_plane(dev, plane);
 -
 -              /* Wait for vblank for the disable to take effect */
 -              if (IS_GEN2(dev))
 -                      intel_wait_for_vblank(dev, pipe);
 -      }
 -
 -      /* Don't disable pipe A or pipe A PLLs if needed */
 -      if (pipe == 0 && (dev_priv->quirks & QUIRK_PIPEA_FORCE))
 -              goto done;
 -
 -      /* Next, disable display pipes */
 -      reg = PIPECONF(pipe);
 -      temp = I915_READ(reg);
 -      if (temp & PIPECONF_ENABLE) {
 -              I915_WRITE(reg, temp & ~PIPECONF_ENABLE);
 -
 -              /* Wait for the pipe to turn off */
 -              POSTING_READ(reg);
 -              intel_wait_for_pipe_off(dev, pipe);
 -      }
 -
 -      reg = DPLL(pipe);
 -      temp = I915_READ(reg);
 -      if (temp & DPLL_VCO_ENABLE) {
 -              I915_WRITE(reg, temp & ~DPLL_VCO_ENABLE);
 -
 -              /* Wait for the clocks to turn off. */
 -              POSTING_READ(reg);
 -              udelay(150);
 -      }
 +      if (dev_priv->cfb_plane == plane &&
 +          dev_priv->display.disable_fbc)
 +              dev_priv->display.disable_fbc(dev);
 +
 +      intel_disable_plane(dev_priv, plane, pipe);
 +      intel_disable_pipe(dev_priv, pipe);
 +      intel_disable_pll(dev_priv, pipe);
  
 -done:
        intel_crtc->active = false;
        intel_update_fbc(dev);
        intel_update_watermarks(dev);
@@@ -3117,7 -2565,7 +3117,7 @@@ static void intel_crtc_dpms(struct drm_
                master_priv->sarea_priv->pipeB_h = enabled ? crtc->mode.vdisplay : 0;
                break;
        default:
 -              DRM_ERROR("Can't update pipe %d in SAREA\n", pipe);
 +              DRM_ERROR("Can't update pipe %c in SAREA\n", pipe_name(pipe));
                break;
        }
  }
@@@ -3314,77 -2762,77 +3314,77 @@@ struct intel_watermark_params 
  };
  
  /* Pineview has different values for various configs */
 -static struct intel_watermark_params pineview_display_wm = {
 +static const struct intel_watermark_params pineview_display_wm = {
        PINEVIEW_DISPLAY_FIFO,
        PINEVIEW_MAX_WM,
        PINEVIEW_DFT_WM,
        PINEVIEW_GUARD_WM,
        PINEVIEW_FIFO_LINE_SIZE
  };
 -static struct intel_watermark_params pineview_display_hplloff_wm = {
 +static const struct intel_watermark_params pineview_display_hplloff_wm = {
        PINEVIEW_DISPLAY_FIFO,
        PINEVIEW_MAX_WM,
        PINEVIEW_DFT_HPLLOFF_WM,
        PINEVIEW_GUARD_WM,
        PINEVIEW_FIFO_LINE_SIZE
  };
 -static struct intel_watermark_params pineview_cursor_wm = {
 +static const struct intel_watermark_params pineview_cursor_wm = {
        PINEVIEW_CURSOR_FIFO,
        PINEVIEW_CURSOR_MAX_WM,
        PINEVIEW_CURSOR_DFT_WM,
        PINEVIEW_CURSOR_GUARD_WM,
        PINEVIEW_FIFO_LINE_SIZE,
  };
 -static struct intel_watermark_params pineview_cursor_hplloff_wm = {
 +static const struct intel_watermark_params pineview_cursor_hplloff_wm = {
        PINEVIEW_CURSOR_FIFO,
        PINEVIEW_CURSOR_MAX_WM,
        PINEVIEW_CURSOR_DFT_WM,
        PINEVIEW_CURSOR_GUARD_WM,
        PINEVIEW_FIFO_LINE_SIZE
  };
 -static struct intel_watermark_params g4x_wm_info = {
 +static const struct intel_watermark_params g4x_wm_info = {
        G4X_FIFO_SIZE,
        G4X_MAX_WM,
        G4X_MAX_WM,
        2,
        G4X_FIFO_LINE_SIZE,
  };
 -static struct intel_watermark_params g4x_cursor_wm_info = {
 +static const struct intel_watermark_params g4x_cursor_wm_info = {
        I965_CURSOR_FIFO,
        I965_CURSOR_MAX_WM,
        I965_CURSOR_DFT_WM,
        2,
        G4X_FIFO_LINE_SIZE,
  };
 -static struct intel_watermark_params i965_cursor_wm_info = {
 +static const struct intel_watermark_params i965_cursor_wm_info = {
        I965_CURSOR_FIFO,
        I965_CURSOR_MAX_WM,
        I965_CURSOR_DFT_WM,
        2,
        I915_FIFO_LINE_SIZE,
  };
 -static struct intel_watermark_params i945_wm_info = {
 +static const struct intel_watermark_params i945_wm_info = {
        I945_FIFO_SIZE,
        I915_MAX_WM,
        1,
        2,
        I915_FIFO_LINE_SIZE
  };
 -static struct intel_watermark_params i915_wm_info = {
 +static const struct intel_watermark_params i915_wm_info = {
        I915_FIFO_SIZE,
        I915_MAX_WM,
        1,
        2,
        I915_FIFO_LINE_SIZE
  };
 -static struct intel_watermark_params i855_wm_info = {
 +static const struct intel_watermark_params i855_wm_info = {
        I855GM_FIFO_SIZE,
        I915_MAX_WM,
        1,
        2,
        I830_FIFO_LINE_SIZE
  };
 -static struct intel_watermark_params i830_wm_info = {
 +static const struct intel_watermark_params i830_wm_info = {
        I830_FIFO_SIZE,
        I915_MAX_WM,
        1,
        I830_FIFO_LINE_SIZE
  };
  
 -static struct intel_watermark_params ironlake_display_wm_info = {
 +static const struct intel_watermark_params ironlake_display_wm_info = {
        ILK_DISPLAY_FIFO,
        ILK_DISPLAY_MAXWM,
        ILK_DISPLAY_DFTWM,
        2,
        ILK_FIFO_LINE_SIZE
  };
 -
 -static struct intel_watermark_params ironlake_cursor_wm_info = {
 +static const struct intel_watermark_params ironlake_cursor_wm_info = {
        ILK_CURSOR_FIFO,
        ILK_CURSOR_MAXWM,
        ILK_CURSOR_DFTWM,
        2,
        ILK_FIFO_LINE_SIZE
  };
 -
 -static struct intel_watermark_params ironlake_display_srwm_info = {
 +static const struct intel_watermark_params ironlake_display_srwm_info = {
        ILK_DISPLAY_SR_FIFO,
        ILK_DISPLAY_MAX_SRWM,
        ILK_DISPLAY_DFT_SRWM,
        2,
        ILK_FIFO_LINE_SIZE
  };
 -
 -static struct intel_watermark_params ironlake_cursor_srwm_info = {
 +static const struct intel_watermark_params ironlake_cursor_srwm_info = {
        ILK_CURSOR_SR_FIFO,
        ILK_CURSOR_MAX_SRWM,
        ILK_CURSOR_DFT_SRWM,
        ILK_FIFO_LINE_SIZE
  };
  
 -static struct intel_watermark_params sandybridge_display_wm_info = {
 +static const struct intel_watermark_params sandybridge_display_wm_info = {
        SNB_DISPLAY_FIFO,
        SNB_DISPLAY_MAXWM,
        SNB_DISPLAY_DFTWM,
        2,
        SNB_FIFO_LINE_SIZE
  };
 -
 -static struct intel_watermark_params sandybridge_cursor_wm_info = {
 +static const struct intel_watermark_params sandybridge_cursor_wm_info = {
        SNB_CURSOR_FIFO,
        SNB_CURSOR_MAXWM,
        SNB_CURSOR_DFTWM,
        2,
        SNB_FIFO_LINE_SIZE
  };
 -
 -static struct intel_watermark_params sandybridge_display_srwm_info = {
 +static const struct intel_watermark_params sandybridge_display_srwm_info = {
        SNB_DISPLAY_SR_FIFO,
        SNB_DISPLAY_MAX_SRWM,
        SNB_DISPLAY_DFT_SRWM,
        2,
        SNB_FIFO_LINE_SIZE
  };
 -
 -static struct intel_watermark_params sandybridge_cursor_srwm_info = {
 +static const struct intel_watermark_params sandybridge_cursor_srwm_info = {
        SNB_CURSOR_SR_FIFO,
        SNB_CURSOR_MAX_SRWM,
        SNB_CURSOR_DFT_SRWM,
   * will occur, and a display engine hang could result.
   */
  static unsigned long intel_calculate_wm(unsigned long clock_in_khz,
 -                                      struct intel_watermark_params *wm,
 +                                      const struct intel_watermark_params *wm,
 +                                      int fifo_size,
                                        int pixel_size,
                                        unsigned long latency_ns)
  {
  
        DRM_DEBUG_KMS("FIFO entries required for mode: %d\n", entries_required);
  
 -      wm_size = wm->fifo_size - (entries_required + wm->guard_size);
 +      wm_size = fifo_size - (entries_required + wm->guard_size);
  
        DRM_DEBUG_KMS("FIFO watermark level: %d\n", wm_size);
  
@@@ -3662,28 -3115,15 +3662,28 @@@ static int i830_get_fifo_size(struct dr
        return size;
  }
  
 -static void pineview_update_wm(struct drm_device *dev,  int planea_clock,
 -                             int planeb_clock, int sr_hdisplay, int unused,
 -                             int pixel_size)
 +static struct drm_crtc *single_enabled_crtc(struct drm_device *dev)
 +{
 +      struct drm_crtc *crtc, *enabled = NULL;
 +
 +      list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 +              if (crtc->enabled && crtc->fb) {
 +                      if (enabled)
 +                              return NULL;
 +                      enabled = crtc;
 +              }
 +      }
 +
 +      return enabled;
 +}
 +
 +static void pineview_update_wm(struct drm_device *dev)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
 +      struct drm_crtc *crtc;
        const struct cxsr_latency *latency;
        u32 reg;
        unsigned long wm;
 -      int sr_clock;
  
        latency = intel_get_cxsr_latency(IS_PINEVIEW_G(dev), dev_priv->is_ddr3,
                                         dev_priv->fsb_freq, dev_priv->mem_freq);
                return;
        }
  
 -      if (!planea_clock || !planeb_clock) {
 -              sr_clock = planea_clock ? planea_clock : planeb_clock;
 +      crtc = single_enabled_crtc(dev);
 +      if (crtc) {
 +              int clock = crtc->mode.clock;
 +              int pixel_size = crtc->fb->bits_per_pixel / 8;
  
                /* Display SR */
 -              wm = intel_calculate_wm(sr_clock, &pineview_display_wm,
 +              wm = intel_calculate_wm(clock, &pineview_display_wm,
 +                                      pineview_display_wm.fifo_size,
                                        pixel_size, latency->display_sr);
                reg = I915_READ(DSPFW1);
                reg &= ~DSPFW_SR_MASK;
                DRM_DEBUG_KMS("DSPFW1 register is %x\n", reg);
  
                /* cursor SR */
 -              wm = intel_calculate_wm(sr_clock, &pineview_cursor_wm,
 +              wm = intel_calculate_wm(clock, &pineview_cursor_wm,
 +                                      pineview_display_wm.fifo_size,
                                        pixel_size, latency->cursor_sr);
                reg = I915_READ(DSPFW3);
                reg &= ~DSPFW_CURSOR_SR_MASK;
                I915_WRITE(DSPFW3, reg);
  
                /* Display HPLL off SR */
 -              wm = intel_calculate_wm(sr_clock, &pineview_display_hplloff_wm,
 +              wm = intel_calculate_wm(clock, &pineview_display_hplloff_wm,
 +                                      pineview_display_hplloff_wm.fifo_size,
                                        pixel_size, latency->display_hpll_disable);
                reg = I915_READ(DSPFW3);
                reg &= ~DSPFW_HPLL_SR_MASK;
                I915_WRITE(DSPFW3, reg);
  
                /* cursor HPLL off SR */
 -              wm = intel_calculate_wm(sr_clock, &pineview_cursor_hplloff_wm,
 +              wm = intel_calculate_wm(clock, &pineview_cursor_hplloff_wm,
 +                                      pineview_display_hplloff_wm.fifo_size,
                                        pixel_size, latency->cursor_hpll_disable);
                reg = I915_READ(DSPFW3);
                reg &= ~DSPFW_HPLL_CURSOR_MASK;
        }
  }
  
 -static void g4x_update_wm(struct drm_device *dev,  int planea_clock,
 -                        int planeb_clock, int sr_hdisplay, int sr_htotal,
 -                        int pixel_size)
 +static bool g4x_compute_wm0(struct drm_device *dev,
 +                          int plane,
 +                          const struct intel_watermark_params *display,
 +                          int display_latency_ns,
 +                          const struct intel_watermark_params *cursor,
 +                          int cursor_latency_ns,
 +                          int *plane_wm,
 +                          int *cursor_wm)
  {
 -      struct drm_i915_private *dev_priv = dev->dev_private;
 -      int total_size, cacheline_size;
 -      int planea_wm, planeb_wm, cursora_wm, cursorb_wm, cursor_sr;
 -      struct intel_watermark_params planea_params, planeb_params;
 -      unsigned long line_time_us;
 -      int sr_clock, sr_entries = 0, entries_required;
 +      struct drm_crtc *crtc;
 +      int htotal, hdisplay, clock, pixel_size;
 +      int line_time_us, line_count;
 +      int entries, tlb_miss;
  
 -      /* Create copies of the base settings for each pipe */
 -      planea_params = planeb_params = g4x_wm_info;
 +      crtc = intel_get_crtc_for_plane(dev, plane);
 +      if (crtc->fb == NULL || !crtc->enabled)
 +              return false;
 +
 +      htotal = crtc->mode.htotal;
 +      hdisplay = crtc->mode.hdisplay;
 +      clock = crtc->mode.clock;
 +      pixel_size = crtc->fb->bits_per_pixel / 8;
  
 -      /* Grab a couple of global values before we overwrite them */
 -      total_size = planea_params.fifo_size;
 -      cacheline_size = planea_params.cacheline_size;
 +      /* Use the small buffer method to calculate plane watermark */
 +      entries = ((clock * pixel_size / 1000) * display_latency_ns) / 1000;
 +      tlb_miss = display->fifo_size*display->cacheline_size - hdisplay * 8;
 +      if (tlb_miss > 0)
 +              entries += tlb_miss;
 +      entries = DIV_ROUND_UP(entries, display->cacheline_size);
 +      *plane_wm = entries + display->guard_size;
 +      if (*plane_wm > (int)display->max_wm)
 +              *plane_wm = display->max_wm;
  
 -      /*
 -       * Note: we need to make sure we don't overflow for various clock &
 -       * latency values.
 -       * clocks go from a few thousand to several hundred thousand.
 -       * latency is usually a few thousand
 -       */
 -      entries_required = ((planea_clock / 1000) * pixel_size * latency_ns) /
 -              1000;
 -      entries_required = DIV_ROUND_UP(entries_required, G4X_FIFO_LINE_SIZE);
 -      planea_wm = entries_required + planea_params.guard_size;
 +      /* Use the large buffer method to calculate cursor watermark */
 +      line_time_us = ((htotal * 1000) / clock);
 +      line_count = (cursor_latency_ns / line_time_us + 1000) / 1000;
 +      entries = line_count * 64 * pixel_size;
 +      tlb_miss = cursor->fifo_size*cursor->cacheline_size - hdisplay * 8;
 +      if (tlb_miss > 0)
 +              entries += tlb_miss;
 +      entries = DIV_ROUND_UP(entries, cursor->cacheline_size);
 +      *cursor_wm = entries + cursor->guard_size;
 +      if (*cursor_wm > (int)cursor->max_wm)
 +              *cursor_wm = (int)cursor->max_wm;
  
 -      entries_required = ((planeb_clock / 1000) * pixel_size * latency_ns) /
 -              1000;
 -      entries_required = DIV_ROUND_UP(entries_required, G4X_FIFO_LINE_SIZE);
 -      planeb_wm = entries_required + planeb_params.guard_size;
 +      return true;
 +}
  
 -      cursora_wm = cursorb_wm = 16;
 -      cursor_sr = 32;
 +/*
 + * Check the wm result.
 + *
 + * If any calculated watermark values is larger than the maximum value that
 + * can be programmed into the associated watermark register, that watermark
 + * must be disabled.
 + */
 +static bool g4x_check_srwm(struct drm_device *dev,
 +                         int display_wm, int cursor_wm,
 +                         const struct intel_watermark_params *display,
 +                         const struct intel_watermark_params *cursor)
 +{
 +      DRM_DEBUG_KMS("SR watermark: display plane %d, cursor %d\n",
 +                    display_wm, cursor_wm);
  
 -      DRM_DEBUG("FIFO watermarks - A: %d, B: %d\n", planea_wm, planeb_wm);
 +      if (display_wm > display->max_wm) {
 +              DRM_DEBUG_KMS("display watermark is too large(%d), disabling\n",
 +                            display_wm, display->max_wm);
 +              return false;
 +      }
  
 -      /* Calc sr entries for one plane configs */
 -      if (sr_hdisplay && (!planea_clock || !planeb_clock)) {
 -              /* self-refresh has much higher latency */
 -              static const int sr_latency_ns = 12000;
 +      if (cursor_wm > cursor->max_wm) {
 +              DRM_DEBUG_KMS("cursor watermark is too large(%d), disabling\n",
 +                            cursor_wm, cursor->max_wm);
 +              return false;
 +      }
  
 -              sr_clock = planea_clock ? planea_clock : planeb_clock;
 -              line_time_us = ((sr_htotal * 1000) / sr_clock);
 +      if (!(display_wm || cursor_wm)) {
 +              DRM_DEBUG_KMS("SR latency is 0, disabling\n");
 +              return false;
 +      }
  
 -              /* Use ns/us then divide to preserve precision */
 -              sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
 -                      pixel_size * sr_hdisplay;
 -              sr_entries = DIV_ROUND_UP(sr_entries, cacheline_size);
 -
 -              entries_required = (((sr_latency_ns / line_time_us) +
 -                                   1000) / 1000) * pixel_size * 64;
 -              entries_required = DIV_ROUND_UP(entries_required,
 -                                              g4x_cursor_wm_info.cacheline_size);
 -              cursor_sr = entries_required + g4x_cursor_wm_info.guard_size;
 -
 -              if (cursor_sr > g4x_cursor_wm_info.max_wm)
 -                      cursor_sr = g4x_cursor_wm_info.max_wm;
 -              DRM_DEBUG_KMS("self-refresh watermark: display plane %d "
 -                            "cursor %d\n", sr_entries, cursor_sr);
 +      return true;
 +}
  
 -              I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN);
 -      } else {
 -              /* Turn off self refresh if both pipes are enabled */
 -              I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF)
 -                         & ~FW_BLC_SELF_EN);
 +static bool g4x_compute_srwm(struct drm_device *dev,
 +                           int plane,
 +                           int latency_ns,
 +                           const struct intel_watermark_params *display,
 +                           const struct intel_watermark_params *cursor,
 +                           int *display_wm, int *cursor_wm)
 +{
 +      struct drm_crtc *crtc;
 +      int hdisplay, htotal, pixel_size, clock;
 +      unsigned long line_time_us;
 +      int line_count, line_size;
 +      int small, large;
 +      int entries;
 +
 +      if (!latency_ns) {
 +              *display_wm = *cursor_wm = 0;
 +              return false;
        }
  
 -      DRM_DEBUG("Setting FIFO watermarks - A: %d, B: %d, SR %d\n",
 -                planea_wm, planeb_wm, sr_entries);
 +      crtc = intel_get_crtc_for_plane(dev, plane);
 +      hdisplay = crtc->mode.hdisplay;
 +      htotal = crtc->mode.htotal;
 +      clock = crtc->mode.clock;
 +      pixel_size = crtc->fb->bits_per_pixel / 8;
 +
 +      line_time_us = (htotal * 1000) / clock;
 +      line_count = (latency_ns / line_time_us + 1000) / 1000;
 +      line_size = hdisplay * pixel_size;
 +
 +      /* Use the minimum of the small and large buffer method for primary */
 +      small = ((clock * pixel_size / 1000) * latency_ns) / 1000;
 +      large = line_count * line_size;
 +
 +      entries = DIV_ROUND_UP(min(small, large), display->cacheline_size);
 +      *display_wm = entries + display->guard_size;
 +
 +      /* calculate the self-refresh watermark for display cursor */
 +      entries = line_count * pixel_size * 64;
 +      entries = DIV_ROUND_UP(entries, cursor->cacheline_size);
 +      *cursor_wm = entries + cursor->guard_size;
 +
 +      return g4x_check_srwm(dev,
 +                            *display_wm, *cursor_wm,
 +                            display, cursor);
 +}
 +
 +static inline bool single_plane_enabled(unsigned int mask)
 +{
 +      return mask && (mask & -mask) == 0;
 +}
 +
 +static void g4x_update_wm(struct drm_device *dev)
 +{
 +      static const int sr_latency_ns = 12000;
 +      struct drm_i915_private *dev_priv = dev->dev_private;
 +      int planea_wm, planeb_wm, cursora_wm, cursorb_wm;
 +      int plane_sr, cursor_sr;
 +      unsigned int enabled = 0;
 +
 +      if (g4x_compute_wm0(dev, 0,
 +                          &g4x_wm_info, latency_ns,
 +                          &g4x_cursor_wm_info, latency_ns,
 +                          &planea_wm, &cursora_wm))
 +              enabled |= 1;
 +
 +      if (g4x_compute_wm0(dev, 1,
 +                          &g4x_wm_info, latency_ns,
 +                          &g4x_cursor_wm_info, latency_ns,
 +                          &planeb_wm, &cursorb_wm))
 +              enabled |= 2;
 +
 +      plane_sr = cursor_sr = 0;
 +      if (single_plane_enabled(enabled) &&
 +          g4x_compute_srwm(dev, ffs(enabled) - 1,
 +                           sr_latency_ns,
 +                           &g4x_wm_info,
 +                           &g4x_cursor_wm_info,
 +                           &plane_sr, &cursor_sr))
 +              I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN);
 +      else
 +              I915_WRITE(FW_BLC_SELF,
 +                         I915_READ(FW_BLC_SELF) & ~FW_BLC_SELF_EN);
  
 -      planea_wm &= 0x3f;
 -      planeb_wm &= 0x3f;
 +      DRM_DEBUG_KMS("Setting FIFO watermarks - A: plane=%d, cursor=%d, B: plane=%d, cursor=%d, SR: plane=%d, cursor=%d\n",
 +                    planea_wm, cursora_wm,
 +                    planeb_wm, cursorb_wm,
 +                    plane_sr, cursor_sr);
  
 -      I915_WRITE(DSPFW1, (sr_entries << DSPFW_SR_SHIFT) |
 +      I915_WRITE(DSPFW1,
 +                 (plane_sr << DSPFW_SR_SHIFT) |
                   (cursorb_wm << DSPFW_CURSORB_SHIFT) |
 -                 (planeb_wm << DSPFW_PLANEB_SHIFT) | planea_wm);
 -      I915_WRITE(DSPFW2, (I915_READ(DSPFW2) & DSPFW_CURSORA_MASK) |
 +                 (planeb_wm << DSPFW_PLANEB_SHIFT) |
 +                 planea_wm);
 +      I915_WRITE(DSPFW2,
 +                 (I915_READ(DSPFW2) & DSPFW_CURSORA_MASK) |
                   (cursora_wm << DSPFW_CURSORA_SHIFT));
        /* HPLL off in SR has some issues on G4x... disable it */
 -      I915_WRITE(DSPFW3, (I915_READ(DSPFW3) & ~DSPFW_HPLL_SR_EN) |
 +      I915_WRITE(DSPFW3,
 +                 (I915_READ(DSPFW3) & ~DSPFW_HPLL_SR_EN) |
                   (cursor_sr << DSPFW_CURSOR_SR_SHIFT));
  }
  
 -static void i965_update_wm(struct drm_device *dev, int planea_clock,
 -                         int planeb_clock, int sr_hdisplay, int sr_htotal,
 -                         int pixel_size)
 +static void i965_update_wm(struct drm_device *dev)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
 -      unsigned long line_time_us;
 -      int sr_clock, sr_entries, srwm = 1;
 +      struct drm_crtc *crtc;
 +      int srwm = 1;
        int cursor_sr = 16;
  
        /* Calc sr entries for one plane configs */
 -      if (sr_hdisplay && (!planea_clock || !planeb_clock)) {
 +      crtc = single_enabled_crtc(dev);
 +      if (crtc) {
                /* self-refresh has much higher latency */
                static const int sr_latency_ns = 12000;
 +              int clock = crtc->mode.clock;
 +              int htotal = crtc->mode.htotal;
 +              int hdisplay = crtc->mode.hdisplay;
 +              int pixel_size = crtc->fb->bits_per_pixel / 8;
 +              unsigned long line_time_us;
 +              int entries;
  
 -              sr_clock = planea_clock ? planea_clock : planeb_clock;
 -              line_time_us = ((sr_htotal * 1000) / sr_clock);
 +              line_time_us = ((htotal * 1000) / clock);
  
                /* Use ns/us then divide to preserve precision */
 -              sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
 -                      pixel_size * sr_hdisplay;
 -              sr_entries = DIV_ROUND_UP(sr_entries, I915_FIFO_LINE_SIZE);
 -              DRM_DEBUG("self-refresh entries: %d\n", sr_entries);
 -              srwm = I965_FIFO_SIZE - sr_entries;
 +              entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
 +                      pixel_size * hdisplay;
 +              entries = DIV_ROUND_UP(entries, I915_FIFO_LINE_SIZE);
 +              srwm = I965_FIFO_SIZE - entries;
                if (srwm < 0)
                        srwm = 1;
                srwm &= 0x1ff;
 +              DRM_DEBUG_KMS("self-refresh entries: %d, wm: %d\n",
 +                            entries, srwm);
  
 -              sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
 +              entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
                        pixel_size * 64;
 -              sr_entries = DIV_ROUND_UP(sr_entries,
 +              entries = DIV_ROUND_UP(entries,
                                          i965_cursor_wm_info.cacheline_size);
                cursor_sr = i965_cursor_wm_info.fifo_size -
 -                      (sr_entries + i965_cursor_wm_info.guard_size);
 +                      (entries + i965_cursor_wm_info.guard_size);
  
                if (cursor_sr > i965_cursor_wm_info.max_wm)
                        cursor_sr = i965_cursor_wm_info.max_wm;
                      srwm);
  
        /* 965 has limitations... */
 -      I915_WRITE(DSPFW1, (srwm << DSPFW_SR_SHIFT) | (8 << 16) | (8 << 8) |
 -                 (8 << 0));
 +      I915_WRITE(DSPFW1, (srwm << DSPFW_SR_SHIFT) |
 +                 (8 << 16) | (8 << 8) | (8 << 0));
        I915_WRITE(DSPFW2, (8 << 8) | (8 << 0));
        /* update cursor SR watermark */
        I915_WRITE(DSPFW3, (cursor_sr << DSPFW_CURSOR_SR_SHIFT));
  }
  
 -static void i9xx_update_wm(struct drm_device *dev, int planea_clock,
 -                         int planeb_clock, int sr_hdisplay, int sr_htotal,
 -                         int pixel_size)
 +static void i9xx_update_wm(struct drm_device *dev)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
 +      const struct intel_watermark_params *wm_info;
        uint32_t fwater_lo;
        uint32_t fwater_hi;
 -      int total_size, cacheline_size, cwm, srwm = 1;
 +      int cwm, srwm = 1;
 +      int fifo_size;
        int planea_wm, planeb_wm;
 -      struct intel_watermark_params planea_params, planeb_params;
 -      unsigned long line_time_us;
 -      int sr_clock, sr_entries = 0;
 +      struct drm_crtc *crtc, *enabled = NULL;
  
 -      /* Create copies of the base settings for each pipe */
 -      if (IS_CRESTLINE(dev) || IS_I945GM(dev))
 -              planea_params = planeb_params = i945_wm_info;
 +      if (IS_I945GM(dev))
 +              wm_info = &i945_wm_info;
        else if (!IS_GEN2(dev))
 -              planea_params = planeb_params = i915_wm_info;
 +              wm_info = &i915_wm_info;
        else
 -              planea_params = planeb_params = i855_wm_info;
 -
 -      /* Grab a couple of global values before we overwrite them */
 -      total_size = planea_params.fifo_size;
 -      cacheline_size = planea_params.cacheline_size;
 -
 -      /* Update per-plane FIFO sizes */
 -      planea_params.fifo_size = dev_priv->display.get_fifo_size(dev, 0);
 -      planeb_params.fifo_size = dev_priv->display.get_fifo_size(dev, 1);
 +              wm_info = &i855_wm_info;
 +
 +      fifo_size = dev_priv->display.get_fifo_size(dev, 0);
 +      crtc = intel_get_crtc_for_plane(dev, 0);
 +      if (crtc->enabled && crtc->fb) {
 +              planea_wm = intel_calculate_wm(crtc->mode.clock,
 +                                             wm_info, fifo_size,
 +                                             crtc->fb->bits_per_pixel / 8,
 +                                             latency_ns);
 +              enabled = crtc;
 +      } else
 +              planea_wm = fifo_size - wm_info->guard_size;
 +
 +      fifo_size = dev_priv->display.get_fifo_size(dev, 1);
 +      crtc = intel_get_crtc_for_plane(dev, 1);
 +      if (crtc->enabled && crtc->fb) {
 +              planeb_wm = intel_calculate_wm(crtc->mode.clock,
 +                                             wm_info, fifo_size,
 +                                             crtc->fb->bits_per_pixel / 8,
 +                                             latency_ns);
 +              if (enabled == NULL)
 +                      enabled = crtc;
 +              else
 +                      enabled = NULL;
 +      } else
 +              planeb_wm = fifo_size - wm_info->guard_size;
  
 -      planea_wm = intel_calculate_wm(planea_clock, &planea_params,
 -                                     pixel_size, latency_ns);
 -      planeb_wm = intel_calculate_wm(planeb_clock, &planeb_params,
 -                                     pixel_size, latency_ns);
        DRM_DEBUG_KMS("FIFO watermarks - A: %d, B: %d\n", planea_wm, planeb_wm);
  
        /*
         */
        cwm = 2;
  
 +      /* Play safe and disable self-refresh before adjusting watermarks. */
 +      if (IS_I945G(dev) || IS_I945GM(dev))
 +              I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN_MASK | 0);
 +      else if (IS_I915GM(dev))
 +              I915_WRITE(INSTPM, I915_READ(INSTPM) & ~INSTPM_SELF_EN);
 +
        /* Calc sr entries for one plane configs */
 -      if (HAS_FW_BLC(dev) && sr_hdisplay &&
 -          (!planea_clock || !planeb_clock)) {
 +      if (HAS_FW_BLC(dev) && enabled) {
                /* self-refresh has much higher latency */
                static const int sr_latency_ns = 6000;
 +              int clock = enabled->mode.clock;
 +              int htotal = enabled->mode.htotal;
 +              int hdisplay = enabled->mode.hdisplay;
 +              int pixel_size = enabled->fb->bits_per_pixel / 8;
 +              unsigned long line_time_us;
 +              int entries;
  
 -              sr_clock = planea_clock ? planea_clock : planeb_clock;
 -              line_time_us = ((sr_htotal * 1000) / sr_clock);
 +              line_time_us = (htotal * 1000) / clock;
  
                /* Use ns/us then divide to preserve precision */
 -              sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
 -                      pixel_size * sr_hdisplay;
 -              sr_entries = DIV_ROUND_UP(sr_entries, cacheline_size);
 -              DRM_DEBUG_KMS("self-refresh entries: %d\n", sr_entries);
 -              srwm = total_size - sr_entries;
 +              entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
 +                      pixel_size * hdisplay;
 +              entries = DIV_ROUND_UP(entries, wm_info->cacheline_size);
 +              DRM_DEBUG_KMS("self-refresh entries: %d\n", entries);
 +              srwm = wm_info->fifo_size - entries;
                if (srwm < 0)
                        srwm = 1;
  
                if (IS_I945G(dev) || IS_I945GM(dev))
 -                      I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_FIFO_MASK | (srwm & 0xff));
 -              else if (IS_I915GM(dev)) {
 -                      /* 915M has a smaller SRWM field */
 +                      I915_WRITE(FW_BLC_SELF,
 +                                 FW_BLC_SELF_FIFO_MASK | (srwm & 0xff));
 +              else if (IS_I915GM(dev))
                        I915_WRITE(FW_BLC_SELF, srwm & 0x3f);
 -                      I915_WRITE(INSTPM, I915_READ(INSTPM) | INSTPM_SELF_EN);
 -              }
 -      } else {
 -              /* Turn off self refresh if both pipes are enabled */
 -              if (IS_I945G(dev) || IS_I945GM(dev)) {
 -                      I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF)
 -                                 & ~FW_BLC_SELF_EN);
 -              } else if (IS_I915GM(dev)) {
 -                      I915_WRITE(INSTPM, I915_READ(INSTPM) & ~INSTPM_SELF_EN);
 -              }
        }
  
        DRM_DEBUG_KMS("Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n",
  
        I915_WRITE(FW_BLC, fwater_lo);
        I915_WRITE(FW_BLC2, fwater_hi);
 +
 +      if (HAS_FW_BLC(dev)) {
 +              if (enabled) {
 +                      if (IS_I945G(dev) || IS_I945GM(dev))
 +                              I915_WRITE(FW_BLC_SELF,
 +                                         FW_BLC_SELF_EN_MASK | FW_BLC_SELF_EN);
 +                      else if (IS_I915GM(dev))
 +                              I915_WRITE(INSTPM, I915_READ(INSTPM) | INSTPM_SELF_EN);
 +                      DRM_DEBUG_KMS("memory self refresh enabled\n");
 +              } else
 +                      DRM_DEBUG_KMS("memory self refresh disabled\n");
 +      }
  }
  
 -static void i830_update_wm(struct drm_device *dev, int planea_clock, int unused,
 -                         int unused2, int unused3, int pixel_size)
 +static void i830_update_wm(struct drm_device *dev)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
 -      uint32_t fwater_lo = I915_READ(FW_BLC) & ~0xfff;
 +      struct drm_crtc *crtc;
 +      uint32_t fwater_lo;
        int planea_wm;
  
 -      i830_wm_info.fifo_size = dev_priv->display.get_fifo_size(dev, 0);
 +      crtc = single_enabled_crtc(dev);
 +      if (crtc == NULL)
 +              return;
  
 -      planea_wm = intel_calculate_wm(planea_clock, &i830_wm_info,
 -                                     pixel_size, latency_ns);
 +      planea_wm = intel_calculate_wm(crtc->mode.clock, &i830_wm_info,
 +                                     dev_priv->display.get_fifo_size(dev, 0),
 +                                     crtc->fb->bits_per_pixel / 8,
 +                                     latency_ns);
 +      fwater_lo = I915_READ(FW_BLC) & ~0xfff;
        fwater_lo |= (3<<8) | planea_wm;
  
        DRM_DEBUG_KMS("Setting FIFO watermarks - A: %d\n", planea_wm);
@@@ -4231,15 -3534,15 +4231,15 @@@ static bool ironlake_check_srwm(struct 
  /*
   * Compute watermark values of WM[1-3],
   */
 -static bool ironlake_compute_srwm(struct drm_device *dev, int level,
 -                                int hdisplay, int htotal,
 -                                int pixel_size, int clock, int latency_ns,
 +static bool ironlake_compute_srwm(struct drm_device *dev, int level, int plane,
 +                                int latency_ns,
                                  const struct intel_watermark_params *display,
                                  const struct intel_watermark_params *cursor,
                                  int *fbc_wm, int *display_wm, int *cursor_wm)
  {
 -
 +      struct drm_crtc *crtc;
        unsigned long line_time_us;
 +      int hdisplay, htotal, pixel_size, clock;
        int line_count, line_size;
        int small, large;
        int entries;
                return false;
        }
  
 +      crtc = intel_get_crtc_for_plane(dev, plane);
 +      hdisplay = crtc->mode.hdisplay;
 +      htotal = crtc->mode.htotal;
 +      clock = crtc->mode.clock;
 +      pixel_size = crtc->fb->bits_per_pixel / 8;
 +
        line_time_us = (htotal * 1000) / clock;
        line_count = (latency_ns / line_time_us + 1000) / 1000;
        line_size = hdisplay * pixel_size;
                                   display, cursor);
  }
  
 -static void ironlake_update_wm(struct drm_device *dev,
 -                             int planea_clock, int planeb_clock,
 -                             int hdisplay, int htotal,
 -                             int pixel_size)
 +static void ironlake_update_wm(struct drm_device *dev)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
 -      int fbc_wm, plane_wm, cursor_wm, enabled;
 -      int clock;
 +      int fbc_wm, plane_wm, cursor_wm;
 +      unsigned int enabled;
  
        enabled = 0;
        if (ironlake_compute_wm0(dev, 0,
                DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
                              " plane %d, " "cursor: %d\n",
                              plane_wm, cursor_wm);
 -              enabled++;
 +              enabled |= 1;
        }
  
        if (ironlake_compute_wm0(dev, 1,
                DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
                              " plane %d, cursor: %d\n",
                              plane_wm, cursor_wm);
 -              enabled++;
 +              enabled |= 2;
        }
  
        /*
        I915_WRITE(WM2_LP_ILK, 0);
        I915_WRITE(WM1_LP_ILK, 0);
  
 -      if (enabled != 1)
 +      if (!single_plane_enabled(enabled))
                return;
 -
 -      clock = planea_clock ? planea_clock : planeb_clock;
 +      enabled = ffs(enabled) - 1;
  
        /* WM1 */
 -      if (!ironlake_compute_srwm(dev, 1, hdisplay, htotal, pixel_size,
 -                                 clock, ILK_READ_WM1_LATENCY() * 500,
 +      if (!ironlake_compute_srwm(dev, 1, enabled,
 +                                 ILK_READ_WM1_LATENCY() * 500,
                                   &ironlake_display_srwm_info,
                                   &ironlake_cursor_srwm_info,
                                   &fbc_wm, &plane_wm, &cursor_wm))
                   cursor_wm);
  
        /* WM2 */
 -      if (!ironlake_compute_srwm(dev, 2, hdisplay, htotal, pixel_size,
 -                                 clock, ILK_READ_WM2_LATENCY() * 500,
 +      if (!ironlake_compute_srwm(dev, 2, enabled,
 +                                 ILK_READ_WM2_LATENCY() * 500,
                                   &ironlake_display_srwm_info,
                                   &ironlake_cursor_srwm_info,
                                   &fbc_wm, &plane_wm, &cursor_wm))
         */
  }
  
 -static void sandybridge_update_wm(struct drm_device *dev,
 -                             int planea_clock, int planeb_clock,
 -                             int hdisplay, int htotal,
 -                             int pixel_size)
 +static void sandybridge_update_wm(struct drm_device *dev)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
        int latency = SNB_READ_WM0_LATENCY() * 100;     /* In unit 0.1us */
 -      int fbc_wm, plane_wm, cursor_wm, enabled;
 -      int clock;
 +      int fbc_wm, plane_wm, cursor_wm;
 +      unsigned int enabled;
  
        enabled = 0;
        if (ironlake_compute_wm0(dev, 0,
                DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
                              " plane %d, " "cursor: %d\n",
                              plane_wm, cursor_wm);
 -              enabled++;
 +              enabled |= 1;
        }
  
        if (ironlake_compute_wm0(dev, 1,
                DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
                              " plane %d, cursor: %d\n",
                              plane_wm, cursor_wm);
 -              enabled++;
 +              enabled |= 2;
        }
  
        /*
        I915_WRITE(WM2_LP_ILK, 0);
        I915_WRITE(WM1_LP_ILK, 0);
  
 -      if (enabled != 1)
 +      if (!single_plane_enabled(enabled))
                return;
 -
 -      clock = planea_clock ? planea_clock : planeb_clock;
 +      enabled = ffs(enabled) - 1;
  
        /* WM1 */
 -      if (!ironlake_compute_srwm(dev, 1, hdisplay, htotal, pixel_size,
 -                                 clock, SNB_READ_WM1_LATENCY() * 500,
 +      if (!ironlake_compute_srwm(dev, 1, enabled,
 +                                 SNB_READ_WM1_LATENCY() * 500,
                                   &sandybridge_display_srwm_info,
                                   &sandybridge_cursor_srwm_info,
                                   &fbc_wm, &plane_wm, &cursor_wm))
                   cursor_wm);
  
        /* WM2 */
 -      if (!ironlake_compute_srwm(dev, 2,
 -                                 hdisplay, htotal, pixel_size,
 -                                 clock, SNB_READ_WM2_LATENCY() * 500,
 +      if (!ironlake_compute_srwm(dev, 2, enabled,
 +                                 SNB_READ_WM2_LATENCY() * 500,
                                   &sandybridge_display_srwm_info,
                                   &sandybridge_cursor_srwm_info,
                                   &fbc_wm, &plane_wm, &cursor_wm))
                   cursor_wm);
  
        /* WM3 */
 -      if (!ironlake_compute_srwm(dev, 3,
 -                                 hdisplay, htotal, pixel_size,
 -                                 clock, SNB_READ_WM3_LATENCY() * 500,
 +      if (!ironlake_compute_srwm(dev, 3, enabled,
 +                                 SNB_READ_WM3_LATENCY() * 500,
                                   &sandybridge_display_srwm_info,
                                   &sandybridge_cursor_srwm_info,
                                   &fbc_wm, &plane_wm, &cursor_wm))
  static void intel_update_watermarks(struct drm_device *dev)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
 +
 +      if (dev_priv->display.update_wm)
 +              dev_priv->display.update_wm(dev);
 +}
 +
 +static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
 +{
 +      return dev_priv->lvds_use_ssc && i915_panel_use_ssc;
 +}
 +
 +static void intel_update_dref(struct drm_i915_private *dev_priv)
 +{
 +      struct drm_device *dev = dev_priv->dev;
 +      struct drm_mode_config *mode_config = &dev->mode_config;
 +      struct intel_encoder *encoder;
        struct drm_crtc *crtc;
 -      int sr_hdisplay = 0;
 -      unsigned long planea_clock = 0, planeb_clock = 0, sr_clock = 0;
 -      int enabled = 0, pixel_size = 0;
 -      int sr_htotal = 0;
 +      u32 temp;
 +      bool lvds_on = false, edp_on = false, pch_edp_on = false, other_on = false;
  
 -      if (!dev_priv->display.update_wm)
 -              return;
 +      list_for_each_entry(encoder, &mode_config->encoder_list, base.head) {
 +              crtc = encoder->base.crtc;
  
 -      /* Get the clock config from both planes */
 -      list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 -              struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 -              if (intel_crtc->active) {
 -                      enabled++;
 -                      if (intel_crtc->plane == 0) {
 -                              DRM_DEBUG_KMS("plane A (pipe %d) clock: %d\n",
 -                                            intel_crtc->pipe, crtc->mode.clock);
 -                              planea_clock = crtc->mode.clock;
 +              if (!crtc || !crtc->enabled)
 +                      continue;
 +
 +              switch (encoder->type) {
 +              case INTEL_OUTPUT_LVDS:
 +                      lvds_on = true;
 +                      break;
 +              case INTEL_OUTPUT_EDP:
 +                      edp_on = true;
 +                      if (!pch_edp_on)
 +                              pch_edp_on = intel_encoder_is_pch_edp(&encoder->base);
 +                      break;
 +              default:
 +                      other_on = true;
 +                      break;
 +              }
 +      }
 +
 +      /*XXX BIOS treats 16:31 as a mask for 0:15 */
 +
 +      temp = I915_READ(PCH_DREF_CONTROL);
 +
 +      /* First clear the current state for output switching */
 +      temp &= ~DREF_SSC1_ENABLE;
 +      temp &= ~DREF_SSC4_ENABLE;
 +      temp &= ~DREF_SUPERSPREAD_SOURCE_MASK;
 +      temp &= ~DREF_NONSPREAD_SOURCE_MASK;
 +      temp &= ~DREF_SSC_SOURCE_MASK;
 +      temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
 +      I915_WRITE(PCH_DREF_CONTROL, temp);
 +
 +      POSTING_READ(PCH_DREF_CONTROL);
 +      udelay(200);
 +
 +      if ((lvds_on || edp_on) && intel_panel_use_ssc(dev_priv)) {
 +              temp |= DREF_SSC_SOURCE_ENABLE;
 +              if (edp_on) {
 +                      if (!pch_edp_on) {
 +                              /* Enable CPU source on CPU attached eDP */
 +                              temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
                        } else {
 -                              DRM_DEBUG_KMS("plane B (pipe %d) clock: %d\n",
 -                                            intel_crtc->pipe, crtc->mode.clock);
 -                              planeb_clock = crtc->mode.clock;
 +                              /* Enable SSC on PCH eDP if needed */
 +                              temp |= DREF_SUPERSPREAD_SOURCE_ENABLE;
                        }
 -                      sr_hdisplay = crtc->mode.hdisplay;
 -                      sr_clock = crtc->mode.clock;
 -                      sr_htotal = crtc->mode.htotal;
 -                      if (crtc->fb)
 -                              pixel_size = crtc->fb->bits_per_pixel / 8;
 -                      else
 -                              pixel_size = 4; /* by default */
 +                      I915_WRITE(PCH_DREF_CONTROL, temp);
                }
 +              if (!dev_priv->display_clock_mode)
 +                      temp |= DREF_SSC1_ENABLE;
        }
  
 -      if (enabled <= 0)
 -              return;
 -
 -      dev_priv->display.update_wm(dev, planea_clock, planeb_clock,
 -                                  sr_hdisplay, sr_htotal, pixel_size);
 -}
 +      if (other_on && dev_priv->display_clock_mode)
 +              temp |= DREF_NONSPREAD_CK505_ENABLE;
 +      else if (other_on) {
 +              temp |= DREF_NONSPREAD_SOURCE_ENABLE;
 +              if (edp_on && !pch_edp_on)
 +                      temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
 +      }
  
 -static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
 -{
 -      return dev_priv->lvds_use_ssc && i915_panel_use_ssc;
 +      I915_WRITE(PCH_DREF_CONTROL, temp);
 +      POSTING_READ(PCH_DREF_CONTROL);
 +      udelay(200);
  }
  
  static int intel_crtc_mode_set(struct drm_crtc *crtc,
        int ret;
        struct fdi_m_n m_n = {0};
        u32 reg, temp;
 +      u32 lvds_sync = 0;
        int target_clock;
  
        drm_vblank_pre_modeset(dev, pipe);
         * PCH B stepping, previous chipset stepping should be
         * ignoring this setting.
         */
 -      if (HAS_PCH_SPLIT(dev)) {
 -              temp = I915_READ(PCH_DREF_CONTROL);
 -              /* Always enable nonspread source */
 -              temp &= ~DREF_NONSPREAD_SOURCE_MASK;
 -              temp |= DREF_NONSPREAD_SOURCE_ENABLE;
 -              temp &= ~DREF_SSC_SOURCE_MASK;
 -              temp |= DREF_SSC_SOURCE_ENABLE;
 -              I915_WRITE(PCH_DREF_CONTROL, temp);
 -
 -              POSTING_READ(PCH_DREF_CONTROL);
 -              udelay(200);
 -
 -              if (has_edp_encoder) {
 -                      if (intel_panel_use_ssc(dev_priv)) {
 -                              temp |= DREF_SSC1_ENABLE;
 -                              I915_WRITE(PCH_DREF_CONTROL, temp);
 -
 -                              POSTING_READ(PCH_DREF_CONTROL);
 -                              udelay(200);
 -                      }
 -                      temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
 -
 -                      /* Enable CPU source on CPU attached eDP */
 -                      if (!intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
 -                              if (intel_panel_use_ssc(dev_priv))
 -                                      temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
 -                              else
 -                                      temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
 -                      } else {
 -                              /* Enable SSC on PCH eDP if needed */
 -                              if (intel_panel_use_ssc(dev_priv)) {
 -                                      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);
 -              }
 -      }
 +      if (HAS_PCH_SPLIT(dev))
 +              intel_update_dref(dev_priv);
  
        if (IS_PINEVIEW(dev)) {
                fp = (1 << clock.n) << 16 | clock.m1 << 8 | clock.m2;
                        pipeconf &= ~PIPECONF_DOUBLE_WIDE;
        }
  
 -      dspcntr |= DISPLAY_PLANE_ENABLE;
 -      pipeconf |= PIPECONF_ENABLE;
 -      dpll |= DPLL_VCO_ENABLE;
 +      if (!HAS_PCH_SPLIT(dev))
 +              dpll |= DPLL_VCO_ENABLE;
  
        DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
        drm_mode_debug_printmodeline(mode);
        /* enable transcoder DPLL */
        if (HAS_PCH_CPT(dev)) {
                temp = I915_READ(PCH_DPLL_SEL);
 -              if (pipe == 0)
 +              switch (pipe) {
 +              case 0:
                        temp |= TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL;
 -              else
 +                      break;
 +              case 1:
                        temp |= TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL;
 +                      break;
 +              case 2:
 +                      /* FIXME: manage transcoder PLLs? */
 +                      temp |= TRANSC_DPLL_ENABLE | TRANSC_DPLLB_SEL;
 +                      break;
 +              default:
 +                      BUG();
 +              }
                I915_WRITE(PCH_DPLL_SEL, temp);
  
                POSTING_READ(PCH_DPLL_SEL);
                        else
                                temp &= ~LVDS_ENABLE_DITHER;
                }
 +              if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC)
 +                      lvds_sync |= LVDS_HSYNC_POLARITY;
 +              if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC)
 +                      lvds_sync |= LVDS_VSYNC_POLARITY;
 +              if ((temp & (LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY))
 +                  != lvds_sync) {
 +                      char flags[2] = "-+";
 +                      DRM_INFO("Changing LVDS panel from "
 +                               "(%chsync, %cvsync) to (%chsync, %cvsync)\n",
 +                               flags[!(temp & LVDS_HSYNC_POLARITY)],
 +                               flags[!(temp & LVDS_VSYNC_POLARITY)],
 +                               flags[!(lvds_sync & LVDS_HSYNC_POLARITY)],
 +                               flags[!(lvds_sync & LVDS_VSYNC_POLARITY)]);
 +                      temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY);
 +                      temp |= lvds_sync;
 +              }
                I915_WRITE(reg, temp);
        }
  
                intel_dp_set_m_n(crtc, mode, adjusted_mode);
        } 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);
 -                      I915_WRITE(TRANSA_DATA_N1, 0);
 -                      I915_WRITE(TRANSA_DP_LINK_M1, 0);
 -                      I915_WRITE(TRANSA_DP_LINK_N1, 0);
 -              } else {
 -                      I915_WRITE(TRANSB_DATA_M1, 0);
 -                      I915_WRITE(TRANSB_DATA_N1, 0);
 -                      I915_WRITE(TRANSB_DP_LINK_M1, 0);
 -                      I915_WRITE(TRANSB_DP_LINK_N1, 0);
 -              }
 +              I915_WRITE(TRANSDATA_M1(pipe), 0);
 +              I915_WRITE(TRANSDATA_N1(pipe), 0);
 +              I915_WRITE(TRANSDPLINK_M1(pipe), 0);
 +              I915_WRITE(TRANSDPLINK_N1(pipe), 0);
        }
  
        if (!has_edp_encoder || intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
  
        I915_WRITE(PIPECONF(pipe), pipeconf);
        POSTING_READ(PIPECONF(pipe));
 +      if (!HAS_PCH_SPLIT(dev))
 +              intel_enable_pipe(dev_priv, pipe, false);
  
        intel_wait_for_vblank(dev, pipe);
  
        }
  
        I915_WRITE(DSPCNTR(plane), dspcntr);
 +      POSTING_READ(DSPCNTR(plane));
 +      if (!HAS_PCH_SPLIT(dev))
 +              intel_enable_plane(dev_priv, plane, pipe);
  
        ret = intel_pipe_set_base(crtc, x, y, old_fb);
  
@@@ -5199,7 -4480,7 +5199,7 @@@ void intel_crtc_load_lut(struct drm_crt
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 -      int palreg = (intel_crtc->pipe == 0) ? PALETTE_A : PALETTE_B;
 +      int palreg = PALETTE(intel_crtc->pipe);
        int i;
  
        /* The clocks have to be on to load the palette. */
  
        /* use legacy palette for Ironlake */
        if (HAS_PCH_SPLIT(dev))
 -              palreg = (intel_crtc->pipe == 0) ? LGC_PALETTE_A :
 -                                                 LGC_PALETTE_B;
 +              palreg = LGC_PALETTE(intel_crtc->pipe);
  
        for (i = 0; i < 256; i++) {
                I915_WRITE(palreg + 4 * i,
@@@ -5229,12 -4511,12 +5229,12 @@@ static void i845_update_cursor(struct d
        if (intel_crtc->cursor_visible == visible)
                return;
  
 -      cntl = I915_READ(CURACNTR);
 +      cntl = I915_READ(_CURACNTR);
        if (visible) {
                /* On these chipsets we can only modify the base whilst
                 * the cursor is disabled.
                 */
 -              I915_WRITE(CURABASE, base);
 +              I915_WRITE(_CURABASE, base);
  
                cntl &= ~(CURSOR_FORMAT_MASK);
                /* XXX width must be 64, stride 256 => 0x00 << 28 */
                        CURSOR_FORMAT_ARGB;
        } else
                cntl &= ~(CURSOR_ENABLE | CURSOR_GAMMA_ENABLE);
 -      I915_WRITE(CURACNTR, cntl);
 +      I915_WRITE(_CURACNTR, cntl);
  
        intel_crtc->cursor_visible = visible;
  }
@@@ -5257,7 -4539,7 +5257,7 @@@ static void i9xx_update_cursor(struct d
        bool visible = base != 0;
  
        if (intel_crtc->cursor_visible != visible) {
 -              uint32_t cntl = I915_READ(pipe == 0 ? CURACNTR : CURBCNTR);
 +              uint32_t cntl = CURCNTR(pipe);
                if (base) {
                        cntl &= ~(CURSOR_MODE | MCURSOR_PIPE_SELECT);
                        cntl |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE;
                        cntl &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE);
                        cntl |= CURSOR_MODE_DISABLE;
                }
 -              I915_WRITE(pipe == 0 ? CURACNTR : CURBCNTR, cntl);
 +              I915_WRITE(CURCNTR(pipe), cntl);
  
                intel_crtc->cursor_visible = visible;
        }
        /* and commit changes on next vblank */
 -      I915_WRITE(pipe == 0 ? CURABASE : CURBBASE, base);
 +      I915_WRITE(CURBASE(pipe), base);
  }
  
  /* If no-part of the cursor is visible on the framebuffer, then the GPU may hang... */
@@@ -5321,7 -4603,7 +5321,7 @@@ static void intel_crtc_update_cursor(st
        if (!visible && !intel_crtc->cursor_visible)
                return;
  
 -      I915_WRITE(pipe == 0 ? CURAPOS : CURBPOS, pos);
 +      I915_WRITE(CURPOS(pipe), pos);
        if (IS_845G(dev) || IS_I865G(dev))
                i845_update_cursor(crtc, base);
        else
@@@ -5627,14 -4909,14 +5627,14 @@@ static int intel_crtc_clock_get(struct 
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe;
 -      u32 dpll = I915_READ((pipe == 0) ? DPLL_A : DPLL_B);
 +      u32 dpll = DPLL(pipe);
        u32 fp;
        intel_clock_t clock;
  
        if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0)
 -              fp = I915_READ((pipe == 0) ? FPA0 : FPB0);
 +              fp = FP0(pipe);
        else
 -              fp = I915_READ((pipe == 0) ? FPA1 : FPB1);
 +              fp = FP1(pipe);
  
        clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT;
        if (IS_PINEVIEW(dev)) {
  struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
                                             struct drm_crtc *crtc)
  {
 -      struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe;
        struct drm_display_mode *mode;
 -      int htot = I915_READ((pipe == 0) ? HTOTAL_A : HTOTAL_B);
 -      int hsync = I915_READ((pipe == 0) ? HSYNC_A : HSYNC_B);
 -      int vtot = I915_READ((pipe == 0) ? VTOTAL_A : VTOTAL_B);
 -      int vsync = I915_READ((pipe == 0) ? VSYNC_A : VSYNC_B);
 +      int htot = HTOTAL(pipe);
 +      int hsync = HSYNC(pipe);
 +      int vtot = VTOTAL(pipe);
 +      int vsync = VSYNC(pipe);
  
        mode = kzalloc(sizeof(*mode), GFP_KERNEL);
        if (!mode)
@@@ -5827,7 -5110,7 +5827,7 @@@ static void intel_decrease_pllclock(str
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe;
 -      int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
 +      int dpll_reg = DPLL(pipe);
        int dpll = I915_READ(dpll_reg);
  
        if (HAS_PCH_SPLIT(dev))
@@@ -5875,6 -5158,7 +5875,6 @@@ static void intel_idle_update(struct wo
        struct drm_device *dev = dev_priv->dev;
        struct drm_crtc *crtc;
        struct intel_crtc *intel_crtc;
 -      int enabled = 0;
  
        if (!i915_powersave)
                return;
                if (!crtc->fb)
                        continue;
  
 -              enabled++;
                intel_crtc = to_intel_crtc(crtc);
                if (!intel_crtc->busy)
                        intel_decrease_pllclock(crtc);
        }
  
 -      if ((enabled == 1) && (IS_I945G(dev) || IS_I945GM(dev))) {
 -              DRM_DEBUG_DRIVER("enable memory self refresh on 945\n");
 -              I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN_MASK | FW_BLC_SELF_EN);
 -      }
  
        mutex_unlock(&dev->struct_mutex);
  }
@@@ -5917,9 -5206,17 +5917,9 @@@ void intel_mark_busy(struct drm_device 
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                return;
  
 -      if (!dev_priv->busy) {
 -              if (IS_I945G(dev) || IS_I945GM(dev)) {
 -                      u32 fw_blc_self;
 -
 -                      DRM_DEBUG_DRIVER("disable memory self refresh on 945\n");
 -                      fw_blc_self = I915_READ(FW_BLC_SELF);
 -                      fw_blc_self &= ~FW_BLC_SELF_EN;
 -                      I915_WRITE(FW_BLC_SELF, fw_blc_self | FW_BLC_SELF_EN_MASK);
 -              }
 +      if (!dev_priv->busy)
                dev_priv->busy = true;
 -      else
 +      else
                mod_timer(&dev_priv->idle_timer, jiffies +
                          msecs_to_jiffies(GPU_IDLE_TIMEOUT));
  
                intel_fb = to_intel_framebuffer(crtc->fb);
                if (intel_fb->obj == obj) {
                        if (!intel_crtc->busy) {
 -                              if (IS_I945G(dev) || IS_I945GM(dev)) {
 -                                      u32 fw_blc_self;
 -
 -                                      DRM_DEBUG_DRIVER("disable memory self refresh on 945\n");
 -                                      fw_blc_self = I915_READ(FW_BLC_SELF);
 -                                      fw_blc_self &= ~FW_BLC_SELF_EN;
 -                                      I915_WRITE(FW_BLC_SELF, fw_blc_self | FW_BLC_SELF_EN_MASK);
 -                              }
                                /* Non-busy -> busy, upclock */
                                intel_increase_pllclock(crtc);
                                intel_crtc->busy = true;
@@@ -6208,7 -5513,7 +6208,7 @@@ static int intel_crtc_page_flip(struct 
                 * pf = I915_READ(pipe == 0 ? PFA_CTL_1 : PFB_CTL_1) & PF_ENABLE;
                 */
                pf = 0;
 -              pipesrc = I915_READ(pipe == 0 ? PIPEASRC : PIPEBSRC) & 0x0fff0fff;
 +              pipesrc = I915_READ(PIPESRC(pipe)) & 0x0fff0fff;
                OUT_RING(pf | pipesrc);
                break;
  
                OUT_RING(fb->pitch | obj->tiling_mode);
                OUT_RING(obj->gtt_offset);
  
 -              pf = I915_READ(pipe == 0 ? PFA_CTL_1 : PFB_CTL_1) & PF_ENABLE;
 -              pipesrc = I915_READ(pipe == 0 ? PIPEASRC : PIPEBSRC) & 0x0fff0fff;
 +              pf = I915_READ(PF_CTL(pipe)) & PF_ENABLE;
 +              pipesrc = I915_READ(PIPESRC(pipe)) & 0x0fff0fff;
                OUT_RING(pf | pipesrc);
                break;
        }
@@@ -6253,9 -5558,7 +6253,7 @@@ static void intel_crtc_reset(struct drm
        /* Reset flags back to the 'unknown' status so that they
         * will be correctly set on the initial modeset.
         */
-       intel_crtc->cursor_addr = 0;
        intel_crtc->dpms_mode = -1;
-       intel_crtc->active = true; /* force the pipe off on setup_init_config */
  }
  
  static struct drm_crtc_helper_funcs intel_helper_funcs = {
@@@ -6310,8 -5613,22 +6308,8 @@@ static void intel_sanitize_modesetting(
        pipe = !pipe;
  
        /* Disable the plane and wait for it to stop reading from the pipe. */
 -      I915_WRITE(reg, val & ~DISPLAY_PLANE_ENABLE);
 -      intel_flush_display_plane(dev, plane);
 -
 -      if (IS_GEN2(dev))
 -              intel_wait_for_vblank(dev, pipe);
 -
 -      if (pipe == 0 && (dev_priv->quirks & QUIRK_PIPEA_FORCE))
 -              return;
 -
 -      /* Switch off the pipe. */
 -      reg = PIPECONF(pipe);
 -      val = I915_READ(reg);
 -      if (val & PIPECONF_ENABLE) {
 -              I915_WRITE(reg, val & ~PIPECONF_ENABLE);
 -              intel_wait_for_pipe_off(dev, pipe);
 -      }
 +      intel_disable_plane(dev_priv, plane, pipe);
 +      intel_disable_pipe(dev_priv, pipe);
  }
  
  static void intel_crtc_init(struct drm_device *dev, int pipe)
        dev_priv->pipe_to_crtc_mapping[intel_crtc->pipe] = &intel_crtc->base;
  
        intel_crtc_reset(&intel_crtc->base);
+       intel_crtc->active = true; /* force the pipe off on setup_init_config */
  
        if (HAS_PCH_SPLIT(dev)) {
                intel_helper_funcs.prepare = ironlake_crtc_prepare;
@@@ -6922,18 -6240,18 +6921,18 @@@ void gen6_enable_rps(struct drm_i915_pr
        I915_WRITE(GEN6_RP_INTERRUPT_LIMITS,
                   18 << 24 |
                   6 << 16);
 -      I915_WRITE(GEN6_RP_UP_THRESHOLD, 90000);
 -      I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 100000);
 +      I915_WRITE(GEN6_RP_UP_THRESHOLD, 10000);
 +      I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 1000000);
        I915_WRITE(GEN6_RP_UP_EI, 100000);
 -      I915_WRITE(GEN6_RP_DOWN_EI, 300000);
 +      I915_WRITE(GEN6_RP_DOWN_EI, 5000000);
        I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10);
        I915_WRITE(GEN6_RP_CONTROL,
                   GEN6_RP_MEDIA_TURBO |
                   GEN6_RP_USE_NORMAL_FREQ |
                   GEN6_RP_MEDIA_IS_GFX |
                   GEN6_RP_ENABLE |
 -                 GEN6_RP_UP_BUSY_MAX |
 -                 GEN6_RP_DOWN_BUSY_MIN);
 +                 GEN6_RP_UP_BUSY_AVG |
 +                 GEN6_RP_DOWN_IDLE_CONT);
  
        if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
                     500))
  void intel_enable_clock_gating(struct drm_device *dev)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
 +      int pipe;
  
        /*
         * Disable clock gating reported to work incorrectly according to the
                                   ILK_DPARB_CLK_GATE  |
                                   ILK_DPFD_CLK_GATE);
  
 -                      I915_WRITE(DSPACNTR,
 -                                 I915_READ(DSPACNTR) |
 -                                 DISPPLANE_TRICKLE_FEED_DISABLE);
 -                      I915_WRITE(DSPBCNTR,
 -                                 I915_READ(DSPBCNTR) |
 -                                 DISPPLANE_TRICKLE_FEED_DISABLE);
 +                      for_each_pipe(pipe)
 +                              I915_WRITE(DSPCNTR(pipe),
 +                                         I915_READ(DSPCNTR(pipe)) |
 +                                         DISPPLANE_TRICKLE_FEED_DISABLE);
                }
        } else if (IS_G4X(dev)) {
                uint32_t dspclk_gate;
        }
  }
  
void intel_disable_clock_gating(struct drm_device *dev)
static void ironlake_teardown_rc6(struct drm_device *dev)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
  
        if (dev_priv->renderctx) {
-               struct drm_i915_gem_object *obj = dev_priv->renderctx;
-               I915_WRITE(CCID, 0);
-               POSTING_READ(CCID);
-               i915_gem_object_unpin(obj);
-               drm_gem_object_unreference(&obj->base);
+               i915_gem_object_unpin(dev_priv->renderctx);
+               drm_gem_object_unreference(&dev_priv->renderctx->base);
                dev_priv->renderctx = NULL;
        }
  
        if (dev_priv->pwrctx) {
-               struct drm_i915_gem_object *obj = dev_priv->pwrctx;
+               i915_gem_object_unpin(dev_priv->pwrctx);
+               drm_gem_object_unreference(&dev_priv->pwrctx->base);
+               dev_priv->pwrctx = NULL;
+       }
+ }
+ static void ironlake_disable_rc6(struct drm_device *dev)
+ {
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       if (I915_READ(PWRCTXA)) {
+               /* Wake the GPU, prevent RC6, then restore RSTDBYCTL */
+               I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) | RCX_SW_EXIT);
+               wait_for(((I915_READ(RSTDBYCTL) & RSX_STATUS_MASK) == RSX_STATUS_ON),
+                        50);
  
                I915_WRITE(PWRCTXA, 0);
                POSTING_READ(PWRCTXA);
  
-               i915_gem_object_unpin(obj);
-               drm_gem_object_unreference(&obj->base);
-               dev_priv->pwrctx = NULL;
+               I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT);
+               POSTING_READ(RSTDBYCTL);
        }
+       ironlake_disable_rc6(dev);
  }
  
- static void ironlake_disable_rc6(struct drm_device *dev)
+ static int ironlake_setup_rc6(struct drm_device *dev)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
  
-       /* Wake the GPU, prevent RC6, then restore RSTDBYCTL */
-       I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) | RCX_SW_EXIT);
-       wait_for(((I915_READ(RSTDBYCTL) & RSX_STATUS_MASK) == RSX_STATUS_ON),
-                10);
-       POSTING_READ(CCID);
-       I915_WRITE(PWRCTXA, 0);
-       POSTING_READ(PWRCTXA);
-       I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT);
-       POSTING_READ(RSTDBYCTL);
-       i915_gem_object_unpin(dev_priv->renderctx);
-       drm_gem_object_unreference(&dev_priv->renderctx->base);
-       dev_priv->renderctx = NULL;
-       i915_gem_object_unpin(dev_priv->pwrctx);
-       drm_gem_object_unreference(&dev_priv->pwrctx->base);
-       dev_priv->pwrctx = NULL;
+       if (dev_priv->renderctx == NULL)
+               dev_priv->renderctx = intel_alloc_context_page(dev);
+       if (!dev_priv->renderctx)
+               return -ENOMEM;
+       if (dev_priv->pwrctx == NULL)
+               dev_priv->pwrctx = intel_alloc_context_page(dev);
+       if (!dev_priv->pwrctx) {
+               ironlake_teardown_rc6(dev);
+               return -ENOMEM;
+       }
+       return 0;
  }
  
  void ironlake_enable_rc6(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int ret;
  
+       /* rc6 disabled by default due to repeated reports of hanging during
+        * boot and resume.
+        */
+       if (!i915_enable_rc6)
+               return;
+       ret = ironlake_setup_rc6(dev);
+       if (ret)
+               return;
        /*
         * GPU can automatically power down the render unit if given a page
         * to save state.
         */
        ret = BEGIN_LP_RING(6);
        if (ret) {
-               ironlake_disable_rc6(dev);
+               ironlake_teardown_rc6(dev);
                return;
        }
        OUT_RING(MI_SUSPEND_FLUSH | MI_SUSPEND_FLUSH_EN);
        OUT_RING(MI_SET_CONTEXT);
        OUT_RING(dev_priv->renderctx->gtt_offset |
        I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT);
  }
  
  /* Set up chip specific display functions */
  static void intel_init_display(struct drm_device *dev)
  {
@@@ -7437,6 -6776,10 +7456,6 @@@ void intel_modeset_init(struct drm_devi
        }
        dev->mode_config.fb_base = dev->agp->base;
  
 -      if (IS_MOBILE(dev) || !IS_GEN2(dev))
 -              dev_priv->num_pipe = 2;
 -      else
 -              dev_priv->num_pipe = 1;
        DRM_DEBUG_KMS("%d display pipe%s available.\n",
                      dev_priv->num_pipe, dev_priv->num_pipe > 1 ? "s" : "");
  
        if (IS_GEN6(dev))
                gen6_enable_rps(dev_priv);
  
-       if (IS_IRONLAKE_M(dev)) {
-               dev_priv->renderctx = intel_alloc_context_page(dev);
-               if (!dev_priv->renderctx)
-                       goto skip_rc6;
-               dev_priv->pwrctx = intel_alloc_context_page(dev);
-               if (!dev_priv->pwrctx) {
-                       i915_gem_object_unpin(dev_priv->renderctx);
-                       drm_gem_object_unreference(&dev_priv->renderctx->base);
-                       dev_priv->renderctx = NULL;
-                       goto skip_rc6;
-               }
+       if (IS_IRONLAKE_M(dev))
                ironlake_enable_rc6(dev);
-       }
  
- skip_rc6:
        INIT_WORK(&dev_priv->idle_work, intel_idle_update);
        setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer,
                    (unsigned long)dev);
@@@ -685,7 -685,6 +685,7 @@@ intel_dp_set_m_n(struct drm_crtc *crtc
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int lane_count = 4, bpp = 24;
        struct intel_dp_m_n m_n;
 +      int pipe = intel_crtc->pipe;
  
        /*
         * Find the lane count in the intel_encoder private
                             mode->clock, adjusted_mode->clock, &m_n);
  
        if (HAS_PCH_SPLIT(dev)) {
 -              if (intel_crtc->pipe == 0) {
 -                      I915_WRITE(TRANSA_DATA_M1,
 -                                 ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) |
 -                                 m_n.gmch_m);
 -                      I915_WRITE(TRANSA_DATA_N1, m_n.gmch_n);
 -                      I915_WRITE(TRANSA_DP_LINK_M1, m_n.link_m);
 -                      I915_WRITE(TRANSA_DP_LINK_N1, m_n.link_n);
 -              } else {
 -                      I915_WRITE(TRANSB_DATA_M1,
 -                                 ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) |
 -                                 m_n.gmch_m);
 -                      I915_WRITE(TRANSB_DATA_N1, m_n.gmch_n);
 -                      I915_WRITE(TRANSB_DP_LINK_M1, m_n.link_m);
 -                      I915_WRITE(TRANSB_DP_LINK_N1, m_n.link_n);
 -              }
 +              I915_WRITE(TRANSDATA_M1(pipe),
 +                         ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) |
 +                         m_n.gmch_m);
 +              I915_WRITE(TRANSDATA_N1(pipe), m_n.gmch_n);
 +              I915_WRITE(TRANSDPLINK_M1(pipe), m_n.link_m);
 +              I915_WRITE(TRANSDPLINK_N1(pipe), m_n.link_n);
        } else {
 -              if (intel_crtc->pipe == 0) {
 -                      I915_WRITE(PIPEA_GMCH_DATA_M,
 -                                 ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) |
 -                                 m_n.gmch_m);
 -                      I915_WRITE(PIPEA_GMCH_DATA_N,
 -                                 m_n.gmch_n);
 -                      I915_WRITE(PIPEA_DP_LINK_M, m_n.link_m);
 -                      I915_WRITE(PIPEA_DP_LINK_N, m_n.link_n);
 -              } else {
 -                      I915_WRITE(PIPEB_GMCH_DATA_M,
 -                                 ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) |
 -                                 m_n.gmch_m);
 -                      I915_WRITE(PIPEB_GMCH_DATA_N,
 -                                      m_n.gmch_n);
 -                      I915_WRITE(PIPEB_DP_LINK_M, m_n.link_m);
 -                      I915_WRITE(PIPEB_DP_LINK_N, m_n.link_n);
 -              }
 +              I915_WRITE(PIPE_GMCH_DATA_M(pipe),
 +                         ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) |
 +                         m_n.gmch_m);
 +              I915_WRITE(PIPE_GMCH_DATA_N(pipe), m_n.gmch_n);
 +              I915_WRITE(PIPE_DP_LINK_M(pipe), m_n.link_m);
 +              I915_WRITE(PIPE_DP_LINK_N(pipe), m_n.link_n);
        }
  }
  
@@@ -794,40 -813,6 +794,40 @@@ intel_dp_mode_set(struct drm_encoder *e
        }
  }
  
 +static void ironlake_edp_panel_vdd_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;
 +
 +      /*
 +       * If the panel wasn't on, make sure there's not a currently
 +       * active PP sequence before enabling AUX VDD.
 +       */
 +      if (!(I915_READ(PCH_PP_STATUS) & PP_ON))
 +              msleep(dev_priv->panel_t3);
 +
 +      pp = I915_READ(PCH_PP_CONTROL);
 +      pp |= EDP_FORCE_VDD;
 +      I915_WRITE(PCH_PP_CONTROL, pp);
 +      POSTING_READ(PCH_PP_CONTROL);
 +}
 +
 +static void ironlake_edp_panel_vdd_off(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;
 +
 +      pp = I915_READ(PCH_PP_CONTROL);
 +      pp &= ~EDP_FORCE_VDD;
 +      I915_WRITE(PCH_PP_CONTROL, pp);
 +      POSTING_READ(PCH_PP_CONTROL);
 +
 +      /* Make sure sequencer is idle before allowing subsequent activity */
 +      msleep(dev_priv->panel_t12);
 +}
 +
  /* Returns true if the panel was already on when called */
  static bool ironlake_edp_panel_on (struct intel_dp *intel_dp)
  {
        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) & idle_on_mask) == idle_on_mask,
                     5000))
                DRM_ERROR("panel on wait timed out: 0x%08x\n",
@@@ -885,6 -875,11 +885,6 @@@ static void ironlake_edp_panel_off (str
        pp |= PANEL_POWER_RESET; /* restore panel reset bit */
        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);
  }
  
  static void ironlake_edp_backlight_on (struct drm_device *dev)
@@@ -950,7 -945,7 +950,7 @@@ static void intel_dp_prepare(struct drm
  
        if (is_edp(intel_dp)) {
                ironlake_edp_backlight_off(dev);
 -              ironlake_edp_panel_on(intel_dp);
 +              ironlake_edp_panel_off(dev);
                if (!is_pch_edp(intel_dp))
                        ironlake_edp_pll_on(encoder);
                else
@@@ -964,15 -959,10 +964,15 @@@ static void intel_dp_commit(struct drm_
        struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
        struct drm_device *dev = encoder->dev;
  
 +      if (is_edp(intel_dp))
 +              ironlake_edp_panel_vdd_on(intel_dp);
 +
        intel_dp_start_link_train(intel_dp);
  
 -      if (is_edp(intel_dp))
 +      if (is_edp(intel_dp)) {
                ironlake_edp_panel_on(intel_dp);
 +              ironlake_edp_panel_vdd_off(intel_dp);
 +      }
  
        intel_dp_complete_link_train(intel_dp);
  
@@@ -998,13 -988,9 +998,13 @@@ intel_dp_dpms(struct drm_encoder *encod
                        ironlake_edp_pll_off(encoder);
        } else {
                if (is_edp(intel_dp))
 -                      ironlake_edp_panel_on(intel_dp);
 +                      ironlake_edp_panel_vdd_on(intel_dp);
                if (!(dp_reg & DP_PORT_EN)) {
                        intel_dp_start_link_train(intel_dp);
 +                      if (is_edp(intel_dp)) {
 +                              ironlake_edp_panel_on(intel_dp);
 +                              ironlake_edp_panel_vdd_off(intel_dp);
 +                      }
                        intel_dp_complete_link_train(intel_dp);
                }
                if (is_edp(intel_dp))
@@@ -1522,13 -1508,9 +1522,13 @@@ ironlake_dp_detect(struct intel_dp *int
  {
        enum drm_connector_status status;
  
 -      /* Can't disconnect eDP */
 -      if (is_edp(intel_dp))
 -              return connector_status_connected;
 +      /* Can't disconnect eDP, but you can close the lid... */
 +      if (is_edp(intel_dp)) {
 +              status = intel_panel_detect(intel_dp->base.base.dev);
 +              if (status == connector_status_unknown)
 +                      status = connector_status_connected;
 +              return status;
 +      }
  
        status = connector_status_disconnected;
        if (intel_dp_aux_native_read(intel_dp,
@@@ -1657,6 -1639,24 +1657,24 @@@ static int intel_dp_get_modes(struct dr
        return 0;
  }
  
+ static bool
+ intel_dp_detect_audio(struct drm_connector *connector)
+ {
+       struct intel_dp *intel_dp = intel_attached_dp(connector);
+       struct edid *edid;
+       bool has_audio = false;
+       edid = drm_get_edid(connector, &intel_dp->adapter);
+       if (edid) {
+               has_audio = drm_detect_monitor_audio(edid);
+               connector->display_info.raw_edid = NULL;
+               kfree(edid);
+       }
+       return has_audio;
+ }
  static int
  intel_dp_set_property(struct drm_connector *connector,
                      struct drm_property *property,
                return ret;
  
        if (property == intel_dp->force_audio_property) {
-               if (val == intel_dp->force_audio)
+               int i = val;
+               bool has_audio;
+               if (i == intel_dp->force_audio)
                        return 0;
  
-               intel_dp->force_audio = val;
+               intel_dp->force_audio = i;
  
-               if (val > 0 && intel_dp->has_audio)
-                       return 0;
-               if (val < 0 && !intel_dp->has_audio)
+               if (i == 0)
+                       has_audio = intel_dp_detect_audio(connector);
+               else
+                       has_audio = i > 0;
+               if (has_audio == intel_dp->has_audio)
                        return 0;
  
-               intel_dp->has_audio = val > 0;
+               intel_dp->has_audio = has_audio;
                goto done;
        }
  
@@@ -1900,18 -1906,9 +1924,18 @@@ intel_dp_init(struct drm_device *dev, i
        /* Cache some DPCD data in the eDP case */
        if (is_edp(intel_dp)) {
                int ret;
 -              bool was_on;
 +              u32 pp_on, pp_div;
  
 -              was_on = ironlake_edp_panel_on(intel_dp);
 +              pp_on = I915_READ(PCH_PP_ON_DELAYS);
 +              pp_div = I915_READ(PCH_PP_DIVISOR);
 +
 +              /* Get T3 & T12 values (note: VESA not bspec terminology) */
 +              dev_priv->panel_t3 = (pp_on & 0x1fff0000) >> 16;
 +              dev_priv->panel_t3 /= 10; /* t3 in 100us units */
 +              dev_priv->panel_t12 = pp_div & 0xf;
 +              dev_priv->panel_t12 *= 100; /* t12 in 100ms units */
 +
 +              ironlake_edp_panel_vdd_on(intel_dp);
                ret = intel_dp_aux_native_read(intel_dp, DP_DPCD_REV,
                                               intel_dp->dpcd,
                                               sizeof(intel_dp->dpcd));
                } else {
                        DRM_ERROR("failed to retrieve link info\n");
                }
 -              if (!was_on)
 -                      ironlake_edp_panel_off(dev);
 +              ironlake_edp_panel_vdd_off(intel_dp);
        }
  
        intel_encoder->hot_plug = intel_dp_hot_plug;
@@@ -217,13 -217,6 +217,13 @@@ intel_get_crtc_for_pipe(struct drm_devi
        return dev_priv->pipe_to_crtc_mapping[pipe];
  }
  
 +static inline struct drm_crtc *
 +intel_get_crtc_for_plane(struct drm_device *dev, int plane)
 +{
 +      struct drm_i915_private *dev_priv = dev->dev_private;
 +      return dev_priv->plane_to_crtc_mapping[plane];
 +}
 +
  struct intel_unpin_work {
        struct work_struct work;
        struct drm_device *dev;
@@@ -267,7 -260,6 +267,7 @@@ extern void intel_panel_set_backlight(s
  extern void intel_panel_setup_backlight(struct drm_device *dev);
  extern void intel_panel_enable_backlight(struct drm_device *dev);
  extern void intel_panel_disable_backlight(struct drm_device *dev);
 +extern enum drm_connector_status intel_panel_detect(struct drm_device *dev);
  
  extern void intel_crtc_load_lut(struct drm_crtc *crtc);
  extern void intel_encoder_prepare (struct drm_encoder *encoder);
@@@ -306,7 -298,6 +306,6 @@@ extern void intel_crtc_fb_gamma_set(str
  extern void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
                                    u16 *blue, int regno);
  extern void intel_enable_clock_gating(struct drm_device *dev);
- extern void intel_disable_clock_gating(struct drm_device *dev);
  extern void ironlake_enable_drps(struct drm_device *dev);
  extern void ironlake_disable_drps(struct drm_device *dev);
  extern void gen6_enable_rps(struct drm_i915_private *dev_priv);
@@@ -231,7 -231,6 +231,7 @@@ static bool intel_lvds_mode_fixup(struc
        struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
        struct drm_encoder *tmp_encoder;
        u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
 +      int pipe;
  
        /* Should never happen!! */
        if (INTEL_INFO(dev)->gen < 4 && intel_crtc->pipe == 0) {
                return true;
        }
  
-       /* Make sure pre-965s set dither correctly */
-       if (INTEL_INFO(dev)->gen < 4) {
-               if (dev_priv->lvds_dither)
-                       pfit_control |= PANEL_8TO6_DITHER_ENABLE;
-       }
        /* Native modes don't need fitting */
        if (adjusted_mode->hdisplay == mode->hdisplay &&
            adjusted_mode->vdisplay == mode->vdisplay)
         * to register description and PRM.
         * Change the value here to see the borders for debugging
         */
 -      I915_WRITE(BCLRPAT_A, 0);
 -      I915_WRITE(BCLRPAT_B, 0);
 +      for_each_pipe(pipe)
 +              I915_WRITE(BCLRPAT(pipe), 0);
  
        switch (intel_lvds->fitting_mode) {
        case DRM_MODE_SCALE_CENTER:
        }
  
  out:
+       /* If not enabling scaling, be consistent and always use 0. */
        if ((pfit_control & PFIT_ENABLE) == 0) {
                pfit_control = 0;
                pfit_pgm_ratios = 0;
        }
+       /* Make sure pre-965 set dither correctly */
+       if (INTEL_INFO(dev)->gen < 4 && dev_priv->lvds_dither)
+               pfit_control |= PANEL_8TO6_DITHER_ENABLE;
        if (pfit_control != intel_lvds->pfit_control ||
            pfit_pgm_ratios != intel_lvds->pfit_pgm_ratios) {
                intel_lvds->pfit_control = pfit_control;
@@@ -475,10 -474,6 +475,10 @@@ intel_lvds_detect(struct drm_connector 
        struct drm_device *dev = connector->dev;
        enum drm_connector_status status = connector_status_connected;
  
 +      status = intel_panel_detect(dev);
 +      if (status != connector_status_unknown)
 +              return status;
 +
        /* ACPI lid methods were generally unreliable in this generation, so
         * don't even bother.
         */
@@@ -501,7 -496,7 +501,7 @@@ static int intel_lvds_get_modes(struct 
                return drm_add_edid_modes(connector, intel_lvds->edid);
  
        mode = drm_mode_duplicate(dev, intel_lvds->fixed_mode);
 -      if (mode == 0)
 +      if (mode == NULL)
                return 0;
  
        drm_mode_probed_add(connector, mode);
@@@ -62,9 -62,18 +62,9 @@@ render_ring_flush(struct intel_ring_buf
                  u32   flush_domains)
  {
        struct drm_device *dev = ring->dev;
 -      drm_i915_private_t *dev_priv = dev->dev_private;
        u32 cmd;
        int ret;
  
 -#if WATCH_EXEC
 -      DRM_INFO("%s: invalidate %08x flush %08x\n", __func__,
 -                invalidate_domains, flush_domains);
 -#endif
 -
 -      trace_i915_gem_request_flush(dev, dev_priv->next_seqno,
 -                                   invalidate_domains, flush_domains);
 -
        if ((invalidate_domains | flush_domains) & I915_GEM_GPU_DOMAINS) {
                /*
                 * read/write caches:
                    (IS_G4X(dev) || IS_GEN5(dev)))
                        cmd |= MI_INVALIDATE_ISP;
  
 -#if WATCH_EXEC
 -              DRM_INFO("%s: queue flush %08x to ring\n", __func__, cmd);
 -#endif
                ret = intel_ring_begin(ring, 2);
                if (ret)
                        return ret;
@@@ -600,6 -612,7 +600,6 @@@ ring_add_request(struct intel_ring_buff
        intel_ring_emit(ring, MI_USER_INTERRUPT);
        intel_ring_advance(ring);
  
 -      DRM_DEBUG_DRIVER("%s %d\n", ring->name, seqno);
        *result = seqno;
        return 0;
  }
@@@ -702,8 -715,11 +702,8 @@@ render_ring_dispatch_execbuffer(struct 
                                u32 offset, u32 len)
  {
        struct drm_device *dev = ring->dev;
 -      drm_i915_private_t *dev_priv = dev->dev_private;
        int ret;
  
 -      trace_i915_gem_request_submit(dev, dev_priv->next_seqno + 1);
 -
        if (IS_I830(dev) || IS_845G(dev)) {
                ret = intel_ring_begin(ring, 4);
                if (ret)
@@@ -878,10 -894,6 +878,10 @@@ void intel_cleanup_ring_buffer(struct i
        /* Disable the ring buffer. The ring must be idle at this point */
        dev_priv = ring->dev->dev_private;
        ret = intel_wait_ring_buffer(ring, ring->size - 8);
 +      if (ret)
 +              DRM_ERROR("failed to quiesce %s whilst cleaning up: %d\n",
 +                        ring->name, ret);
 +
        I915_WRITE_CTL(ring, 0);
  
        drm_core_ioremapfree(&ring->map, ring->dev);
@@@ -938,13 -950,13 +938,13 @@@ int intel_wait_ring_buffer(struct intel
                        return 0;
        }
  
 -      trace_i915_ring_wait_begin (dev);
 +      trace_i915_ring_wait_begin(ring);
        end = jiffies + 3 * HZ;
        do {
                ring->head = I915_READ_HEAD(ring);
                ring->space = ring_space(ring);
                if (ring->space >= n) {
 -                      trace_i915_ring_wait_end(dev);
 +                      trace_i915_ring_wait_end(ring);
                        return 0;
                }
  
                if (atomic_read(&dev_priv->mm.wedged))
                        return -EAGAIN;
        } while (!time_after(jiffies, end));
 -      trace_i915_ring_wait_end (dev);
 +      trace_i915_ring_wait_end(ring);
        return -EBUSY;
  }
  
  int intel_ring_begin(struct intel_ring_buffer *ring,
                     int num_dwords)
  {
 +      struct drm_i915_private *dev_priv = ring->dev->dev_private;
        int n = 4*num_dwords;
        int ret;
  
 +      if (unlikely(atomic_read(&dev_priv->mm.wedged)))
 +              return -EIO;
 +
        if (unlikely(ring->tail + n > ring->effective_size)) {
                ret = intel_wrap_ring_buffer(ring);
                if (unlikely(ret))
@@@ -1051,22 -1059,25 +1051,25 @@@ static void gen6_bsd_ring_write_tail(st
  }
  
  static int gen6_ring_flush(struct intel_ring_buffer *ring,
-                          u32 invalidate_domains,
-                          u32 flush_domains)
+                          u32 invalidate, u32 flush)
  {
+       uint32_t cmd;
        int ret;
  
-       if ((flush_domains & I915_GEM_DOMAIN_RENDER) == 0)
+       if (((invalidate | flush) & I915_GEM_GPU_DOMAINS) == 0)
                return 0;
  
        ret = intel_ring_begin(ring, 4);
        if (ret)
                return ret;
  
-       intel_ring_emit(ring, MI_FLUSH_DW);
-       intel_ring_emit(ring, 0);
+       cmd = MI_FLUSH_DW;
+       if (invalidate & I915_GEM_GPU_DOMAINS)
+               cmd |= MI_INVALIDATE_TLB | MI_INVALIDATE_BSD;
+       intel_ring_emit(ring, cmd);
        intel_ring_emit(ring, 0);
        intel_ring_emit(ring, 0);
+       intel_ring_emit(ring, MI_NOOP);
        intel_ring_advance(ring);
        return 0;
  }
@@@ -1222,22 -1233,25 +1225,25 @@@ static int blt_ring_begin(struct intel_
  }
  
  static int blt_ring_flush(struct intel_ring_buffer *ring,
-                          u32 invalidate_domains,
-                          u32 flush_domains)
+                         u32 invalidate, u32 flush)
  {
+       uint32_t cmd;
        int ret;
  
-       if ((flush_domains & I915_GEM_DOMAIN_RENDER) == 0)
+       if (((invalidate | flush) & I915_GEM_DOMAIN_RENDER) == 0)
                return 0;
  
        ret = blt_ring_begin(ring, 4);
        if (ret)
                return ret;
  
-       intel_ring_emit(ring, MI_FLUSH_DW);
-       intel_ring_emit(ring, 0);
+       cmd = MI_FLUSH_DW;
+       if (invalidate & I915_GEM_DOMAIN_RENDER)
+               cmd |= MI_INVALIDATE_TLB;
+       intel_ring_emit(ring, cmd);
        intel_ring_emit(ring, 0);
        intel_ring_emit(ring, 0);
+       intel_ring_emit(ring, MI_NOOP);
        intel_ring_advance(ring);
        return 0;
  }
@@@ -46,6 -46,7 +46,7 @@@
                           SDVO_TV_MASK)
  
  #define IS_TV(c)      (c->output_flag & SDVO_TV_MASK)
+ #define IS_TMDS(c)    (c->output_flag & SDVO_TMDS_MASK)
  #define IS_LVDS(c)    (c->output_flag & SDVO_LVDS_MASK)
  #define IS_TV_OR_LVDS(c) (c->output_flag & (SDVO_TV_MASK | SDVO_LVDS_MASK))
  
@@@ -584,7 -585,6 +585,7 @@@ static bool intel_sdvo_get_trained_inpu
  {
        struct intel_sdvo_get_trained_inputs_response response;
  
 +      BUILD_BUG_ON(sizeof(response) != 1);
        if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_TRAINED_INPUTS,
                                  &response, sizeof(response)))
                return false;
@@@ -632,7 -632,6 +633,7 @@@ static bool intel_sdvo_get_input_pixel_
  {
        struct intel_sdvo_pixel_clock_range clocks;
  
 +      BUILD_BUG_ON(sizeof(clocks) != 4);
        if (!intel_sdvo_get_value(intel_sdvo,
                                  SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE,
                                  &clocks, sizeof(clocks)))
@@@ -700,8 -699,6 +701,8 @@@ intel_sdvo_create_preferred_input_timin
  static bool intel_sdvo_get_preferred_input_timing(struct intel_sdvo *intel_sdvo,
                                                  struct intel_sdvo_dtd *dtd)
  {
 +      BUILD_BUG_ON(sizeof(dtd->part1) != 8);
 +      BUILD_BUG_ON(sizeof(dtd->part2) != 8);
        return intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1,
                                    &dtd->part1, sizeof(dtd->part1)) &&
                intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2,
@@@ -799,7 -796,6 +800,7 @@@ static bool intel_sdvo_check_supp_encod
  {
        struct intel_sdvo_encode encode;
  
 +      BUILD_BUG_ON(sizeof(encode) != 2);
        return intel_sdvo_get_value(intel_sdvo,
                                  SDVO_CMD_GET_SUPP_ENCODE,
                                  &encode, sizeof(encode));
@@@ -1166,7 -1162,6 +1167,7 @@@ static int intel_sdvo_mode_valid(struc
  
  static bool intel_sdvo_get_capabilities(struct intel_sdvo *intel_sdvo, struct intel_sdvo_caps *caps)
  {
 +      BUILD_BUG_ON(sizeof(*caps) != 8);
        if (!intel_sdvo_get_value(intel_sdvo,
                                  SDVO_CMD_GET_DEVICE_CAPS,
                                  caps, sizeof(*caps)))
@@@ -1273,9 -1268,33 +1274,9 @@@ void intel_sdvo_set_hotplug(struct drm_
  static bool
  intel_sdvo_multifunc_encoder(struct intel_sdvo *intel_sdvo)
  {
 -      int caps = 0;
 -
 -      if (intel_sdvo->caps.output_flags &
 -              (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1))
 -              caps++;
 -      if (intel_sdvo->caps.output_flags &
 -              (SDVO_OUTPUT_RGB0 | SDVO_OUTPUT_RGB1))
 -              caps++;
 -      if (intel_sdvo->caps.output_flags &
 -              (SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_SVID1))
 -              caps++;
 -      if (intel_sdvo->caps.output_flags &
 -              (SDVO_OUTPUT_CVBS0 | SDVO_OUTPUT_CVBS1))
 -              caps++;
 -      if (intel_sdvo->caps.output_flags &
 -              (SDVO_OUTPUT_YPRPB0 | SDVO_OUTPUT_YPRPB1))
 -              caps++;
 -
 -      if (intel_sdvo->caps.output_flags &
 -              (SDVO_OUTPUT_SCART0 | SDVO_OUTPUT_SCART1))
 -              caps++;
 -
 -      if (intel_sdvo->caps.output_flags &
 -              (SDVO_OUTPUT_LVDS0 | SDVO_OUTPUT_LVDS1))
 -              caps++;
 -
 -      return (caps > 1);
 +      /* Is there more than one type of output? */
 +      int caps = intel_sdvo->caps.output_flags & 0xf;
 +      return caps & -caps;
  }
  
  static struct edid *
@@@ -1341,7 -1360,8 +1342,8 @@@ intel_sdvo_hdmi_sink_detect(struct drm_
                                intel_sdvo->has_hdmi_monitor = drm_detect_hdmi_monitor(edid);
                                intel_sdvo->has_hdmi_audio = drm_detect_monitor_audio(edid);
                        }
-               }
+               } else
+                       status = connector_status_disconnected;
                connector->display_info.raw_edid = NULL;
                kfree(edid);
        }
@@@ -1389,10 -1409,25 +1391,25 @@@ intel_sdvo_detect(struct drm_connector 
  
        if ((intel_sdvo_connector->output_flag & response) == 0)
                ret = connector_status_disconnected;
-       else if (response & SDVO_TMDS_MASK)
+       else if (IS_TMDS(intel_sdvo_connector))
                ret = intel_sdvo_hdmi_sink_detect(connector);
-       else
-               ret = connector_status_connected;
+       else {
+               struct edid *edid;
+               /* if we have an edid check it matches the connection */
+               edid = intel_sdvo_get_edid(connector);
+               if (edid == NULL)
+                       edid = intel_sdvo_get_analog_edid(connector);
+               if (edid != NULL) {
+                       if (edid->input & DRM_EDID_INPUT_DIGITAL)
+                               ret = connector_status_disconnected;
+                       else
+                               ret = connector_status_connected;
+                       connector->display_info.raw_edid = NULL;
+                       kfree(edid);
+               } else
+                       ret = connector_status_connected;
+       }
  
        /* May update encoder flag for like clock for SDVO TV, etc.*/
        if (ret == connector_status_connected) {
@@@ -1428,10 -1463,15 +1445,15 @@@ static void intel_sdvo_get_ddc_modes(st
                edid = intel_sdvo_get_analog_edid(connector);
  
        if (edid != NULL) {
-               if (edid->input & DRM_EDID_INPUT_DIGITAL) {
+               struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
+               bool monitor_is_digital = !!(edid->input & DRM_EDID_INPUT_DIGITAL);
+               bool connector_is_digital = !!IS_TMDS(intel_sdvo_connector);
+               if (connector_is_digital == monitor_is_digital) {
                        drm_mode_connector_update_edid_property(connector, edid);
                        drm_add_edid_modes(connector, edid);
                }
                connector->display_info.raw_edid = NULL;
                kfree(edid);
        }
@@@ -1650,6 -1690,22 +1672,22 @@@ static void intel_sdvo_destroy(struct d
        kfree(connector);
  }
  
+ static bool intel_sdvo_detect_hdmi_audio(struct drm_connector *connector)
+ {
+       struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
+       struct edid *edid;
+       bool has_audio = false;
+       if (!intel_sdvo->is_hdmi)
+               return false;
+       edid = intel_sdvo_get_edid(connector);
+       if (edid != NULL && edid->input & DRM_EDID_INPUT_DIGITAL)
+               has_audio = drm_detect_monitor_audio(edid);
+       return has_audio;
+ }
  static int
  intel_sdvo_set_property(struct drm_connector *connector,
                        struct drm_property *property,
                return ret;
  
        if (property == intel_sdvo_connector->force_audio_property) {
-               if (val == intel_sdvo_connector->force_audio)
+               int i = val;
+               bool has_audio;
+               if (i == intel_sdvo_connector->force_audio)
                        return 0;
  
-               intel_sdvo_connector->force_audio = val;
+               intel_sdvo_connector->force_audio = i;
  
-               if (val > 0 && intel_sdvo->has_hdmi_audio)
-                       return 0;
-               if (val < 0 && !intel_sdvo->has_hdmi_audio)
+               if (i == 0)
+                       has_audio = intel_sdvo_detect_hdmi_audio(connector);
+               else
+                       has_audio = i > 0;
+               if (has_audio == intel_sdvo->has_hdmi_audio)
                        return 0;
  
-               intel_sdvo->has_hdmi_audio = val > 0;
+               intel_sdvo->has_hdmi_audio = has_audio;
                goto done;
        }
  
@@@ -2206,7 -2268,6 +2250,7 @@@ static bool intel_sdvo_tv_create_proper
        if (!intel_sdvo_set_target_output(intel_sdvo, type))
                return false;
  
 +      BUILD_BUG_ON(sizeof(format) != 6);
        if (!intel_sdvo_get_value(intel_sdvo,
                                  SDVO_CMD_GET_SUPPORTED_TV_FORMATS,
                                  &format, sizeof(format)))
@@@ -2413,8 -2474,6 +2457,8 @@@ static bool intel_sdvo_create_enhance_p
                uint16_t response;
        } enhancements;
  
 +      BUILD_BUG_ON(sizeof(enhancements) != 2);
 +
        enhancements.response = 0;
        intel_sdvo_get_value(intel_sdvo,
                             SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS,
@@@ -1006,7 -1006,6 +1006,7 @@@ intel_tv_mode_set(struct drm_encoder *e
        const struct video_levels *video_levels;
        const struct color_conversion *color_conversion;
        bool burst_ena;
 +      int pipe = intel_crtc->pipe;
  
        if (!tv_mode)
                return; /* can't happen (mode_prepare prevents this) */
                           ((video_levels->black << TV_BLACK_LEVEL_SHIFT) |
                            (video_levels->blank << TV_BLANK_LEVEL_SHIFT)));
        {
 -              int pipeconf_reg = (intel_crtc->pipe == 0) ?
 -                      PIPEACONF : PIPEBCONF;
 -              int dspcntr_reg = (intel_crtc->plane == 0) ?
 -                      DSPACNTR : DSPBCNTR;
 +              int pipeconf_reg = PIPECONF(pipe);
 +              int dspcntr_reg = DSPCNTR(pipe);
                int pipeconf = I915_READ(pipeconf_reg);
                int dspcntr = I915_READ(dspcntr_reg);
 -              int dspbase_reg = (intel_crtc->plane == 0) ?
 -                      DSPAADDR : DSPBADDR;
 +              int dspbase_reg = DSPADDR(pipe);
                int xpos = 0x0, ypos = 0x0;
                unsigned int xsize, ysize;
                /* Pipe must be off here */
@@@ -1232,7 -1234,8 +1232,8 @@@ static const struct drm_display_mode re
   * \return false if TV is disconnected.
   */
  static int
- intel_tv_detect_type (struct intel_tv *intel_tv)
+ intel_tv_detect_type (struct intel_tv *intel_tv,
+                     struct drm_connector *connector)
  {
        struct drm_encoder *encoder = &intel_tv->base.base;
        struct drm_device *dev = encoder->dev;
        int type;
  
        /* Disable TV interrupts around load detect or we'll recurse */
-       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-       i915_disable_pipestat(dev_priv, 0,
-                             PIPE_HOTPLUG_INTERRUPT_ENABLE |
-                             PIPE_HOTPLUG_TV_INTERRUPT_ENABLE);
-       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+       if (connector->polled & DRM_CONNECTOR_POLL_HPD) {
+               spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+               i915_disable_pipestat(dev_priv, 0,
+                                     PIPE_HOTPLUG_INTERRUPT_ENABLE |
+                                     PIPE_HOTPLUG_TV_INTERRUPT_ENABLE);
+               spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+       }
  
        save_tv_dac = tv_dac = I915_READ(TV_DAC);
        save_tv_ctl = tv_ctl = I915_READ(TV_CTL);
        I915_WRITE(TV_CTL, save_tv_ctl);
  
        /* Restore interrupt config */
-       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-       i915_enable_pipestat(dev_priv, 0,
-                            PIPE_HOTPLUG_INTERRUPT_ENABLE |
-                            PIPE_HOTPLUG_TV_INTERRUPT_ENABLE);
-       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+       if (connector->polled & DRM_CONNECTOR_POLL_HPD) {
+               spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+               i915_enable_pipestat(dev_priv, 0,
+                                    PIPE_HOTPLUG_INTERRUPT_ENABLE |
+                                    PIPE_HOTPLUG_TV_INTERRUPT_ENABLE);
+               spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+       }
  
        return type;
  }
@@@ -1354,7 -1361,7 +1359,7 @@@ intel_tv_detect(struct drm_connector *c
        drm_mode_set_crtcinfo(&mode, CRTC_INTERLACE_HALVE_V);
  
        if (intel_tv->base.base.crtc && intel_tv->base.base.crtc->enabled) {
-               type = intel_tv_detect_type(intel_tv);
+               type = intel_tv_detect_type(intel_tv, connector);
        } else if (force) {
                struct drm_crtc *crtc;
                int dpms_mode;
                crtc = intel_get_load_detect_pipe(&intel_tv->base, connector,
                                                  &mode, &dpms_mode);
                if (crtc) {
-                       type = intel_tv_detect_type(intel_tv);
+                       type = intel_tv_detect_type(intel_tv, connector);
                        intel_release_load_detect_pipe(&intel_tv->base, connector,
                                                       dpms_mode);
                } else
@@@ -1656,6 -1663,18 +1661,18 @@@ intel_tv_init(struct drm_device *dev
        intel_encoder = &intel_tv->base;
        connector = &intel_connector->base;
  
+       /* The documentation, for the older chipsets at least, recommend
+        * using a polling method rather than hotplug detection for TVs.
+        * This is because in order to perform the hotplug detection, the PLLs
+        * for the TV must be kept alive increasing power drain and starving
+        * bandwidth from other encoders. Notably for instance, it causes
+        * pipe underruns on Crestline when this encoder is supposedly idle.
+        *
+        * More recent chipsets favour HDMI rather than integrated S-Video.
+        */
+       connector->polled =
+               DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT;
        drm_connector_init(dev, connector, &intel_tv_connector_funcs,
                           DRM_MODE_CONNECTOR_SVIDEO);