Merge tag 'drm-intel-next-2018-09-21' of git://anongit.freedesktop.org/drm/drm-intel...
authorDave Airlie <airlied@redhat.com>
Thu, 27 Sep 2018 23:37:51 +0000 (09:37 +1000)
committerDave Airlie <airlied@redhat.com>
Thu, 27 Sep 2018 23:37:55 +0000 (09:37 +1000)
Driver Changes:

- Bugzilla 107600: Fix stuttering video playback on MythTV on old hardware (Chris)
- Avoid black screen when using CSC coefficient matrix (Raviraj)
- Hammer PDs on Baytrail to make sure they reload (Chris)
- Capture some objects if unable to capture all, on error (Chris)
- Add W/A for 16 GB DIMMs on SKL+ (Mahesh)
- Only enable IPC for symmetric memory configurations on KBL+ (Mahesh)
- Assume pipe A to have maximum stride limits (Ville)
- Always update update OA contexts via context image (Tvrtko)
- Icelake enabling patches (Madhav, Dhinakaran)
- Add Icelake DMC firmware (Anusha)
- Fixes for CI found corner cases (Chris)
- Limit the backpressure for request allocation (Chris)
- Park GPU on module load so usage starts from known state (Chris)
- Flush tasklet when checking for idle (Chris)
- Use coherent write into the context image on BSW+ (Chris)
- Fix possible integer overflow for framebuffers that get aligned past 4GiB (Ville)
- Downgrade fence timeout from warn to notice and add debug hint (Chris)

- Fixes to multi function encoder code (Ville)
- Fix sprite plane check logic (Dan, Ville)
- PAGE_SIZE vs. I915_GTT_PAGE_SIZE fixes (Ville)
- Decode memory bandwidth and parameters for BXT and SKL+ (Mahesh)
- Overwrite BIOS set IPC value from KMS (Mahesh)
- Multiple pipe handling code cleanups/restructurings/optimizations (Ville)
- Spare low 4G address for non-48bit objects (Chris)
- Free context_setparam of struct_mutex (Chris)
- Delay updating ring register state on resume (Chris)
- Avoid unnecessarily copying overlay IOCTL parameters (Chris)
- Update GuC power domain states even without submission (Michal)
- Restore GuC preempt-context across S3/S4 (Chris)
- Add kernel selftest for rapid context switching (Chris)
- Keep runtime power management ref for live selftests (Chris)
- GEM code cleanups (Matt)

Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20180927095933.GA11458@jlahtine-desk.ger.corp.intel.com
1  2 
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem_execbuffer.c
drivers/gpu/drm/i915/i915_gpu_error.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_drv.h

index 2ddf8538cb474f909830f4d4f8257369ce970fca,dbe40b21fef884a40349932ccef60485aee2712e..44e2c0f5ec502bc1a6c27007c77d56df89019ce3
@@@ -1063,6 -1063,300 +1063,300 @@@ static void intel_sanitize_options(stru
        intel_gvt_sanitize_options(dev_priv);
  }
  
+ static enum dram_rank skl_get_dimm_rank(u8 size, u32 rank)
+ {
+       if (size == 0)
+               return I915_DRAM_RANK_INVALID;
+       if (rank == SKL_DRAM_RANK_SINGLE)
+               return I915_DRAM_RANK_SINGLE;
+       else if (rank == SKL_DRAM_RANK_DUAL)
+               return I915_DRAM_RANK_DUAL;
+       return I915_DRAM_RANK_INVALID;
+ }
+ static bool
+ skl_is_16gb_dimm(enum dram_rank rank, u8 size, u8 width)
+ {
+       if (rank == I915_DRAM_RANK_SINGLE && width == 8 && size == 16)
+               return true;
+       else if (rank == I915_DRAM_RANK_DUAL && width == 8 && size == 32)
+               return true;
+       else if (rank == SKL_DRAM_RANK_SINGLE && width == 16 && size == 8)
+               return true;
+       else if (rank == SKL_DRAM_RANK_DUAL && width == 16 && size == 16)
+               return true;
+       return false;
+ }
+ static int
+ skl_dram_get_channel_info(struct dram_channel_info *ch, u32 val)
+ {
+       u32 tmp_l, tmp_s;
+       u32 s_val = val >> SKL_DRAM_S_SHIFT;
+       if (!val)
+               return -EINVAL;
+       tmp_l = val & SKL_DRAM_SIZE_MASK;
+       tmp_s = s_val & SKL_DRAM_SIZE_MASK;
+       if (tmp_l == 0 && tmp_s == 0)
+               return -EINVAL;
+       ch->l_info.size = tmp_l;
+       ch->s_info.size = tmp_s;
+       tmp_l = (val & SKL_DRAM_WIDTH_MASK) >> SKL_DRAM_WIDTH_SHIFT;
+       tmp_s = (s_val & SKL_DRAM_WIDTH_MASK) >> SKL_DRAM_WIDTH_SHIFT;
+       ch->l_info.width = (1 << tmp_l) * 8;
+       ch->s_info.width = (1 << tmp_s) * 8;
+       tmp_l = val & SKL_DRAM_RANK_MASK;
+       tmp_s = s_val & SKL_DRAM_RANK_MASK;
+       ch->l_info.rank = skl_get_dimm_rank(ch->l_info.size, tmp_l);
+       ch->s_info.rank = skl_get_dimm_rank(ch->s_info.size, tmp_s);
+       if (ch->l_info.rank == I915_DRAM_RANK_DUAL ||
+           ch->s_info.rank == I915_DRAM_RANK_DUAL)
+               ch->rank = I915_DRAM_RANK_DUAL;
+       else if (ch->l_info.rank == I915_DRAM_RANK_SINGLE &&
+                ch->s_info.rank == I915_DRAM_RANK_SINGLE)
+               ch->rank = I915_DRAM_RANK_DUAL;
+       else
+               ch->rank = I915_DRAM_RANK_SINGLE;
+       ch->is_16gb_dimm = skl_is_16gb_dimm(ch->l_info.rank, ch->l_info.size,
+                                           ch->l_info.width) ||
+                          skl_is_16gb_dimm(ch->s_info.rank, ch->s_info.size,
+                                           ch->s_info.width);
+       DRM_DEBUG_KMS("(size:width:rank) L(%dGB:X%d:%s) S(%dGB:X%d:%s)\n",
+                     ch->l_info.size, ch->l_info.width,
+                     ch->l_info.rank ? "dual" : "single",
+                     ch->s_info.size, ch->s_info.width,
+                     ch->s_info.rank ? "dual" : "single");
+       return 0;
+ }
+ static bool
+ intel_is_dram_symmetric(u32 val_ch0, u32 val_ch1,
+                       struct dram_channel_info *ch0)
+ {
+       return (val_ch0 == val_ch1 &&
+               (ch0->s_info.size == 0 ||
+                (ch0->l_info.size == ch0->s_info.size &&
+                 ch0->l_info.width == ch0->s_info.width &&
+                 ch0->l_info.rank == ch0->s_info.rank)));
+ }
+ static int
+ skl_dram_get_channels_info(struct drm_i915_private *dev_priv)
+ {
+       struct dram_info *dram_info = &dev_priv->dram_info;
+       struct dram_channel_info ch0, ch1;
+       u32 val_ch0, val_ch1;
+       int ret;
+       val_ch0 = I915_READ(SKL_MAD_DIMM_CH0_0_0_0_MCHBAR_MCMAIN);
+       ret = skl_dram_get_channel_info(&ch0, val_ch0);
+       if (ret == 0)
+               dram_info->num_channels++;
+       val_ch1 = I915_READ(SKL_MAD_DIMM_CH1_0_0_0_MCHBAR_MCMAIN);
+       ret = skl_dram_get_channel_info(&ch1, val_ch1);
+       if (ret == 0)
+               dram_info->num_channels++;
+       if (dram_info->num_channels == 0) {
+               DRM_INFO("Number of memory channels is zero\n");
+               return -EINVAL;
+       }
+       dram_info->valid_dimm = true;
+       /*
+        * If any of the channel is single rank channel, worst case output
+        * will be same as if single rank memory, so consider single rank
+        * memory.
+        */
+       if (ch0.rank == I915_DRAM_RANK_SINGLE ||
+           ch1.rank == I915_DRAM_RANK_SINGLE)
+               dram_info->rank = I915_DRAM_RANK_SINGLE;
+       else
+               dram_info->rank = max(ch0.rank, ch1.rank);
+       if (dram_info->rank == I915_DRAM_RANK_INVALID) {
+               DRM_INFO("couldn't get memory rank information\n");
+               return -EINVAL;
+       }
+       if (ch0.is_16gb_dimm || ch1.is_16gb_dimm)
+               dram_info->is_16gb_dimm = true;
+       dev_priv->dram_info.symmetric_memory = intel_is_dram_symmetric(val_ch0,
+                                                                      val_ch1,
+                                                                      &ch0);
+       DRM_DEBUG_KMS("memory configuration is %sSymmetric memory\n",
+                     dev_priv->dram_info.symmetric_memory ? "" : "not ");
+       return 0;
+ }
+ static int
+ skl_get_dram_info(struct drm_i915_private *dev_priv)
+ {
+       struct dram_info *dram_info = &dev_priv->dram_info;
+       u32 mem_freq_khz, val;
+       int ret;
+       ret = skl_dram_get_channels_info(dev_priv);
+       if (ret)
+               return ret;
+       val = I915_READ(SKL_MC_BIOS_DATA_0_0_0_MCHBAR_PCU);
+       mem_freq_khz = DIV_ROUND_UP((val & SKL_REQ_DATA_MASK) *
+                                   SKL_MEMORY_FREQ_MULTIPLIER_HZ, 1000);
+       dram_info->bandwidth_kbps = dram_info->num_channels *
+                                                       mem_freq_khz * 8;
+       if (dram_info->bandwidth_kbps == 0) {
+               DRM_INFO("Couldn't get system memory bandwidth\n");
+               return -EINVAL;
+       }
+       dram_info->valid = true;
+       return 0;
+ }
+ static int
+ bxt_get_dram_info(struct drm_i915_private *dev_priv)
+ {
+       struct dram_info *dram_info = &dev_priv->dram_info;
+       u32 dram_channels;
+       u32 mem_freq_khz, val;
+       u8 num_active_channels;
+       int i;
+       val = I915_READ(BXT_P_CR_MC_BIOS_REQ_0_0_0);
+       mem_freq_khz = DIV_ROUND_UP((val & BXT_REQ_DATA_MASK) *
+                                   BXT_MEMORY_FREQ_MULTIPLIER_HZ, 1000);
+       dram_channels = val & BXT_DRAM_CHANNEL_ACTIVE_MASK;
+       num_active_channels = hweight32(dram_channels);
+       /* Each active bit represents 4-byte channel */
+       dram_info->bandwidth_kbps = (mem_freq_khz * num_active_channels * 4);
+       if (dram_info->bandwidth_kbps == 0) {
+               DRM_INFO("Couldn't get system memory bandwidth\n");
+               return -EINVAL;
+       }
+       /*
+        * Now read each DUNIT8/9/10/11 to check the rank of each dimms.
+        */
+       for (i = BXT_D_CR_DRP0_DUNIT_START; i <= BXT_D_CR_DRP0_DUNIT_END; i++) {
+               u8 size, width;
+               enum dram_rank rank;
+               u32 tmp;
+               val = I915_READ(BXT_D_CR_DRP0_DUNIT(i));
+               if (val == 0xFFFFFFFF)
+                       continue;
+               dram_info->num_channels++;
+               tmp = val & BXT_DRAM_RANK_MASK;
+               if (tmp == BXT_DRAM_RANK_SINGLE)
+                       rank = I915_DRAM_RANK_SINGLE;
+               else if (tmp == BXT_DRAM_RANK_DUAL)
+                       rank = I915_DRAM_RANK_DUAL;
+               else
+                       rank = I915_DRAM_RANK_INVALID;
+               tmp = val & BXT_DRAM_SIZE_MASK;
+               if (tmp == BXT_DRAM_SIZE_4GB)
+                       size = 4;
+               else if (tmp == BXT_DRAM_SIZE_6GB)
+                       size = 6;
+               else if (tmp == BXT_DRAM_SIZE_8GB)
+                       size = 8;
+               else if (tmp == BXT_DRAM_SIZE_12GB)
+                       size = 12;
+               else if (tmp == BXT_DRAM_SIZE_16GB)
+                       size = 16;
+               else
+                       size = 0;
+               tmp = (val & BXT_DRAM_WIDTH_MASK) >> BXT_DRAM_WIDTH_SHIFT;
+               width = (1 << tmp) * 8;
+               DRM_DEBUG_KMS("dram size:%dGB width:X%d rank:%s\n", size,
+                             width, rank == I915_DRAM_RANK_SINGLE ? "single" :
+                             rank == I915_DRAM_RANK_DUAL ? "dual" : "unknown");
+               /*
+                * If any of the channel is single rank channel,
+                * worst case output will be same as if single rank
+                * memory, so consider single rank memory.
+                */
+               if (dram_info->rank == I915_DRAM_RANK_INVALID)
+                       dram_info->rank = rank;
+               else if (rank == I915_DRAM_RANK_SINGLE)
+                       dram_info->rank = I915_DRAM_RANK_SINGLE;
+       }
+       if (dram_info->rank == I915_DRAM_RANK_INVALID) {
+               DRM_INFO("couldn't get memory rank information\n");
+               return -EINVAL;
+       }
+       dram_info->valid_dimm = true;
+       dram_info->valid = true;
+       return 0;
+ }
+ static void
+ intel_get_dram_info(struct drm_i915_private *dev_priv)
+ {
+       struct dram_info *dram_info = &dev_priv->dram_info;
+       char bandwidth_str[32];
+       int ret;
+       dram_info->valid = false;
+       dram_info->valid_dimm = false;
+       dram_info->is_16gb_dimm = false;
+       dram_info->rank = I915_DRAM_RANK_INVALID;
+       dram_info->bandwidth_kbps = 0;
+       dram_info->num_channels = 0;
+       if (INTEL_GEN(dev_priv) < 9 || IS_GEMINILAKE(dev_priv))
+               return;
+       /* Need to calculate bandwidth only for Gen9 */
+       if (IS_BROXTON(dev_priv))
+               ret = bxt_get_dram_info(dev_priv);
+       else if (INTEL_GEN(dev_priv) == 9)
+               ret = skl_get_dram_info(dev_priv);
+       else
+               ret = skl_dram_get_channels_info(dev_priv);
+       if (ret)
+               return;
+       if (dram_info->bandwidth_kbps)
+               sprintf(bandwidth_str, "%d KBps", dram_info->bandwidth_kbps);
+       else
+               sprintf(bandwidth_str, "unknown");
+       DRM_DEBUG_KMS("DRAM bandwidth:%s, total-channels: %u\n",
+                     bandwidth_str, dram_info->num_channels);
+       DRM_DEBUG_KMS("DRAM rank: %s rank 16GB-dimm:%s\n",
+                     (dram_info->rank == I915_DRAM_RANK_DUAL) ?
+                     "dual" : "single", yesno(dram_info->is_16gb_dimm));
+ }
  /**
   * i915_driver_init_hw - setup state requiring device access
   * @dev_priv: device private
@@@ -1180,6 -1474,12 +1474,12 @@@ static int i915_driver_init_hw(struct d
                goto err_msi;
  
        intel_opregion_setup(dev_priv);
+       /*
+        * Fill the dram structure to get the system raw bandwidth and
+        * dram info. This will be used for memory latency calculation.
+        */
+       intel_get_dram_info(dev_priv);
  
        return 0;
  
