Merge branch 'for-airlied' of git://people.freedesktop.org/~danvet/drm-intel into...
Dave Airlie [Tue, 7 Feb 2012 15:29:04 +0000 (15:29 +0000)]
* 'for-airlied' of git://people.freedesktop.org/~danvet/drm-intel:
  drm/i915: add a LLC feature flag in device description
  drm/i915: kill i915_mem.c
  drm/i915: Use kcalloc instead of kzalloc to allocate array
  drm/i915/dp: Check for AUXCH error before checking for success
  drm/i915/dp: Use auxch precharge value of 5 everywhere
  drm/i915/dp: Tweak auxch clock divider for PCH
  drm/i915: Remove a comment about PCH from the non-PCH path
  drm/i915: Fix assert_pch_hdmi_disabled to mention HDMI (not DP)
  drm/i915: Implement plane-disabled assertion for PCH too
  drivers: i915: Fix BLC PWM register setup
  drm/i915: Check that plane/pipe is disabled before removing the fb
  drm/i915: fix typo in function name
  drm/i915: split out pll divider code
  drm/i915: split 9xx refclk & sdvo tv code out
  agp/intel: Add pci id for hostbridge from has/qemu
  drm/i915: there is no pipe CxSR on ironlake
  drm/i915: Only look for matching clocks for LVDS downclock
  drm/i915: Silence _DSM errors

1  2 
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/intel_display.c

@@@ -83,6 -83,7 +83,7 @@@ static int i915_capabilities(struct seq
        B(supports_tv);
        B(has_bsd_ring);
        B(has_blt_ring);
+       B(has_llc);
  #undef B
  
        return 0;
@@@ -121,11 -122,11 +122,11 @@@ static const char *cache_level_str(int 
  static void
  describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
  {
 -      seq_printf(m, "%p: %s%s %8zd %04x %04x %d %d%s%s%s",
 +      seq_printf(m, "%p: %s%s %8zdKiB %04x %04x %d %d%s%s%s",
                   &obj->base,
                   get_pin_flag(obj),
                   get_tiling_flag(obj),
 -                 obj->base.size,
 +                 obj->base.size / 1024,
                   obj->base.read_domains,
                   obj->base.write_domain,
                   obj->last_rendering_seqno,
@@@ -653,7 -654,7 +654,7 @@@ static int i915_ringbuffer_info(struct 
        seq_printf(m, "  Size :    %08x\n", ring->size);
        seq_printf(m, "  Active :  %08x\n", intel_ring_get_active_head(ring));
        seq_printf(m, "  NOPID :   %08x\n", I915_READ_NOPID(ring));
 -      if (IS_GEN6(dev)) {
 +      if (IS_GEN6(dev) || IS_GEN7(dev)) {
                seq_printf(m, "  Sync 0 :   %08x\n", I915_READ_SYNC_0(ring));
                seq_printf(m, "  Sync 1 :   %08x\n", I915_READ_SYNC_1(ring));
        }
@@@ -1075,7 -1076,6 +1076,7 @@@ static int gen6_drpc_info(struct seq_fi
        struct drm_device *dev = node->minor->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 rpmodectl1, gt_core_status, rcctl1;
 +      unsigned forcewake_count;
        int count=0, ret;
  
  
        if (ret)
                return ret;
  
 -      if (atomic_read(&dev_priv->forcewake_count)) {
 -              seq_printf(m, "RC information inaccurate because userspace "
 -                            "holds a reference \n");
 +      spin_lock_irq(&dev_priv->gt_lock);
 +      forcewake_count = dev_priv->forcewake_count;
 +      spin_unlock_irq(&dev_priv->gt_lock);
 +
 +      if (forcewake_count) {
 +              seq_printf(m, "RC information inaccurate because somebody "
 +                            "holds a forcewake reference \n");
        } else {
                /* NB: we cannot use forcewake, else we read the wrong values */
                while (count++ < 50 && (I915_READ_NOTRACE(FORCEWAKE_ACK) & 1))
        seq_printf(m, "SW control enabled: %s\n",
                   yesno((rpmodectl1 & GEN6_RP_MEDIA_MODE_MASK) ==
                          GEN6_RP_MEDIA_SW_MODE));
 -      seq_printf(m, "RC6 Enabled: %s\n",
 +      seq_printf(m, "RC1e Enabled: %s\n",
                   yesno(rcctl1 & GEN6_RC_CTL_RC1e_ENABLE));
        seq_printf(m, "RC6 Enabled: %s\n",
                   yesno(rcctl1 & GEN6_RC_CTL_RC6_ENABLE));
@@@ -1403,13 -1399,9 +1404,13 @@@ static int i915_gen6_forcewake_count_in
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        struct drm_device *dev = node->minor->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
 +      unsigned forcewake_count;
 +
 +      spin_lock_irq(&dev_priv->gt_lock);
 +      forcewake_count = dev_priv->forcewake_count;
 +      spin_unlock_irq(&dev_priv->gt_lock);
  
 -      seq_printf(m, "forcewake count = %d\n",
 -                 atomic_read(&dev_priv->forcewake_count));
 +      seq_printf(m, "forcewake count = %u\n", forcewake_count);
  
        return 0;
  }
@@@ -1674,7 -1666,7 +1675,7 @@@ static int i915_forcewake_open(struct i
        struct drm_i915_private *dev_priv = dev->dev_private;
        int ret;
  
 -      if (!IS_GEN6(dev))
 +      if (INTEL_INFO(dev)->gen < 6)
                return 0;
  
        ret = mutex_lock_interruptible(&dev->struct_mutex);
@@@ -1691,7 -1683,7 +1692,7 @@@ int i915_forcewake_release(struct inod
        struct drm_device *dev = inode->i_private;
        struct drm_i915_private *dev_priv = dev->dev_private;
  
 -      if (!IS_GEN6(dev))
 +      if (INTEL_INFO(dev)->gen < 6)
                return 0;
  
        /*
@@@ -784,6 -784,9 +784,9 @@@ static int i915_getparam(struct drm_dev
        case I915_PARAM_HAS_GEN7_SOL_RESET:
                value = 1;
                break;
+       case I915_PARAM_HAS_LLC:
+               value = HAS_LLC(dev);
+               break;
        default:
                DRM_DEBUG_DRIVER("Unknown parameter %d\n",
                                 param->param);
@@@ -2045,7 -2048,6 +2048,7 @@@ int i915_driver_load(struct drm_device 
        if (!IS_I945G(dev) && !IS_I945GM(dev))
                pci_enable_msi(dev->pdev);
  
 +      spin_lock_init(&dev_priv->gt_lock);
        spin_lock_init(&dev_priv->irq_lock);
        spin_lock_init(&dev_priv->error_lock);
        spin_lock_init(&dev_priv->rps_lock);
@@@ -2247,18 -2249,12 +2250,12 @@@ void i915_driver_lastclose(struct drm_d
  
        i915_gem_lastclose(dev);
  
-       if (dev_priv->agp_heap)
-               i915_mem_takedown(&(dev_priv->agp_heap));
        i915_dma_cleanup(dev);
  }
  
  void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
  {
-       drm_i915_private_t *dev_priv = dev->dev_private;
        i915_gem_release(dev, file_priv);
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
-               i915_mem_release(dev, file_priv, dev_priv->agp_heap);
  }
  
  void i915_driver_postclose(struct drm_device *dev, struct drm_file *file)
@@@ -2277,11 -2273,11 +2274,11 @@@ struct drm_ioctl_desc i915_ioctls[] = 
        DRM_IOCTL_DEF_DRV(I915_IRQ_WAIT, i915_irq_wait, DRM_AUTH),
        DRM_IOCTL_DEF_DRV(I915_GETPARAM, i915_getparam, DRM_AUTH),
        DRM_IOCTL_DEF_DRV(I915_SETPARAM, i915_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
-       DRM_IOCTL_DEF_DRV(I915_ALLOC, i915_mem_alloc, DRM_AUTH),
-       DRM_IOCTL_DEF_DRV(I915_FREE, i915_mem_free, DRM_AUTH),
-       DRM_IOCTL_DEF_DRV(I915_INIT_HEAP, i915_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF_DRV(I915_ALLOC, drm_noop, DRM_AUTH),
+       DRM_IOCTL_DEF_DRV(I915_FREE, drm_noop, DRM_AUTH),
+       DRM_IOCTL_DEF_DRV(I915_INIT_HEAP, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
        DRM_IOCTL_DEF_DRV(I915_CMDBUFFER, i915_cmdbuffer, DRM_AUTH),
-       DRM_IOCTL_DEF_DRV(I915_DESTROY_HEAP,  i915_mem_destroy_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF_DRV(I915_DESTROY_HEAP,  drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
        DRM_IOCTL_DEF_DRV(I915_SET_VBLANK_PIPE,  i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
        DRM_IOCTL_DEF_DRV(I915_GET_VBLANK_PIPE,  i915_vblank_pipe_get, DRM_AUTH),
        DRM_IOCTL_DEF_DRV(I915_VBLANK_SWAP, i915_vblank_swap, DRM_AUTH),
@@@ -198,7 -198,7 +198,7 @@@ static const struct intel_device_info i
  
  static const struct intel_device_info intel_ironlake_d_info = {
        .gen = 5,
-       .need_gfx_hws = 1, .has_pipe_cxsr = 1, .has_hotplug = 1,
+       .need_gfx_hws = 1, .has_hotplug = 1,
        .has_bsd_ring = 1,
  };
  
@@@ -214,6 -214,7 +214,7 @@@ static const struct intel_device_info i
        .need_gfx_hws = 1, .has_hotplug = 1,
        .has_bsd_ring = 1,
        .has_blt_ring = 1,
+       .has_llc = 1,
  };
  
  static const struct intel_device_info intel_sandybridge_m_info = {
        .has_fbc = 1,
        .has_bsd_ring = 1,
        .has_blt_ring = 1,
+       .has_llc = 1,
  };
  
  static const struct intel_device_info intel_ivybridge_d_info = {
        .need_gfx_hws = 1, .has_hotplug = 1,
        .has_bsd_ring = 1,
        .has_blt_ring = 1,
+       .has_llc = 1,
  };
  
  static const struct intel_device_info intel_ivybridge_m_info = {
        .has_fbc = 0,   /* FBC is not enabled on Ivybridge mobile yet */
        .has_bsd_ring = 1,
        .has_blt_ring = 1,
+       .has_llc = 1,
  };
  
  static const struct pci_device_id pciidlist[] = {             /* aka */
@@@ -368,12 -372,11 +372,12 @@@ void __gen6_gt_force_wake_mt_get(struc
   */
  void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
  {
 -      WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
 +      unsigned long irqflags;
  
 -      /* Forcewake is atomic in case we get in here without the lock */
 -      if (atomic_add_return(1, &dev_priv->forcewake_count) == 1)
 +      spin_lock_irqsave(&dev_priv->gt_lock, irqflags);
 +      if (dev_priv->forcewake_count++ == 0)
                dev_priv->display.force_wake_get(dev_priv);
 +      spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags);
  }
  
  void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
@@@ -393,12 -396,10 +397,12 @@@ void __gen6_gt_force_wake_mt_put(struc
   */
  void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
  {
 -      WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
 +      unsigned long irqflags;
  
 -      if (atomic_dec_and_test(&dev_priv->forcewake_count))
 +      spin_lock_irqsave(&dev_priv->gt_lock, irqflags);
 +      if (--dev_priv->forcewake_count == 0)
                dev_priv->display.force_wake_put(dev_priv);
 +      spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags);
  }
  
  void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv)
@@@ -600,40 -601,13 +604,40 @@@ static int ironlake_do_reset(struct drm
  static int gen6_do_reset(struct drm_device *dev, u8 flags)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
 +      int     ret;
 +      unsigned long irqflags;
  
 -      I915_WRITE(GEN6_GDRST, GEN6_GRDOM_FULL);
 -      return wait_for((I915_READ(GEN6_GDRST) & GEN6_GRDOM_FULL) == 0, 500);
 +      /* Hold gt_lock across reset to prevent any register access
 +       * with forcewake not set correctly
 +       */
 +      spin_lock_irqsave(&dev_priv->gt_lock, irqflags);
 +
 +      /* Reset the chip */
 +
 +      /* GEN6_GDRST is not in the gt power well, no need to check
 +       * for fifo space for the write or forcewake the chip for
 +       * the read
 +       */
 +      I915_WRITE_NOTRACE(GEN6_GDRST, GEN6_GRDOM_FULL);
 +
 +      /* Spin waiting for the device to ack the reset request */
 +      ret = wait_for((I915_READ_NOTRACE(GEN6_GDRST) & GEN6_GRDOM_FULL) == 0, 500);
 +
 +      /* If reset with a user forcewake, try to restore, otherwise turn it off */
 +      if (dev_priv->forcewake_count)
 +              dev_priv->display.force_wake_get(dev_priv);
 +      else
 +              dev_priv->display.force_wake_put(dev_priv);
 +
 +      /* Restore fifo count */
 +      dev_priv->gt_fifo_count = I915_READ_NOTRACE(GT_FIFO_FREE_ENTRIES);
 +
 +      spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags);
 +      return ret;
  }
  
  /**
-  * i965_reset - reset chip after a hang
+  * i915_reset - reset chip after a hang
   * @dev: drm device to reset
   * @flags: reset domains
   *
@@@ -673,6 -647,9 +677,6 @@@ int i915_reset(struct drm_device *dev, 
        case 7:
        case 6:
                ret = gen6_do_reset(dev, flags);
 -              /* If reset with a user forcewake, try to restore */
 -              if (atomic_read(&dev_priv->forcewake_count))
 -                      __gen6_gt_force_wake_get(dev_priv);
                break;
        case 5:
                ret = ironlake_do_reset(dev, flags);
@@@ -954,14 -931,9 +958,14 @@@ MODULE_LICENSE("GPL and additional righ
  u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \
        u##x val = 0; \
        if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
 -              gen6_gt_force_wake_get(dev_priv); \
 +              unsigned long irqflags; \
 +              spin_lock_irqsave(&dev_priv->gt_lock, irqflags); \
 +              if (dev_priv->forcewake_count == 0) \
 +                      dev_priv->display.force_wake_get(dev_priv); \
                val = read##y(dev_priv->regs + reg); \
 -              gen6_gt_force_wake_put(dev_priv); \
 +              if (dev_priv->forcewake_count == 0) \
 +                      dev_priv->display.force_wake_put(dev_priv); \
 +              spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags); \
        } else { \
                val = read##y(dev_priv->regs + reg); \
        } \
@@@ -255,6 -255,7 +255,7 @@@ struct intel_device_info 
        u8 supports_tv:1;
        u8 has_bsd_ring:1;
        u8 has_blt_ring:1;
+       u8 has_llc:1;
  };
  
  enum no_fbc_reason {
@@@ -288,13 -289,7 +289,13 @@@ typedef struct drm_i915_private 
        int relative_constants_mode;
  
        void __iomem *regs;
 -      u32 gt_fifo_count;
 +      /** gt_fifo_count and the subsequent register write are synchronized
 +       * with dev->struct_mutex. */
 +      unsigned gt_fifo_count;
 +      /** forcewake_count is protected by gt_lock */
 +      unsigned forcewake_count;
 +      /** gt_lock is also taken in irq contexts. */
 +      struct spinlock gt_lock;
  
        struct intel_gmbus {
                struct i2c_adapter adapter;
  
        int tex_lru_log_granularity;
        int allow_batchbuffer;
-       struct mem_block *agp_heap;
        unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds;
        int vblank_pipe;
        int num_pipe;
  
        struct drm_property *broadcast_rgb_property;
        struct drm_property *force_audio_property;
 -
 -      atomic_t forcewake_count;
  } drm_i915_private_t;
  
  enum i915_cache_level {
@@@ -974,6 -970,7 +974,7 @@@ struct drm_i915_file_private 
  
  #define HAS_BSD(dev)            (INTEL_INFO(dev)->has_bsd_ring)
  #define HAS_BLT(dev)            (INTEL_INFO(dev)->has_blt_ring)
+ #define HAS_LLC(dev)            (INTEL_INFO(dev)->has_llc)
  #define I915_NEED_GFX_HWS(dev)        (INTEL_INFO(dev)->need_gfx_hws)
  
  #define HAS_OVERLAY(dev)              (INTEL_INFO(dev)->has_overlay)
@@@ -1079,18 -1076,6 +1080,6 @@@ extern void i915_destroy_error_state(st
  #endif
  
  
- /* i915_mem.c */
- extern int i915_mem_alloc(struct drm_device *dev, void *data,
-                         struct drm_file *file_priv);
- extern int i915_mem_free(struct drm_device *dev, void *data,
-                        struct drm_file *file_priv);
- extern int i915_mem_init_heap(struct drm_device *dev, void *data,
-                             struct drm_file *file_priv);
- extern int i915_mem_destroy_heap(struct drm_device *dev, void *data,
-                                struct drm_file *file_priv);
- extern void i915_mem_takedown(struct mem_block **heap);
- extern void i915_mem_release(struct drm_device * dev,
-                            struct drm_file *file_priv, struct mem_block *heap);
  /* i915_gem.c */
  int i915_gem_init_ioctl(struct drm_device *dev, void *data,
                        struct drm_file *file_priv);
@@@ -75,7 -75,7 +75,7 @@@ struct intel_limit 
        intel_range_t   dot, vco, n, m, m1, m2, p, p1;
        intel_p2_t          p2;
        bool (* find_pll)(const intel_limit_t *, struct drm_crtc *,
-                       int, int, intel_clock_t *);
+                       int, int, intel_clock_t *, intel_clock_t *);
  };
  
  /* FDI */
  
  static bool
  intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
-                   int target, int refclk, intel_clock_t *best_clock);
+                   int target, int refclk, intel_clock_t *match_clock,
+                   intel_clock_t *best_clock);
  static bool
  intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
-                       int target, int refclk, intel_clock_t *best_clock);
+                       int target, int refclk, intel_clock_t *match_clock,
+                       intel_clock_t *best_clock);
  
  static bool
  intel_find_pll_g4x_dp(const intel_limit_t *, struct drm_crtc *crtc,
-                     int target, int refclk, intel_clock_t *best_clock);
+                     int target, int refclk, intel_clock_t *match_clock,
+                     intel_clock_t *best_clock);
  static bool
  intel_find_pll_ironlake_dp(const intel_limit_t *, struct drm_crtc *crtc,
-                          int target, int refclk, intel_clock_t *best_clock);
+                          int target, int refclk, intel_clock_t *match_clock,
+                          intel_clock_t *best_clock);
  
  static inline u32 /* units of 100MHz */
  intel_fdi_link_freq(struct drm_device *dev)
@@@ -515,7 -519,8 +519,8 @@@ static bool intel_PLL_is_valid(struct d
  
  static bool
  intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
-                   int target, int refclk, intel_clock_t *best_clock)
+                   int target, int refclk, intel_clock_t *match_clock,
+                   intel_clock_t *best_clock)
  
  {
        struct drm_device *dev = crtc->dev;
                                        if (!intel_PLL_is_valid(dev, limit,
                                                                &clock))
                                                continue;
+                                       if (match_clock &&
+                                           clock.p != match_clock->p)
+                                               continue;
  
                                        this_err = abs(clock.dot - target);
                                        if (this_err < err) {
  
  static bool
  intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
-                       int target, int refclk, intel_clock_t *best_clock)
+                       int target, int refclk, intel_clock_t *match_clock,
+                       intel_clock_t *best_clock)
  {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
                                        if (!intel_PLL_is_valid(dev, limit,
                                                                &clock))
                                                continue;
+                                       if (match_clock &&
+                                           clock.p != match_clock->p)
+                                               continue;
  
                                        this_err = abs(clock.dot - target);
                                        if (this_err < err_most) {
  
  static bool
  intel_find_pll_ironlake_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
-                          int target, int refclk, intel_clock_t *best_clock)
+                          int target, int refclk, intel_clock_t *match_clock,
+                          intel_clock_t *best_clock)
  {
        struct drm_device *dev = crtc->dev;
        intel_clock_t clock;
  /* DisplayPort has only two frequencies, 162MHz and 270MHz */
  static bool
  intel_find_pll_g4x_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
-                     int target, int refclk, intel_clock_t *best_clock)
+                     int target, int refclk, intel_clock_t *match_clock,
+                     intel_clock_t *best_clock)
  {
        intel_clock_t clock;
        if (target < 200000) {
@@@ -930,19 -944,24 +944,24 @@@ void assert_pipe(struct drm_i915_privat
             pipe_name(pipe), state_string(state), state_string(cur_state));
  }
  
- static void assert_plane_enabled(struct drm_i915_private *dev_priv,
-                                enum plane plane)
+ static void assert_plane(struct drm_i915_private *dev_priv,
+                        enum plane plane, bool state)
  {
        int reg;
        u32 val;
+       bool cur_state;
  
        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));
+       cur_state = !!(val & DISPLAY_PLANE_ENABLE);
+       WARN(cur_state != state,
+            "plane %c assertion failure (expected %s, current %s)\n",
+            plane_name(plane), state_string(state), state_string(cur_state));
  }
  