@@@ -1384,14 -1684,14 +1684,14 @@@ int i915_driver_load(struct pci_dev *pd
        struct drm_i915_private *dev_priv;
        int ret;
  
 -      /* Enable nuclear pageflip on ILK+ */
 -      if (!i915_modparams.nuclear_pageflip && match_info->gen < 5)
 -              driver.driver_features &= ~DRIVER_ATOMIC;
 -
        dev_priv = i915_driver_create(pdev, ent);
        if (!dev_priv)
                return -ENOMEM;
  
 +      /* Disable nuclear pageflip by default on pre-ILK */
 +      if (!i915_modparams.nuclear_pageflip && match_info->gen < 5)
 +              dev_priv->drm.driver_features &= ~DRIVER_ATOMIC;
 +
        ret = pci_enable_device(pdev);
        if (ret)
                goto out_fini;
index 7ea442033a577d883ae40eb1a1bfd5fae5edeabc,808204a7ca7c5187477c5a96eceec97766f5ea42..8624b4bdc242dd7cbd77d527eb3b84fe59a0777f
@@@ -52,7 -52,6 +52,7 @@@
  #include <drm/drm_gem.h>
  #include <drm/drm_auth.h>
  #include <drm/drm_cache.h>
 +#include <drm/drm_util.h>
  
  #include "i915_params.h"
  #include "i915_reg.h"
@@@ -87,8 -86,8 +87,8 @@@
  
  #define DRIVER_NAME           "i915"
  #define DRIVER_DESC           "Intel Graphics"
- #define DRIVER_DATE           "20180906"
- #define DRIVER_TIMESTAMP      1536242083
+ #define DRIVER_DATE           "20180921"
+ #define DRIVER_TIMESTAMP      1537521997
  
  /* Use I915_STATE_WARN(x) and I915_STATE_WARN_ON() (rather than WARN() and
   * WARN_ON()) for hw state sanity checks to check for unexpected conditions
@@@ -1946,6 -1945,20 +1946,20 @@@ struct drm_i915_private 
                bool distrust_bios_wm;
        } wm;
  
+       struct dram_info {
+               bool valid;
+               bool valid_dimm;
+               bool is_16gb_dimm;
+               u8 num_channels;
+               enum dram_rank {
+                       I915_DRAM_RANK_INVALID = 0,
+                       I915_DRAM_RANK_SINGLE,
+                       I915_DRAM_RANK_DUAL
+               } rank;
+               u32 bandwidth_kbps;
+               bool symmetric_memory;
+       } dram_info;
        struct i915_runtime_pm runtime_pm;
  
        struct {
         */
  };
  
+ struct dram_channel_info {
+       struct info {
+               u8 size, width;
+               enum dram_rank rank;
+       } l_info, s_info;
+       enum dram_rank rank;
+       bool is_16gb_dimm;
+ };
  static inline struct drm_i915_private *to_i915(const struct drm_device *dev)
  {
        return container_of(dev, struct drm_i915_private, drm);
@@@ -2284,7 -2306,7 +2307,7 @@@ static inline struct scatterlist *__sg_
  #define for_each_sgt_dma(__dmap, __iter, __sgt)                               \
        for ((__iter) = __sgt_iter((__sgt)->sgl, true);                 \
             ((__dmap) = (__iter).dma + (__iter).curr);                 \
-            (((__iter).curr += PAGE_SIZE) >= (__iter).max) ?           \
+            (((__iter).curr += I915_GTT_PAGE_SIZE) >= (__iter).max) ?  \
             (__iter) = __sgt_iter(__sg_next((__iter).sgp), true), 0 : 0)
  
  /**
@@@ -3074,6 -3096,12 +3097,12 @@@ enum i915_map_type 
        I915_MAP_FORCE_WC = I915_MAP_WC | I915_MAP_OVERRIDE,
  };
  
+ static inline enum i915_map_type
+ i915_coherent_map_type(struct drm_i915_private *i915)
+ {
+       return HAS_LLC(i915) ? I915_MAP_WB : I915_MAP_WC;
+ }
  /**
   * i915_gem_object_pin_map - return a contiguous mapping of the entire object
   * @obj: the object to map into kernel address space
@@@ -3311,7 -3339,7 +3340,7 @@@ int i915_gem_stolen_insert_node_in_rang
  void i915_gem_stolen_remove_node(struct drm_i915_private *dev_priv,
                                 struct drm_mm_node *node);
  int i915_gem_init_stolen(struct drm_i915_private *dev_priv);
- void i915_gem_cleanup_stolen(struct drm_device *dev);
+ void i915_gem_cleanup_stolen(struct drm_i915_private *dev_priv);
  struct drm_i915_gem_object *
  i915_gem_object_create_stolen(struct drm_i915_private *dev_priv,
                              resource_size_t size);
index 22b4cb77557631e726afbfeaefdeea735c48e3dc,bb0980793b486c259639b29a258ae3589f097e6d..09187286d34627df882e4ede753db7e40da41934
@@@ -693,9 -693,14 +693,14 @@@ static int eb_reserve(struct i915_execb
                        eb_unreserve_vma(vma, &eb->flags[i]);
  
                        if (flags & EXEC_OBJECT_PINNED)
+                               /* Pinned must have their slot */
                                list_add(&vma->exec_link, &eb->unbound);
                        else if (flags & __EXEC_OBJECT_NEEDS_MAP)
+                               /* Map require the lowest 256MiB (aperture) */
                                list_add_tail(&vma->exec_link, &eb->unbound);
+                       else if (!(flags & EXEC_OBJECT_SUPPORTS_48B_ADDRESS))
+                               /* Prioritise 4GiB region for restricted bo */
+                               list_add(&vma->exec_link, &last);
                        else
                                list_add_tail(&vma->exec_link, &last);
                }