+ #define assert_plane_enabled(d, p) assert_plane(d, p, true)
+ #define assert_plane_disabled(d, p) assert_plane(d, p, false)
  static void assert_planes_disabled(struct drm_i915_private *dev_priv,
                                   enum pipe pipe)
  {
        int cur_pipe;
  
        /* Planes are fixed to pipes on ILK+ */
-       if (HAS_PCH_SPLIT(dev_priv->dev))
+       if (HAS_PCH_SPLIT(dev_priv->dev)) {
+               reg = DSPCNTR(pipe);
+               val = I915_READ(reg);
+               WARN((val & DISPLAY_PLANE_ENABLE),
+                    "plane %c assertion failure, should be disabled but not\n",
+                    plane_name(pipe));
                return;
+       }
  
        /* Need to check both planes against the pipe */
        for (i = 0; i < 2; i++) {
@@@ -1071,7 -1096,7 +1096,7 @@@ static void assert_pch_hdmi_disabled(st
  {
        u32 val = I915_READ(reg);
        WARN(hdmi_pipe_enabled(dev_priv, val, pipe),
-            "PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n",
+            "PCH HDMI (0x%08x) enabled on transcoder %c, should be disabled\n",
             reg, pipe_name(pipe));
  }
  
@@@ -3321,6 -3346,8 +3346,8 @@@ static void intel_crtc_disable(struct d
        struct drm_device *dev = crtc->dev;
  
        crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
+       assert_plane_disabled(dev->dev_private, to_intel_crtc(crtc)->plane);
+       assert_pipe_disabled(dev->dev_private, to_intel_crtc(crtc)->pipe);
  
        if (crtc->fb) {
                mutex_lock(&dev->struct_mutex);
@@@ -4968,6 -4995,82 +4995,82 @@@ static bool intel_choose_pipe_bpp_dithe
        return display_bpc != bpc;
  }
  
+ static int i9xx_get_refclk(struct drm_crtc *crtc, int num_connectors)
+ {
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int refclk;
+       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
+           intel_panel_use_ssc(dev_priv) && num_connectors < 2) {
+               refclk = dev_priv->lvds_ssc_freq * 1000;
+               DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n",
+                             refclk / 1000);
+       } else if (!IS_GEN2(dev)) {
+               refclk = 96000;
+       } else {
+               refclk = 48000;
+       }
+       return refclk;
+ }
+ static void i9xx_adjust_sdvo_tv_clock(struct drm_display_mode *adjusted_mode,
+                                     intel_clock_t *clock)
+ {
+       /* SDVO TV has fixed PLL values depend on its clock range,
+          this mirrors vbios setting. */
+       if (adjusted_mode->clock >= 100000
+           && adjusted_mode->clock < 140500) {
+               clock->p1 = 2;
+               clock->p2 = 10;
+               clock->n = 3;
+               clock->m1 = 16;
+               clock->m2 = 8;
+       } else if (adjusted_mode->clock >= 140500
+                  && adjusted_mode->clock <= 200000) {
+               clock->p1 = 1;
+               clock->p2 = 10;
+               clock->n = 6;
+               clock->m1 = 12;
+               clock->m2 = 8;
+       }
+ }
+ static void i9xx_update_pll_dividers(struct drm_crtc *crtc,
+                                    intel_clock_t *clock,
+                                    intel_clock_t *reduced_clock)
+ {
+       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 fp, fp2 = 0;
+       if (IS_PINEVIEW(dev)) {
+               fp = (1 << clock->n) << 16 | clock->m1 << 8 | clock->m2;
+               if (reduced_clock)
+                       fp2 = (1 << reduced_clock->n) << 16 |
+                               reduced_clock->m1 << 8 | reduced_clock->m2;
+       } else {
+               fp = clock->n << 16 | clock->m1 << 8 | clock->m2;
+               if (reduced_clock)
+                       fp2 = reduced_clock->n << 16 | reduced_clock->m1 << 8 |
+                               reduced_clock->m2;
+       }
+       I915_WRITE(FP0(pipe), fp);
+       intel_crtc->lowfreq_avail = false;
+       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
+           reduced_clock && i915_powersave) {
+               I915_WRITE(FP1(pipe), fp2);
+               intel_crtc->lowfreq_avail = true;
+       } else {
+               I915_WRITE(FP1(pipe), fp);
+       }
+ }
  static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
                              struct drm_display_mode *mode,
                              struct drm_display_mode *adjusted_mode,
        int plane = intel_crtc->plane;
        int refclk, num_connectors = 0;
        intel_clock_t clock, reduced_clock;
-       u32 dpll, fp = 0, fp2 = 0, dspcntr, pipeconf;
+       u32 dpll, dspcntr, pipeconf;
        bool ok, has_reduced_clock = false, is_sdvo = false, is_dvo = false;
        bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false;
        struct drm_mode_config *mode_config = &dev->mode_config;
                num_connectors++;
        }
  
-       if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2) {
-               refclk = dev_priv->lvds_ssc_freq * 1000;
-               DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n",
-                             refclk / 1000);
-       } else if (!IS_GEN2(dev)) {
-               refclk = 96000;
-       } else {
-               refclk = 48000;
-       }
+       refclk = i9xx_get_refclk(crtc, num_connectors);
  
        /*
         * Returns a set of divisors for the desired target clock with the given
         * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
         */
        limit = intel_limit(crtc, refclk);
-       ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, &clock);
+       ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, NULL,
+                            &clock);
        if (!ok) {
                DRM_ERROR("Couldn't find PLL settings for mode!\n");
                return -EINVAL;
        intel_crtc_update_cursor(crtc, true);
  
        if (is_lvds && dev_priv->lvds_downclock_avail) {
+               /*
+                * Ensure we match the reduced clock's P to the target clock.
+                * If the clocks don't match, we can't switch the display clock
+                * by using the FP0/FP1. In such case we will disable the LVDS
+                * downclock feature.
+               */
                has_reduced_clock = limit->find_pll(limit, crtc,
                                                    dev_priv->lvds_downclock,
                                                    refclk,
+                                                   &clock,
                                                    &reduced_clock);
-               if (has_reduced_clock && (clock.p != reduced_clock.p)) {
-                       /*
-                        * If the different P is found, it means that we can't
-                        * switch the display clock by using the FP0/FP1.
-                        * In such case we will disable the LVDS downclock
-                        * feature.
-                        */
-                       DRM_DEBUG_KMS("Different P is found for "
-                                     "LVDS clock/downclock\n");
-                       has_reduced_clock = 0;
-               }
-       }
-       /* SDVO TV has fixed PLL values depend on its clock range,
-          this mirrors vbios setting. */
-       if (is_sdvo && is_tv) {
-               if (adjusted_mode->clock >= 100000
-                   && adjusted_mode->clock < 140500) {
-                       clock.p1 = 2;
-                       clock.p2 = 10;
-                       clock.n = 3;
-                       clock.m1 = 16;
-                       clock.m2 = 8;
-               } else if (adjusted_mode->clock >= 140500
-                          && adjusted_mode->clock <= 200000) {
-                       clock.p1 = 1;
-                       clock.p2 = 10;
-                       clock.n = 6;
-                       clock.m1 = 12;
-                       clock.m2 = 8;
-               }
        }
  
-       if (IS_PINEVIEW(dev)) {
-               fp = (1 << clock.n) << 16 | clock.m1 << 8 | clock.m2;
-               if (has_reduced_clock)
-                       fp2 = (1 << reduced_clock.n) << 16 |
-                               reduced_clock.m1 << 8 | reduced_clock.m2;
-       } else {
-               fp = clock.n << 16 | clock.m1 << 8 | clock.m2;
-               if (has_reduced_clock)
-                       fp2 = reduced_clock.n << 16 | reduced_clock.m1 << 8 |
-                               reduced_clock.m2;
-       }
+       if (is_sdvo && is_tv)
+               i9xx_adjust_sdvo_tv_clock(adjusted_mode, &clock);
+       i9xx_update_pll_dividers(crtc, &clock, has_reduced_clock ?
+                                &reduced_clock : NULL);
  
        dpll = DPLL_VGA_MODE_DIS;
  
        /* Set up the display plane register */
        dspcntr = DISPPLANE_GAMMA_ENABLE;
  
-       /* Ironlake's plane is forced to pipe, bit 24 is to
-          enable color space conversion */
        if (pipe == 0)
                dspcntr &= ~DISPPLANE_SEL_PIPE_MASK;
        else
        DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
        drm_mode_debug_printmodeline(mode);
  
-       I915_WRITE(FP0(pipe), fp);
        I915_WRITE(DPLL(pipe), dpll & ~DPLL_VCO_ENABLE);
  
        POSTING_READ(DPLL(pipe));
                I915_WRITE(DPLL(pipe), dpll);
        }
  