@@@ -743,7 -748,7 +748,7 @@@ static int eb_select_context(struct i91
        }
  
        eb->context_flags = 0;
-       if (ctx->flags & CONTEXT_NO_ZEROMAP)
+       if (test_bit(UCONTEXT_NO_ZEROMAP, &ctx->user_flags))
                eb->context_flags |= __EXEC_OBJECT_NEEDS_BIAS;
  
        return 0;
@@@ -2181,7 -2186,7 +2186,7 @@@ signal_fence_array(struct i915_execbuff
                if (!(flags & I915_EXEC_FENCE_SIGNAL))
                        continue;
  
 -              drm_syncobj_replace_fence(syncobj, fence);
 +              drm_syncobj_replace_fence(syncobj, 0, fence);
        }
  }
  
index f7f2aa71d8d99f1c4fa4e4d4632adeb48ecd50f3,1175fec08fe194b88e18075d790e94068763d5b1..2835cacd0d08ffd6b1e8158c818c56fcf5d99c95
@@@ -31,7 -31,6 +31,7 @@@
  #include <linux/stop_machine.h>
  #include <linux/zlib.h>
  #include <drm/drm_print.h>
 +#include <linux/ascii85.h>
  
  #include "i915_gpu_error.h"
  #include "i915_drv.h"
@@@ -518,12 -517,35 +518,12 @@@ void i915_error_printf(struct drm_i915_
        va_end(args);
  }
  
 -static int
 -ascii85_encode_len(int len)
 -{
 -      return DIV_ROUND_UP(len, 4);
 -}
 -
 -static bool
 -ascii85_encode(u32 in, char *out)
 -{
 -      int i;
 -
 -      if (in == 0)
 -              return false;
 -
 -      out[5] = '\0';
 -      for (i = 5; i--; ) {
 -              out[i] = '!' + in % 85;
 -              in /= 85;
 -      }
 -
 -      return true;
 -}
 -
  static void print_error_obj(struct drm_i915_error_state_buf *m,
                            struct intel_engine_cs *engine,
                            const char *name,
                            struct drm_i915_error_object *obj)
  {
 -      char out[6];
 +      char out[ASCII85_BUFSZ];
        int page;
  
        if (!obj)
                        len -= obj->unused;
                len = ascii85_encode_len(len);
  
 -              for (i = 0; i < len; i++) {
 -                      if (ascii85_encode(obj->pages[page][i], out))
 -                              err_puts(m, out);
 -                      else
 -                              err_puts(m, "z");
 -              }
 +              for (i = 0; i < len; i++)
 +                      err_puts(m, ascii85_encode(obj->pages[page][i], out));
        }
        err_puts(m, "\n");
  }
@@@ -1365,15 -1391,20 +1365,20 @@@ static void request_record_user_bo(stru
  {
        struct i915_capture_list *c;
        struct drm_i915_error_object **bo;
-       long count;
+       long count, max;
  
-       count = 0;
+       max = 0;
        for (c = request->capture_list; c; c = c->next)
-               count++;
+               max++;
+       if (!max)
+               return;
  
-       bo = NULL;
-       if (count)
-               bo = kcalloc(count, sizeof(*bo), GFP_ATOMIC);
+       bo = kmalloc_array(max, sizeof(*bo), GFP_ATOMIC);
+       if (!bo) {
+               /* If we can't capture everything, try to capture something. */
+               max = min_t(long, max, PAGE_SIZE / sizeof(*bo));
+               bo = kmalloc_array(max, sizeof(*bo), GFP_ATOMIC);
+       }
        if (!bo)
                return;
  
                bo[count] = i915_error_object_create(request->i915, c->vma);
                if (!bo[count])
                        break;
-               count++;
+               if (++count == max)
+                       break;
        }
  
        ee->user_bo = bo;
index 5711cb7017601b4319d3b710b07fea2adefa8919,376173eb733d6824d063ef66ef51b7bacd3c9698..fbcc56caffb6596a75ddc8975a8c813caef2c909
@@@ -46,7 -46,6 +46,7 @@@
  #include <drm/drm_crtc_helper.h>
  #include <drm/drm_plane_helper.h>
  #include <drm/drm_rect.h>
 +#include <drm/drm_atomic_uapi.h>
  #include <linux/dma_remapping.h>
  #include <linux/reservation.h>
  
@@@ -1917,10 -1916,10 +1917,10 @@@ static unsigned int intel_tile_size(con
  }
  
  static unsigned int
- intel_tile_width_bytes(const struct drm_framebuffer *fb, int plane)
+ intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane)
  {
        struct drm_i915_private *dev_priv = to_i915(fb->dev);
-       unsigned int cpp = fb->format->cpp[plane];
+       unsigned int cpp = fb->format->cpp[color_plane];
  
        switch (fb->modifier) {
        case DRM_FORMAT_MOD_LINEAR:
                else
                        return 512;
        case I915_FORMAT_MOD_Y_TILED_CCS:
-               if (plane == 1)
+               if (color_plane == 1)
                        return 128;
                /* fall through */
        case I915_FORMAT_MOD_Y_TILED:
                else
                        return 512;
        case I915_FORMAT_MOD_Yf_TILED_CCS:
-               if (plane == 1)
+               if (color_plane == 1)
                        return 128;
                /* fall through */
        case I915_FORMAT_MOD_Yf_TILED:
  }
  
  static unsigned int
- intel_tile_height(const struct drm_framebuffer *fb, int plane)
+ intel_tile_height(const struct drm_framebuffer *fb, int color_plane)
  {
        if (fb->modifier == DRM_FORMAT_MOD_LINEAR)
                return 1;
        else
                return intel_tile_size(to_i915(fb->dev)) /
-                       intel_tile_width_bytes(fb, plane);
+                       intel_tile_width_bytes(fb, color_plane);
  }
  
  /* Return the tile dimensions in pixel units */
- static void intel_tile_dims(const struct drm_framebuffer *fb, int plane,
+ static void intel_tile_dims(const struct drm_framebuffer *fb, int color_plane,
                            unsigned int *tile_width,
                            unsigned int *tile_height)
  {
-       unsigned int tile_width_bytes = intel_tile_width_bytes(fb, plane);
-       unsigned int cpp = fb->format->cpp[plane];
+       unsigned int tile_width_bytes = intel_tile_width_bytes(fb, color_plane);
+       unsigned int cpp = fb->format->cpp[color_plane];
  
        *tile_width = tile_width_bytes / cpp;
        *tile_height = intel_tile_size(to_i915(fb->dev)) / tile_width_bytes;
  
  unsigned int
  intel_fb_align_height(const struct drm_framebuffer *fb,
-                     int plane, unsigned int height)
+                     int color_plane, unsigned int height)
  {
-       unsigned int tile_height = intel_tile_height(fb, plane);
+       unsigned int tile_height = intel_tile_height(fb, color_plane);
  
        return ALIGN(height, tile_height);
  }
@@@ -2044,12 -2043,12 +2044,12 @@@ static unsigned int intel_linear_alignm
  }
  
  static unsigned int intel_surf_alignment(const struct drm_framebuffer *fb,
-                                        int plane)
+                                        int color_plane)
  {
        struct drm_i915_private *dev_priv = to_i915(fb->dev);
  
        /* AUX_DIST needs only 4K alignment */
-       if (plane == 1)
+       if (color_plane == 1)
                return 4096;
  
        switch (fb->modifier) {
@@@ -2080,14 -2079,13 +2080,13 @@@ static bool intel_plane_uses_fence(cons
  
  struct i915_vma *
  intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb,
-                          unsigned int rotation,
+                          const struct i915_ggtt_view *view,
                           bool uses_fence,
                           unsigned long *out_flags)
  {
        struct drm_device *dev = fb->dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct drm_i915_gem_object *obj = intel_fb_obj(fb);
-       struct i915_ggtt_view view;
        struct i915_vma *vma;
        unsigned int pinctl;
        u32 alignment;
  
        alignment = intel_surf_alignment(fb, 0);
  
-       intel_fill_fb_ggtt_view(&view, fb, rotation);
        /* Note that the w/a also requires 64 PTE of padding following the
         * bo. We currently fill all unused PTE with the shadow page and so
         * we should always have valid PTE following the scanout preventing
                pinctl |= PIN_MAPPABLE;
  
        vma = i915_gem_object_pin_to_display_plane(obj,
-                                                  alignment, &view, pinctl);
+                                                  alignment, view, pinctl);
        if (IS_ERR(vma))
                goto err;
  
@@@ -2182,13 -2178,13 +2179,13 @@@ void intel_unpin_fb_vma(struct i915_vm
        i915_vma_put(vma);
  }
  
- static int intel_fb_pitch(const struct drm_framebuffer *fb, int plane,
+ static int intel_fb_pitch(const struct drm_framebuffer *fb, int color_plane,
                          unsigned int rotation)
  {
        if (drm_rotation_90_or_270(rotation))
-               return to_intel_framebuffer(fb)->rotated[plane].pitch;
+               return to_intel_framebuffer(fb)->rotated[color_plane].pitch;
        else
-               return fb->pitches[plane];
+               return fb->pitches[color_plane];
  }
  
  /*
   */
  u32 intel_fb_xy_to_linear(int x, int y,
                          const struct intel_plane_state *state,
-                         int plane)
+                         int color_plane)
  {
        const struct drm_framebuffer *fb = state->base.fb;
-       unsigned int cpp = fb->format->cpp[plane];
-       unsigned int pitch = fb->pitches[plane];
+       unsigned int cpp = fb->format->cpp[color_plane];
+       unsigned int pitch = state->color_plane[color_plane].stride;
  
        return y * pitch + x * cpp;
  }
   */
  void intel_add_fb_offsets(int *x, int *y,
                          const struct intel_plane_state *state,
-                         int plane)
+                         int color_plane)
  
  {
        const struct intel_framebuffer *intel_fb = to_intel_framebuffer(state->base.fb);
        unsigned int rotation = state->base.rotation;
  
        if (drm_rotation_90_or_270(rotation)) {
-               *x += intel_fb->rotated[plane].x;
-               *y += intel_fb->rotated[plane].y;
+               *x += intel_fb->rotated[color_plane].x;
+               *y += intel_fb->rotated[color_plane].y;
        } else {
-               *x += intel_fb->normal[plane].x;
-               *y += intel_fb->normal[plane].y;
+               *x += intel_fb->normal[color_plane].x;
+               *y += intel_fb->normal[color_plane].y;
        }
  }
  
- static u32 __intel_adjust_tile_offset(int *x, int *y,
-                                     unsigned int tile_width,
-                                     unsigned int tile_height,
-                                     unsigned int tile_size,
-                                     unsigned int pitch_tiles,
-                                     u32 old_offset,
-                                     u32 new_offset)
+ static u32 intel_adjust_tile_offset(int *x, int *y,
+                                   unsigned int tile_width,
+                                   unsigned int tile_height,
+                                   unsigned int tile_size,
+                                   unsigned int pitch_tiles,
+                                   u32 old_offset,
+                                   u32 new_offset)
  {
        unsigned int pitch_pixels = pitch_tiles * tile_width;
        unsigned int tiles;
        return new_offset;
  }
  
- static u32 _intel_adjust_tile_offset(int *x, int *y,
-                                    const struct drm_framebuffer *fb, int plane,
-                                    unsigned int rotation,
-                                    u32 old_offset, u32 new_offset)
+ static u32 intel_adjust_aligned_offset(int *x, int *y,
+                                      const struct drm_framebuffer *fb,
+                                      int color_plane,
+                                      unsigned int rotation,
+                                      unsigned int pitch,
+                                      u32 old_offset, u32 new_offset)
  {
-       const struct drm_i915_private *dev_priv = to_i915(fb->dev);
-       unsigned int cpp = fb->format->cpp[plane];
-       unsigned int pitch = intel_fb_pitch(fb, plane, rotation);
+       struct drm_i915_private *dev_priv = to_i915(fb->dev);
+       unsigned int cpp = fb->format->cpp[color_plane];
  
        WARN_ON(new_offset > old_offset);
  
                unsigned int pitch_tiles;
  
                tile_size = intel_tile_size(dev_priv);
-               intel_tile_dims(fb, plane, &tile_width, &tile_height);
+               intel_tile_dims(fb, color_plane, &tile_width, &tile_height);
  
                if (drm_rotation_90_or_270(rotation)) {
                        pitch_tiles = pitch / tile_height;
                        pitch_tiles = pitch / (tile_width * cpp);
                }
  
-               __intel_adjust_tile_offset(x, y, tile_width, tile_height,
-                                          tile_size, pitch_tiles,
-                                          old_offset, new_offset);
+               intel_adjust_tile_offset(x, y, tile_width, tile_height,
+                                        tile_size, pitch_tiles,
+                                        old_offset, new_offset);
        } else {
                old_offset += *y * pitch + *x * cpp;
  
   * Adjust the tile offset by moving the difference into
   * the x/y offsets.
   */
- static u32 intel_adjust_tile_offset(int *x, int *y,
-                                   const struct intel_plane_state *state, int plane,
-                                   u32 old_offset, u32 new_offset)
- {
-       return _intel_adjust_tile_offset(x, y, state->base.fb, plane,
-                                        state->base.rotation,
-                                        old_offset, new_offset);
+ static u32 intel_plane_adjust_aligned_offset(int *x, int *y,
+                                            const struct intel_plane_state *state,
+                                            int color_plane,
+                                            u32 old_offset, u32 new_offset)
+ {
+       return intel_adjust_aligned_offset(x, y, state->base.fb, color_plane,
+                                          state->base.rotation,
+                                          state->color_plane[color_plane].stride,
+                                          old_offset, new_offset);
  }
  
  /*
-  * Computes the linear offset to the base tile and adjusts
+  * Computes the aligned offset to the base tile and adjusts
   * x, y. bytes per pixel is assumed to be a power-of-two.
   *
   * In the 90/270 rotated case, x and y are assumed
   * used. This is why the user has to pass in the pitch since it
   * is specified in the rotated orientation.
   */
- static u32 _intel_compute_tile_offset(const struct drm_i915_private *dev_priv,
-                                     int *x, int *y,
-                                     const struct drm_framebuffer *fb, int plane,
-                                     unsigned int pitch,
-                                     unsigned int rotation,
-                                     u32 alignment)
+ static u32 intel_compute_aligned_offset(struct drm_i915_private *dev_priv,
+                                       int *x, int *y,
+                                       const struct drm_framebuffer *fb,
+                                       int color_plane,
+                                       unsigned int pitch,
+                                       unsigned int rotation,
+                                       u32 alignment)
  {
        uint64_t fb_modifier = fb->modifier;
-       unsigned int cpp = fb->format->cpp[plane];
+       unsigned int cpp = fb->format->cpp[color_plane];
        u32 offset, offset_aligned;
  
        if (alignment)
                unsigned int tile_rows, tiles, pitch_tiles;
  
                tile_size = intel_tile_size(dev_priv);
-               intel_tile_dims(fb, plane, &tile_width, &tile_height);
+               intel_tile_dims(fb, color_plane, &tile_width, &tile_height);
  
                if (drm_rotation_90_or_270(rotation)) {
                        pitch_tiles = pitch / tile_height;
                offset = (tile_rows * pitch_tiles + tiles) * tile_size;
                offset_aligned = offset & ~alignment;
  
-               __intel_adjust_tile_offset(x, y, tile_width, tile_height,
-                                          tile_size, pitch_tiles,
-                                          offset, offset_aligned);
+               intel_adjust_tile_offset(x, y, tile_width, tile_height,
+                                        tile_size, pitch_tiles,
+                                        offset, offset_aligned);
        } else {
                offset = *y * pitch + *x * cpp;
                offset_aligned = offset & ~alignment;
        return offset_aligned;
  }
  
u32 intel_compute_tile_offset(int *x, int *y,
-                             const struct intel_plane_state *state,
-                             int plane)
static u32 intel_plane_compute_aligned_offset(int *x, int *y,
+                                             const struct intel_plane_state *state,
+                                             int color_plane)
  {
        struct intel_plane *intel_plane = to_intel_plane(state->base.plane);
        struct drm_i915_private *dev_priv = to_i915(intel_plane->base.dev);
        const struct drm_framebuffer *fb = state->base.fb;
        unsigned int rotation = state->base.rotation;
-       int pitch = intel_fb_pitch(fb, plane, rotation);
+       int pitch = state->color_plane[color_plane].stride;
        u32 alignment;
  
        if (intel_plane->id == PLANE_CURSOR)
                alignment = intel_cursor_alignment(dev_priv);
        else
-               alignment = intel_surf_alignment(fb, plane);
+               alignment = intel_surf_alignment(fb, color_plane);
  
-       return _intel_compute_tile_offset(dev_priv, x, y, fb, plane, pitch,
-                                         rotation, alignment);
+       return intel_compute_aligned_offset(dev_priv, x, y, fb, color_plane,
+                                           pitch, rotation, alignment);
  }
  
  /* Convert the fb->offset[] into x/y offsets */
  static int intel_fb_offset_to_xy(int *x, int *y,
-                                const struct drm_framebuffer *fb, int plane)
+                                const struct drm_framebuffer *fb,
+                                int color_plane)
  {
        struct drm_i915_private *dev_priv = to_i915(fb->dev);
  
        if (fb->modifier != DRM_FORMAT_MOD_LINEAR &&
-           fb->offsets[plane] % intel_tile_size(dev_priv))
+           fb->offsets[color_plane] % intel_tile_size(dev_priv))
                return -EINVAL;
  
        *x = 0;
        *y = 0;
  
-       _intel_adjust_tile_offset(x, y,
-                                 fb, plane, DRM_MODE_ROTATE_0,
-                                 fb->offsets[plane], 0);
+       intel_adjust_aligned_offset(x, y,
+                                   fb, color_plane, DRM_MODE_ROTATE_0,
+                                   fb->pitches[color_plane],
+                                   fb->offsets[color_plane], 0);
  
        return 0;
  }
@@@ -2565,9 -2567,10 +2568,10 @@@ intel_fill_fb_info(struct drm_i915_priv
                intel_fb->normal[i].x = x;
                intel_fb->normal[i].y = y;
  
-               offset = _intel_compute_tile_offset(dev_priv, &x, &y,
-                                                   fb, i, fb->pitches[i],
-                                                   DRM_MODE_ROTATE_0, tile_size);
+               offset = intel_compute_aligned_offset(dev_priv, &x, &y, fb, i,
+                                                     fb->pitches[i],
+                                                     DRM_MODE_ROTATE_0,
+                                                     tile_size);
                offset /= tile_size;
  
                if (fb->modifier != DRM_FORMAT_MOD_LINEAR) {
                         * We only keep the x/y offsets, so push all of the
                         * gtt offset into the x/y offsets.
                         */
-                       __intel_adjust_tile_offset(&x, &y,
-                                                  tile_width, tile_height,
-                                                  tile_size, pitch_tiles,
-                                                  gtt_offset_rotated * tile_size, 0);
+                       intel_adjust_tile_offset(&x, &y,
+                                                tile_width, tile_height,
+                                                tile_size, pitch_tiles,
+                                                gtt_offset_rotated * tile_size, 0);
  
                        gtt_offset_rotated += rot_info->plane[i].width * rot_info->plane[i].height;
  
                max_size = max(max_size, offset + size);
        }
  
-       if (max_size * tile_size > obj->base.size) {
-               DRM_DEBUG_KMS("fb too big for bo (need %u bytes, have %zu bytes)\n",
-                             max_size * tile_size, obj->base.size);
+       if (mul_u32_u32(max_size, tile_size) > obj->base.size) {
+               DRM_DEBUG_KMS("fb too big for bo (need %llu bytes, have %zu bytes)\n",
+                             mul_u32_u32(max_size, tile_size), obj->base.size);
                return -EINVAL;
        }
  
@@@ -2853,10 -2856,15 +2857,15 @@@ intel_find_initial_plane_obj(struct int
        return;
  
  valid_fb:
+       intel_fill_fb_ggtt_view(&intel_state->view, fb,
+                               intel_state->base.rotation);
+       intel_state->color_plane[0].stride =
+               intel_fb_pitch(fb, 0, intel_state->base.rotation);
        mutex_lock(&dev->struct_mutex);
        intel_state->vma =
                intel_pin_and_fence_fb_obj(fb,
-                                          primary->state->rotation,
+                                          &intel_state->view,
                                           intel_plane_uses_fence(intel_state),
                                           &intel_state->flags);
        mutex_unlock(&dev->struct_mutex);
                  &obj->frontbuffer_bits);
  }
  
- static int skl_max_plane_width(const struct drm_framebuffer *fb, int plane,
+ static int skl_max_plane_width(const struct drm_framebuffer *fb,
+                              int color_plane,
                               unsigned int rotation)
  {
-       int cpp = fb->format->cpp[plane];
+       int cpp = fb->format->cpp[color_plane];
  
        switch (fb->modifier) {
        case DRM_FORMAT_MOD_LINEAR:
@@@ -2950,9 -2959,9 +2960,9 @@@ static bool skl_check_main_ccs_coordina
        const struct drm_framebuffer *fb = plane_state->base.fb;
        int hsub = fb->format->hsub;
        int vsub = fb->format->vsub;
-       int aux_x = plane_state->aux.x;
-       int aux_y = plane_state->aux.y;
-       u32 aux_offset = plane_state->aux.offset;
+       int aux_x = plane_state->color_plane[1].x;
+       int aux_y = plane_state->color_plane[1].y;
+       u32 aux_offset = plane_state->color_plane[1].offset;
        u32 alignment = intel_surf_alignment(fb, 1);
  
        while (aux_offset >= main_offset && aux_y <= main_y) {
  
                x = aux_x / hsub;
                y = aux_y / vsub;
-               aux_offset = intel_adjust_tile_offset(&x, &y, plane_state, 1,
-                                                     aux_offset, aux_offset - alignment);
+               aux_offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, 1,
+                                                              aux_offset, aux_offset - alignment);
                aux_x = x * hsub + aux_x % hsub;
                aux_y = y * vsub + aux_y % vsub;
        }
        if (aux_x != main_x || aux_y != main_y)
                return false;
  
-       plane_state->aux.offset = aux_offset;
-       plane_state->aux.x = aux_x;
-       plane_state->aux.y = aux_y;
+       plane_state->color_plane[1].offset = aux_offset;
+       plane_state->color_plane[1].x = aux_x;
+       plane_state->color_plane[1].y = aux_y;
  
        return true;
  }
  
- static int skl_check_main_surface(const struct intel_crtc_state *crtc_state,
-                                 struct intel_plane_state *plane_state)
+ static int skl_check_main_surface(struct intel_plane_state *plane_state)
  {
-       struct drm_i915_private *dev_priv =
-               to_i915(plane_state->base.plane->dev);
        const struct drm_framebuffer *fb = plane_state->base.fb;
        unsigned int rotation = plane_state->base.rotation;
        int x = plane_state->base.src.x1 >> 16;
        int y = plane_state->base.src.y1 >> 16;
        int w = drm_rect_width(&plane_state->base.src) >> 16;
        int h = drm_rect_height(&plane_state->base.src) >> 16;
-       int dst_x = plane_state->base.dst.x1;
-       int dst_w = drm_rect_width(&plane_state->base.dst);
-       int pipe_src_w = crtc_state->pipe_src_w;
        int max_width = skl_max_plane_width(fb, 0, rotation);
        int max_height = 4096;
-       u32 alignment, offset, aux_offset = plane_state->aux.offset;
+       u32 alignment, offset, aux_offset = plane_state->color_plane[1].offset;
  
        if (w > max_width || h > max_height) {
                DRM_DEBUG_KMS("requested Y/RGB source size %dx%d too big (limit %dx%d)\n",
                return -EINVAL;
        }
  
-       /*
-        * Display WA #1175: cnl,glk
-        * Planes other than the cursor may cause FIFO underflow and display
-        * corruption if starting less than 4 pixels from the right edge of
-        * the screen.
-        * Besides the above WA fix the similar problem, where planes other
-        * than the cursor ending less than 4 pixels from the left edge of the
-        * screen may cause FIFO underflow and display corruption.
-        */
-       if ((IS_GEMINILAKE(dev_priv) || IS_CANNONLAKE(dev_priv)) &&
-           (dst_x + dst_w < 4 || dst_x > pipe_src_w - 4)) {
-               DRM_DEBUG_KMS("requested plane X %s position %d invalid (valid range %d-%d)\n",
-                             dst_x + dst_w < 4 ? "end" : "start",
-                             dst_x + dst_w < 4 ? dst_x + dst_w : dst_x,
-                             4, pipe_src_w - 4);
-               return -ERANGE;
-       }
        intel_add_fb_offsets(&x, &y, plane_state, 0);
-       offset = intel_compute_tile_offset(&x, &y, plane_state, 0);
+       offset = intel_plane_compute_aligned_offset(&x, &y, plane_state, 0);
        alignment = intel_surf_alignment(fb, 0);
  
        /*
         * sure that is what we will get.
         */
        if (offset > aux_offset)
-               offset = intel_adjust_tile_offset(&x, &y, plane_state, 0,
-                                                 offset, aux_offset & ~(alignment - 1));
+               offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, 0,
+                                                          offset, aux_offset & ~(alignment - 1));
  
        /*
         * When using an X-tiled surface, the plane blows up
        if (fb->modifier == I915_FORMAT_MOD_X_TILED) {
                int cpp = fb->format->cpp[0];
  
-               while ((x + w) * cpp > fb->pitches[0]) {
+               while ((x + w) * cpp > plane_state->color_plane[0].stride) {
                        if (offset == 0) {
                                DRM_DEBUG_KMS("Unable to find suitable display surface offset due to X-tiling\n");
                                return -EINVAL;
                        }
  
-                       offset = intel_adjust_tile_offset(&x, &y, plane_state, 0,
-                                                         offset, offset - alignment);
+                       offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, 0,
+                                                                  offset, offset - alignment);
                }
        }
  
                        if (offset == 0)
                                break;
  
-                       offset = intel_adjust_tile_offset(&x, &y, plane_state, 0,
-                                                         offset, offset - alignment);
+                       offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, 0,
+                                                                  offset, offset - alignment);
                }
  
-               if (x != plane_state->aux.x || y != plane_state->aux.y) {
+               if (x != plane_state->color_plane[1].x || y != plane_state->color_plane[1].y) {
                        DRM_DEBUG_KMS("Unable to find suitable display surface offset due to CCS\n");
                        return -EINVAL;
                }
        }
  
-       plane_state->main.offset = offset;
-       plane_state->main.x = x;
-       plane_state->main.y = y;
+       plane_state->color_plane[0].offset = offset;
+       plane_state->color_plane[0].x = x;
+       plane_state->color_plane[0].y = y;
  
        return 0;
  }
  
  static int
- skl_check_nv12_surface(const struct intel_crtc_state *crtc_state,
-                      struct intel_plane_state *plane_state)
+ skl_check_nv12_surface(struct intel_plane_state *plane_state)
  {
        /* Display WA #1106 */
        if (plane_state->base.rotation !=
@@@ -3119,7 -3103,7 +3104,7 @@@ static int skl_check_nv12_aux_surface(s
        u32 offset;
  
        intel_add_fb_offsets(&x, &y, plane_state, 1);
-       offset = intel_compute_tile_offset(&x, &y, plane_state, 1);
+       offset = intel_plane_compute_aligned_offset(&x, &y, plane_state, 1);
  
        /* FIXME not quite sure how/if these apply to the chroma plane */
        if (w > max_width || h > max_height) {
                return -EINVAL;
        }
  
-       plane_state->aux.offset = offset;
-       plane_state->aux.x = x;
-       plane_state->aux.y = y;
+       plane_state->color_plane[1].offset = offset;
+       plane_state->color_plane[1].x = x;
+       plane_state->color_plane[1].y = y;
  
        return 0;
  }
@@@ -3146,34 -3130,25 +3131,25 @@@ static int skl_check_ccs_aux_surface(st
        int y = src_y / vsub;
        u32 offset;
  
-       if (plane_state->base.rotation & ~(DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180)) {
-               DRM_DEBUG_KMS("RC support only with 0/180 degree rotation %x\n",
-                             plane_state->base.rotation);
-               return -EINVAL;
-       }
        intel_add_fb_offsets(&x, &y, plane_state, 1);
-       offset = intel_compute_tile_offset(&x, &y, plane_state, 1);
+       offset = intel_plane_compute_aligned_offset(&x, &y, plane_state, 1);
  
-       plane_state->aux.offset = offset;
-       plane_state->aux.x = x * hsub + src_x % hsub;
-       plane_state->aux.y = y * vsub + src_y % vsub;
+       plane_state->color_plane[1].offset = offset;
+       plane_state->color_plane[1].x = x * hsub + src_x % hsub;
+       plane_state->color_plane[1].y = y * vsub + src_y % vsub;
  
        return 0;
  }
  
- int skl_check_plane_surface(const struct intel_crtc_state *crtc_state,
-                           struct intel_plane_state *plane_state)
+ int skl_check_plane_surface(struct intel_plane_state *plane_state)
  {
        const struct drm_framebuffer *fb = plane_state->base.fb;
        unsigned int rotation = plane_state->base.rotation;
        int ret;
  
-       if (rotation & DRM_MODE_REFLECT_X &&
-           fb->modifier == DRM_FORMAT_MOD_LINEAR) {
-               DRM_DEBUG_KMS("horizontal flip is not supported with linear surface formats\n");
-               return -EINVAL;
-       }
+       intel_fill_fb_ggtt_view(&plane_state->view, fb, rotation);
+       plane_state->color_plane[0].stride = intel_fb_pitch(fb, 0, rotation);
+       plane_state->color_plane[1].stride = intel_fb_pitch(fb, 1, rotation);
  
        if (!plane_state->base.visible)
                return 0;
         * the main surface setup depends on it.
         */
        if (fb->format->format == DRM_FORMAT_NV12) {
-               ret = skl_check_nv12_surface(crtc_state, plane_state);
+               ret = skl_check_nv12_surface(plane_state);
                if (ret)
                        return ret;
                ret = skl_check_nv12_aux_surface(plane_state);
                if (ret)
                        return ret;
        } else {
-               plane_state->aux.offset = ~0xfff;
-               plane_state->aux.x = 0;
-               plane_state->aux.y = 0;
+               plane_state->color_plane[1].offset = ~0xfff;
+               plane_state->color_plane[1].x = 0;
+               plane_state->color_plane[1].y = 0;
        }
  
-       ret = skl_check_main_surface(crtc_state, plane_state);
+       ret = skl_check_main_surface(plane_state);
        if (ret)
                return ret;
  
        return 0;
  }
  
+ unsigned int
+ i9xx_plane_max_stride(struct intel_plane *plane,
+                     u32 pixel_format, u64 modifier,
+                     unsigned int rotation)
+ {
+       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
+       if (!HAS_GMCH_DISPLAY(dev_priv)) {
+               return 32*1024;
+       } else if (INTEL_GEN(dev_priv) >= 4) {
+               if (modifier == I915_FORMAT_MOD_X_TILED)
+                       return 16*1024;
+               else
+                       return 32*1024;
+       } else if (INTEL_GEN(dev_priv) >= 3) {
+               if (modifier == I915_FORMAT_MOD_X_TILED)
+                       return 8*1024;
+               else
+                       return 16*1024;
+       } else {
+               if (plane->i9xx_plane == PLANE_C)
+                       return 4*1024;
+               else
+                       return 8*1024;
+       }
+ }
  static u32 i9xx_plane_ctl(const struct intel_crtc_state *crtc_state,
                          const struct intel_plane_state *plane_state)
  {
@@@ -3278,21 -3280,25 +3281,25 @@@ int i9xx_check_plane_surface(struct int
  {
        struct drm_i915_private *dev_priv =
                to_i915(plane_state->base.plane->dev);
+       const struct drm_framebuffer *fb = plane_state->base.fb;
+       unsigned int rotation = plane_state->base.rotation;
        int src_x = plane_state->base.src.x1 >> 16;
        int src_y = plane_state->base.src.y1 >> 16;
        u32 offset;
  
+       intel_fill_fb_ggtt_view(&plane_state->view, fb, rotation);
+       plane_state->color_plane[0].stride = intel_fb_pitch(fb, 0, rotation);
        intel_add_fb_offsets(&src_x, &src_y, plane_state, 0);
  
        if (INTEL_GEN(dev_priv) >= 4)
-               offset = intel_compute_tile_offset(&src_x, &src_y,
-                                                  plane_state, 0);
+               offset = intel_plane_compute_aligned_offset(&src_x, &src_y,
+                                                           plane_state, 0);
        else
                offset = 0;
  
        /* HSW/BDW do this automagically in hardware */
        if (!IS_HASWELL(dev_priv) && !IS_BROADWELL(dev_priv)) {
-               unsigned int rotation = plane_state->base.rotation;
                int src_w = drm_rect_width(&plane_state->base.src) >> 16;
                int src_h = drm_rect_height(&plane_state->base.src) >> 16;
  
                }
        }
  
-       plane_state->main.offset = offset;
-       plane_state->main.x = src_x;
-       plane_state->main.y = src_y;
+       plane_state->color_plane[0].offset = offset;
+       plane_state->color_plane[0].x = src_x;
+       plane_state->color_plane[0].y = src_y;
+       return 0;
+ }
+ static int
+ i9xx_plane_check(struct intel_crtc_state *crtc_state,
+                struct intel_plane_state *plane_state)
+ {
+       int ret;
+       ret = chv_plane_check_rotation(plane_state);
+       if (ret)
+               return ret;
+       ret = drm_atomic_helper_check_plane_state(&plane_state->base,
+                                                 &crtc_state->base,
+                                                 DRM_PLANE_HELPER_NO_SCALING,
+                                                 DRM_PLANE_HELPER_NO_SCALING,
+                                                 false, true);
+       if (ret)
+               return ret;
+       if (!plane_state->base.visible)
+               return 0;
+       ret = intel_plane_check_src_coordinates(plane_state);
+       if (ret)
+               return ret;
+       ret = i9xx_check_plane_surface(plane_state);
+       if (ret)
+               return ret;
+       plane_state->ctl = i9xx_plane_ctl(crtc_state, plane_state);
  
        return 0;
  }
@@@ -3316,20 -3356,19 +3357,19 @@@ static void i9xx_update_plane(struct in
                              const struct intel_plane_state *plane_state)
  {
        struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
-       const struct drm_framebuffer *fb = plane_state->base.fb;
        enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
        u32 linear_offset;
        u32 dspcntr = plane_state->ctl;
        i915_reg_t reg = DSPCNTR(i9xx_plane);
-       int x = plane_state->main.x;
-       int y = plane_state->main.y;
+       int x = plane_state->color_plane[0].x;
+       int y = plane_state->color_plane[0].y;
        unsigned long irqflags;
        u32 dspaddr_offset;
  
        linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0);
  
        if (INTEL_GEN(dev_priv) >= 4)
-               dspaddr_offset = plane_state->main.offset;
+               dspaddr_offset = plane_state->color_plane[0].offset;
        else
                dspaddr_offset = linear_offset;
  
  
        I915_WRITE_FW(reg, dspcntr);
  
-       I915_WRITE_FW(DSPSTRIDE(i9xx_plane), fb->pitches[0]);
+       I915_WRITE_FW(DSPSTRIDE(i9xx_plane), plane_state->color_plane[0].stride);
        if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
                I915_WRITE_FW(DSPSURF(i9xx_plane),
                              intel_plane_ggtt_offset(plane_state) +
@@@ -3428,12 -3467,12 +3468,12 @@@ static bool i9xx_plane_get_hw_state(str
  }
  
  static u32
- intel_fb_stride_alignment(const struct drm_framebuffer *fb, int plane)
+ intel_fb_stride_alignment(const struct drm_framebuffer *fb, int color_plane)
  {
        if (fb->modifier == DRM_FORMAT_MOD_LINEAR)
                return 64;
        else
-               return intel_tile_width_bytes(fb, plane);
+               return intel_tile_width_bytes(fb, color_plane);
  }
  
  static void skl_detach_scaler(struct intel_crtc *intel_crtc, int id)
@@@ -3463,24 -3502,24 +3503,24 @@@ static void skl_detach_scalers(struct i
        }
  }
  
- u32 skl_plane_stride(const struct drm_framebuffer *fb, int plane,
-                    unsigned int rotation)
+ u32 skl_plane_stride(const struct intel_plane_state *plane_state,
+                    int color_plane)
  {
-       u32 stride;
+       const struct drm_framebuffer *fb = plane_state->base.fb;
+       unsigned int rotation = plane_state->base.rotation;
+       u32 stride = plane_state->color_plane[color_plane].stride;
  
-       if (plane >= fb->format->num_planes)
+       if (color_plane >= fb->format->num_planes)
                return 0;
  
-       stride = intel_fb_pitch(fb, plane, rotation);
        /*
         * The stride is either expressed as a multiple of 64 bytes chunks for
         * linear buffers or in number of tiles for tiled buffers.
         */
        if (drm_rotation_90_or_270(rotation))
-               stride /= intel_tile_height(fb, plane);
+               stride /= intel_tile_height(fb, color_plane);
        else
-               stride /= intel_fb_stride_alignment(fb, plane);
+               stride /= intel_fb_stride_alignment(fb, color_plane);
  
        return stride;
  }
@@@ -6014,6 -6053,8 +6054,8 @@@ static void valleyview_crtc_enable(stru
  
        i9xx_set_pipeconf(intel_crtc);
  
+       intel_color_set_csc(&pipe_config->base);
        intel_crtc->active = true;
  
        intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
@@@ -6113,8 -6154,8 +6155,8 @@@ static void i9xx_pfit_disable(struct in
  
        assert_pipe_disabled(dev_priv, crtc->pipe);
  
-       DRM_DEBUG_DRIVER("disabling pfit, current: 0x%08x\n",
-                        I915_READ(PFIT_CONTROL));
+       DRM_DEBUG_KMS("disabling pfit, current: 0x%08x\n",
+                     I915_READ(PFIT_CONTROL));
        I915_WRITE(PFIT_CONTROL, 0);
  }
  
@@@ -6685,20 -6726,22 +6727,20 @@@ intel_reduce_m_n_ratio(uint32_t *num, u
  
  static void compute_m_n(unsigned int m, unsigned int n,
                        uint32_t *ret_m, uint32_t *ret_n,
 -                      bool reduce_m_n)
 +                      bool constant_n)
  {
        /*
 -       * Reduce M/N as much as possible without loss in precision. Several DP
 -       * dongles in particular seem to be fussy about too large *link* M/N
 -       * values. The passed in values are more likely to have the least
 -       * significant bits zero than M after rounding below, so do this first.
 +       * Several DP dongles in particular seem to be fussy about
 +       * too large link M/N values. Give N value as 0x8000 that
 +       * should be acceptable by specific devices. 0x8000 is the
 +       * specified fixed N value for asynchronous clock mode,
 +       * which the devices expect also in synchronous clock mode.
         */
 -      if (reduce_m_n) {
 -              while ((m & 1) == 0 && (n & 1) == 0) {
 -                      m >>= 1;
 -                      n >>= 1;
 -              }
 -      }
 +      if (constant_n)
 +              *ret_n = 0x8000;
 +      else
 +              *ret_n = min_t(unsigned int, roundup_pow_of_two(n), DATA_LINK_N_MAX);
  
 -      *ret_n = min_t(unsigned int, roundup_pow_of_two(n), DATA_LINK_N_MAX);
        *ret_m = div_u64((uint64_t) m * *ret_n, n);
        intel_reduce_m_n_ratio(ret_m, ret_n);
  }
  intel_link_compute_m_n(int bits_per_pixel, int nlanes,
                       int pixel_clock, int link_clock,
                       struct intel_link_m_n *m_n,
 -                     bool reduce_m_n)
 +                     bool constant_n)
  {
        m_n->tu = 64;
  
        compute_m_n(bits_per_pixel * pixel_clock,
                    link_clock * nlanes * 8,
                    &m_n->gmch_m, &m_n->gmch_n,
 -                  reduce_m_n);
 +                  constant_n);
  
        compute_m_n(pixel_clock, link_clock,
                    &m_n->link_m, &m_n->link_n,
 -                  reduce_m_n);
 +                  constant_n);
  }
  
  static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
@@@ -8634,8 -8677,8 +8676,8 @@@ static int ironlake_crtc_compute_clock(
        ironlake_compute_dpll(crtc, crtc_state, NULL);
  
        if (!intel_get_shared_dpll(crtc, crtc_state, NULL)) {
-               DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n",
-                                pipe_name(crtc->pipe));
+               DRM_DEBUG_KMS("failed to find PLL for pipe %c\n",
+                             pipe_name(crtc->pipe));
                return -EINVAL;
        }
  
@@@ -9202,8 -9245,8 +9244,8 @@@ static int haswell_crtc_compute_clock(s
                        intel_get_crtc_new_encoder(state, crtc_state);
  
                if (!intel_get_shared_dpll(crtc, crtc_state, encoder)) {
-                       DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n",
-                                        pipe_name(crtc->pipe));
+                       DRM_DEBUG_KMS("failed to find PLL for pipe %c\n",
+                                     pipe_name(crtc->pipe));
                        return -EINVAL;
                }
        }
@@@ -9592,7 -9635,7 +9634,7 @@@ static u32 intel_cursor_base(const stru
        else
                base = intel_plane_ggtt_offset(plane_state);
  
-       base += plane_state->main.offset;
+       base += plane_state->color_plane[0].offset;
  
        /* ILK+ do this automagically */
        if (HAS_GMCH_DISPLAY(dev_priv) &&
@@@ -9635,14 -9678,44 +9677,44 @@@ static bool intel_cursor_size_ok(const 
                height > 0 && height <= config->cursor_height;
  }
  
- static int intel_check_cursor(struct intel_crtc_state *crtc_state,
-                             struct intel_plane_state *plane_state)
+ static int intel_cursor_check_surface(struct intel_plane_state *plane_state)
  {
        const struct drm_framebuffer *fb = plane_state->base.fb;
+       unsigned int rotation = plane_state->base.rotation;
        int src_x, src_y;
        u32 offset;
+       intel_fill_fb_ggtt_view(&plane_state->view, fb, rotation);
+       plane_state->color_plane[0].stride = intel_fb_pitch(fb, 0, rotation);
+       src_x = plane_state->base.src_x >> 16;
+       src_y = plane_state->base.src_y >> 16;
+       intel_add_fb_offsets(&src_x, &src_y, plane_state, 0);
+       offset = intel_plane_compute_aligned_offset(&src_x, &src_y,
+                                                   plane_state, 0);
+       if (src_x != 0 || src_y != 0) {
+               DRM_DEBUG_KMS("Arbitrary cursor panning not supported\n");
+               return -EINVAL;
+       }
+       plane_state->color_plane[0].offset = offset;
+       return 0;
+ }
+ static int intel_check_cursor(struct intel_crtc_state *crtc_state,
+                             struct intel_plane_state *plane_state)
+ {
+       const struct drm_framebuffer *fb = plane_state->base.fb;
        int ret;
  
+       if (fb && fb->modifier != DRM_FORMAT_MOD_LINEAR) {
+               DRM_DEBUG_KMS("cursor cannot be tiled\n");
+               return -EINVAL;
+       }
        ret = drm_atomic_helper_check_plane_state(&plane_state->base,
                                                  &crtc_state->base,
                                                  DRM_PLANE_HELPER_NO_SCALING,
        if (ret)
                return ret;
  
-       if (!fb)
+       if (!plane_state->base.visible)
                return 0;
  
-       if (fb->modifier != DRM_FORMAT_MOD_LINEAR) {
-               DRM_DEBUG_KMS("cursor cannot be tiled\n");
-               return -EINVAL;
-       }
-       src_x = plane_state->base.src_x >> 16;
-       src_y = plane_state->base.src_y >> 16;
-       intel_add_fb_offsets(&src_x, &src_y, plane_state, 0);
-       offset = intel_compute_tile_offset(&src_x, &src_y, plane_state, 0);
-       if (src_x != 0 || src_y != 0) {
-               DRM_DEBUG_KMS("Arbitrary cursor panning not supported\n");
-               return -EINVAL;
-       }
+       ret = intel_plane_check_src_coordinates(plane_state);
+       if (ret)
+               return ret;
  
-       plane_state->main.offset = offset;
+       ret = intel_cursor_check_surface(plane_state);
+       if (ret)
+               return ret;
  
        return 0;
  }
  
+ static unsigned int
+ i845_cursor_max_stride(struct intel_plane *plane,
+                      u32 pixel_format, u64 modifier,
+                      unsigned int rotation)
+ {
+       return 2048;
+ }
  static u32 i845_cursor_ctl(const struct intel_crtc_state *crtc_state,
                           const struct intel_plane_state *plane_state)
  {
-       const struct drm_framebuffer *fb = plane_state->base.fb;
        return CURSOR_ENABLE |
                CURSOR_GAMMA_ENABLE |
                CURSOR_FORMAT_ARGB |
-               CURSOR_STRIDE(fb->pitches[0]);
+               CURSOR_STRIDE(plane_state->color_plane[0].stride);
  }
  
  static bool i845_cursor_size_ok(const struct intel_plane_state *plane_state)
@@@ -9719,6 -9788,9 +9787,9 @@@ static int i845_check_cursor(struct int
                return -EINVAL;
        }
  
+       WARN_ON(plane_state->base.visible &&
+               plane_state->color_plane[0].stride != fb->pitches[0]);
        switch (fb->pitches[0]) {
        case 256:
        case 512:
@@@ -9807,6 -9879,14 +9878,14 @@@ static bool i845_cursor_get_hw_state(st
        return ret;
  }
  
+ static unsigned int
+ i9xx_cursor_max_stride(struct intel_plane *plane,
+                      u32 pixel_format, u64 modifier,
+                      unsigned int rotation)
+ {
+       return plane->base.dev->mode_config.cursor_width * 4;
+ }
  static u32 i9xx_cursor_ctl(const struct intel_crtc_state *crtc_state,
                           const struct intel_plane_state *plane_state)
  {
@@@ -9912,6 -9992,9 +9991,9 @@@ static int i9xx_check_cursor(struct int
                return -EINVAL;
        }
  
+       WARN_ON(plane_state->base.visible &&
+               plane_state->color_plane[0].stride != fb->pitches[0]);
        if (fb->pitches[0] != plane_state->base.crtc_w * fb->format->cpp[0]) {
                DRM_DEBUG_KMS("Invalid cursor stride (%u) (cursor width %d)\n",
                              fb->pitches[0], plane_state->base.crtc_w);
@@@ -12901,8 -12984,6 +12983,8 @@@ static const struct drm_crtc_funcs inte
        .atomic_duplicate_state = intel_crtc_duplicate_state,
        .atomic_destroy_state = intel_crtc_destroy_state,
        .set_crc_source = intel_crtc_set_crc_source,
 +      .verify_crc_source = intel_crtc_verify_crc_source,
 +      .get_crc_sources = intel_crtc_get_crc_sources,
  };
  
  struct wait_rps_boost {
@@@ -12982,7 -13063,7 +13064,7 @@@ static int intel_plane_pin_fb(struct in
        }
  
        vma = intel_pin_and_fence_fb_obj(fb,
-                                        plane_state->base.rotation,
+                                        &plane_state->view,
                                         intel_plane_uses_fence(plane_state),
                                         &plane_state->flags);
        if (IS_ERR(vma))
@@@ -13160,19 -13241,17 +13242,17 @@@ intel_cleanup_plane_fb(struct drm_plan
  }
  
  int
- skl_max_scale(struct intel_crtc *intel_crtc,
-             struct intel_crtc_state *crtc_state,
-             uint32_t pixel_format)
+ skl_max_scale(const struct intel_crtc_state *crtc_state,
+             u32 pixel_format)
  {
-       struct drm_i915_private *dev_priv;
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
        int max_scale, mult;
        int crtc_clock, max_dotclk, tmpclk1, tmpclk2;
  
-       if (!intel_crtc || !crtc_state->base.enable)
+       if (!crtc_state->base.enable)
                return DRM_PLANE_HELPER_NO_SCALING;
  
-       dev_priv = to_i915(intel_crtc->base.dev);
        crtc_clock = crtc_state->base.adjusted_mode.crtc_clock;
        max_dotclk = to_intel_atomic_state(crtc_state->base.state)->cdclk.logical.cdclk;
  
        return max_scale;
  }
  
- static int
- intel_check_primary_plane(struct intel_crtc_state *crtc_state,
-                         struct intel_plane_state *state)
- {
-       struct intel_plane *plane = to_intel_plane(state->base.plane);
-       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
-       struct drm_crtc *crtc = state->base.crtc;
-       int min_scale = DRM_PLANE_HELPER_NO_SCALING;
-       int max_scale = DRM_PLANE_HELPER_NO_SCALING;
-       bool can_position = false;
-       int ret;
-       uint32_t pixel_format = 0;
-       if (INTEL_GEN(dev_priv) >= 9) {
-               /* use scaler when colorkey is not required */
-               if (!state->ckey.flags) {
-                       min_scale = 1;
-                       if (state->base.fb)
-                               pixel_format = state->base.fb->format->format;
-                       max_scale = skl_max_scale(to_intel_crtc(crtc),
-                                                 crtc_state, pixel_format);
-               }
-               can_position = true;
-       }
-       ret = drm_atomic_helper_check_plane_state(&state->base,
-                                                 &crtc_state->base,
-                                                 min_scale, max_scale,
-                                                 can_position, true);
-       if (ret)
-               return ret;
-       if (!state->base.fb)
-               return 0;
-       if (INTEL_GEN(dev_priv) >= 9) {
-               ret = skl_check_plane_surface(crtc_state, state);
-               if (ret)
-                       return ret;
-               state->ctl = skl_plane_ctl(crtc_state, state);
-       } else {
-               ret = i9xx_check_plane_surface(state);
-               if (ret)
-                       return ret;
-               state->ctl = i9xx_plane_ctl(crtc_state, state);
-       }
-       if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
-               state->color_ctl = glk_plane_color_ctl(crtc_state, state);
-       return 0;
- }
  static void intel_begin_crtc_commit(struct drm_crtc *crtc,
                                    struct drm_crtc_state *old_crtc_state)
  {
@@@ -13672,12 -13696,8 +13697,8 @@@ intel_primary_plane_create(struct drm_i
  
        primary->base.state = &state->base;
  
-       primary->can_scale = false;
-       primary->max_downscale = 1;
-       if (INTEL_GEN(dev_priv) >= 9) {
-               primary->can_scale = true;
+       if (INTEL_GEN(dev_priv) >= 9)
                state->scaler_id = -1;
-       }
        primary->pipe = pipe;
        /*
         * On gen2/3 only plane A can do FBC, but the panel fitter and LVDS
                fbc->possible_framebuffer_bits |= primary->frontbuffer_bit;
        }
  
-       primary->check_plane = intel_check_primary_plane;
        if (INTEL_GEN(dev_priv) >= 9) {
                primary->has_ccs = skl_plane_has_ccs(dev_priv, pipe,
                                                     PLANE_PRIMARY);
                else
                        modifiers = skl_format_modifiers_noccs;
  
+               primary->max_stride = skl_plane_max_stride;
                primary->update_plane = skl_update_plane;
                primary->disable_plane = skl_disable_plane;
                primary->get_hw_state = skl_plane_get_hw_state;
+               primary->check_plane = skl_plane_check;
  
                plane_funcs = &skl_plane_funcs;
        } else if (INTEL_GEN(dev_priv) >= 4) {
                num_formats = ARRAY_SIZE(i965_primary_formats);
                modifiers = i9xx_format_modifiers;
  
+               primary->max_stride = i9xx_plane_max_stride;
                primary->update_plane = i9xx_update_plane;
                primary->disable_plane = i9xx_disable_plane;
                primary->get_hw_state = i9xx_plane_get_hw_state;
+               primary->check_plane = i9xx_plane_check;
  
                plane_funcs = &i965_plane_funcs;
        } else {
                num_formats = ARRAY_SIZE(i8xx_primary_formats);
                modifiers = i9xx_format_modifiers;
  
+               primary->max_stride = i9xx_plane_max_stride;
                primary->update_plane = i9xx_update_plane;
                primary->disable_plane = i9xx_disable_plane;
                primary->get_hw_state = i9xx_plane_get_hw_state;
+               primary->check_plane = i9xx_plane_check;
  
                plane_funcs = &i8xx_plane_funcs;
        }
@@@ -13842,19 -13866,19 +13867,19 @@@ intel_cursor_plane_create(struct drm_i9
  
        cursor->base.state = &state->base;
  
-       cursor->can_scale = false;
-       cursor->max_downscale = 1;
        cursor->pipe = pipe;
        cursor->i9xx_plane = (enum i9xx_plane_id) pipe;
        cursor->id = PLANE_CURSOR;
        cursor->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, cursor->id);
  
        if (IS_I845G(dev_priv) || IS_I865G(dev_priv)) {
+               cursor->max_stride = i845_cursor_max_stride;
                cursor->update_plane = i845_update_cursor;
                cursor->disable_plane = i845_disable_cursor;
                cursor->get_hw_state = i845_cursor_get_hw_state;
                cursor->check_plane = i845_check_cursor;
        } else {
+               cursor->max_stride = i9xx_cursor_max_stride;
                cursor->update_plane = i9xx_update_cursor;
                cursor->disable_plane = i9xx_disable_cursor;
                cursor->get_hw_state = i9xx_cursor_get_hw_state;
  u32 intel_fb_pitch_limit(struct drm_i915_private *dev_priv,
                         uint64_t fb_modifier, uint32_t pixel_format)
  {
-       u32 gen = INTEL_GEN(dev_priv);
+       struct intel_crtc *crtc;
+       struct intel_plane *plane;
  
-       if (gen >= 9) {
-               int cpp = drm_format_plane_cpp(pixel_format, 0);
+       /*
+        * We assume the primary plane for pipe A has
+        * the highest stride limits of them all.
+        */
+       crtc = intel_get_crtc_for_pipe(dev_priv, PIPE_A);
+       plane = to_intel_plane(crtc->base.primary);
  
-               /* "The stride in bytes must not exceed the of the size of 8K
-                *  pixels and 32K bytes."
-                */
-               return min(8192 * cpp, 32768);
-       } else if (gen >= 5 && !HAS_GMCH_DISPLAY(dev_priv)) {
-               return 32*1024;
-       } else if (gen >= 4) {
-               if (fb_modifier == I915_FORMAT_MOD_X_TILED)
-                       return 16*1024;
-               else
-                       return 32*1024;
-       } else if (gen >= 3) {
-               if (fb_modifier == I915_FORMAT_MOD_X_TILED)
-                       return 8*1024;
-               else
-                       return 16*1024;
-       } else {
-               /* XXX DSPC is limited to 4k tiled */
-               return 8*1024;
-       }
+       return plane->max_stride(plane, pixel_format, fb_modifier,
+                                DRM_MODE_ROTATE_0);
  }
  
  static int intel_framebuffer_init(struct intel_framebuffer *intel_fb,
index f5731215210a409c29636a33c9df07913781e63f,521d6aaa2d44d51430a7d456e8fa39fd60b09b41..bf1c38728a5907c927c4853f01811b1c76501cc9
@@@ -39,7 -39,6 +39,7 @@@
  #include <drm/drm_dp_mst_helper.h>
  #include <drm/drm_rect.h>
  #include <drm/drm_atomic.h>
 +#include <media/cec-notifier.h>
  
  /**
   * __wait_for - magic wait macro
@@@ -497,18 -496,21 +497,21 @@@ struct intel_atomic_state 
  
  struct intel_plane_state {
        struct drm_plane_state base;
+       struct i915_ggtt_view view;
        struct i915_vma *vma;
        unsigned long flags;
  #define PLANE_HAS_FENCE BIT(0)
  
        struct {
                u32 offset;
+               /*
+                * Plane stride in:
+                * bytes for 0/180 degree rotation
+                * pixels for 90/270 degree rotation
+                */
+               u32 stride;
                int x, y;
-       } main;
-       struct {
-               u32 offset;
-               int x, y;
-       } aux;
+       } color_plane[2];
  
        /* plane control register */
        u32 ctl;
@@@ -950,10 -952,8 +953,8 @@@ struct intel_plane 
        enum i9xx_plane_id i9xx_plane;
        enum plane_id id;
        enum pipe pipe;
-       bool can_scale;
        bool has_fbc;
        bool has_ccs;
-       int max_downscale;
        uint32_t frontbuffer_bit;
  
        struct {
         * the intel_plane_state structure and accessed via plane_state.
         */
  
+       unsigned int (*max_stride)(struct intel_plane *plane,
+                                  u32 pixel_format, u64 modifier,
+                                  unsigned int rotation);
        void (*update_plane)(struct intel_plane *plane,
                             const struct intel_crtc_state *crtc_state,
                             const struct intel_plane_state *plane_state);
@@@ -1016,7 -1019,6 +1020,7 @@@ struct intel_hdmi 
        bool has_audio;
        bool rgb_quant_range_selectable;
        struct intel_connector *attached_connector;
 +      struct cec_notifier *cec_notifier;
  };
  
  struct intel_dp_mst_encoder;
@@@ -1442,7 -1444,7 +1446,7 @@@ void icl_unmap_plls_to_ports(struct drm
                             struct drm_atomic_state *old_state);
  
  unsigned int intel_fb_align_height(const struct drm_framebuffer *fb,
-                                  int plane, unsigned int height);
+                                  int color_plane, unsigned int height);
  
  /* intel_audio.c */
  void intel_init_audio_hooks(struct drm_i915_private *dev_priv);
@@@ -1565,7 -1567,7 +1569,7 @@@ void intel_release_load_detect_pipe(str
                                    struct drm_modeset_acquire_ctx *ctx);
  struct i915_vma *
  intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb,
-                          unsigned int rotation,
+                          const struct i915_ggtt_view *view,
                           bool uses_fence,
                           unsigned long *out_flags);
  void intel_unpin_fb_vma(struct i915_vma *vma, unsigned long flags);
@@@ -1614,8 -1616,6 +1618,6 @@@ void assert_fdi_rx_pll(struct drm_i915_
  void assert_pipe(struct drm_i915_private *dev_priv, enum pipe pipe, bool state);
  #define assert_pipe_enabled(d, p) assert_pipe(d, p, true)
  #define assert_pipe_disabled(d, p) assert_pipe(d, p, false)
- u32 intel_compute_tile_offset(int *x, int *y,
-                             const struct intel_plane_state *state, int plane);
  void intel_prepare_reset(struct drm_i915_private *dev_priv);
  void intel_finish_reset(struct drm_i915_private *dev_priv);
  void hsw_enable_pc8(struct drm_i915_private *dev_priv);
@@@ -1645,8 -1645,8 +1647,8 @@@ void intel_crtc_arm_fifo_underrun(struc
  
  u16 skl_scaler_calc_phase(int sub, bool chroma_center);
  int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state);
- int skl_max_scale(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
-                 uint32_t pixel_format);
+ int skl_max_scale(const struct intel_crtc_state *crtc_state,
+                 u32 pixel_format);
  
  static inline u32 intel_plane_ggtt_offset(const struct intel_plane_state *state)
  {
@@@ -1658,12 -1658,14 +1660,14 @@@ u32 glk_plane_color_ctl(const struct in
  u32 skl_plane_ctl(const struct intel_crtc_state *crtc_state,
                  const struct intel_plane_state *plane_state);
  u32 glk_color_ctl(const struct intel_plane_state *plane_state);
- u32 skl_plane_stride(const struct drm_framebuffer *fb, int plane,
-                    unsigned int rotation);
- int skl_check_plane_surface(const struct intel_crtc_state *crtc_state,
-                           struct intel_plane_state *plane_state);
+ u32 skl_plane_stride(const struct intel_plane_state *plane_state,
+                    int plane);
+ int skl_check_plane_surface(struct intel_plane_state *plane_state);
  int i9xx_check_plane_surface(struct intel_plane_state *plane_state);
  int skl_format_to_fourcc(int format, bool rgb_order, bool alpha);
+ unsigned int i9xx_plane_max_stride(struct intel_plane *plane,
+                                  u32 pixel_format, u64 modifier,
+                                  unsigned int rotation);
  
  /* intel_csr.c */
  void intel_csr_ucode_init(struct drm_i915_private *);
@@@ -2131,6 -2133,13 +2135,13 @@@ bool skl_plane_has_ccs(struct drm_i915_
                       enum pipe pipe, enum plane_id plane_id);
  bool skl_plane_has_planar(struct drm_i915_private *dev_priv,
                          enum pipe pipe, enum plane_id plane_id);
+ unsigned int skl_plane_max_stride(struct intel_plane *plane,
+                                 u32 pixel_format, u64 modifier,
+                                 unsigned int rotation);
+ int skl_plane_check(struct intel_crtc_state *crtc_state,
+                   struct intel_plane_state *plane_state);
+ int intel_plane_check_src_coordinates(struct intel_plane_state *plane_state);
+ int chv_plane_check_rotation(const struct intel_plane_state *plane_state);
  
  /* intel_tv.c */
  void intel_tv_init(struct drm_i915_private *dev_priv);
@@@ -2195,17 -2204,12 +2206,17 @@@ void lspcon_wait_pcon_mode(struct intel
  
  /* intel_pipe_crc.c */
  #ifdef CONFIG_DEBUG_FS
 -int intel_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name,
 -                            size_t *values_cnt);
 +int intel_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name);
 +int intel_crtc_verify_crc_source(struct drm_crtc *crtc,
 +                               const char *source_name, size_t *values_cnt);
 +const char *const *intel_crtc_get_crc_sources(struct drm_crtc *crtc,
 +                                            size_t *count);
  void intel_crtc_disable_pipe_crc(struct intel_crtc *crtc);
  void intel_crtc_enable_pipe_crc(struct intel_crtc *crtc);
  #else
  #define intel_crtc_set_crc_source NULL
 +#define intel_crtc_verify_crc_source NULL
 +#define intel_crtc_get_crc_sources NULL
  static inline void intel_crtc_disable_pipe_crc(struct intel_crtc *crtc)
  {
  }