-       intel_crtc->lowfreq_avail = false;
-       if (is_lvds && has_reduced_clock && i915_powersave) {
-               I915_WRITE(FP1(pipe), fp2);
-               intel_crtc->lowfreq_avail = true;
-               if (HAS_PIPE_CXSR(dev)) {
+       if (HAS_PIPE_CXSR(dev)) {
+               if (intel_crtc->lowfreq_avail) {
                        DRM_DEBUG_KMS("enabling CxSR downclocking\n");
                        pipeconf |= PIPECONF_CXSR_DOWNCLOCK;
-               }
-       } else {
-               I915_WRITE(FP1(pipe), fp);
-               if (HAS_PIPE_CXSR(dev)) {
+               } else {
                        DRM_DEBUG_KMS("disabling CxSR downclocking\n");
                        pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK;
                }
@@@ -5583,7 -5641,8 +5641,8 @@@ static int ironlake_crtc_mode_set(struc
         * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
         */
        limit = intel_limit(crtc, refclk);
-       ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, &clock);
+       ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, NULL,
+                            &clock);
        if (!ok) {
                DRM_ERROR("Couldn't find PLL settings for mode!\n");
                return -EINVAL;
        intel_crtc_update_cursor(crtc, true);
  
        if (is_lvds && dev_priv->lvds_downclock_avail) {
+               /*
+                * Ensure we match the reduced clock's P to the target clock.
+                * If the clocks don't match, we can't switch the display clock
+                * by using the FP0/FP1. In such case we will disable the LVDS
+                * downclock feature.
+               */
                has_reduced_clock = limit->find_pll(limit, crtc,
                                                    dev_priv->lvds_downclock,
                                                    refclk,
+                                                   &clock,
                                                    &reduced_clock);
-               if (has_reduced_clock && (clock.p != reduced_clock.p)) {
-                       /*
-                        * If the different P is found, it means that we can't
-                        * switch the display clock by using the FP0/FP1.
-                        * In such case we will disable the LVDS downclock
-                        * feature.
-                        */
-                       DRM_DEBUG_KMS("Different P is found for "
-                                     "LVDS clock/downclock\n");
-                       has_reduced_clock = 0;
-               }
        }
        /* SDVO TV has fixed PLL values depend on its clock range,
           this mirrors vbios setting. */
        if (is_lvds) {
                temp = I915_READ(PCH_LVDS);
                temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
 -              if (HAS_PCH_CPT(dev))
 +              if (HAS_PCH_CPT(dev)) {
 +                      temp &= ~PORT_TRANS_SEL_MASK;
                        temp |= PORT_TRANS_SEL_CPT(pipe);
 -              else if (pipe == 1)
 -                      temp |= LVDS_PIPEB_SELECT;
 -              else
 -                      temp &= ~LVDS_PIPEB_SELECT;
 +              } else {
 +                      if (pipe == 1)
 +                              temp |= LVDS_PIPEB_SELECT;
 +                      else
 +                              temp &= ~LVDS_PIPEB_SELECT;
 +              }
  
                /* set the corresponsding LVDS_BORDER bit */
                temp |= dev_priv->lvds_border_bits;
@@@ -8135,11 -8187,13 +8190,11 @@@ static bool intel_enable_rc6(struct drm
                return 0;
  
        /*
 -       * Enable rc6 on Sandybridge if DMA remapping is disabled
 +       * Disable rc6 on Sandybridge
         */
        if (INTEL_INFO(dev)->gen == 6) {
 -              DRM_DEBUG_DRIVER("Sandybridge: intel_iommu_enabled %s -- RC6 %sabled\n",
 -                               intel_iommu_enabled ? "true" : "false",
 -                               !intel_iommu_enabled ? "en" : "dis");
 -              return !intel_iommu_enabled;
 +              DRM_DEBUG_DRIVER("Sandybridge: RC6 disabled\n");
 +              return 0;
        }
        DRM_DEBUG_DRIVER("RC6 enabled\n");
        return 1;
@@@ -9028,9 -9082,12 +9083,9 @@@ void intel_modeset_init(struct drm_devi
  
        for (i = 0; i < dev_priv->num_pipe; i++) {
                intel_crtc_init(dev, i);
 -              if (HAS_PCH_SPLIT(dev)) {
 -                      ret = intel_plane_init(dev, i);
 -                      if (ret)
 -                              DRM_ERROR("plane %d init failed: %d\n",
 -                                        i, ret);
 -              }
 +              ret = intel_plane_init(dev, i);
 +              if (ret)
 +                      DRM_DEBUG_KMS("plane %d init failed: %d\n", i, ret);
        }
  
        /* Just disable it once at startup */