Merge drm/drm-next into drm-intel-next-queued
authorJani Nikula <jani.nikula@intel.com>
Wed, 26 Sep 2018 08:24:04 +0000 (11:24 +0300)
committerJani Nikula <jani.nikula@intel.com>
Wed, 26 Sep 2018 08:24:04 +0000 (11:24 +0300)
Catch up in general, and get DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT
specifically.

Signed-off-by: Jani Nikula <jani.nikula@intel.com>
41 files changed:
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_context.c
drivers/gpu/drm/i915/i915_gem_context.h
drivers/gpu/drm/i915/i915_gem_execbuffer.c
drivers/gpu/drm/i915/i915_gem_gtt.c
drivers/gpu/drm/i915/i915_gem_stolen.c
drivers/gpu/drm/i915/i915_gpu_error.c
drivers/gpu/drm/i915/i915_perf.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_request.c
drivers/gpu/drm/i915/i915_request.h
drivers/gpu/drm/i915/i915_sw_fence.c
drivers/gpu/drm/i915/icl_dsi.c
drivers/gpu/drm/i915/intel_atomic.c
drivers/gpu/drm/i915/intel_atomic_plane.c
drivers/gpu/drm/i915/intel_csr.c
drivers/gpu/drm/i915/intel_ddi.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_engine_cs.c
drivers/gpu/drm/i915/intel_fbc.c
drivers/gpu/drm/i915/intel_fbdev.c
drivers/gpu/drm/i915/intel_guc_submission.c
drivers/gpu/drm/i915/intel_lrc.c
drivers/gpu/drm/i915/intel_overlay.c
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/i915/intel_runtime_pm.c
drivers/gpu/drm/i915/intel_sdvo.c
drivers/gpu/drm/i915/intel_sprite.c
drivers/gpu/drm/i915/intel_uc.c
drivers/gpu/drm/i915/selftests/huge_pages.c
drivers/gpu/drm/i915/selftests/i915_gem_coherency.c
drivers/gpu/drm/i915/selftests/i915_gem_context.c
drivers/gpu/drm/i915/selftests/i915_request.c
drivers/gpu/drm/i915/selftests/intel_guc.c
drivers/gpu/drm/i915/selftests/intel_lrc.c
drivers/gpu/drm/i915/selftests/intel_workarounds.c

index 1f7051e..b4744a6 100644 (file)
@@ -4117,6 +4117,17 @@ i915_ring_test_irq_set(void *data, u64 val)
 {
        struct drm_i915_private *i915 = data;
 
+       /* GuC keeps the user interrupt permanently enabled for submission */
+       if (USES_GUC_SUBMISSION(i915))
+               return -ENODEV;
+
+       /*
+        * From icl, we can no longer individually mask interrupt generation
+        * from each engine.
+        */
+       if (INTEL_GEN(i915) >= 11)
+               return -ENODEV;
+
        val &= INTEL_INFO(i915)->ring_mask;
        DRM_DEBUG_DRIVER("Masking interrupts on rings 0x%08llx\n", val);
 
index 2ddf853..44e2c0f 100644 (file)
@@ -1063,6 +1063,300 @@ static void intel_sanitize_options(struct drm_i915_private *dev_priv)
        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 @@ static int i915_driver_init_hw(struct drm_i915_private *dev_priv)
                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;
 
index 7ea4420..8624b4b 100644 (file)
@@ -87,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 +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 {
@@ -2159,6 +2173,15 @@ struct drm_i915_private {
         */
 };
 
+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 +2307,7 @@ static inline struct scatterlist *__sg_next(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 +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 +3340,7 @@ int i915_gem_stolen_insert_node_in_range(struct drm_i915_private *dev_priv,
 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 89834ce..db9688d 100644 (file)
@@ -2506,7 +2506,9 @@ static bool i915_sg_trim(struct sg_table *orig_st)
        new_sg = new_st.sgl;
        for_each_sg(orig_st->sgl, sg, orig_st->nents, i) {
                sg_set_page(new_sg, sg_page(sg), sg->length, 0);
-               /* called before being DMA mapped, no need to copy sg->dma_* */
+               sg_dma_address(new_sg) = sg_dma_address(sg);
+               sg_dma_len(new_sg) = sg_dma_len(sg);
+
                new_sg = sg_next(new_sg);
        }
        GEM_BUG_ON(new_sg); /* Should walk exactly nents and hit the end */
@@ -3438,6 +3440,9 @@ bool i915_gem_unset_wedged(struct drm_i915_private *i915)
        i915_retire_requests(i915);
        GEM_BUG_ON(i915->gt.active_requests);
 
+       if (!intel_gpu_reset(i915, ALL_ENGINES))
+               intel_engines_sanitize(i915);
+
        /*
         * Undo nop_submit_request. We prevent all new i915 requests from
         * being queued (by disallowing execbuf whilst wedged) so having
@@ -5414,8 +5419,19 @@ static int __intel_engines_record_defaults(struct drm_i915_private *i915)
 
        assert_kernel_context_is_current(i915);
 
+       /*
+        * Immediately park the GPU so that we enable powersaving and
+        * treat it as idle. The next time we issue a request, we will
+        * unpark and start using the engine->pinned_default_state, otherwise
+        * it is in limbo and an early reset may fail.
+        */
+       __i915_gem_park(i915);
+
        for_each_engine(engine, i915, id) {
                struct i915_vma *state;
+               void *vaddr;
+
+               GEM_BUG_ON(to_intel_context(ctx, engine)->pin_count);
 
                state = to_intel_context(ctx, engine)->state;
                if (!state)
@@ -5438,6 +5454,16 @@ static int __intel_engines_record_defaults(struct drm_i915_private *i915)
                        goto err_active;
 
                engine->default_state = i915_gem_object_get(state->obj);
+
+               /* Check we can acquire the image of the context state */
+               vaddr = i915_gem_object_pin_map(engine->default_state,
+                                               I915_MAP_FORCE_WB);
+               if (IS_ERR(vaddr)) {
+                       err = PTR_ERR(vaddr);
+                       goto err_active;
+               }
+
+               i915_gem_object_unpin_map(engine->default_state);
        }
 
        if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)) {
index 747b817..f772593 100644 (file)
@@ -862,7 +862,7 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
                ret = -EINVAL;
                break;
        case I915_CONTEXT_PARAM_NO_ZEROMAP:
-               args->value = ctx->flags & CONTEXT_NO_ZEROMAP;
+               args->value = test_bit(UCONTEXT_NO_ZEROMAP, &ctx->user_flags);
                break;
        case I915_CONTEXT_PARAM_GTT_SIZE:
                if (ctx->ppgtt)
@@ -896,27 +896,23 @@ int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data,
        struct drm_i915_file_private *file_priv = file->driver_priv;
        struct drm_i915_gem_context_param *args = data;
        struct i915_gem_context *ctx;
-       int ret;
+       int ret = 0;
 
        ctx = i915_gem_context_lookup(file_priv, args->ctx_id);
        if (!ctx)
                return -ENOENT;
 
-       ret = i915_mutex_lock_interruptible(dev);
-       if (ret)
-               goto out;
-
        switch (args->param) {
        case I915_CONTEXT_PARAM_BAN_PERIOD:
                ret = -EINVAL;
                break;
        case I915_CONTEXT_PARAM_NO_ZEROMAP:
-               if (args->size) {
+               if (args->size)
                        ret = -EINVAL;
-               } else {
-                       ctx->flags &= ~CONTEXT_NO_ZEROMAP;
-                       ctx->flags |= args->value ? CONTEXT_NO_ZEROMAP : 0;
-               }
+               else if (args->value)
+                       set_bit(UCONTEXT_NO_ZEROMAP, &ctx->user_flags);
+               else
+                       clear_bit(UCONTEXT_NO_ZEROMAP, &ctx->user_flags);
                break;
        case I915_CONTEXT_PARAM_NO_ERROR_CAPTURE:
                if (args->size)
@@ -960,9 +956,7 @@ int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data,
                ret = -EINVAL;
                break;
        }
-       mutex_unlock(&dev->struct_mutex);
 
-out:
        i915_gem_context_put(ctx);
        return ret;
 }
index e09673c..08165f6 100644 (file)
@@ -116,16 +116,21 @@ struct i915_gem_context {
         */
        struct rcu_head rcu;
 
+       /**
+        * @user_flags: small set of booleans controlled by the user
+        */
+       unsigned long user_flags;
+#define UCONTEXT_NO_ZEROMAP            0
+#define UCONTEXT_NO_ERROR_CAPTURE      1
+#define UCONTEXT_BANNABLE              2
+
        /**
         * @flags: small set of booleans
         */
        unsigned long flags;
-#define CONTEXT_NO_ZEROMAP             BIT(0)
-#define CONTEXT_NO_ERROR_CAPTURE       1
-#define CONTEXT_CLOSED                 2
-#define CONTEXT_BANNABLE               3
-#define CONTEXT_BANNED                 4
-#define CONTEXT_FORCE_SINGLE_SUBMISSION        5
+#define CONTEXT_BANNED                 0
+#define CONTEXT_CLOSED                 1
+#define CONTEXT_FORCE_SINGLE_SUBMISSION        2
 
        /**
         * @hw_id: - unique identifier for the context
@@ -209,37 +214,37 @@ static inline bool i915_gem_context_is_closed(const struct i915_gem_context *ctx
 static inline void i915_gem_context_set_closed(struct i915_gem_context *ctx)
 {
        GEM_BUG_ON(i915_gem_context_is_closed(ctx));
-       __set_bit(CONTEXT_CLOSED, &ctx->flags);
+       set_bit(CONTEXT_CLOSED, &ctx->flags);
 }
 
 static inline bool i915_gem_context_no_error_capture(const struct i915_gem_context *ctx)
 {
-       return test_bit(CONTEXT_NO_ERROR_CAPTURE, &ctx->flags);
+       return test_bit(UCONTEXT_NO_ERROR_CAPTURE, &ctx->user_flags);
 }
 
 static inline void i915_gem_context_set_no_error_capture(struct i915_gem_context *ctx)
 {
-       __set_bit(CONTEXT_NO_ERROR_CAPTURE, &ctx->flags);
+       set_bit(UCONTEXT_NO_ERROR_CAPTURE, &ctx->user_flags);
 }
 
 static inline void i915_gem_context_clear_no_error_capture(struct i915_gem_context *ctx)
 {
-       __clear_bit(CONTEXT_NO_ERROR_CAPTURE, &ctx->flags);
+       clear_bit(UCONTEXT_NO_ERROR_CAPTURE, &ctx->user_flags);
 }
 
 static inline bool i915_gem_context_is_bannable(const struct i915_gem_context *ctx)
 {
-       return test_bit(CONTEXT_BANNABLE, &ctx->flags);
+       return test_bit(UCONTEXT_BANNABLE, &ctx->user_flags);
 }
 
 static inline void i915_gem_context_set_bannable(struct i915_gem_context *ctx)
 {
-       __set_bit(CONTEXT_BANNABLE, &ctx->flags);
+       set_bit(UCONTEXT_BANNABLE, &ctx->user_flags);
 }
 
 static inline void i915_gem_context_clear_bannable(struct i915_gem_context *ctx)
 {
-       __clear_bit(CONTEXT_BANNABLE, &ctx->flags);
+       clear_bit(UCONTEXT_BANNABLE, &ctx->user_flags);
 }
 
 static inline bool i915_gem_context_is_banned(const struct i915_gem_context *ctx)
@@ -249,7 +254,7 @@ static inline bool i915_gem_context_is_banned(const struct i915_gem_context *ctx
 
 static inline void i915_gem_context_set_banned(struct i915_gem_context *ctx)
 {
-       __set_bit(CONTEXT_BANNED, &ctx->flags);
+       set_bit(CONTEXT_BANNED, &ctx->flags);
 }
 
 static inline bool i915_gem_context_force_single_submission(const struct i915_gem_context *ctx)
index 22b4cb7..0918728 100644 (file)
@@ -693,9 +693,14 @@ static int eb_reserve(struct i915_execbuffer *eb)
                        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 @@ static int eb_select_context(struct i915_execbuffer *eb)
        }
 
        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;
index eb0e446..f6c7ab4 100644 (file)
@@ -152,10 +152,10 @@ int intel_sanitize_enable_ppgtt(struct drm_i915_private *dev_priv,
        }
 
        /*
-        * We don't allow disabling PPGTT for gen9+ as it's a requirement for
+        * We don't allow disabling PPGTT for gen8+ as it's a requirement for
         * execlists, the sole mechanism available to submit work.
         */
-       if (enable_ppgtt == 0 && INTEL_GEN(dev_priv) < 9)
+       if (enable_ppgtt == 0 && !HAS_EXECLISTS(dev_priv))
                return 0;
 
        if (enable_ppgtt == 1)
@@ -1050,7 +1050,7 @@ gen8_ppgtt_insert_pte_entries(struct i915_hw_ppgtt *ppgtt,
        do {
                vaddr[idx->pte] = pte_encode | iter->dma;
 
-               iter->dma += PAGE_SIZE;
+               iter->dma += I915_GTT_PAGE_SIZE;
                if (iter->dma >= iter->max) {
                        iter->sg = __sg_next(iter->sg);
                        if (!iter->sg) {
@@ -1144,7 +1144,7 @@ static void gen8_ppgtt_insert_huge_entries(struct i915_vma *vma,
                            vma->page_sizes.sg & I915_GTT_PAGE_SIZE_64K &&
                            IS_ALIGNED(iter->dma, I915_GTT_PAGE_SIZE_64K) &&
                            (IS_ALIGNED(rem, I915_GTT_PAGE_SIZE_64K) ||
-                            rem >= (max - index) << PAGE_SHIFT))
+                            rem >= (max - index) * I915_GTT_PAGE_SIZE))
                                maybe_64K = true;
 
                        vaddr = kmap_atomic_px(pt);
@@ -1169,7 +1169,7 @@ static void gen8_ppgtt_insert_huge_entries(struct i915_vma *vma,
                                if (maybe_64K && index < max &&
                                    !(IS_ALIGNED(iter->dma, I915_GTT_PAGE_SIZE_64K) &&
                                      (IS_ALIGNED(rem, I915_GTT_PAGE_SIZE_64K) ||
-                                      rem >= (max - index) << PAGE_SHIFT)))
+                                      rem >= (max - index) * I915_GTT_PAGE_SIZE)))
                                        maybe_64K = false;
 
                                if (unlikely(!IS_ALIGNED(iter->dma, page_size)))
@@ -1759,7 +1759,7 @@ static void gen6_dump_ppgtt(struct i915_hw_ppgtt *base, struct seq_file *m)
 
                        seq_printf(m, "\t\t(%03d, %04d) %08lx: ",
                                   pde, pte,
-                                  (pde * GEN6_PTES + pte) * PAGE_SIZE);
+                                  (pde * GEN6_PTES + pte) * I915_GTT_PAGE_SIZE);
                        for (i = 0; i < 4; i++) {
                                if (vaddr[pte + i] != scratch_pte)
                                        seq_printf(m, " %08x", vaddr[pte + i]);
@@ -1842,10 +1842,10 @@ static void gen6_ppgtt_clear_range(struct i915_address_space *vm,
                                   u64 start, u64 length)
 {
        struct gen6_hw_ppgtt *ppgtt = to_gen6_ppgtt(i915_vm_to_ppgtt(vm));
-       unsigned int first_entry = start >> PAGE_SHIFT;
+       unsigned int first_entry = start / I915_GTT_PAGE_SIZE;
        unsigned int pde = first_entry / GEN6_PTES;
        unsigned int pte = first_entry % GEN6_PTES;
-       unsigned int num_entries = length >> PAGE_SHIFT;
+       unsigned int num_entries = length / I915_GTT_PAGE_SIZE;
        const gen6_pte_t scratch_pte = ppgtt->scratch_pte;
 
        while (num_entries) {
@@ -1886,7 +1886,7 @@ static void gen6_ppgtt_insert_entries(struct i915_address_space *vm,
                                      u32 flags)
 {
        struct i915_hw_ppgtt *ppgtt = i915_vm_to_ppgtt(vm);
-       unsigned first_entry = vma->node.start >> PAGE_SHIFT;
+       unsigned first_entry = vma->node.start / I915_GTT_PAGE_SIZE;
        unsigned act_pt = first_entry / GEN6_PTES;
        unsigned act_pte = first_entry % GEN6_PTES;
        const u32 pte_encode = vm->pte_encode(0, cache_level, flags);
@@ -1899,7 +1899,7 @@ static void gen6_ppgtt_insert_entries(struct i915_address_space *vm,
        do {
                vaddr[act_pte] = pte_encode | GEN6_PTE_ADDR_ENCODE(iter.dma);
 
-               iter.dma += PAGE_SIZE;
+               iter.dma += I915_GTT_PAGE_SIZE;
                if (iter.dma == iter.max) {
                        iter.sg = __sg_next(iter.sg);
                        if (!iter.sg)
@@ -2037,7 +2037,7 @@ static int pd_vma_bind(struct i915_vma *vma,
 {
        struct i915_ggtt *ggtt = i915_vm_to_ggtt(vma->vm);
        struct gen6_hw_ppgtt *ppgtt = vma->private;
-       u32 ggtt_offset = i915_ggtt_offset(vma) / PAGE_SIZE;
+       u32 ggtt_offset = i915_ggtt_offset(vma) / I915_GTT_PAGE_SIZE;
        struct i915_page_table *pt;
        unsigned int pde;
 
@@ -2163,7 +2163,7 @@ static struct i915_hw_ppgtt *gen6_ppgtt_create(struct drm_i915_private *i915)
        ppgtt->base.vm.i915 = i915;
        ppgtt->base.vm.dma = &i915->drm.pdev->dev;
 
-       ppgtt->base.vm.total = I915_PDES * GEN6_PTES * PAGE_SIZE;
+       ppgtt->base.vm.total = I915_PDES * GEN6_PTES * I915_GTT_PAGE_SIZE;
 
        i915_address_space_init(&ppgtt->base.vm, i915);
 
@@ -2456,7 +2456,7 @@ static void gen8_ggtt_insert_page(struct i915_address_space *vm,
 {
        struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
        gen8_pte_t __iomem *pte =
-               (gen8_pte_t __iomem *)ggtt->gsm + (offset >> PAGE_SHIFT);
+               (gen8_pte_t __iomem *)ggtt->gsm + offset / I915_GTT_PAGE_SIZE;
 
        gen8_set_pte(pte, gen8_pte_encode(addr, level, 0));
 
@@ -2480,7 +2480,7 @@ static void gen8_ggtt_insert_entries(struct i915_address_space *vm,
         */
 
        gtt_entries = (gen8_pte_t __iomem *)ggtt->gsm;
-       gtt_entries += vma->node.start >> PAGE_SHIFT;
+       gtt_entries += vma->node.start / I915_GTT_PAGE_SIZE;
        for_each_sgt_dma(addr, sgt_iter, vma->pages)
                gen8_set_pte(gtt_entries++, pte_encode | addr);
 
@@ -2499,7 +2499,7 @@ static void gen6_ggtt_insert_page(struct i915_address_space *vm,
 {
        struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
        gen6_pte_t __iomem *pte =
-               (gen6_pte_t __iomem *)ggtt->gsm + (offset >> PAGE_SHIFT);
+               (gen6_pte_t __iomem *)ggtt->gsm + offset / I915_GTT_PAGE_SIZE;
 
        iowrite32(vm->pte_encode(addr, level, flags), pte);
 
@@ -2519,7 +2519,7 @@ static void gen6_ggtt_insert_entries(struct i915_address_space *vm,
 {
        struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
        gen6_pte_t __iomem *entries = (gen6_pte_t __iomem *)ggtt->gsm;
-       unsigned int i = vma->node.start >> PAGE_SHIFT;
+       unsigned int i = vma->node.start / I915_GTT_PAGE_SIZE;
        struct sgt_iter iter;
        dma_addr_t addr;
        for_each_sgt_dma(addr, iter, vma->pages)
@@ -2541,8 +2541,8 @@ static void gen8_ggtt_clear_range(struct i915_address_space *vm,
                                  u64 start, u64 length)
 {
        struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
-       unsigned first_entry = start >> PAGE_SHIFT;
-       unsigned num_entries = length >> PAGE_SHIFT;
+       unsigned first_entry = start / I915_GTT_PAGE_SIZE;
+       unsigned num_entries = length / I915_GTT_PAGE_SIZE;
        const gen8_pte_t scratch_pte =
                gen8_pte_encode(vm->scratch_page.daddr, I915_CACHE_LLC, 0);
        gen8_pte_t __iomem *gtt_base =
@@ -2657,8 +2657,8 @@ static void gen6_ggtt_clear_range(struct i915_address_space *vm,
                                  u64 start, u64 length)
 {
        struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
-       unsigned first_entry = start >> PAGE_SHIFT;
-       unsigned num_entries = length >> PAGE_SHIFT;
+       unsigned first_entry = start / I915_GTT_PAGE_SIZE;
+       unsigned num_entries = length / I915_GTT_PAGE_SIZE;
        gen6_pte_t scratch_pte, __iomem *gtt_base =
                (gen6_pte_t __iomem *)ggtt->gsm + first_entry;
        const int max_entries = ggtt_total_entries(ggtt) - first_entry;
@@ -3005,7 +3005,7 @@ void i915_ggtt_cleanup_hw(struct drm_i915_private *dev_priv)
        arch_phys_wc_del(ggtt->mtrr);
        io_mapping_fini(&ggtt->iomap);
 
-       i915_gem_cleanup_stolen(&dev_priv->drm);
+       i915_gem_cleanup_stolen(dev_priv);
 }
 
 static unsigned int gen6_get_total_gtt_size(u16 snb_gmch_ctl)
@@ -3023,7 +3023,7 @@ static unsigned int gen8_get_total_gtt_size(u16 bdw_gmch_ctl)
                bdw_gmch_ctl = 1 << bdw_gmch_ctl;
 
 #ifdef CONFIG_X86_32
-       /* Limit 32b platforms to a 2GB GGTT: 4 << 20 / pte size * PAGE_SIZE */
+       /* Limit 32b platforms to a 2GB GGTT: 4 << 20 / pte size * I915_GTT_PAGE_SIZE */
        if (bdw_gmch_ctl > 4)
                bdw_gmch_ctl = 4;
 #endif
@@ -3398,7 +3398,7 @@ static int gen8_gmch_probe(struct i915_ggtt *ggtt)
        else
                size = gen8_get_total_gtt_size(snb_gmch_ctl);
 
-       ggtt->vm.total = (size / sizeof(gen8_pte_t)) << PAGE_SHIFT;
+       ggtt->vm.total = (size / sizeof(gen8_pte_t)) * I915_GTT_PAGE_SIZE;
        ggtt->vm.cleanup = gen6_gmch_remove;
        ggtt->vm.insert_page = gen8_ggtt_insert_page;
        ggtt->vm.clear_range = nop_clear_range;
@@ -3456,7 +3456,7 @@ static int gen6_gmch_probe(struct i915_ggtt *ggtt)
        pci_read_config_word(pdev, SNB_GMCH_CTRL, &snb_gmch_ctl);
 
        size = gen6_get_total_gtt_size(snb_gmch_ctl);
-       ggtt->vm.total = (size / sizeof(gen6_pte_t)) << PAGE_SHIFT;
+       ggtt->vm.total = (size / sizeof(gen6_pte_t)) * I915_GTT_PAGE_SIZE;
 
        ggtt->vm.clear_range = gen6_ggtt_clear_range;
        ggtt->vm.insert_page = gen6_ggtt_insert_page;
@@ -3727,9 +3727,9 @@ rotate_pages(const dma_addr_t *in, unsigned int offset,
                         * the entries so the sg list can be happily traversed.
                         * The only thing we need are DMA addresses.
                         */
-                       sg_set_page(sg, NULL, PAGE_SIZE, 0);
+                       sg_set_page(sg, NULL, I915_GTT_PAGE_SIZE, 0);
                        sg_dma_address(sg) = in[offset + src_idx];
-                       sg_dma_len(sg) = PAGE_SIZE;
+                       sg_dma_len(sg) = I915_GTT_PAGE_SIZE;
                        sg = sg_next(sg);
                        src_idx -= stride;
                }
@@ -3742,7 +3742,7 @@ static noinline struct sg_table *
 intel_rotate_pages(struct intel_rotation_info *rot_info,
                   struct drm_i915_gem_object *obj)
 {
-       const unsigned long n_pages = obj->base.size / PAGE_SIZE;
+       const unsigned long n_pages = obj->base.size / I915_GTT_PAGE_SIZE;
        unsigned int size = intel_rotation_info_size(rot_info);
        struct sgt_iter sgt_iter;
        dma_addr_t dma_addr;
index 53440bf..f29a7ff 100644 (file)
@@ -167,10 +167,8 @@ static int i915_adjust_stolen(struct drm_i915_private *dev_priv,
        return 0;
 }
 
-void i915_gem_cleanup_stolen(struct drm_device *dev)
+void i915_gem_cleanup_stolen(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
-
        if (!drm_mm_initialized(&dev_priv->mm.stolen))
                return;
 
index f7f2aa7..2835cac 100644 (file)
@@ -1365,15 +1365,20 @@ static void request_record_user_bo(struct i915_request *request,
 {
        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;
 
@@ -1382,7 +1387,8 @@ static void request_record_user_bo(struct i915_request *request,
                bo[count] = i915_error_object_create(request->i915, c->vma);
                if (!bo[count])
                        break;
-               count++;
+               if (++count == max)
+                       break;
        }
 
        ee->user_bo = bo;
index ccb2023..664b96b 100644 (file)
@@ -1679,107 +1679,6 @@ static void gen8_update_reg_state_unlocked(struct i915_gem_context *ctx,
        }
 }
 
-/*
- * Same as gen8_update_reg_state_unlocked only through the batchbuffer. This
- * is only used by the kernel context.
- */
-static int gen8_emit_oa_config(struct i915_request *rq,
-                              const struct i915_oa_config *oa_config)
-{
-       struct drm_i915_private *dev_priv = rq->i915;
-       /* The MMIO offsets for Flex EU registers aren't contiguous */
-       u32 flex_mmio[] = {
-               i915_mmio_reg_offset(EU_PERF_CNTL0),
-               i915_mmio_reg_offset(EU_PERF_CNTL1),
-               i915_mmio_reg_offset(EU_PERF_CNTL2),
-               i915_mmio_reg_offset(EU_PERF_CNTL3),
-               i915_mmio_reg_offset(EU_PERF_CNTL4),
-               i915_mmio_reg_offset(EU_PERF_CNTL5),
-               i915_mmio_reg_offset(EU_PERF_CNTL6),
-       };
-       u32 *cs;
-       int i;
-
-       cs = intel_ring_begin(rq, ARRAY_SIZE(flex_mmio) * 2 + 4);
-       if (IS_ERR(cs))
-               return PTR_ERR(cs);
-
-       *cs++ = MI_LOAD_REGISTER_IMM(ARRAY_SIZE(flex_mmio) + 1);
-
-       *cs++ = i915_mmio_reg_offset(GEN8_OACTXCONTROL);
-       *cs++ = (dev_priv->perf.oa.period_exponent << GEN8_OA_TIMER_PERIOD_SHIFT) |
-               (dev_priv->perf.oa.periodic ? GEN8_OA_TIMER_ENABLE : 0) |
-               GEN8_OA_COUNTER_RESUME;
-
-       for (i = 0; i < ARRAY_SIZE(flex_mmio); i++) {
-               u32 mmio = flex_mmio[i];
-
-               /*
-                * This arbitrary default will select the 'EU FPU0 Pipeline
-                * Active' event. In the future it's anticipated that there
-                * will be an explicit 'No Event' we can select, but not
-                * yet...
-                */
-               u32 value = 0;
-
-               if (oa_config) {
-                       u32 j;
-
-                       for (j = 0; j < oa_config->flex_regs_len; j++) {
-                               if (i915_mmio_reg_offset(oa_config->flex_regs[j].addr) == mmio) {
-                                       value = oa_config->flex_regs[j].value;
-                                       break;
-                               }
-                       }
-               }
-
-               *cs++ = mmio;
-               *cs++ = value;
-       }
-
-       *cs++ = MI_NOOP;
-       intel_ring_advance(rq, cs);
-
-       return 0;
-}
-
-static int gen8_switch_to_updated_kernel_context(struct drm_i915_private *dev_priv,
-                                                const struct i915_oa_config *oa_config)
-{
-       struct intel_engine_cs *engine = dev_priv->engine[RCS];
-       struct i915_timeline *timeline;
-       struct i915_request *rq;
-       int ret;
-
-       lockdep_assert_held(&dev_priv->drm.struct_mutex);
-
-       i915_retire_requests(dev_priv);
-
-       rq = i915_request_alloc(engine, dev_priv->kernel_context);
-       if (IS_ERR(rq))
-               return PTR_ERR(rq);
-
-       ret = gen8_emit_oa_config(rq, oa_config);
-       if (ret) {
-               i915_request_add(rq);
-               return ret;
-       }
-
-       /* Queue this switch after all other activity */
-       list_for_each_entry(timeline, &dev_priv->gt.timelines, link) {
-               struct i915_request *prev;
-
-               prev = i915_gem_active_raw(&timeline->last_request,
-                                          &dev_priv->drm.struct_mutex);
-               if (prev)
-                       i915_request_await_dma_fence(rq, &prev->fence);
-       }
-
-       i915_request_add(rq);
-
-       return 0;
-}
-
 /*
  * Manages updating the per-context aspects of the OA stream
  * configuration across all contexts.
@@ -1808,17 +1707,13 @@ static int gen8_configure_all_contexts(struct drm_i915_private *dev_priv,
                                       const struct i915_oa_config *oa_config)
 {
        struct intel_engine_cs *engine = dev_priv->engine[RCS];
+       unsigned int map_type = i915_coherent_map_type(dev_priv);
        struct i915_gem_context *ctx;
+       struct i915_request *rq;
        int ret;
-       unsigned int wait_flags = I915_WAIT_LOCKED;
 
        lockdep_assert_held(&dev_priv->drm.struct_mutex);
 
-       /* Switch away from any user context. */
-       ret = gen8_switch_to_updated_kernel_context(dev_priv, oa_config);
-       if (ret)
-               return ret;
-
        /*
         * The OA register config is setup through the context image. This image
         * might be written to by the GPU on context switch (in particular on
@@ -1833,7 +1728,7 @@ static int gen8_configure_all_contexts(struct drm_i915_private *dev_priv,
         * the GPU from any submitted work.
         */
        ret = i915_gem_wait_for_idle(dev_priv,
-                                    wait_flags,
+                                    I915_WAIT_LOCKED,
                                     MAX_SCHEDULE_TIMEOUT);
        if (ret)
                return ret;
@@ -1847,7 +1742,7 @@ static int gen8_configure_all_contexts(struct drm_i915_private *dev_priv,
                if (!ce->state)
                        continue;
 
-               regs = i915_gem_object_pin_map(ce->state->obj, I915_MAP_WB);
+               regs = i915_gem_object_pin_map(ce->state->obj, map_type);
                if (IS_ERR(regs))
                        return PTR_ERR(regs);
 
@@ -1859,7 +1754,17 @@ static int gen8_configure_all_contexts(struct drm_i915_private *dev_priv,
                i915_gem_object_unpin_map(ce->state->obj);
        }
 
-       return ret;
+       /*
+        * Apply the configuration by doing one context restore of the edited
+        * context image.
+        */
+       rq = i915_request_alloc(engine, dev_priv->kernel_context);
+       if (IS_ERR(rq))
+               return PTR_ERR(rq);
+
+       i915_request_add(rq);
+
+       return 0;
 }
 
 static int gen8_enable_metric_set(struct drm_i915_private *dev_priv,
index 09bc8e7..e7e6ca7 100644 (file)
@@ -6850,11 +6850,12 @@ enum {
 #define _PS_2B_CTRL      0x68A80
 #define _PS_1C_CTRL      0x69180
 #define PS_SCALER_EN        (1 << 31)
-#define PS_SCALER_MODE_MASK (3 << 28)
-#define PS_SCALER_MODE_DYN  (0 << 28)
-#define PS_SCALER_MODE_HQ  (1 << 28)
+#define SKL_PS_SCALER_MODE_MASK (3 << 28)
+#define SKL_PS_SCALER_MODE_DYN  (0 << 28)
+#define SKL_PS_SCALER_MODE_HQ  (1 << 28)
 #define SKL_PS_SCALER_MODE_NV12 (2 << 28)
 #define PS_SCALER_MODE_PLANAR (1 << 29)
+#define PS_SCALER_MODE_PACKED (0 << 29)
 #define PS_PLANE_SEL_MASK  (7 << 25)
 #define PS_PLANE_SEL(plane) (((plane) + 1) << 25)
 #define PS_FILTER_MASK         (3 << 23)
@@ -9583,6 +9584,54 @@ enum skl_power_gate {
 #define  DC_STATE_DEBUG_MASK_CORES     (1 << 0)
 #define  DC_STATE_DEBUG_MASK_MEMORY_UP (1 << 1)
 
+#define BXT_P_CR_MC_BIOS_REQ_0_0_0     _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x7114)
+#define  BXT_REQ_DATA_MASK                     0x3F
+#define  BXT_DRAM_CHANNEL_ACTIVE_SHIFT         12
+#define  BXT_DRAM_CHANNEL_ACTIVE_MASK          (0xF << 12)
+#define  BXT_MEMORY_FREQ_MULTIPLIER_HZ         133333333
+
+#define BXT_D_CR_DRP0_DUNIT8                   0x1000
+#define BXT_D_CR_DRP0_DUNIT9                   0x1200
+#define  BXT_D_CR_DRP0_DUNIT_START             8
+#define  BXT_D_CR_DRP0_DUNIT_END               11
+#define BXT_D_CR_DRP0_DUNIT(x) _MMIO(MCHBAR_MIRROR_BASE_SNB + \
+                                     _PICK_EVEN((x) - 8, BXT_D_CR_DRP0_DUNIT8,\
+                                                BXT_D_CR_DRP0_DUNIT9))
+#define  BXT_DRAM_RANK_MASK                    0x3
+#define  BXT_DRAM_RANK_SINGLE                  0x1
+#define  BXT_DRAM_RANK_DUAL                    0x3
+#define  BXT_DRAM_WIDTH_MASK                   (0x3 << 4)
+#define  BXT_DRAM_WIDTH_SHIFT                  4
+#define  BXT_DRAM_WIDTH_X8                     (0x0 << 4)
+#define  BXT_DRAM_WIDTH_X16                    (0x1 << 4)
+#define  BXT_DRAM_WIDTH_X32                    (0x2 << 4)
+#define  BXT_DRAM_WIDTH_X64                    (0x3 << 4)
+#define  BXT_DRAM_SIZE_MASK                    (0x7 << 6)
+#define  BXT_DRAM_SIZE_SHIFT                   6
+#define  BXT_DRAM_SIZE_4GB                     (0x0 << 6)
+#define  BXT_DRAM_SIZE_6GB                     (0x1 << 6)
+#define  BXT_DRAM_SIZE_8GB                     (0x2 << 6)
+#define  BXT_DRAM_SIZE_12GB                    (0x3 << 6)
+#define  BXT_DRAM_SIZE_16GB                    (0x4 << 6)
+
+#define SKL_MEMORY_FREQ_MULTIPLIER_HZ          266666666
+#define SKL_MC_BIOS_DATA_0_0_0_MCHBAR_PCU      _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5E04)
+#define  SKL_REQ_DATA_MASK                     (0xF << 0)
+
+#define SKL_MAD_DIMM_CH0_0_0_0_MCHBAR_MCMAIN   _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x500C)
+#define SKL_MAD_DIMM_CH1_0_0_0_MCHBAR_MCMAIN   _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5010)
+#define  SKL_DRAM_S_SHIFT                      16
+#define  SKL_DRAM_SIZE_MASK                    0x3F
+#define  SKL_DRAM_WIDTH_MASK                   (0x3 << 8)
+#define  SKL_DRAM_WIDTH_SHIFT                  8
+#define  SKL_DRAM_WIDTH_X8                     (0x0 << 8)
+#define  SKL_DRAM_WIDTH_X16                    (0x1 << 8)
+#define  SKL_DRAM_WIDTH_X32                    (0x2 << 8)
+#define  SKL_DRAM_RANK_MASK                    (0x1 << 10)
+#define  SKL_DRAM_RANK_SHIFT                   10
+#define  SKL_DRAM_RANK_SINGLE                  (0x0 << 10)
+#define  SKL_DRAM_RANK_DUAL                    (0x1 << 10)
+
 /* Please see hsw_read_dcomp() and hsw_write_dcomp() before using this register,
  * since on HSW we can't write to it using I915_WRITE. */
 #define D_COMP_HSW                     _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5F0C)
@@ -10231,6 +10280,12 @@ enum skl_power_gate {
 #define  PREPARE_COUNT_SHIFT                           0
 #define  PREPARE_COUNT_MASK                            (0x3f << 0)
 
+#define _ICL_DSI_T_INIT_MASTER_0       0x6b088
+#define _ICL_DSI_T_INIT_MASTER_1       0x6b888
+#define ICL_DSI_T_INIT_MASTER(port)    _MMIO_PORT(port,        \
+                                                  _ICL_DSI_T_INIT_MASTER_0,\
+                                                  _ICL_DSI_T_INIT_MASTER_1)
+
 /* bits 31:0 */
 #define _MIPIA_DBI_BW_CTRL             (dev_priv->mipi_mmio_base + 0xb084)
 #define _MIPIC_DBI_BW_CTRL             (dev_priv->mipi_mmio_base + 0xb884)
index 09ed488..a492385 100644 (file)
@@ -732,13 +732,13 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx)
        rq = kmem_cache_alloc(i915->requests,
                              GFP_KERNEL | __GFP_RETRY_MAYFAIL | __GFP_NOWARN);
        if (unlikely(!rq)) {
+               i915_retire_requests(i915);
+
                /* Ratelimit ourselves to prevent oom from malicious clients */
-               ret = i915_gem_wait_for_idle(i915,
-                                            I915_WAIT_LOCKED |
-                                            I915_WAIT_INTERRUPTIBLE,
-                                            MAX_SCHEDULE_TIMEOUT);
-               if (ret)
-                       goto err_unreserve;
+               rq = i915_gem_active_raw(&ce->ring->timeline->last_request,
+                                        &i915->drm.struct_mutex);
+               if (rq)
+                       cond_synchronize_rcu(rq->rcustate);
 
                /*
                 * We've forced the client to stall and catch up with whatever
@@ -758,6 +758,8 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx)
                }
        }
 
+       rq->rcustate = get_state_synchronize_rcu();
+
        INIT_LIST_HEAD(&rq->active_list);
        rq->i915 = i915;
        rq->engine = engine;
index 9898301..7fa94b0 100644 (file)
@@ -100,6 +100,14 @@ struct i915_request {
        struct i915_timeline *timeline;
        struct intel_signal_node signaling;
 
+       /*
+        * The rcu epoch of when this request was allocated. Used to judiciously
+        * apply backpressure on future allocations to ensure that under
+        * mempressure there is sufficient RCU ticks for us to reclaim our
+        * RCU protected slabs.
+        */
+       unsigned long rcustate;
+
        /*
         * Fences for the various phases in the request's lifetime.
         *
index 1de5173..6dbeed0 100644 (file)
@@ -24,13 +24,13 @@ enum {
        DEBUG_FENCE_NOTIFY,
 };
 
-#ifdef CONFIG_DRM_I915_SW_FENCE_DEBUG_OBJECTS
-
 static void *i915_sw_fence_debug_hint(void *addr)
 {
        return (void *)(((struct i915_sw_fence *)addr)->flags & I915_SW_FENCE_MASK);
 }
 
+#ifdef CONFIG_DRM_I915_SW_FENCE_DEBUG_OBJECTS
+
 static struct debug_obj_descr i915_sw_fence_debug_descr = {
        .name = "i915_sw_fence",
        .debug_hint = i915_sw_fence_debug_hint,
@@ -393,10 +393,11 @@ static void timer_i915_sw_fence_wake(struct timer_list *t)
        if (!fence)
                return;
 
-       pr_warn("asynchronous wait on fence %s:%s:%x timed out\n",
-               cb->dma->ops->get_driver_name(cb->dma),
-               cb->dma->ops->get_timeline_name(cb->dma),
-               cb->dma->seqno);
+       pr_notice("Asynchronous wait on fence %s:%s:%x timed out (hint:%pS)\n",
+                 cb->dma->ops->get_driver_name(cb->dma),
+                 cb->dma->ops->get_timeline_name(cb->dma),
+                 cb->dma->seqno,
+                 i915_sw_fence_debug_hint(fence));
 
        i915_sw_fence_complete(fence);
 }
index 13830e4..ff5b285 100644 (file)
 
 #include "intel_dsi.h"
 
+static void dsi_program_swing_and_deemphasis(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       enum port port;
+       u32 tmp;
+       int lane;
+
+       for_each_dsi_port(port, intel_dsi->ports) {
+
+               /*
+                * Program voltage swing and pre-emphasis level values as per
+                * table in BSPEC under DDI buffer programing
+                */
+               tmp = I915_READ(ICL_PORT_TX_DW5_LN0(port));
+               tmp &= ~(SCALING_MODE_SEL_MASK | RTERM_SELECT_MASK);
+               tmp |= SCALING_MODE_SEL(0x2);
+               tmp |= TAP2_DISABLE | TAP3_DISABLE;
+               tmp |= RTERM_SELECT(0x6);
+               I915_WRITE(ICL_PORT_TX_DW5_GRP(port), tmp);
+
+               tmp = I915_READ(ICL_PORT_TX_DW5_AUX(port));
+               tmp &= ~(SCALING_MODE_SEL_MASK | RTERM_SELECT_MASK);
+               tmp |= SCALING_MODE_SEL(0x2);
+               tmp |= TAP2_DISABLE | TAP3_DISABLE;
+               tmp |= RTERM_SELECT(0x6);
+               I915_WRITE(ICL_PORT_TX_DW5_AUX(port), tmp);
+
+               tmp = I915_READ(ICL_PORT_TX_DW2_LN0(port));
+               tmp &= ~(SWING_SEL_LOWER_MASK | SWING_SEL_UPPER_MASK |
+                        RCOMP_SCALAR_MASK);
+               tmp |= SWING_SEL_UPPER(0x2);
+               tmp |= SWING_SEL_LOWER(0x2);
+               tmp |= RCOMP_SCALAR(0x98);
+               I915_WRITE(ICL_PORT_TX_DW2_GRP(port), tmp);
+
+               tmp = I915_READ(ICL_PORT_TX_DW2_AUX(port));
+               tmp &= ~(SWING_SEL_LOWER_MASK | SWING_SEL_UPPER_MASK |
+                        RCOMP_SCALAR_MASK);
+               tmp |= SWING_SEL_UPPER(0x2);
+               tmp |= SWING_SEL_LOWER(0x2);
+               tmp |= RCOMP_SCALAR(0x98);
+               I915_WRITE(ICL_PORT_TX_DW2_AUX(port), tmp);
+
+               tmp = I915_READ(ICL_PORT_TX_DW4_AUX(port));
+               tmp &= ~(POST_CURSOR_1_MASK | POST_CURSOR_2_MASK |
+                        CURSOR_COEFF_MASK);
+               tmp |= POST_CURSOR_1(0x0);
+               tmp |= POST_CURSOR_2(0x0);
+               tmp |= CURSOR_COEFF(0x3f);
+               I915_WRITE(ICL_PORT_TX_DW4_AUX(port), tmp);
+
+               for (lane = 0; lane <= 3; lane++) {
+                       /* Bspec: must not use GRP register for write */
+                       tmp = I915_READ(ICL_PORT_TX_DW4_LN(port, lane));
+                       tmp &= ~(POST_CURSOR_1_MASK | POST_CURSOR_2_MASK |
+                                CURSOR_COEFF_MASK);
+                       tmp |= POST_CURSOR_1(0x0);
+                       tmp |= POST_CURSOR_2(0x0);
+                       tmp |= CURSOR_COEFF(0x3f);
+                       I915_WRITE(ICL_PORT_TX_DW4_LN(port, lane), tmp);
+               }
+       }
+}
+
 static void gen11_dsi_program_esc_clk_div(struct intel_encoder *encoder)
 {
        struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
@@ -105,10 +170,145 @@ static void gen11_dsi_power_up_lanes(struct intel_encoder *encoder)
        }
 }
 
+static void gen11_dsi_config_phy_lanes_sequence(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       enum port port;
+       u32 tmp;
+       int lane;
+
+       /* Step 4b(i) set loadgen select for transmit and aux lanes */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               tmp = I915_READ(ICL_PORT_TX_DW4_AUX(port));
+               tmp &= ~LOADGEN_SELECT;
+               I915_WRITE(ICL_PORT_TX_DW4_AUX(port), tmp);
+               for (lane = 0; lane <= 3; lane++) {
+                       tmp = I915_READ(ICL_PORT_TX_DW4_LN(port, lane));
+                       tmp &= ~LOADGEN_SELECT;
+                       if (lane != 2)
+                               tmp |= LOADGEN_SELECT;
+                       I915_WRITE(ICL_PORT_TX_DW4_LN(port, lane), tmp);
+               }
+       }
+
+       /* Step 4b(ii) set latency optimization for transmit and aux lanes */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               tmp = I915_READ(ICL_PORT_TX_DW2_AUX(port));
+               tmp &= ~FRC_LATENCY_OPTIM_MASK;
+               tmp |= FRC_LATENCY_OPTIM_VAL(0x5);
+               I915_WRITE(ICL_PORT_TX_DW2_AUX(port), tmp);
+               tmp = I915_READ(ICL_PORT_TX_DW2_LN0(port));
+               tmp &= ~FRC_LATENCY_OPTIM_MASK;
+               tmp |= FRC_LATENCY_OPTIM_VAL(0x5);
+               I915_WRITE(ICL_PORT_TX_DW2_GRP(port), tmp);
+       }
+
+}
+
+static void gen11_dsi_voltage_swing_program_seq(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       u32 tmp;
+       enum port port;
+
+       /* clear common keeper enable bit */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               tmp = I915_READ(ICL_PORT_PCS_DW1_LN0(port));
+               tmp &= ~COMMON_KEEPER_EN;
+               I915_WRITE(ICL_PORT_PCS_DW1_GRP(port), tmp);
+               tmp = I915_READ(ICL_PORT_PCS_DW1_AUX(port));
+               tmp &= ~COMMON_KEEPER_EN;
+               I915_WRITE(ICL_PORT_PCS_DW1_AUX(port), tmp);
+       }
+
+       /*
+        * Set SUS Clock Config bitfield to 11b
+        * Note: loadgen select program is done
+        * as part of lane phy sequence configuration
+        */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               tmp = I915_READ(ICL_PORT_CL_DW5(port));
+               tmp |= SUS_CLOCK_CONFIG;
+               I915_WRITE(ICL_PORT_CL_DW5(port), tmp);
+       }
+
+       /* Clear training enable to change swing values */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               tmp = I915_READ(ICL_PORT_TX_DW5_LN0(port));
+               tmp &= ~TX_TRAINING_EN;
+               I915_WRITE(ICL_PORT_TX_DW5_GRP(port), tmp);
+               tmp = I915_READ(ICL_PORT_TX_DW5_AUX(port));
+               tmp &= ~TX_TRAINING_EN;
+               I915_WRITE(ICL_PORT_TX_DW5_AUX(port), tmp);
+       }
+
+       /* Program swing and de-emphasis */
+       dsi_program_swing_and_deemphasis(encoder);
+
+       /* Set training enable to trigger update */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               tmp = I915_READ(ICL_PORT_TX_DW5_LN0(port));
+               tmp |= TX_TRAINING_EN;
+               I915_WRITE(ICL_PORT_TX_DW5_GRP(port), tmp);
+               tmp = I915_READ(ICL_PORT_TX_DW5_AUX(port));
+               tmp |= TX_TRAINING_EN;
+               I915_WRITE(ICL_PORT_TX_DW5_AUX(port), tmp);
+       }
+}
+
+static void gen11_dsi_enable_ddi_buffer(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       u32 tmp;
+       enum port port;
+
+       for_each_dsi_port(port, intel_dsi->ports) {
+               tmp = I915_READ(DDI_BUF_CTL(port));
+               tmp |= DDI_BUF_CTL_ENABLE;
+               I915_WRITE(DDI_BUF_CTL(port), tmp);
+
+               if (wait_for_us(!(I915_READ(DDI_BUF_CTL(port)) &
+                                 DDI_BUF_IS_IDLE),
+                                 500))
+                       DRM_ERROR("DDI port:%c buffer idle\n", port_name(port));
+       }
+}
+
+static void gen11_dsi_setup_dphy_timings(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       u32 tmp;
+       enum port port;
+
+       /* Program T-INIT master registers */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               tmp = I915_READ(ICL_DSI_T_INIT_MASTER(port));
+               tmp &= ~MASTER_INIT_TIMER_MASK;
+               tmp |= intel_dsi->init_count;
+               I915_WRITE(ICL_DSI_T_INIT_MASTER(port), tmp);
+       }
+}
+
 static void gen11_dsi_enable_port_and_phy(struct intel_encoder *encoder)
 {
        /* step 4a: power up all lanes of the DDI used by DSI */
        gen11_dsi_power_up_lanes(encoder);
+
+       /* step 4b: configure lane sequencing of the Combo-PHY transmitters */
+       gen11_dsi_config_phy_lanes_sequence(encoder);
+
+       /* step 4c: configure voltage swing and skew */
+       gen11_dsi_voltage_swing_program_seq(encoder);
+
+       /* enable DDI buffer */
+       gen11_dsi_enable_ddi_buffer(encoder);
+
+       /* setup D-PHY timings */
+       gen11_dsi_setup_dphy_timings(encoder);
 }
 
 static void __attribute__((unused))
index b04952b..760758a 100644 (file)
@@ -203,6 +203,62 @@ intel_crtc_destroy_state(struct drm_crtc *crtc,
        drm_atomic_helper_crtc_destroy_state(crtc, state);
 }
 
+static void intel_atomic_setup_scaler(struct intel_crtc_scaler_state *scaler_state,
+                                     int num_scalers_need, struct intel_crtc *intel_crtc,
+                                     const char *name, int idx,
+                                     struct intel_plane_state *plane_state,
+                                     int *scaler_id)
+{
+       struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
+       int j;
+       u32 mode;
+
+       if (*scaler_id < 0) {
+               /* find a free scaler */
+               for (j = 0; j < intel_crtc->num_scalers; j++) {
+                       if (scaler_state->scalers[j].in_use)
+                               continue;
+
+                       *scaler_id = j;
+                       scaler_state->scalers[*scaler_id].in_use = 1;
+                       break;
+               }
+       }
+
+       if (WARN(*scaler_id < 0, "Cannot find scaler for %s:%d\n", name, idx))
+               return;
+
+       /* set scaler mode */
+       if (plane_state && plane_state->base.fb &&
+           plane_state->base.fb->format->is_yuv &&
+           plane_state->base.fb->format->num_planes > 1) {
+               if (INTEL_GEN(dev_priv) == 9 &&
+                   !IS_GEMINILAKE(dev_priv))
+                       mode = SKL_PS_SCALER_MODE_NV12;
+               else
+                       mode = PS_SCALER_MODE_PLANAR;
+
+       } else if (INTEL_GEN(dev_priv) > 9 || IS_GEMINILAKE(dev_priv)) {
+               mode = PS_SCALER_MODE_PACKED;
+       } else if (num_scalers_need == 1 && intel_crtc->num_scalers > 1) {
+               /*
+                * when only 1 scaler is in use on a pipe with 2 scalers
+                * scaler 0 operates in high quality (HQ) mode.
+                * In this case use scaler 0 to take advantage of HQ mode
+                */
+               scaler_state->scalers[*scaler_id].in_use = 0;
+               *scaler_id = 0;
+               scaler_state->scalers[0].in_use = 1;
+               mode = SKL_PS_SCALER_MODE_HQ;
+       } else {
+               mode = SKL_PS_SCALER_MODE_DYN;
+       }
+
+       DRM_DEBUG_KMS("Attached scaler id %u.%u to %s:%d\n",
+                     intel_crtc->pipe, *scaler_id, name, idx);
+       scaler_state->scalers[*scaler_id].mode = mode;
+}
+
 /**
  * intel_atomic_setup_scalers() - setup scalers for crtc per staged requests
  * @dev_priv: i915 device
@@ -232,7 +288,7 @@ int intel_atomic_setup_scalers(struct drm_i915_private *dev_priv,
        struct drm_atomic_state *drm_state = crtc_state->base.state;
        struct intel_atomic_state *intel_state = to_intel_atomic_state(drm_state);
        int num_scalers_need;
-       int i, j;
+       int i;
 
        num_scalers_need = hweight32(scaler_state->scaler_users);
 
@@ -304,59 +360,17 @@ int intel_atomic_setup_scalers(struct drm_i915_private *dev_priv,
                        idx = plane->base.id;
 
                        /* plane on different crtc cannot be a scaler user of this crtc */
-                       if (WARN_ON(intel_plane->pipe != intel_crtc->pipe)) {
+                       if (WARN_ON(intel_plane->pipe != intel_crtc->pipe))
                                continue;
-                       }
 
                        plane_state = intel_atomic_get_new_plane_state(intel_state,
                                                                       intel_plane);
                        scaler_id = &plane_state->scaler_id;
                }
 
-               if (*scaler_id < 0) {
-                       /* find a free scaler */
-                       for (j = 0; j < intel_crtc->num_scalers; j++) {
-                               if (!scaler_state->scalers[j].in_use) {
-                                       scaler_state->scalers[j].in_use = 1;
-                                       *scaler_id = j;
-                                       DRM_DEBUG_KMS("Attached scaler id %u.%u to %s:%d\n",
-                                               intel_crtc->pipe, *scaler_id, name, idx);
-                                       break;
-                               }
-                       }
-               }
-
-               if (WARN_ON(*scaler_id < 0)) {
-                       DRM_DEBUG_KMS("Cannot find scaler for %s:%d\n", name, idx);
-                       continue;
-               }
-
-               /* set scaler mode */
-               if ((INTEL_GEN(dev_priv) >= 9) &&
-                   plane_state && plane_state->base.fb &&
-                   plane_state->base.fb->format->format ==
-                   DRM_FORMAT_NV12) {
-                       if (INTEL_GEN(dev_priv) == 9 &&
-                           !IS_GEMINILAKE(dev_priv) &&
-                           !IS_SKYLAKE(dev_priv))
-                               scaler_state->scalers[*scaler_id].mode =
-                                       SKL_PS_SCALER_MODE_NV12;
-                       else
-                               scaler_state->scalers[*scaler_id].mode =
-                                       PS_SCALER_MODE_PLANAR;
-               } else if (num_scalers_need == 1 && intel_crtc->pipe != PIPE_C) {
-                       /*
-                        * when only 1 scaler is in use on either pipe A or B,
-                        * scaler 0 operates in high quality (HQ) mode.
-                        * In this case use scaler 0 to take advantage of HQ mode
-                        */
-                       *scaler_id = 0;
-                       scaler_state->scalers[0].in_use = 1;
-                       scaler_state->scalers[0].mode = PS_SCALER_MODE_HQ;
-                       scaler_state->scalers[1].in_use = 0;
-               } else {
-                       scaler_state->scalers[*scaler_id].mode = PS_SCALER_MODE_DYN;
-               }
+               intel_atomic_setup_scaler(scaler_state, num_scalers_need,
+                                         intel_crtc, name, idx,
+                                         plane_state, scaler_id);
        }
 
        return 0;
index fa7df5f..984bc1f 100644 (file)
@@ -113,81 +113,28 @@ int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_
                                        struct intel_plane_state *intel_state)
 {
        struct drm_plane *plane = intel_state->base.plane;
-       struct drm_i915_private *dev_priv = to_i915(plane->dev);
        struct drm_plane_state *state = &intel_state->base;
        struct intel_plane *intel_plane = to_intel_plane(plane);
-       const struct drm_display_mode *adjusted_mode =
-               &crtc_state->base.adjusted_mode;
        int ret;
 
+       crtc_state->active_planes &= ~BIT(intel_plane->id);
+       crtc_state->nv12_planes &= ~BIT(intel_plane->id);
+       intel_state->base.visible = false;
+
+       /* If this is a cursor plane, no further checks are needed. */
        if (!intel_state->base.crtc && !old_plane_state->base.crtc)
                return 0;
 
-       if (state->fb && drm_rotation_90_or_270(state->rotation)) {
-               struct drm_format_name_buf format_name;
-
-               if (state->fb->modifier != I915_FORMAT_MOD_Y_TILED &&
-                   state->fb->modifier != I915_FORMAT_MOD_Yf_TILED) {
-                       DRM_DEBUG_KMS("Y/Yf tiling required for 90/270!\n");
-                       return -EINVAL;
-               }
-
-               /*
-                * 90/270 is not allowed with RGB64 16:16:16:16,
-                * RGB 16-bit 5:6:5, and Indexed 8-bit.
-                * TBD: Add RGB64 case once its added in supported format list.
-                */
-               switch (state->fb->format->format) {
-               case DRM_FORMAT_C8:
-               case DRM_FORMAT_RGB565:
-                       DRM_DEBUG_KMS("Unsupported pixel format %s for 90/270!\n",
-                                     drm_get_format_name(state->fb->format->format,
-                                                         &format_name));
-                       return -EINVAL;
-
-               default:
-                       break;
-               }
-       }
-
-       /* CHV ignores the mirror bit when the rotate bit is set :( */
-       if (IS_CHERRYVIEW(dev_priv) &&
-           state->rotation & DRM_MODE_ROTATE_180 &&
-           state->rotation & DRM_MODE_REFLECT_X) {
-               DRM_DEBUG_KMS("Cannot rotate and reflect at the same time\n");
-               return -EINVAL;
-       }
-
-       intel_state->base.visible = false;
        ret = intel_plane->check_plane(crtc_state, intel_state);
        if (ret)
                return ret;
 
-       /*
-        * Y-tiling is not supported in IF-ID Interlace mode in
-        * GEN9 and above.
-        */
-       if (state->fb && INTEL_GEN(dev_priv) >= 9 && crtc_state->base.enable &&
-           adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
-               if (state->fb->modifier == I915_FORMAT_MOD_Y_TILED ||
-                   state->fb->modifier == I915_FORMAT_MOD_Yf_TILED ||
-                   state->fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
-                   state->fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS) {
-                       DRM_DEBUG_KMS("Y/Yf tiling not supported in IF-ID mode\n");
-                       return -EINVAL;
-               }
-       }
-
        /* FIXME pre-g4x don't work like this */
        if (state->visible)
                crtc_state->active_planes |= BIT(intel_plane->id);
-       else
-               crtc_state->active_planes &= ~BIT(intel_plane->id);
 
        if (state->visible && state->fb->format->format == DRM_FORMAT_NV12)
                crtc_state->nv12_planes |= BIT(intel_plane->id);
-       else
-               crtc_state->nv12_planes &= ~BIT(intel_plane->id);
 
        return intel_plane_atomic_calc_changes(old_crtc_state,
                                               &crtc_state->base,
@@ -205,6 +152,7 @@ static int intel_plane_atomic_check(struct drm_plane *plane,
        const struct drm_crtc_state *old_crtc_state;
        struct drm_crtc_state *new_crtc_state;
 
+       new_plane_state->visible = false;
        if (!crtc)
                return 0;
 
@@ -217,29 +165,33 @@ static int intel_plane_atomic_check(struct drm_plane *plane,
                                                   to_intel_plane_state(new_plane_state));
 }
 
-static void intel_plane_atomic_update(struct drm_plane *plane,
-                                     struct drm_plane_state *old_state)
+void intel_update_planes_on_crtc(struct intel_atomic_state *old_state,
+                                struct intel_crtc *crtc,
+                                struct intel_crtc_state *old_crtc_state,
+                                struct intel_crtc_state *new_crtc_state)
 {
-       struct intel_atomic_state *state = to_intel_atomic_state(old_state->state);
-       struct intel_plane *intel_plane = to_intel_plane(plane);
-       const struct intel_plane_state *new_plane_state =
-               intel_atomic_get_new_plane_state(state, intel_plane);
-       struct drm_crtc *crtc = new_plane_state->base.crtc ?: old_state->crtc;
+       struct intel_plane_state *new_plane_state;
+       struct intel_plane *plane;
+       u32 update_mask;
+       int i;
 
-       if (new_plane_state->base.visible) {
-               const struct intel_crtc_state *new_crtc_state =
-                       intel_atomic_get_new_crtc_state(state, to_intel_crtc(crtc));
+       update_mask = old_crtc_state->active_planes;
+       update_mask |= new_crtc_state->active_planes;
 
-               trace_intel_update_plane(plane,
-                                        to_intel_crtc(crtc));
+       for_each_new_intel_plane_in_state(old_state, plane, new_plane_state, i) {
+               if (crtc->pipe != plane->pipe ||
+                   !(update_mask & BIT(plane->id)))
+                       continue;
 
-               intel_plane->update_plane(intel_plane,
-                                         new_crtc_state, new_plane_state);
-       } else {
-               trace_intel_disable_plane(plane,
-                                         to_intel_crtc(crtc));
+               if (new_plane_state->base.visible) {
+                       trace_intel_update_plane(&plane->base, crtc);
 
-               intel_plane->disable_plane(intel_plane, to_intel_crtc(crtc));
+                       plane->update_plane(plane, new_crtc_state, new_plane_state);
+               } else {
+                       trace_intel_disable_plane(&plane->base, crtc);
+
+                       plane->disable_plane(plane, crtc);
+               }
        }
 }
 
@@ -247,7 +199,6 @@ const struct drm_plane_helper_funcs intel_plane_helper_funcs = {
        .prepare_fb = intel_prepare_plane_fb,
        .cleanup_fb = intel_cleanup_plane_fb,
        .atomic_check = intel_plane_atomic_check,
-       .atomic_update = intel_plane_atomic_update,
 };
 
 /**
index 14cf4c3..4aa8f3d 100644 (file)
@@ -34,6 +34,9 @@
  * low-power state and comes back to normal.
  */
 
+#define I915_CSR_ICL "i915/icl_dmc_ver1_07.bin"
+#define ICL_CSR_VERSION_REQUIRED       CSR_VERSION(1, 7)
+
 #define I915_CSR_GLK "i915/glk_dmc_ver1_04.bin"
 MODULE_FIRMWARE(I915_CSR_GLK);
 #define GLK_CSR_VERSION_REQUIRED       CSR_VERSION(1, 4)
@@ -304,6 +307,8 @@ static uint32_t *parse_csr_fw(struct drm_i915_private *dev_priv,
        if (csr->fw_path == i915_modparams.dmc_firmware_path) {
                /* Bypass version check for firmware override. */
                required_version = csr->version;
+       } else if (IS_ICELAKE(dev_priv)) {
+               required_version = ICL_CSR_VERSION_REQUIRED;
        } else if (IS_CANNONLAKE(dev_priv)) {
                required_version = CNL_CSR_VERSION_REQUIRED;
        } else if (IS_GEMINILAKE(dev_priv)) {
@@ -471,6 +476,8 @@ void intel_csr_ucode_init(struct drm_i915_private *dev_priv)
 
        if (i915_modparams.dmc_firmware_path)
                csr->fw_path = i915_modparams.dmc_firmware_path;
+       else if (IS_ICELAKE(dev_priv))
+               csr->fw_path = I915_CSR_ICL;
        else if (IS_CANNONLAKE(dev_priv))
                csr->fw_path = I915_CSR_CNL;
        else if (IS_GEMINILAKE(dev_priv))
index cd01a09..7f34d39 100644 (file)
@@ -2077,7 +2077,7 @@ out:
 static inline enum intel_display_power_domain
 intel_ddi_main_link_aux_domain(struct intel_dp *intel_dp)
 {
-       /* CNL HW requires corresponding AUX IOs to be powered up for PSR with
+       /* CNL+ HW requires corresponding AUX IOs to be powered up for PSR with
         * DC states enabled at the same time, while for driver initiated AUX
         * transfers we need the same AUX IOs to be powered but with DC states
         * disabled. Accordingly use the AUX power domain here which leaves DC
@@ -3751,6 +3751,7 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
        struct intel_encoder *intel_encoder;
        struct drm_encoder *encoder;
        bool init_hdmi, init_dp, init_lspcon = false;
+       enum pipe pipe;
 
 
        init_hdmi = (dev_priv->vbt.ddi_port_info[port].supports_dvi ||
@@ -3801,8 +3802,9 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
        intel_encoder->type = INTEL_OUTPUT_DDI;
        intel_encoder->power_domain = intel_port_to_power_domain(port);
        intel_encoder->port = port;
-       intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
        intel_encoder->cloneable = 0;
+       for_each_pipe(dev_priv, pipe)
+               intel_encoder->crtc_mask |= BIT(pipe);
 
        if (INTEL_GEN(dev_priv) >= 11)
                intel_dig_port->saved_port_bits = I915_READ(DDI_BUF_CTL(port)) &
index 5711cb7..4c5c2b3 100644 (file)
@@ -1917,10 +1917,10 @@ static unsigned int intel_tile_size(const struct drm_i915_private *dev_priv)
 }
 
 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:
@@ -1931,7 +1931,7 @@ intel_tile_width_bytes(const struct drm_framebuffer *fb, int plane)
                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:
@@ -1940,7 +1940,7 @@ intel_tile_width_bytes(const struct drm_framebuffer *fb, int plane)
                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:
@@ -1965,22 +1965,22 @@ intel_tile_width_bytes(const struct drm_framebuffer *fb, int plane)
 }
 
 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;
@@ -1988,9 +1988,9 @@ static void intel_tile_dims(const struct drm_framebuffer *fb, int plane,
 
 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 +2044,12 @@ static unsigned int intel_linear_alignment(const struct drm_i915_private *dev_pr
 }
 
 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 +2080,13 @@ static bool intel_plane_uses_fence(const struct intel_plane_state *plane_state)
 
 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;
@@ -2096,8 +2095,6 @@ intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb,
 
        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
@@ -2130,7 +2127,7 @@ intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb,
                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 +2179,13 @@ void intel_unpin_fb_vma(struct i915_vma *vma, unsigned long flags)
        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];
 }
 
 /*
@@ -2199,11 +2196,11 @@ static int intel_fb_pitch(const struct drm_framebuffer *fb, int 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;
 }
@@ -2215,28 +2212,28 @@ u32 intel_fb_xy_to_linear(int x, int y,
  */
 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;
@@ -2257,14 +2254,15 @@ static u32 __intel_adjust_tile_offset(int *x, int *y,
        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);
 
@@ -2273,7 +2271,7 @@ static u32 _intel_adjust_tile_offset(int *x, int *y,
                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;
@@ -2282,9 +2280,9 @@ static u32 _intel_adjust_tile_offset(int *x, int *y,
                        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;
 
@@ -2299,17 +2297,19 @@ static u32 _intel_adjust_tile_offset(int *x, int *y,
  * 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
@@ -2322,15 +2322,16 @@ static u32 intel_adjust_tile_offset(int *x, int *y,
  * 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)
@@ -2341,7 +2342,7 @@ static u32 _intel_compute_tile_offset(const struct drm_i915_private *dev_priv,
                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;
@@ -2359,9 +2360,9 @@ static u32 _intel_compute_tile_offset(const struct drm_i915_private *dev_priv,
                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;
@@ -2373,42 +2374,44 @@ static u32 _intel_compute_tile_offset(const struct drm_i915_private *dev_priv,
        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 +2568,10 @@ intel_fill_fb_info(struct drm_i915_private *dev_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) {
@@ -2614,10 +2618,10 @@ intel_fill_fb_info(struct drm_i915_private *dev_priv,
                         * 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;
 
@@ -2636,9 +2640,9 @@ intel_fill_fb_info(struct drm_i915_private *dev_priv,
                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 +2857,15 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
        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);
@@ -2899,10 +2908,11 @@ valid_fb:
                  &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 +2960,9 @@ static bool skl_check_main_ccs_coordinates(struct intel_plane_state *plane_state
        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) {
@@ -2966,8 +2976,8 @@ static bool skl_check_main_ccs_coordinates(struct intel_plane_state *plane_state
 
                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;
        }
@@ -2975,30 +2985,24 @@ static bool skl_check_main_ccs_coordinates(struct intel_plane_state *plane_state
        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",
@@ -3006,26 +3010,8 @@ static int skl_check_main_surface(const struct intel_crtc_state *crtc_state,
                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);
 
        /*
@@ -3034,8 +3020,8 @@ static int skl_check_main_surface(const struct intel_crtc_state *crtc_state,
         * 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
@@ -3046,14 +3032,14 @@ static int skl_check_main_surface(const struct intel_crtc_state *crtc_state,
        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);
                }
        }
 
@@ -3066,26 +3052,25 @@ static int skl_check_main_surface(const struct intel_crtc_state *crtc_state,
                        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 +3104,7 @@ static int skl_check_nv12_aux_surface(struct intel_plane_state *plane_state)
        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) {
@@ -3128,9 +3113,9 @@ static int skl_check_nv12_aux_surface(struct intel_plane_state *plane_state)
                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 +3131,29 @@ static int skl_check_ccs_aux_surface(struct intel_plane_state *plane_state)
        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);
+
+       ret = intel_plane_check_stride(plane_state);
+       if (ret)
+               return ret;
 
        if (!plane_state->base.visible)
                return 0;
@@ -3189,7 +3169,7 @@ int skl_check_plane_surface(const struct intel_crtc_state *crtc_state,
         * 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);
@@ -3200,18 +3180,45 @@ int skl_check_plane_surface(const struct intel_crtc_state *crtc_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 +3285,30 @@ int i9xx_check_plane_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 src_x = plane_state->base.src.x1 >> 16;
        int src_y = plane_state->base.src.y1 >> 16;
        u32 offset;
+       int ret;
+
+       intel_fill_fb_ggtt_view(&plane_state->view, fb, rotation);
+       plane_state->color_plane[0].stride = intel_fb_pitch(fb, 0, rotation);
+
+       ret = intel_plane_check_stride(plane_state);
+       if (ret)
+               return ret;
 
        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;
 
@@ -3304,9 +3320,43 @@ int i9xx_check_plane_surface(struct intel_plane_state *plane_state)
                }
        }
 
-       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 +3366,19 @@ static void i9xx_update_plane(struct intel_plane *plane,
                              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;
 
@@ -3353,7 +3402,7 @@ static void i9xx_update_plane(struct intel_plane *plane,
 
        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 +3477,12 @@ static bool i9xx_plane_get_hw_state(struct intel_plane *plane,
 }
 
 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 +3512,24 @@ static void skl_detach_scalers(struct intel_crtc *intel_crtc)
        }
 }
 
-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;
 }
@@ -5362,24 +5411,23 @@ static void intel_pre_plane_update(struct intel_crtc_state *old_crtc_state,
                intel_update_watermarks(crtc);
 }
 
-static void intel_crtc_disable_planes(struct drm_crtc *crtc, unsigned plane_mask)
+static void intel_crtc_disable_planes(struct intel_crtc *crtc, unsigned plane_mask)
 {
-       struct drm_device *dev = crtc->dev;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct drm_plane *p;
-       int pipe = intel_crtc->pipe;
+       struct drm_device *dev = crtc->base.dev;
+       struct intel_plane *plane;
+       unsigned fb_bits = 0;
 
-       intel_crtc_dpms_overlay_disable(intel_crtc);
+       intel_crtc_dpms_overlay_disable(crtc);
 
-       drm_for_each_plane_mask(p, dev, plane_mask)
-               to_intel_plane(p)->disable_plane(to_intel_plane(p), intel_crtc);
+       for_each_intel_plane_on_crtc(dev, crtc, plane) {
+               if (plane_mask & BIT(plane->id)) {
+                       plane->disable_plane(plane, crtc);
 
-       /*
-        * FIXME: Once we grow proper nuclear flip support out of this we need
-        * to compute the mask of flip planes precisely. For the time being
-        * consider this a flip to a NULL plane.
-        */
-       intel_frontbuffer_flip(to_i915(dev), INTEL_FRONTBUFFER_ALL_MASK(pipe));
+                       fb_bits |= plane->frontbuffer_bit;
+               }
+       }
+
+       intel_frontbuffer_flip(to_i915(dev), fb_bits);
 }
 
 static void intel_encoders_pre_pll_enable(struct drm_crtc *crtc,
@@ -6014,6 +6062,8 @@ static void valleyview_crtc_enable(struct intel_crtc_state *pipe_config,
 
        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 +6163,8 @@ static void i9xx_pfit_disable(struct intel_crtc *crtc)
 
        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);
 }
 
@@ -8634,8 +8684,8 @@ static int ironlake_crtc_compute_clock(struct intel_crtc *crtc,
        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 +9252,8 @@ static int haswell_crtc_compute_clock(struct intel_crtc *crtc,
                        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 +9642,7 @@ static u32 intel_cursor_base(const struct intel_plane_state *plane_state)
        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,55 +9685,86 @@ static bool intel_cursor_size_ok(const struct intel_plane_state *plane_state)
                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;
        int ret;
 
-       ret = drm_atomic_helper_check_plane_state(&plane_state->base,
-                                                 &crtc_state->base,
-                                                 DRM_PLANE_HELPER_NO_SCALING,
-                                                 DRM_PLANE_HELPER_NO_SCALING,
-                                                 true, true);
+       intel_fill_fb_ggtt_view(&plane_state->view, fb, rotation);
+       plane_state->color_plane[0].stride = intel_fb_pitch(fb, 0, rotation);
+
+       ret = intel_plane_check_stride(plane_state);
        if (ret)
                return ret;
 
-       if (!fb)
-               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);
+       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->main.offset = offset;
+       plane_state->color_plane[0].offset = offset;
 
        return 0;
 }
 
-static u32 i845_cursor_ctl(const struct intel_crtc_state *crtc_state,
-                          const struct intel_plane_state *plane_state)
+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,
+                                                 DRM_PLANE_HELPER_NO_SCALING,
+                                                 true, 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 = 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)
+{
        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 +9800,9 @@ static int i845_check_cursor(struct intel_crtc_state *crtc_state,
                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 +9891,14 @@ static bool i845_cursor_get_hw_state(struct intel_plane *plane,
        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 +10004,9 @@ static int i9xx_check_cursor(struct intel_crtc_state *crtc_state,
                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);
@@ -10730,8 +10825,6 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc,
 }
 
 static const struct drm_crtc_helper_funcs intel_helper_funcs = {
-       .atomic_begin = intel_begin_crtc_commit,
-       .atomic_flush = intel_finish_crtc_commit,
        .atomic_check = intel_crtc_atomic_check,
 };
 
@@ -12400,6 +12493,7 @@ static void intel_update_crtc(struct drm_crtc *crtc,
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct intel_crtc_state *old_intel_cstate = to_intel_crtc_state(old_crtc_state);
        struct intel_crtc_state *pipe_config = to_intel_crtc_state(new_crtc_state);
        bool modeset = needs_modeset(new_crtc_state);
        struct intel_plane_state *new_plane_state =
@@ -12420,7 +12514,12 @@ static void intel_update_crtc(struct drm_crtc *crtc,
        if (new_plane_state)
                intel_fbc_enable(intel_crtc, pipe_config, new_plane_state);
 
-       drm_atomic_helper_commit_planes_on_crtc(old_crtc_state);
+       intel_begin_crtc_commit(crtc, old_crtc_state);
+
+       intel_update_planes_on_crtc(to_intel_atomic_state(state), intel_crtc,
+                                   old_intel_cstate, pipe_config);
+
+       intel_finish_crtc_commit(crtc, old_crtc_state);
 }
 
 static void intel_update_crtcs(struct drm_atomic_state *state)
@@ -12581,8 +12680,9 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
        struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct drm_crtc_state *old_crtc_state, *new_crtc_state;
+       struct intel_crtc_state *new_intel_crtc_state, *old_intel_crtc_state;
        struct drm_crtc *crtc;
-       struct intel_crtc_state *intel_cstate;
+       struct intel_crtc *intel_crtc;
        u64 put_domains[I915_MAX_PIPES] = {};
        int i;
 
@@ -12594,24 +12694,25 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
                intel_display_power_get(dev_priv, POWER_DOMAIN_MODESET);
 
        for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
-               struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+               old_intel_crtc_state = to_intel_crtc_state(old_crtc_state);
+               new_intel_crtc_state = to_intel_crtc_state(new_crtc_state);
+               intel_crtc = to_intel_crtc(crtc);
 
                if (needs_modeset(new_crtc_state) ||
                    to_intel_crtc_state(new_crtc_state)->update_pipe) {
 
-                       put_domains[to_intel_crtc(crtc)->pipe] =
+                       put_domains[intel_crtc->pipe] =
                                modeset_get_crtc_power_domains(crtc,
-                                       to_intel_crtc_state(new_crtc_state));
+                                       new_intel_crtc_state);
                }
 
                if (!needs_modeset(new_crtc_state))
                        continue;
 
-               intel_pre_plane_update(to_intel_crtc_state(old_crtc_state),
-                                      to_intel_crtc_state(new_crtc_state));
+               intel_pre_plane_update(old_intel_crtc_state, new_intel_crtc_state);
 
                if (old_crtc_state->active) {
-                       intel_crtc_disable_planes(crtc, old_crtc_state->plane_mask);
+                       intel_crtc_disable_planes(intel_crtc, old_intel_crtc_state->active_planes);
 
                        /*
                         * We need to disable pipe CRC before disabling the pipe,
@@ -12619,7 +12720,7 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
                         */
                        intel_crtc_disable_pipe_crc(intel_crtc);
 
-                       dev_priv->display.crtc_disable(to_intel_crtc_state(old_crtc_state), state);
+                       dev_priv->display.crtc_disable(old_intel_crtc_state, state);
                        intel_crtc->active = false;
                        intel_fbc_disable(intel_crtc);
                        intel_disable_shared_dpll(intel_crtc);
@@ -12640,7 +12741,7 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
                                 */
                                if (INTEL_GEN(dev_priv) >= 9)
                                        dev_priv->display.initial_watermarks(intel_state,
-                                                                            to_intel_crtc_state(new_crtc_state));
+                                                                            new_intel_crtc_state);
                        }
                }
        }
@@ -12700,11 +12801,11 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
         * TODO: Move this (and other cleanup) to an async worker eventually.
         */
        for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
-               intel_cstate = to_intel_crtc_state(new_crtc_state);
+               new_intel_crtc_state = to_intel_crtc_state(new_crtc_state);
 
                if (dev_priv->display.optimize_watermarks)
                        dev_priv->display.optimize_watermarks(intel_state,
-                                                             intel_cstate);
+                                                             new_intel_crtc_state);
        }
 
        for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
@@ -12982,7 +13083,7 @@ static int intel_plane_pin_fb(struct intel_plane_state *plane_state)
        }
 
        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 +13261,17 @@ intel_cleanup_plane_fb(struct drm_plane *plane,
 }
 
 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;
 
@@ -13196,61 +13295,6 @@ skl_max_scale(struct intel_crtc *intel_crtc,
        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)
 {
@@ -13488,14 +13532,16 @@ intel_legacy_cursor_update(struct drm_plane *plane,
        struct drm_plane_state *old_plane_state, *new_plane_state;
        struct intel_plane *intel_plane = to_intel_plane(plane);
        struct drm_framebuffer *old_fb;
-       struct drm_crtc_state *crtc_state = crtc->state;
+       struct intel_crtc_state *crtc_state =
+               to_intel_crtc_state(crtc->state);
+       struct intel_crtc_state *new_crtc_state;
 
        /*
         * When crtc is inactive or there is a modeset pending,
         * wait for it to complete in the slowpath
         */
-       if (!crtc_state->active || needs_modeset(crtc_state) ||
-           to_intel_crtc_state(crtc_state)->update_pipe)
+       if (!crtc_state->base.active || needs_modeset(&crtc_state->base) ||
+           crtc_state->update_pipe)
                goto slow;
 
        old_plane_state = plane->state;
@@ -13525,6 +13571,12 @@ intel_legacy_cursor_update(struct drm_plane *plane,
        if (!new_plane_state)
                return -ENOMEM;
 
+       new_crtc_state = to_intel_crtc_state(intel_crtc_duplicate_state(crtc));
+       if (!new_crtc_state) {
+               ret = -ENOMEM;
+               goto out_free;
+       }
+
        drm_atomic_set_fb_for_plane(new_plane_state, fb);
 
        new_plane_state->src_x = src_x;
@@ -13536,9 +13588,8 @@ intel_legacy_cursor_update(struct drm_plane *plane,
        new_plane_state->crtc_w = crtc_w;
        new_plane_state->crtc_h = crtc_h;
 
-       ret = intel_plane_atomic_check_with_state(to_intel_crtc_state(crtc->state),
-                                                 to_intel_crtc_state(crtc->state), /* FIXME need a new crtc state? */
-                                                 to_intel_plane_state(plane->state),
+       ret = intel_plane_atomic_check_with_state(crtc_state, new_crtc_state,
+                                                 to_intel_plane_state(old_plane_state),
                                                  to_intel_plane_state(new_plane_state));
        if (ret)
                goto out_free;
@@ -13560,10 +13611,21 @@ intel_legacy_cursor_update(struct drm_plane *plane,
        /* Swap plane state */
        plane->state = new_plane_state;
 
+       /*
+        * We cannot swap crtc_state as it may be in use by an atomic commit or
+        * page flip that's running simultaneously. If we swap crtc_state and
+        * destroy the old state, we will cause a use-after-free there.
+        *
+        * Only update active_planes, which is needed for our internal
+        * bookkeeping. Either value will do the right thing when updating
+        * planes atomically. If the cursor was part of the atomic update then
+        * we would have taken the slowpath.
+        */
+       crtc_state->active_planes = new_crtc_state->active_planes;
+
        if (plane->state->visible) {
                trace_intel_update_plane(plane, to_intel_crtc(crtc));
-               intel_plane->update_plane(intel_plane,
-                                         to_intel_crtc_state(crtc->state),
+               intel_plane->update_plane(intel_plane, crtc_state,
                                          to_intel_plane_state(plane->state));
        } else {
                trace_intel_disable_plane(plane, to_intel_crtc(crtc));
@@ -13575,6 +13637,8 @@ intel_legacy_cursor_update(struct drm_plane *plane,
 out_unlock:
        mutex_unlock(&dev_priv->drm.struct_mutex);
 out_free:
+       if (new_crtc_state)
+               intel_crtc_destroy_state(crtc, &new_crtc_state->base);
        if (ret)
                intel_plane_destroy_state(plane, new_plane_state);
        else
@@ -13672,12 +13736,8 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
 
        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
@@ -13704,8 +13764,6 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
                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);
@@ -13723,9 +13781,11 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
                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) {
@@ -13733,9 +13793,11 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
                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 {
@@ -13743,9 +13805,11 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
                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 +13906,19 @@ intel_cursor_plane_create(struct drm_i915_private *dev_priv,
 
        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;
@@ -13913,7 +13977,7 @@ static void intel_crtc_init_scalers(struct intel_crtc *crtc,
                struct intel_scaler *scaler = &scaler_state->scalers[i];
 
                scaler->in_use = 0;
-               scaler->mode = PS_SCALER_MODE_DYN;
+               scaler->mode = 0;
        }
 
        scaler_state->scaler_id = -1;
@@ -14380,31 +14444,18 @@ static
 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 f573121..4fcba99 100644 (file)
@@ -497,18 +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 +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 {
@@ -966,6 +967,9 @@ struct intel_plane {
         * 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);
@@ -1442,7 +1446,7 @@ void icl_unmap_plls_to_ports(struct drm_crtc *crtc,
                             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 +1569,7 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
                                    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 +1618,6 @@ void assert_fdi_rx_pll(struct drm_i915_private *dev_priv,
 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 +1647,8 @@ void intel_crtc_arm_fifo_underrun(struct intel_crtc *crtc,
 
 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 +1660,14 @@ u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state,
 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 +2135,14 @@ bool skl_plane_has_ccs(struct drm_i915_private *dev_priv,
                       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_stride(const 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);
@@ -2177,6 +2189,10 @@ struct drm_plane_state *intel_plane_duplicate_state(struct drm_plane *plane);
 void intel_plane_destroy_state(struct drm_plane *plane,
                               struct drm_plane_state *state);
 extern const struct drm_plane_helper_funcs intel_plane_helper_funcs;
+void intel_update_planes_on_crtc(struct intel_atomic_state *old_state,
+                                struct intel_crtc *crtc,
+                                struct intel_crtc_state *old_crtc_state,
+                                struct intel_crtc_state *new_crtc_state);
 int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_state,
                                        struct intel_crtc_state *crtc_state,
                                        const struct intel_plane_state *old_plane_state,
index 10cd051..217ed3e 100644 (file)
@@ -990,6 +990,9 @@ bool intel_engine_is_idle(struct intel_engine_cs *engine)
                }
                local_bh_enable();
 
+               /* Otherwise flush the tasklet if it was on another cpu */
+               tasklet_unlock_wait(t);
+
                if (READ_ONCE(engine->execlists.active))
                        return false;
        }
index 01d1d20..74d425c 100644 (file)
@@ -670,8 +670,8 @@ static void intel_fbc_update_state_cache(struct intel_crtc *crtc,
        cache->plane.src_w = drm_rect_width(&plane_state->base.src) >> 16;
        cache->plane.src_h = drm_rect_height(&plane_state->base.src) >> 16;
        cache->plane.visible = plane_state->base.visible;
-       cache->plane.adjusted_x = plane_state->main.x;
-       cache->plane.adjusted_y = plane_state->main.y;
+       cache->plane.adjusted_x = plane_state->color_plane[0].x;
+       cache->plane.adjusted_y = plane_state->color_plane[0].y;
        cache->plane.y = plane_state->base.src.y1 >> 16;
 
        if (!cache->plane.visible)
index fb2f9fc..f993329 100644 (file)
@@ -175,6 +175,9 @@ static int intelfb_create(struct drm_fb_helper *helper,
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct pci_dev *pdev = dev_priv->drm.pdev;
        struct i915_ggtt *ggtt = &dev_priv->ggtt;
+       const struct i915_ggtt_view view = {
+               .type = I915_GGTT_VIEW_NORMAL,
+       };
        struct fb_info *info;
        struct drm_framebuffer *fb;
        struct i915_vma *vma;
@@ -214,8 +217,7 @@ static int intelfb_create(struct drm_fb_helper *helper,
         * BIOS is suitable for own access.
         */
        vma = intel_pin_and_fence_fb_obj(&ifbdev->fb->base,
-                                        DRM_MODE_ROTATE_0,
-                                        false, &flags);
+                                        &view, false, &flags);
        if (IS_ERR(vma)) {
                ret = PTR_ERR(vma);
                goto out_unlock;
index 07b9d31..a81f04d 100644 (file)
@@ -557,16 +557,36 @@ static void inject_preempt_context(struct work_struct *work)
                                             preempt_work[engine->id]);
        struct intel_guc_client *client = guc->preempt_client;
        struct guc_stage_desc *stage_desc = __get_stage_desc(client);
-       u32 ctx_desc = lower_32_bits(to_intel_context(client->owner,
-                                                     engine)->lrc_desc);
+       struct intel_context *ce = to_intel_context(client->owner, engine);
        u32 data[7];
 
-       /*
-        * The ring contains commands to write GUC_PREEMPT_FINISHED into HWSP.
-        * See guc_fill_preempt_context().
-        */
+       if (!ce->ring->emit) { /* recreate upon load/resume */
+               u32 addr = intel_hws_preempt_done_address(engine);
+               u32 *cs;
+
+               cs = ce->ring->vaddr;
+               if (engine->id == RCS) {
+                       cs = gen8_emit_ggtt_write_rcs(cs,
+                                                     GUC_PREEMPT_FINISHED,
+                                                     addr);
+               } else {
+                       cs = gen8_emit_ggtt_write(cs,
+                                                 GUC_PREEMPT_FINISHED,
+                                                 addr);
+                       *cs++ = MI_NOOP;
+                       *cs++ = MI_NOOP;
+               }
+               *cs++ = MI_USER_INTERRUPT;
+               *cs++ = MI_NOOP;
+
+               ce->ring->emit = GUC_PREEMPT_BREADCRUMB_BYTES;
+               GEM_BUG_ON((void *)cs - ce->ring->vaddr != ce->ring->emit);
+
+               flush_ggtt_writes(ce->ring->vma);
+       }
+
        spin_lock_irq(&client->wq_lock);
-       guc_wq_item_append(client, engine->guc_id, ctx_desc,
+       guc_wq_item_append(client, engine->guc_id, lower_32_bits(ce->lrc_desc),
                           GUC_PREEMPT_BREADCRUMB_BYTES / sizeof(u64), 0);
        spin_unlock_irq(&client->wq_lock);
 
@@ -1044,50 +1064,6 @@ static inline bool ctx_save_restore_disabled(struct intel_context *ce)
 #undef SR_DISABLED
 }
 
-static void guc_fill_preempt_context(struct intel_guc *guc)
-{
-       struct drm_i915_private *dev_priv = guc_to_i915(guc);
-       struct intel_guc_client *client = guc->preempt_client;
-       struct intel_engine_cs *engine;
-       enum intel_engine_id id;
-
-       for_each_engine(engine, dev_priv, id) {
-               struct intel_context *ce =
-                       to_intel_context(client->owner, engine);
-               u32 addr = intel_hws_preempt_done_address(engine);
-               u32 *cs;
-
-               GEM_BUG_ON(!ce->pin_count);
-
-               /*
-                * We rely on this context image *not* being saved after
-                * preemption. This ensures that the RING_HEAD / RING_TAIL
-                * remain pointing at initial values forever.
-                */
-               GEM_BUG_ON(!ctx_save_restore_disabled(ce));
-
-               cs = ce->ring->vaddr;
-               if (id == RCS) {
-                       cs = gen8_emit_ggtt_write_rcs(cs,
-                                                     GUC_PREEMPT_FINISHED,
-                                                     addr);
-               } else {
-                       cs = gen8_emit_ggtt_write(cs,
-                                                 GUC_PREEMPT_FINISHED,
-                                                 addr);
-                       *cs++ = MI_NOOP;
-                       *cs++ = MI_NOOP;
-               }
-               *cs++ = MI_USER_INTERRUPT;
-               *cs++ = MI_NOOP;
-
-               GEM_BUG_ON((void *)cs - ce->ring->vaddr !=
-                          GUC_PREEMPT_BREADCRUMB_BYTES);
-
-               flush_ggtt_writes(ce->ring->vma);
-       }
-}
-
 static int guc_clients_create(struct intel_guc *guc)
 {
        struct drm_i915_private *dev_priv = guc_to_i915(guc);
@@ -1118,8 +1094,6 @@ static int guc_clients_create(struct intel_guc *guc)
                        return PTR_ERR(client);
                }
                guc->preempt_client = client;
-
-               guc_fill_preempt_context(guc);
        }
 
        return 0;
index 9b1f0e5..4b28225 100644 (file)
@@ -344,6 +344,7 @@ static void __unwind_incomplete_requests(struct intel_engine_cs *engine)
                        last_prio = rq_prio(rq);
                        p = lookup_priolist(engine, last_prio);
                }
+               GEM_BUG_ON(RB_EMPTY_ROOT(&engine->execlists.queue.rb_root));
 
                GEM_BUG_ON(p->priority != rq_prio(rq));
                list_add(&rq->sched.link, &p->requests);
@@ -429,7 +430,7 @@ static u64 execlists_update_context(struct i915_request *rq)
         * PML4 is allocated during ppgtt init, so this is not needed
         * in 48-bit mode.
         */
-       if (ppgtt && !i915_vm_is_48bit(&ppgtt->vm))
+       if (!i915_vm_is_48bit(&ppgtt->vm))
                execlists_update_context_pdps(ppgtt, reg_state);
 
        return ce->lrc_desc;
@@ -1294,7 +1295,7 @@ static int __context_pin(struct i915_gem_context *ctx, struct i915_vma *vma)
         * on an active context (which by nature is already on the GPU).
         */
        if (!(vma->flags & I915_VMA_GLOBAL_BIND)) {
-               err = i915_gem_object_set_to_gtt_domain(vma->obj, true);
+               err = i915_gem_object_set_to_wc_domain(vma->obj, true);
                if (err)
                        return err;
        }
@@ -1322,7 +1323,9 @@ __execlists_context_pin(struct intel_engine_cs *engine,
        if (ret)
                goto err;
 
-       vaddr = i915_gem_object_pin_map(ce->state->obj, I915_MAP_WB);
+       vaddr = i915_gem_object_pin_map(ce->state->obj,
+                                       i915_coherent_map_type(ctx->i915) |
+                                       I915_MAP_OVERRIDE);
        if (IS_ERR(vaddr)) {
                ret = PTR_ERR(vaddr);
                goto unpin_vma;
@@ -1338,11 +1341,13 @@ __execlists_context_pin(struct intel_engine_cs *engine,
 
        intel_lr_context_descriptor_update(ctx, engine, ce);
 
+       GEM_BUG_ON(!intel_ring_offset_valid(ce->ring, ce->ring->head));
+
        ce->lrc_reg_state = vaddr + LRC_STATE_PN * PAGE_SIZE;
        ce->lrc_reg_state[CTX_RING_BUFFER_START+1] =
                i915_ggtt_offset(ce->ring->vma);
-       GEM_BUG_ON(!intel_ring_offset_valid(ce->ring, ce->ring->head));
-       ce->lrc_reg_state[CTX_RING_HEAD+1] = ce->ring->head;
+       ce->lrc_reg_state[CTX_RING_HEAD + 1] = ce->ring->head;
+       ce->lrc_reg_state[CTX_RING_TAIL + 1] = ce->ring->tail;
 
        ce->state->obj->pin_global++;
        i915_gem_context_get(ctx);
@@ -1371,6 +1376,7 @@ execlists_context_pin(struct intel_engine_cs *engine,
        struct intel_context *ce = to_intel_context(ctx, engine);
 
        lockdep_assert_held(&ctx->i915->drm.struct_mutex);
+       GEM_BUG_ON(!(ctx->ppgtt ?: ctx->i915->mm.aliasing_ppgtt));
 
        if (likely(ce->pin_count++))
                return ce;
@@ -2392,7 +2398,7 @@ static int logical_ring_init(struct intel_engine_cs *engine)
 
        ret = intel_engine_init_common(engine);
        if (ret)
-               goto error;
+               return ret;
 
        if (HAS_LOGICAL_RING_ELSQ(i915)) {
                execlists->submit_reg = i915->regs +
@@ -2434,10 +2440,6 @@ static int logical_ring_init(struct intel_engine_cs *engine)
        reset_csb_pointers(execlists);
 
        return 0;
-
-error:
-       intel_logical_ring_cleanup(engine);
-       return ret;
 }
 
 int logical_render_ring_init(struct intel_engine_cs *engine)
@@ -2460,10 +2462,14 @@ int logical_render_ring_init(struct intel_engine_cs *engine)
        engine->emit_breadcrumb = gen8_emit_breadcrumb_rcs;
        engine->emit_breadcrumb_sz = gen8_emit_breadcrumb_rcs_sz;
 
-       ret = intel_engine_create_scratch(engine, PAGE_SIZE);
+       ret = logical_ring_init(engine);
        if (ret)
                return ret;
 
+       ret = intel_engine_create_scratch(engine, PAGE_SIZE);
+       if (ret)
+               goto err_cleanup_common;
+
        ret = intel_init_workaround_bb(engine);
        if (ret) {
                /*
@@ -2475,7 +2481,11 @@ int logical_render_ring_init(struct intel_engine_cs *engine)
                          ret);
        }
 
-       return logical_ring_init(engine);
+       return 0;
+
+err_cleanup_common:
+       intel_engine_cleanup_common(engine);
+       return ret;
 }
 
 int logical_xcs_ring_init(struct intel_engine_cs *engine)
@@ -2696,7 +2706,7 @@ static void execlists_init_reg_state(u32 *regs,
        CTX_REG(regs, CTX_PDP0_UDW, GEN8_RING_PDP_UDW(engine, 0), 0);
        CTX_REG(regs, CTX_PDP0_LDW, GEN8_RING_PDP_LDW(engine, 0), 0);
 
-       if (ppgtt && i915_vm_is_48bit(&ppgtt->vm)) {
+       if (i915_vm_is_48bit(&ppgtt->vm)) {
                /* 64b PPGTT (48bit canonical)
                 * PDP0_DESCRIPTOR contains the base address to PML4 and
                 * other PDP Descriptors are ignored.
@@ -2841,13 +2851,14 @@ error_deref_obj:
        return ret;
 }
 
-void intel_lr_context_resume(struct drm_i915_private *dev_priv)
+void intel_lr_context_resume(struct drm_i915_private *i915)
 {
        struct intel_engine_cs *engine;
        struct i915_gem_context *ctx;
        enum intel_engine_id id;
 
-       /* Because we emit WA_TAIL_DWORDS there may be a disparity
+       /*
+        * Because we emit WA_TAIL_DWORDS there may be a disparity
         * between our bookkeeping in ce->ring->head and ce->ring->tail and
         * that stored in context. As we only write new commands from
         * ce->ring->tail onwards, everything before that is junk. If the GPU
@@ -2857,28 +2868,22 @@ void intel_lr_context_resume(struct drm_i915_private *dev_priv)
         * So to avoid that we reset the context images upon resume. For
         * simplicity, we just zero everything out.
         */
-       list_for_each_entry(ctx, &dev_priv->contexts.list, link) {
-               for_each_engine(engine, dev_priv, id) {
+       list_for_each_entry(ctx, &i915->contexts.list, link) {
+               for_each_engine(engine, i915, id) {
                        struct intel_context *ce =
                                to_intel_context(ctx, engine);
-                       u32 *reg;
 
                        if (!ce->state)
                                continue;
 
-                       reg = i915_gem_object_pin_map(ce->state->obj,
-                                                     I915_MAP_WB);
-                       if (WARN_ON(IS_ERR(reg)))
-                               continue;
-
-                       reg += LRC_STATE_PN * PAGE_SIZE / sizeof(*reg);
-                       reg[CTX_RING_HEAD+1] = 0;
-                       reg[CTX_RING_TAIL+1] = 0;
+                       intel_ring_reset(ce->ring, 0);
 
-                       ce->state->obj->mm.dirty = true;
-                       i915_gem_object_unpin_map(ce->state->obj);
+                       if (ce->pin_count) { /* otherwise done in context_pin */
+                               u32 *regs = ce->lrc_reg_state;
 
-                       intel_ring_reset(ce->ring, 0);
+                               regs[CTX_RING_HEAD + 1] = ce->ring->head;
+                               regs[CTX_RING_TAIL + 1] = ce->ring->tail;
+                       }
                }
        }
 }
index c2f10d8..72eb7e4 100644 (file)
@@ -181,8 +181,9 @@ struct intel_overlay {
        u32 brightness, contrast, saturation;
        u32 old_xscale, old_yscale;
        /* register access */
-       u32 flip_addr;
        struct drm_i915_gem_object *reg_bo;
+       struct overlay_registers __iomem *regs;
+       u32 flip_addr;
        /* flip handling */
        struct i915_gem_active last_flip;
 };
@@ -210,29 +211,6 @@ static void i830_overlay_clock_gating(struct drm_i915_private *dev_priv,
                                  PCI_DEVFN(0, 0), I830_CLOCK_GATE, val);
 }
 
-static struct overlay_registers __iomem *
-intel_overlay_map_regs(struct intel_overlay *overlay)
-{
-       struct drm_i915_private *dev_priv = overlay->i915;
-       struct overlay_registers __iomem *regs;
-
-       if (OVERLAY_NEEDS_PHYSICAL(dev_priv))
-               regs = (struct overlay_registers __iomem *)overlay->reg_bo->phys_handle->vaddr;
-       else
-               regs = io_mapping_map_wc(&dev_priv->ggtt.iomap,
-                                        overlay->flip_addr,
-                                        PAGE_SIZE);
-
-       return regs;
-}
-
-static void intel_overlay_unmap_regs(struct intel_overlay *overlay,
-                                    struct overlay_registers __iomem *regs)
-{
-       if (!OVERLAY_NEEDS_PHYSICAL(overlay->i915))
-               io_mapping_unmap(regs);
-}
-
 static void intel_overlay_submit_request(struct intel_overlay *overlay,
                                         struct i915_request *rq,
                                         i915_gem_retire_fn retire)
@@ -509,23 +487,6 @@ void intel_overlay_reset(struct drm_i915_private *dev_priv)
        overlay->active = false;
 }
 
-struct put_image_params {
-       int format;
-       short dst_x;
-       short dst_y;
-       short dst_w;
-       short dst_h;
-       short src_w;
-       short src_scan_h;
-       short src_scan_w;
-       short src_h;
-       short stride_Y;
-       short stride_UV;
-       int offset_Y;
-       int offset_U;
-       int offset_V;
-};
-
 static int packed_depth_bytes(u32 format)
 {
        switch (format & I915_OVERLAY_DEPTH_MASK) {
@@ -640,25 +601,25 @@ static void update_polyphase_filter(struct overlay_registers __iomem *regs)
 
 static bool update_scaling_factors(struct intel_overlay *overlay,
                                   struct overlay_registers __iomem *regs,
-                                  struct put_image_params *params)
+                                  struct drm_intel_overlay_put_image *params)
 {
        /* fixed point with a 12 bit shift */
        u32 xscale, yscale, xscale_UV, yscale_UV;
 #define FP_SHIFT 12
 #define FRACT_MASK 0xfff
        bool scale_changed = false;
-       int uv_hscale = uv_hsubsampling(params->format);
-       int uv_vscale = uv_vsubsampling(params->format);
+       int uv_hscale = uv_hsubsampling(params->flags);
+       int uv_vscale = uv_vsubsampling(params->flags);
 
-       if (params->dst_w > 1)
-               xscale = ((params->src_scan_w - 1) << FP_SHIFT)
-                       /(params->dst_w);
+       if (params->dst_width > 1)
+               xscale = ((params->src_scan_width - 1) << FP_SHIFT) /
+                       params->dst_width;
        else
                xscale = 1 << FP_SHIFT;
 
-       if (params->dst_h > 1)
-               yscale = ((params->src_scan_h - 1) << FP_SHIFT)
-                       /(params->dst_h);
+       if (params->dst_height > 1)
+               yscale = ((params->src_scan_height - 1) << FP_SHIFT) /
+                       params->dst_height;
        else
                yscale = 1 << FP_SHIFT;
 
@@ -735,12 +696,12 @@ static void update_colorkey(struct intel_overlay *overlay,
        iowrite32(flags, &regs->DCLRKM);
 }
 
-static u32 overlay_cmd_reg(struct put_image_params *params)
+static u32 overlay_cmd_reg(struct drm_intel_overlay_put_image *params)
 {
        u32 cmd = OCMD_ENABLE | OCMD_BUF_TYPE_FRAME | OCMD_BUFFER0;
 
-       if (params->format & I915_OVERLAY_YUV_PLANAR) {
-               switch (params->format & I915_OVERLAY_DEPTH_MASK) {
+       if (params->flags & I915_OVERLAY_YUV_PLANAR) {
+               switch (params->flags & I915_OVERLAY_DEPTH_MASK) {
                case I915_OVERLAY_YUV422:
                        cmd |= OCMD_YUV_422_PLANAR;
                        break;
@@ -753,7 +714,7 @@ static u32 overlay_cmd_reg(struct put_image_params *params)
                        break;
                }
        } else { /* YUV packed */
-               switch (params->format & I915_OVERLAY_DEPTH_MASK) {
+               switch (params->flags & I915_OVERLAY_DEPTH_MASK) {
                case I915_OVERLAY_YUV422:
                        cmd |= OCMD_YUV_422_PACKED;
                        break;
@@ -762,7 +723,7 @@ static u32 overlay_cmd_reg(struct put_image_params *params)
                        break;
                }
 
-               switch (params->format & I915_OVERLAY_SWAP_MASK) {
+               switch (params->flags & I915_OVERLAY_SWAP_MASK) {
                case I915_OVERLAY_NO_SWAP:
                        break;
                case I915_OVERLAY_UV_SWAP:
@@ -782,15 +743,15 @@ static u32 overlay_cmd_reg(struct put_image_params *params)
 
 static int intel_overlay_do_put_image(struct intel_overlay *overlay,
                                      struct drm_i915_gem_object *new_bo,
-                                     struct put_image_params *params)
+                                     struct drm_intel_overlay_put_image *params)
 {
-       int ret, tmp_width;
-       struct overlay_registers __iomem *regs;
-       bool scale_changed = false;
+       struct overlay_registers __iomem *regs = overlay->regs;
        struct drm_i915_private *dev_priv = overlay->i915;
        u32 swidth, swidthsw, sheight, ostride;
        enum pipe pipe = overlay->crtc->pipe;
+       bool scale_changed = false;
        struct i915_vma *vma;
+       int ret, tmp_width;
 
        lockdep_assert_held(&dev_priv->drm.struct_mutex);
        WARN_ON(!drm_modeset_is_locked(&dev_priv->drm.mode_config.connection_mutex));
@@ -815,59 +776,53 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay,
 
        if (!overlay->active) {
                u32 oconfig;
-               regs = intel_overlay_map_regs(overlay);
-               if (!regs) {
-                       ret = -ENOMEM;
-                       goto out_unpin;
-               }
+
                oconfig = OCONF_CC_OUT_8BIT;
                if (IS_GEN4(dev_priv))
                        oconfig |= OCONF_CSC_MODE_BT709;
                oconfig |= pipe == 0 ?
                        OCONF_PIPE_A : OCONF_PIPE_B;
                iowrite32(oconfig, &regs->OCONFIG);
-               intel_overlay_unmap_regs(overlay, regs);
 
                ret = intel_overlay_on(overlay);
                if (ret != 0)
                        goto out_unpin;
        }
 
-       regs = intel_overlay_map_regs(overlay);
-       if (!regs) {
-               ret = -ENOMEM;
-               goto out_unpin;
-       }
-
-       iowrite32((params->dst_y << 16) | params->dst_x, &regs->DWINPOS);
-       iowrite32((params->dst_h << 16) | params->dst_w, &regs->DWINSZ);
+       iowrite32(params->dst_y << 16 | params->dst_x, &regs->DWINPOS);
+       iowrite32(params->dst_height << 16 | params->dst_width, &regs->DWINSZ);
 
-       if (params->format & I915_OVERLAY_YUV_PACKED)
-               tmp_width = packed_width_bytes(params->format, params->src_w);
+       if (params->flags & I915_OVERLAY_YUV_PACKED)
+               tmp_width = packed_width_bytes(params->flags,
+                                              params->src_width);
        else
-               tmp_width = params->src_w;
+               tmp_width = params->src_width;
 
-       swidth = params->src_w;
+       swidth = params->src_width;
        swidthsw = calc_swidthsw(dev_priv, params->offset_Y, tmp_width);
-       sheight = params->src_h;
+       sheight = params->src_height;
        iowrite32(i915_ggtt_offset(vma) + params->offset_Y, &regs->OBUF_0Y);
        ostride = params->stride_Y;
 
-       if (params->format & I915_OVERLAY_YUV_PLANAR) {
-               int uv_hscale = uv_hsubsampling(params->format);
-               int uv_vscale = uv_vsubsampling(params->format);
+       if (params->flags & I915_OVERLAY_YUV_PLANAR) {
+               int uv_hscale = uv_hsubsampling(params->flags);
+               int uv_vscale = uv_vsubsampling(params->flags);
                u32 tmp_U, tmp_V;
-               swidth |= (params->src_w/uv_hscale) << 16;
+
+               swidth |= (params->src_width / uv_hscale) << 16;
+               sheight |= (params->src_height / uv_vscale) << 16;
+
                tmp_U = calc_swidthsw(dev_priv, params->offset_U,
-                                     params->src_w/uv_hscale);
+                                     params->src_width / uv_hscale);
                tmp_V = calc_swidthsw(dev_priv, params->offset_V,
-                                     params->src_w/uv_hscale);
-               swidthsw |= max_t(u32, tmp_U, tmp_V) << 16;
-               sheight |= (params->src_h/uv_vscale) << 16;
+                                     params->src_width / uv_hscale);
+               swidthsw |= max(tmp_U, tmp_V) << 16;
+
                iowrite32(i915_ggtt_offset(vma) + params->offset_U,
                          &regs->OBUF_0U);
                iowrite32(i915_ggtt_offset(vma) + params->offset_V,
                          &regs->OBUF_0V);
+
                ostride |= params->stride_UV << 16;
        }
 
@@ -882,8 +837,6 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay,
 
        iowrite32(overlay_cmd_reg(params), &regs->OCMD);
 
-       intel_overlay_unmap_regs(overlay, regs);
-
        ret = intel_overlay_continue(overlay, vma, scale_changed);
        if (ret)
                goto out_unpin;
@@ -901,7 +854,6 @@ out_pin_section:
 int intel_overlay_switch_off(struct intel_overlay *overlay)
 {
        struct drm_i915_private *dev_priv = overlay->i915;
-       struct overlay_registers __iomem *regs;
        int ret;
 
        lockdep_assert_held(&dev_priv->drm.struct_mutex);
@@ -918,9 +870,7 @@ int intel_overlay_switch_off(struct intel_overlay *overlay)
        if (ret != 0)
                return ret;
 
-       regs = intel_overlay_map_regs(overlay);
-       iowrite32(0, &regs->OCMD);
-       intel_overlay_unmap_regs(overlay, regs);
+       iowrite32(0, &overlay->regs->OCMD);
 
        return intel_overlay_off(overlay);
 }
@@ -976,15 +926,16 @@ static int check_overlay_dst(struct intel_overlay *overlay,
                return -EINVAL;
 }
 
-static int check_overlay_scaling(struct put_image_params *rec)
+static int check_overlay_scaling(struct drm_intel_overlay_put_image *rec)
 {
        u32 tmp;
 
        /* downscaling limit is 8.0 */
-       tmp = ((rec->src_scan_h << 16) / rec->dst_h) >> 16;
+       tmp = ((rec->src_scan_height << 16) / rec->dst_height) >> 16;
        if (tmp > 7)
                return -EINVAL;
-       tmp = ((rec->src_scan_w << 16) / rec->dst_w) >> 16;
+
+       tmp = ((rec->src_scan_width << 16) / rec->dst_width) >> 16;
        if (tmp > 7)
                return -EINVAL;
 
@@ -1105,13 +1056,12 @@ static int check_overlay_src(struct drm_i915_private *dev_priv,
 int intel_overlay_put_image_ioctl(struct drm_device *dev, void *data,
                                  struct drm_file *file_priv)
 {
-       struct drm_intel_overlay_put_image *put_image_rec = data;
+       struct drm_intel_overlay_put_image *params = data;
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_overlay *overlay;
        struct drm_crtc *drmmode_crtc;
        struct intel_crtc *crtc;
        struct drm_i915_gem_object *new_bo;
-       struct put_image_params *params;
        int ret;
 
        overlay = dev_priv->overlay;
@@ -1120,7 +1070,7 @@ int intel_overlay_put_image_ioctl(struct drm_device *dev, void *data,
                return -ENODEV;
        }
 
-       if (!(put_image_rec->flags & I915_OVERLAY_ENABLE)) {
+       if (!(params->flags & I915_OVERLAY_ENABLE)) {
                drm_modeset_lock_all(dev);
                mutex_lock(&dev->struct_mutex);
 
@@ -1132,22 +1082,14 @@ int intel_overlay_put_image_ioctl(struct drm_device *dev, void *data,
                return ret;
        }
 
-       params = kmalloc(sizeof(*params), GFP_KERNEL);
-       if (!params)
-               return -ENOMEM;
-
-       drmmode_crtc = drm_crtc_find(dev, file_priv, put_image_rec->crtc_id);
-       if (!drmmode_crtc) {
-               ret = -ENOENT;
-               goto out_free;
-       }
+       drmmode_crtc = drm_crtc_find(dev, file_priv, params->crtc_id);
+       if (!drmmode_crtc)
+               return -ENOENT;
        crtc = to_intel_crtc(drmmode_crtc);
 
-       new_bo = i915_gem_object_lookup(file_priv, put_image_rec->bo_handle);
-       if (!new_bo) {
-               ret = -ENOENT;
-               goto out_free;
-       }
+       new_bo = i915_gem_object_lookup(file_priv, params->bo_handle);
+       if (!new_bo)
+               return -ENOENT;
 
        drm_modeset_lock_all(dev);
        mutex_lock(&dev->struct_mutex);
@@ -1183,42 +1125,27 @@ int intel_overlay_put_image_ioctl(struct drm_device *dev, void *data,
                        overlay->pfit_active = false;
        }
 
-       ret = check_overlay_dst(overlay, put_image_rec);
+       ret = check_overlay_dst(overlay, params);
        if (ret != 0)
                goto out_unlock;
 
        if (overlay->pfit_active) {
-               params->dst_y = ((((u32)put_image_rec->dst_y) << 12) /
+               params->dst_y = (((u32)params->dst_y << 12) /
                                 overlay->pfit_vscale_ratio);
                /* shifting right rounds downwards, so add 1 */
-               params->dst_h = ((((u32)put_image_rec->dst_height) << 12) /
+               params->dst_height = (((u32)params->dst_height << 12) /
                                 overlay->pfit_vscale_ratio) + 1;
-       } else {
-               params->dst_y = put_image_rec->dst_y;
-               params->dst_h = put_image_rec->dst_height;
        }
-       params->dst_x = put_image_rec->dst_x;
-       params->dst_w = put_image_rec->dst_width;
-
-       params->src_w = put_image_rec->src_width;
-       params->src_h = put_image_rec->src_height;
-       params->src_scan_w = put_image_rec->src_scan_width;
-       params->src_scan_h = put_image_rec->src_scan_height;
-       if (params->src_scan_h > params->src_h ||
-           params->src_scan_w > params->src_w) {
+
+       if (params->src_scan_height > params->src_height ||
+           params->src_scan_width > params->src_width) {
                ret = -EINVAL;
                goto out_unlock;
        }
 
-       ret = check_overlay_src(dev_priv, put_image_rec, new_bo);
+       ret = check_overlay_src(dev_priv, params, new_bo);
        if (ret != 0)
                goto out_unlock;
-       params->format = put_image_rec->flags & ~I915_OVERLAY_FLAGS_MASK;
-       params->stride_Y = put_image_rec->stride_Y;
-       params->stride_UV = put_image_rec->stride_UV;
-       params->offset_Y = put_image_rec->offset_Y;
-       params->offset_U = put_image_rec->offset_U;
-       params->offset_V = put_image_rec->offset_V;
 
        /* Check scaling after src size to prevent a divide-by-zero. */
        ret = check_overlay_scaling(params);
@@ -1233,16 +1160,12 @@ int intel_overlay_put_image_ioctl(struct drm_device *dev, void *data,
        drm_modeset_unlock_all(dev);
        i915_gem_object_put(new_bo);
 
-       kfree(params);
-
        return 0;
 
 out_unlock:
        mutex_unlock(&dev->struct_mutex);
        drm_modeset_unlock_all(dev);
        i915_gem_object_put(new_bo);
-out_free:
-       kfree(params);
 
        return ret;
 }
@@ -1305,7 +1228,6 @@ int intel_overlay_attrs_ioctl(struct drm_device *dev, void *data,
        struct drm_intel_overlay_attrs *attrs = data;
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_overlay *overlay;
-       struct overlay_registers __iomem *regs;
        int ret;
 
        overlay = dev_priv->overlay;
@@ -1345,15 +1267,7 @@ int intel_overlay_attrs_ioctl(struct drm_device *dev, void *data,
                overlay->contrast   = attrs->contrast;
                overlay->saturation = attrs->saturation;
 
-               regs = intel_overlay_map_regs(overlay);
-               if (!regs) {
-                       ret = -ENOMEM;
-                       goto out_unlock;
-               }
-
-               update_reg_attrs(overlay, regs);
-
-               intel_overlay_unmap_regs(overlay, regs);
+               update_reg_attrs(overlay, overlay->regs);
 
                if (attrs->flags & I915_OVERLAY_UPDATE_GAMMA) {
                        if (IS_GEN2(dev_priv))
@@ -1386,12 +1300,47 @@ out_unlock:
        return ret;
 }
 
+static int get_registers(struct intel_overlay *overlay, bool use_phys)
+{
+       struct drm_i915_gem_object *obj;
+       struct i915_vma *vma;
+       int err;
+
+       obj = i915_gem_object_create_stolen(overlay->i915, PAGE_SIZE);
+       if (obj == NULL)
+               obj = i915_gem_object_create_internal(overlay->i915, PAGE_SIZE);
+       if (IS_ERR(obj))
+               return PTR_ERR(obj);
+
+       vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, PIN_MAPPABLE);
+       if (IS_ERR(vma)) {
+               err = PTR_ERR(vma);
+               goto err_put_bo;
+       }
+
+       if (use_phys)
+               overlay->flip_addr = sg_dma_address(obj->mm.pages->sgl);
+       else
+               overlay->flip_addr = i915_ggtt_offset(vma);
+       overlay->regs = i915_vma_pin_iomap(vma);
+       i915_vma_unpin(vma);
+
+       if (IS_ERR(overlay->regs)) {
+               err = PTR_ERR(overlay->regs);
+               goto err_put_bo;
+       }
+
+       overlay->reg_bo = obj;
+       return 0;
+
+err_put_bo:
+       i915_gem_object_put(obj);
+       return err;
+}
+
 void intel_setup_overlay(struct drm_i915_private *dev_priv)
 {
        struct intel_overlay *overlay;
-       struct drm_i915_gem_object *reg_bo;
-       struct overlay_registers __iomem *regs;
-       struct i915_vma *vma = NULL;
        int ret;
 
        if (!HAS_OVERLAY(dev_priv))
@@ -1401,46 +1350,8 @@ void intel_setup_overlay(struct drm_i915_private *dev_priv)
        if (!overlay)
                return;
 
-       mutex_lock(&dev_priv->drm.struct_mutex);
-       if (WARN_ON(dev_priv->overlay))
-               goto out_free;
-
        overlay->i915 = dev_priv;
 
-       reg_bo = NULL;
-       if (!OVERLAY_NEEDS_PHYSICAL(dev_priv))
-               reg_bo = i915_gem_object_create_stolen(dev_priv, PAGE_SIZE);
-       if (reg_bo == NULL)
-               reg_bo = i915_gem_object_create(dev_priv, PAGE_SIZE);
-       if (IS_ERR(reg_bo))
-               goto out_free;
-       overlay->reg_bo = reg_bo;
-
-       if (OVERLAY_NEEDS_PHYSICAL(dev_priv)) {
-               ret = i915_gem_object_attach_phys(reg_bo, PAGE_SIZE);
-               if (ret) {
-                       DRM_ERROR("failed to attach phys overlay regs\n");
-                       goto out_free_bo;
-               }
-               overlay->flip_addr = reg_bo->phys_handle->busaddr;
-       } else {
-               vma = i915_gem_object_ggtt_pin(reg_bo, NULL,
-                                              0, PAGE_SIZE, PIN_MAPPABLE);
-               if (IS_ERR(vma)) {
-                       DRM_ERROR("failed to pin overlay register bo\n");
-                       ret = PTR_ERR(vma);
-                       goto out_free_bo;
-               }
-               overlay->flip_addr = i915_ggtt_offset(vma);
-
-               ret = i915_gem_object_set_to_gtt_domain(reg_bo, true);
-               if (ret) {
-                       DRM_ERROR("failed to move overlay register bo into the GTT\n");
-                       goto out_unpin_bo;
-               }
-       }
-
-       /* init all values */
        overlay->color_key = 0x0101fe;
        overlay->color_key_enabled = true;
        overlay->brightness = -19;
@@ -1449,44 +1360,51 @@ void intel_setup_overlay(struct drm_i915_private *dev_priv)
 
        init_request_active(&overlay->last_flip, NULL);
 
-       regs = intel_overlay_map_regs(overlay);
-       if (!regs)
-               goto out_unpin_bo;
+       mutex_lock(&dev_priv->drm.struct_mutex);
 
-       memset_io(regs, 0, sizeof(struct overlay_registers));
-       update_polyphase_filter(regs);
-       update_reg_attrs(overlay, regs);
+       ret = get_registers(overlay, OVERLAY_NEEDS_PHYSICAL(dev_priv));
+       if (ret)
+               goto out_free;
 
-       intel_overlay_unmap_regs(overlay, regs);
+       ret = i915_gem_object_set_to_gtt_domain(overlay->reg_bo, true);
+       if (ret)
+               goto out_reg_bo;
 
-       dev_priv->overlay = overlay;
        mutex_unlock(&dev_priv->drm.struct_mutex);
-       DRM_INFO("initialized overlay support\n");
+
+       memset_io(overlay->regs, 0, sizeof(struct overlay_registers));
+       update_polyphase_filter(overlay->regs);
+       update_reg_attrs(overlay, overlay->regs);
+
+       dev_priv->overlay = overlay;
+       DRM_INFO("Initialized overlay support.\n");
        return;
 
-out_unpin_bo:
-       if (vma)
-               i915_vma_unpin(vma);
-out_free_bo:
-       i915_gem_object_put(reg_bo);
+out_reg_bo:
+       i915_gem_object_put(overlay->reg_bo);
 out_free:
        mutex_unlock(&dev_priv->drm.struct_mutex);
        kfree(overlay);
-       return;
 }
 
 void intel_cleanup_overlay(struct drm_i915_private *dev_priv)
 {
-       if (!dev_priv->overlay)
+       struct intel_overlay *overlay;
+
+       overlay = fetch_and_zero(&dev_priv->overlay);
+       if (!overlay)
                return;
 
-       /* The bo's should be free'd by the generic code already.
+       /*
+        * The bo's should be free'd by the generic code already.
         * Furthermore modesetting teardown happens beforehand so the
-        * hardware should be off already */
-       WARN_ON(dev_priv->overlay->active);
+        * hardware should be off already.
+        */
+       WARN_ON(overlay->active);
 
-       i915_gem_object_put(dev_priv->overlay->reg_bo);
-       kfree(dev_priv->overlay);
+       i915_gem_object_put(overlay->reg_bo);
+
+       kfree(overlay);
 }
 
 #if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR)
@@ -1498,37 +1416,11 @@ struct intel_overlay_error_state {
        u32 isr;
 };
 
-static struct overlay_registers __iomem *
-intel_overlay_map_regs_atomic(struct intel_overlay *overlay)
-{
-       struct drm_i915_private *dev_priv = overlay->i915;
-       struct overlay_registers __iomem *regs;
-
-       if (OVERLAY_NEEDS_PHYSICAL(dev_priv))
-               /* Cast to make sparse happy, but it's wc memory anyway, so
-                * equivalent to the wc io mapping on X86. */
-               regs = (struct overlay_registers __iomem *)
-                       overlay->reg_bo->phys_handle->vaddr;
-       else
-               regs = io_mapping_map_atomic_wc(&dev_priv->ggtt.iomap,
-                                               overlay->flip_addr);
-
-       return regs;
-}
-
-static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay,
-                                       struct overlay_registers __iomem *regs)
-{
-       if (!OVERLAY_NEEDS_PHYSICAL(overlay->i915))
-               io_mapping_unmap_atomic(regs);
-}
-
 struct intel_overlay_error_state *
 intel_overlay_capture_error_state(struct drm_i915_private *dev_priv)
 {
        struct intel_overlay *overlay = dev_priv->overlay;
        struct intel_overlay_error_state *error;
-       struct overlay_registers __iomem *regs;
 
        if (!overlay || !overlay->active)
                return NULL;
@@ -1541,18 +1433,9 @@ intel_overlay_capture_error_state(struct drm_i915_private *dev_priv)
        error->isr = I915_READ(ISR);
        error->base = overlay->flip_addr;
 
-       regs = intel_overlay_map_regs_atomic(overlay);
-       if (!regs)
-               goto err;
-
-       memcpy_fromio(&error->regs, regs, sizeof(struct overlay_registers));
-       intel_overlay_unmap_regs_atomic(overlay, regs);
+       memcpy_fromio(&error->regs, overlay->regs, sizeof(error->regs));
 
        return error;
-
-err:
-       kfree(error);
-       return NULL;
 }
 
 void
index d99e5fa..1db9b83 100644 (file)
@@ -2875,6 +2875,16 @@ static void intel_read_wm_latency(struct drm_i915_private *dev_priv,
                        }
                }
 
+               /*
+                * WA Level-0 adjustment for 16GB DIMMs: SKL+
+                * If we could not get dimm info enable this WA to prevent from
+                * any underrun. If not able to get Dimm info assume 16GB dimm
+                * to avoid any underrun.
+                */
+               if (!dev_priv->dram_info.valid_dimm ||
+                   dev_priv->dram_info.is_16gb_dimm)
+                       wm[0] += 1;
+
        } else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
                uint64_t sskpd = I915_READ64(MCH_SSKPD);
 
@@ -6108,10 +6118,13 @@ void intel_enable_ipc(struct drm_i915_private *dev_priv)
        u32 val;
 
        /* Display WA #0477 WaDisableIPC: skl */
-       if (IS_SKYLAKE(dev_priv)) {
+       if (IS_SKYLAKE(dev_priv))
+               dev_priv->ipc_enabled = false;
+
+       /* Display WA #1141: SKL:all KBL:all CFL */
+       if ((IS_KABYLAKE(dev_priv) || IS_COFFEELAKE(dev_priv)) &&
+           !dev_priv->dram_info.symmetric_memory)
                dev_priv->ipc_enabled = false;
-               return;
-       }
 
        val = I915_READ(DISP_ARB_CTL2);
 
index 472939f..d0ef50b 100644 (file)
@@ -1677,9 +1677,26 @@ static int switch_context(struct i915_request *rq)
        GEM_BUG_ON(HAS_EXECLISTS(rq->i915));
 
        if (ppgtt) {
-               ret = load_pd_dir(rq, ppgtt);
-               if (ret)
-                       goto err;
+               int loops;
+
+               /*
+                * Baytail takes a little more convincing that it really needs
+                * to reload the PD between contexts. It is not just a little
+                * longer, as adding more stalls after the load_pd_dir (i.e.
+                * adding a long loop around flush_pd_dir) is not as effective
+                * as reloading the PD umpteen times. 32 is derived from
+                * experimentation (gem_exec_parallel/fds) and has no good
+                * explanation.
+                */
+               loops = 1;
+               if (engine->id == BCS && IS_VALLEYVIEW(engine->i915))
+                       loops = 32;
+
+               do {
+                       ret = load_pd_dir(rq, ppgtt);
+                       if (ret)
+                               goto err;
+               } while (--loops);
 
                if (intel_engine_flag(engine) & ppgtt->pd_dirty_rings) {
                        unwind_mm = intel_engine_flag(engine);
index 480dadb..0fdabce 100644 (file)
@@ -1996,6 +1996,7 @@ void intel_display_power_put(struct drm_i915_private *dev_priv,
        BIT_ULL(POWER_DOMAIN_PORT_DDI_F_IO))
 
 #define ICL_AUX_A_IO_POWER_DOMAINS (                   \
+       BIT_ULL(POWER_DOMAIN_AUX_IO_A) |                \
        BIT_ULL(POWER_DOMAIN_AUX_A))
 #define ICL_AUX_B_IO_POWER_DOMAINS (                   \
        BIT_ULL(POWER_DOMAIN_AUX_B))
@@ -3563,6 +3564,9 @@ static void icl_display_core_init(struct drm_i915_private *dev_priv,
 
        /* 7. Setup MBUS. */
        icl_mbus_init(dev_priv);
+
+       if (resume && dev_priv->csr.dmc_payload)
+               intel_csr_load_program(dev_priv);
 }
 
 static void icl_display_core_uninit(struct drm_i915_private *dev_priv)
index 812fe7b..701372e 100644 (file)
@@ -99,31 +99,12 @@ struct intel_sdvo {
         */
        uint16_t hotplug_active;
 
-       /**
-        * This is set if we're going to treat the device as TV-out.
-        *
-        * While we have these nice friendly flags for output types that ought
-        * to decide this for us, the S-Video output on our HDMI+S-Video card
-        * shows up as RGB1 (VGA).
-        */
-       bool is_tv;
-
        enum port port;
 
-       /**
-        * This is set if we treat the device as HDMI, instead of DVI.
-        */
-       bool is_hdmi;
        bool has_hdmi_monitor;
        bool has_hdmi_audio;
        bool rgb_quant_range_selectable;
 
-       /**
-        * This is set if we detect output of sdvo device as LVDS and
-        * have a valid fixed mode to use with the panel.
-        */
-       bool is_lvds;
-
        /**
         * This is sdvo fixed pannel mode pointer
         */
@@ -172,6 +153,11 @@ struct intel_sdvo_connector {
 
        /* this is to get the range of margin.*/
        u32 max_hscan, max_vscan;
+
+       /**
+        * This is set if we treat the device as HDMI, instead of DVI.
+        */
+       bool is_hdmi;
 };
 
 struct intel_sdvo_connector_state {
@@ -766,6 +752,7 @@ static bool intel_sdvo_get_input_timing(struct intel_sdvo *intel_sdvo,
 
 static bool
 intel_sdvo_create_preferred_input_timing(struct intel_sdvo *intel_sdvo,
+                                        struct intel_sdvo_connector *intel_sdvo_connector,
                                         uint16_t clock,
                                         uint16_t width,
                                         uint16_t height)
@@ -778,7 +765,7 @@ intel_sdvo_create_preferred_input_timing(struct intel_sdvo *intel_sdvo,
        args.height = height;
        args.interlace = 0;
 
-       if (intel_sdvo->is_lvds &&
+       if (IS_LVDS(intel_sdvo_connector) &&
           (intel_sdvo->sdvo_lvds_fixed_mode->hdisplay != width ||
            intel_sdvo->sdvo_lvds_fixed_mode->vdisplay != height))
                args.scaled = 1;
@@ -1067,6 +1054,7 @@ intel_sdvo_set_output_timings_from_mode(struct intel_sdvo *intel_sdvo,
  */
 static bool
 intel_sdvo_get_preferred_input_mode(struct intel_sdvo *intel_sdvo,
+                                   struct intel_sdvo_connector *intel_sdvo_connector,
                                    const struct drm_display_mode *mode,
                                    struct drm_display_mode *adjusted_mode)
 {
@@ -1077,6 +1065,7 @@ intel_sdvo_get_preferred_input_mode(struct intel_sdvo *intel_sdvo,
                return false;
 
        if (!intel_sdvo_create_preferred_input_timing(intel_sdvo,
+                                                     intel_sdvo_connector,
                                                      mode->clock / 10,
                                                      mode->hdisplay,
                                                      mode->vdisplay))
@@ -1127,6 +1116,8 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder,
        struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
        struct intel_sdvo_connector_state *intel_sdvo_state =
                to_intel_sdvo_connector_state(conn_state);
+       struct intel_sdvo_connector *intel_sdvo_connector =
+               to_intel_sdvo_connector(conn_state->connector);
        struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
        struct drm_display_mode *mode = &pipe_config->base.mode;
 
@@ -1142,20 +1133,22 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder,
         * timings, even though this isn't really the right place in
         * the sequence to do it. Oh well.
         */
-       if (intel_sdvo->is_tv) {
+       if (IS_TV(intel_sdvo_connector)) {
                if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, mode))
                        return false;
 
                (void) intel_sdvo_get_preferred_input_mode(intel_sdvo,
+                                                          intel_sdvo_connector,
                                                           mode,
                                                           adjusted_mode);
                pipe_config->sdvo_tv_clock = true;
-       } else if (intel_sdvo->is_lvds) {
+       } else if (IS_LVDS(intel_sdvo_connector)) {
                if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo,
                                                             intel_sdvo->sdvo_lvds_fixed_mode))
                        return false;
 
                (void) intel_sdvo_get_preferred_input_mode(intel_sdvo,
+                                                          intel_sdvo_connector,
                                                           mode,
                                                           adjusted_mode);
        }
@@ -1194,11 +1187,11 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder,
        }
 
        /* Clock computation needs to happen after pixel multiplier. */
-       if (intel_sdvo->is_tv)
+       if (IS_TV(intel_sdvo_connector))
                i9xx_adjust_sdvo_tv_clock(pipe_config);
 
        /* Set user selected PAR to incoming mode's member */
-       if (intel_sdvo->is_hdmi)
+       if (intel_sdvo_connector->is_hdmi)
                adjusted_mode->picture_aspect_ratio = conn_state->picture_aspect_ratio;
 
        return true;
@@ -1275,6 +1268,8 @@ static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder,
        const struct drm_display_mode *adjusted_mode = &crtc_state->base.adjusted_mode;
        const struct intel_sdvo_connector_state *sdvo_state =
                to_intel_sdvo_connector_state(conn_state);
+       const struct intel_sdvo_connector *intel_sdvo_connector =
+               to_intel_sdvo_connector(conn_state->connector);
        const struct drm_display_mode *mode = &crtc_state->base.mode;
        struct intel_sdvo *intel_sdvo = to_sdvo(intel_encoder);
        u32 sdvox;
@@ -1304,7 +1299,7 @@ static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder,
                return;
 
        /* lvds has a special fixed output timing. */
-       if (intel_sdvo->is_lvds)
+       if (IS_LVDS(intel_sdvo_connector))
                intel_sdvo_get_dtd_from_mode(&output_dtd,
                                             intel_sdvo->sdvo_lvds_fixed_mode);
        else
@@ -1325,13 +1320,13 @@ static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder,
        } else
                intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_DVI);
 
-       if (intel_sdvo->is_tv &&
+       if (IS_TV(intel_sdvo_connector) &&
            !intel_sdvo_set_tv_format(intel_sdvo, conn_state))
                return;
 
        intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode);
 
-       if (intel_sdvo->is_tv || intel_sdvo->is_lvds)
+       if (IS_TV(intel_sdvo_connector) || IS_LVDS(intel_sdvo_connector))
                input_dtd.part2.sdvo_flags = intel_sdvo->dtd_sdvo_flags;
        if (!intel_sdvo_set_input_timing(intel_sdvo, &input_dtd))
                DRM_INFO("Setting input timings on %s failed\n",
@@ -1630,6 +1625,8 @@ intel_sdvo_mode_valid(struct drm_connector *connector,
                      struct drm_display_mode *mode)
 {
        struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
+       struct intel_sdvo_connector *intel_sdvo_connector =
+               to_intel_sdvo_connector(connector);
        int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
 
        if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
@@ -1644,7 +1641,7 @@ intel_sdvo_mode_valid(struct drm_connector *connector,
        if (mode->clock > max_dotclk)
                return MODE_CLOCK_HIGH;
 
-       if (intel_sdvo->is_lvds) {
+       if (IS_LVDS(intel_sdvo_connector)) {
                if (mode->hdisplay > intel_sdvo->sdvo_lvds_fixed_mode->hdisplay)
                        return MODE_PANEL;
 
@@ -1759,6 +1756,8 @@ static enum drm_connector_status
 intel_sdvo_tmds_sink_detect(struct drm_connector *connector)
 {
        struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
+       struct intel_sdvo_connector *intel_sdvo_connector =
+               to_intel_sdvo_connector(connector);
        enum drm_connector_status status;
        struct edid *edid;
 
@@ -1797,7 +1796,7 @@ intel_sdvo_tmds_sink_detect(struct drm_connector *connector)
                /* DDC bus is shared, match EDID to connector type */
                if (edid->input & DRM_EDID_INPUT_DIGITAL) {
                        status = connector_status_connected;
-                       if (intel_sdvo->is_hdmi) {
+                       if (intel_sdvo_connector->is_hdmi) {
                                intel_sdvo->has_hdmi_monitor = drm_detect_hdmi_monitor(edid);
                                intel_sdvo->has_hdmi_audio = drm_detect_monitor_audio(edid);
                                intel_sdvo->rgb_quant_range_selectable =
@@ -1875,17 +1874,6 @@ intel_sdvo_detect(struct drm_connector *connector, bool force)
                        ret = connector_status_connected;
        }
 
-       /* May update encoder flag for like clock for SDVO TV, etc.*/
-       if (ret == connector_status_connected) {
-               intel_sdvo->is_tv = false;
-               intel_sdvo->is_lvds = false;
-
-               if (response & SDVO_TV_MASK)
-                       intel_sdvo->is_tv = true;
-               if (response & SDVO_LVDS_MASK)
-                       intel_sdvo->is_lvds = intel_sdvo->sdvo_lvds_fixed_mode != NULL;
-       }
-
        return ret;
 }
 
@@ -2054,16 +2042,6 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
         * arranged in priority order.
         */
        intel_ddc_get_modes(connector, &intel_sdvo->ddc);
-
-       list_for_each_entry(newmode, &connector->probed_modes, head) {
-               if (newmode->type & DRM_MODE_TYPE_PREFERRED) {
-                       intel_sdvo->sdvo_lvds_fixed_mode =
-                               drm_mode_duplicate(connector->dev, newmode);
-
-                       intel_sdvo->is_lvds = true;
-                       break;
-               }
-       }
 }
 
 static int intel_sdvo_get_modes(struct drm_connector *connector)
@@ -2555,7 +2533,7 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
        if (INTEL_GEN(dev_priv) >= 4 &&
            intel_sdvo_is_hdmi_connector(intel_sdvo, device)) {
                connector->connector_type = DRM_MODE_CONNECTOR_HDMIA;
-               intel_sdvo->is_hdmi = true;
+               intel_sdvo_connector->is_hdmi = true;
        }
 
        if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0) {
@@ -2563,7 +2541,7 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
                return false;
        }
 
-       if (intel_sdvo->is_hdmi)
+       if (intel_sdvo_connector->is_hdmi)
                intel_sdvo_add_hdmi_properties(intel_sdvo, intel_sdvo_connector);
 
        return true;
@@ -2591,8 +2569,6 @@ intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, int type)
        intel_sdvo->controlled_output |= type;
        intel_sdvo_connector->output_flag = type;
 
-       intel_sdvo->is_tv = true;
-
        if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0) {
                kfree(intel_sdvo_connector);
                return false;
@@ -2654,6 +2630,7 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device)
        struct drm_connector *connector;
        struct intel_connector *intel_connector;
        struct intel_sdvo_connector *intel_sdvo_connector;
+       struct drm_display_mode *mode;
 
        DRM_DEBUG_KMS("initialising LVDS device %d\n", device);
 
@@ -2682,6 +2659,19 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device)
        if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
                goto err;
 
+       intel_sdvo_get_lvds_modes(connector);
+
+       list_for_each_entry(mode, &connector->probed_modes, head) {
+               if (mode->type & DRM_MODE_TYPE_PREFERRED) {
+                       intel_sdvo->sdvo_lvds_fixed_mode =
+                               drm_mode_duplicate(connector->dev, mode);
+                       break;
+               }
+       }
+
+       if (!intel_sdvo->sdvo_lvds_fixed_mode)
+               goto err;
+
        return true;
 
 err:
@@ -2692,9 +2682,6 @@ err:
 static bool
 intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, uint16_t flags)
 {
-       intel_sdvo->is_tv = false;
-       intel_sdvo->is_lvds = false;
-
        /* SDVO requires XXX1 function may not exist unless it has XXX0 function.*/
 
        if (flags & SDVO_OUTPUT_TMDS0)
index 9600ccf..d9e407d 100644 (file)
@@ -230,27 +230,153 @@ void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state)
 #endif
 }
 
+int intel_plane_check_stride(const struct intel_plane_state *plane_state)
+{
+       struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
+       const struct drm_framebuffer *fb = plane_state->base.fb;
+       unsigned int rotation = plane_state->base.rotation;
+       u32 stride, max_stride;
+
+       /* FIXME other color planes? */
+       stride = plane_state->color_plane[0].stride;
+       max_stride = plane->max_stride(plane, fb->format->format,
+                                      fb->modifier, rotation);
+
+       if (stride > max_stride) {
+               DRM_DEBUG_KMS("[FB:%d] stride (%d) exceeds [PLANE:%d:%s] max stride (%d)\n",
+                             fb->base.id, stride,
+                             plane->base.base.id, plane->base.name, max_stride);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+int intel_plane_check_src_coordinates(struct intel_plane_state *plane_state)
+{
+       const struct drm_framebuffer *fb = plane_state->base.fb;
+       struct drm_rect *src = &plane_state->base.src;
+       u32 src_x, src_y, src_w, src_h;
+
+       /*
+        * Hardware doesn't handle subpixel coordinates.
+        * Adjust to (macro)pixel boundary, but be careful not to
+        * increase the source viewport size, because that could
+        * push the downscaling factor out of bounds.
+        */
+       src_x = src->x1 >> 16;
+       src_w = drm_rect_width(src) >> 16;
+       src_y = src->y1 >> 16;
+       src_h = drm_rect_height(src) >> 16;
+
+       src->x1 = src_x << 16;
+       src->x2 = (src_x + src_w) << 16;
+       src->y1 = src_y << 16;
+       src->y2 = (src_y + src_h) << 16;
+
+       if (fb->format->is_yuv &&
+           (src_x & 1 || src_w & 1)) {
+               DRM_DEBUG_KMS("src x/w (%u, %u) must be a multiple of 2 for YUV planes\n",
+                             src_x, src_w);
+               return -EINVAL;
+       }
+
+       if (fb->format->is_yuv &&
+           fb->format->num_planes > 1 &&
+           (src_y & 1 || src_h & 1)) {
+               DRM_DEBUG_KMS("src y/h (%u, %u) must be a multiple of 2 for planar YUV planes\n",
+                             src_y, src_h);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+unsigned int
+skl_plane_max_stride(struct intel_plane *plane,
+                    u32 pixel_format, u64 modifier,
+                    unsigned int rotation)
+{
+       int cpp = drm_format_plane_cpp(pixel_format, 0);
+
+       /*
+        * "The stride in bytes must not exceed the
+        * of the size of 8K pixels and 32K bytes."
+        */
+       if (drm_rotation_90_or_270(rotation))
+               return min(8192, 32768 / cpp);
+       else
+               return min(8192 * cpp, 32768);
+}
+
+static void
+skl_program_scaler(struct drm_i915_private *dev_priv,
+                  struct intel_plane *plane,
+                  const struct intel_crtc_state *crtc_state,
+                  const struct intel_plane_state *plane_state)
+{
+       enum plane_id plane_id = plane->id;
+       enum pipe pipe = plane->pipe;
+       int scaler_id = plane_state->scaler_id;
+       const struct intel_scaler *scaler =
+               &crtc_state->scaler_state.scalers[scaler_id];
+       int crtc_x = plane_state->base.dst.x1;
+       int crtc_y = plane_state->base.dst.y1;
+       uint32_t crtc_w = drm_rect_width(&plane_state->base.dst);
+       uint32_t crtc_h = drm_rect_height(&plane_state->base.dst);
+       u16 y_hphase, uv_rgb_hphase;
+       u16 y_vphase, uv_rgb_vphase;
+
+       /* Sizes are 0 based */
+       crtc_w--;
+       crtc_h--;
+
+       /* TODO: handle sub-pixel coordinates */
+       if (plane_state->base.fb->format->format == DRM_FORMAT_NV12) {
+               y_hphase = skl_scaler_calc_phase(1, false);
+               y_vphase = skl_scaler_calc_phase(1, false);
+
+               /* MPEG2 chroma siting convention */
+               uv_rgb_hphase = skl_scaler_calc_phase(2, true);
+               uv_rgb_vphase = skl_scaler_calc_phase(2, false);
+       } else {
+               /* not used */
+               y_hphase = 0;
+               y_vphase = 0;
+
+               uv_rgb_hphase = skl_scaler_calc_phase(1, false);
+               uv_rgb_vphase = skl_scaler_calc_phase(1, false);
+       }
+
+       I915_WRITE_FW(SKL_PS_CTRL(pipe, scaler_id),
+                     PS_SCALER_EN | PS_PLANE_SEL(plane_id) | scaler->mode);
+       I915_WRITE_FW(SKL_PS_PWR_GATE(pipe, scaler_id), 0);
+       I915_WRITE_FW(SKL_PS_VPHASE(pipe, scaler_id),
+                     PS_Y_PHASE(y_vphase) | PS_UV_RGB_PHASE(uv_rgb_vphase));
+       I915_WRITE_FW(SKL_PS_HPHASE(pipe, scaler_id),
+                     PS_Y_PHASE(y_hphase) | PS_UV_RGB_PHASE(uv_rgb_hphase));
+       I915_WRITE_FW(SKL_PS_WIN_POS(pipe, scaler_id), (crtc_x << 16) | crtc_y);
+       I915_WRITE_FW(SKL_PS_WIN_SZ(pipe, scaler_id),
+                     ((crtc_w + 1) << 16)|(crtc_h + 1));
+}
+
 void
 skl_update_plane(struct intel_plane *plane,
                 const struct intel_crtc_state *crtc_state,
                 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 plane_id plane_id = plane->id;
        enum pipe pipe = plane->pipe;
        u32 plane_ctl = plane_state->ctl;
        const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
-       u32 surf_addr = plane_state->main.offset;
-       unsigned int rotation = plane_state->base.rotation;
-       u32 stride = skl_plane_stride(fb, 0, rotation);
-       u32 aux_stride = skl_plane_stride(fb, 1, rotation);
+       u32 surf_addr = plane_state->color_plane[0].offset;
+       u32 stride = skl_plane_stride(plane_state, 0);
+       u32 aux_stride = skl_plane_stride(plane_state, 1);
        int crtc_x = plane_state->base.dst.x1;
        int crtc_y = plane_state->base.dst.y1;
-       uint32_t crtc_w = drm_rect_width(&plane_state->base.dst);
-       uint32_t crtc_h = drm_rect_height(&plane_state->base.dst);
-       uint32_t x = plane_state->main.x;
-       uint32_t y = plane_state->main.y;
+       uint32_t x = plane_state->color_plane[0].x;
+       uint32_t y = plane_state->color_plane[0].y;
        uint32_t src_w = drm_rect_width(&plane_state->base.src) >> 16;
        uint32_t src_h = drm_rect_height(&plane_state->base.src) >> 16;
        unsigned long irqflags;
@@ -258,8 +384,6 @@ skl_update_plane(struct intel_plane *plane,
        /* Sizes are 0 based */
        src_w--;
        src_h--;
-       crtc_w--;
-       crtc_h--;
 
        spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
 
@@ -277,45 +401,14 @@ skl_update_plane(struct intel_plane *plane,
        I915_WRITE_FW(PLANE_STRIDE(pipe, plane_id), stride);
        I915_WRITE_FW(PLANE_SIZE(pipe, plane_id), (src_h << 16) | src_w);
        I915_WRITE_FW(PLANE_AUX_DIST(pipe, plane_id),
-                     (plane_state->aux.offset - surf_addr) | aux_stride);
+                     (plane_state->color_plane[1].offset - surf_addr) | aux_stride);
        I915_WRITE_FW(PLANE_AUX_OFFSET(pipe, plane_id),
-                     (plane_state->aux.y << 16) | plane_state->aux.x);
+                     (plane_state->color_plane[1].y << 16) |
+                     plane_state->color_plane[1].x);
 
        /* program plane scaler */
        if (plane_state->scaler_id >= 0) {
-               int scaler_id = plane_state->scaler_id;
-               const struct intel_scaler *scaler =
-                       &crtc_state->scaler_state.scalers[scaler_id];
-               u16 y_hphase, uv_rgb_hphase;
-               u16 y_vphase, uv_rgb_vphase;
-
-               /* TODO: handle sub-pixel coordinates */
-               if (fb->format->format == DRM_FORMAT_NV12) {
-                       y_hphase = skl_scaler_calc_phase(1, false);
-                       y_vphase = skl_scaler_calc_phase(1, false);
-
-                       /* MPEG2 chroma siting convention */
-                       uv_rgb_hphase = skl_scaler_calc_phase(2, true);
-                       uv_rgb_vphase = skl_scaler_calc_phase(2, false);
-               } else {
-                       /* not used */
-                       y_hphase = 0;
-                       y_vphase = 0;
-
-                       uv_rgb_hphase = skl_scaler_calc_phase(1, false);
-                       uv_rgb_vphase = skl_scaler_calc_phase(1, false);
-               }
-
-               I915_WRITE_FW(SKL_PS_CTRL(pipe, scaler_id),
-                             PS_SCALER_EN | PS_PLANE_SEL(plane_id) | scaler->mode);
-               I915_WRITE_FW(SKL_PS_PWR_GATE(pipe, scaler_id), 0);
-               I915_WRITE_FW(SKL_PS_VPHASE(pipe, scaler_id),
-                             PS_Y_PHASE(y_vphase) | PS_UV_RGB_PHASE(uv_rgb_vphase));
-               I915_WRITE_FW(SKL_PS_HPHASE(pipe, scaler_id),
-                             PS_Y_PHASE(y_hphase) | PS_UV_RGB_PHASE(uv_rgb_hphase));
-               I915_WRITE_FW(SKL_PS_WIN_POS(pipe, scaler_id), (crtc_x << 16) | crtc_y);
-               I915_WRITE_FW(SKL_PS_WIN_SZ(pipe, scaler_id),
-                             ((crtc_w + 1) << 16)|(crtc_h + 1));
+               skl_program_scaler(dev_priv, plane, crtc_state, plane_state);
 
                I915_WRITE_FW(PLANE_POS(pipe, plane_id), 0);
        } else {
@@ -545,15 +638,15 @@ vlv_update_plane(struct intel_plane *plane,
        enum pipe pipe = plane->pipe;
        enum plane_id plane_id = plane->id;
        u32 sprctl = plane_state->ctl;
-       u32 sprsurf_offset = plane_state->main.offset;
+       u32 sprsurf_offset = plane_state->color_plane[0].offset;
        u32 linear_offset;
        const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
        int crtc_x = plane_state->base.dst.x1;
        int crtc_y = plane_state->base.dst.y1;
        uint32_t crtc_w = drm_rect_width(&plane_state->base.dst);
        uint32_t crtc_h = drm_rect_height(&plane_state->base.dst);
-       uint32_t x = plane_state->main.x;
-       uint32_t y = plane_state->main.y;
+       uint32_t x = plane_state->color_plane[0].x;
+       uint32_t y = plane_state->color_plane[0].y;
        unsigned long irqflags;
 
        /* Sizes are 0 based */
@@ -574,7 +667,8 @@ vlv_update_plane(struct intel_plane *plane,
                I915_WRITE_FW(SPKEYMAXVAL(pipe, plane_id), key->max_value);
                I915_WRITE_FW(SPKEYMSK(pipe, plane_id), key->channel_mask);
        }
-       I915_WRITE_FW(SPSTRIDE(pipe, plane_id), fb->pitches[0]);
+       I915_WRITE_FW(SPSTRIDE(pipe, plane_id),
+                     plane_state->color_plane[0].stride);
        I915_WRITE_FW(SPPOS(pipe, plane_id), (crtc_y << 16) | crtc_x);
 
        if (fb->modifier == I915_FORMAT_MOD_X_TILED)
@@ -704,15 +798,15 @@ ivb_update_plane(struct intel_plane *plane,
        const struct drm_framebuffer *fb = plane_state->base.fb;
        enum pipe pipe = plane->pipe;
        u32 sprctl = plane_state->ctl, sprscale = 0;
-       u32 sprsurf_offset = plane_state->main.offset;
+       u32 sprsurf_offset = plane_state->color_plane[0].offset;
        u32 linear_offset;
        const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
        int crtc_x = plane_state->base.dst.x1;
        int crtc_y = plane_state->base.dst.y1;
        uint32_t crtc_w = drm_rect_width(&plane_state->base.dst);
        uint32_t crtc_h = drm_rect_height(&plane_state->base.dst);
-       uint32_t x = plane_state->main.x;
-       uint32_t y = plane_state->main.y;
+       uint32_t x = plane_state->color_plane[0].x;
+       uint32_t y = plane_state->color_plane[0].y;
        uint32_t src_w = drm_rect_width(&plane_state->base.src) >> 16;
        uint32_t src_h = drm_rect_height(&plane_state->base.src) >> 16;
        unsigned long irqflags;
@@ -736,7 +830,7 @@ ivb_update_plane(struct intel_plane *plane,
                I915_WRITE_FW(SPRKEYMSK(pipe), key->channel_mask);
        }
 
-       I915_WRITE_FW(SPRSTRIDE(pipe), fb->pitches[0]);
+       I915_WRITE_FW(SPRSTRIDE(pipe), plane_state->color_plane[0].stride);
        I915_WRITE_FW(SPRPOS(pipe), (crtc_y << 16) | crtc_x);
 
        /* HSW consolidates SPRTILEOFF and SPRLINOFF into a single SPROFFSET
@@ -749,7 +843,7 @@ ivb_update_plane(struct intel_plane *plane,
                I915_WRITE_FW(SPRLINOFF(pipe), linear_offset);
 
        I915_WRITE_FW(SPRSIZE(pipe), (crtc_h << 16) | crtc_w);
-       if (plane->can_scale)
+       if (IS_IVYBRIDGE(dev_priv))
                I915_WRITE_FW(SPRSCALE(pipe), sprscale);
        I915_WRITE_FW(SPRCTL(pipe), sprctl);
        I915_WRITE_FW(SPRSURF(pipe),
@@ -770,7 +864,7 @@ ivb_disable_plane(struct intel_plane *plane, struct intel_crtc *crtc)
 
        I915_WRITE_FW(SPRCTL(pipe), 0);
        /* Can't leave the scaler enabled... */
-       if (plane->can_scale)
+       if (IS_IVYBRIDGE(dev_priv))
                I915_WRITE_FW(SPRSCALE(pipe), 0);
 
        I915_WRITE_FW(SPRSURF(pipe), 0);
@@ -800,6 +894,14 @@ ivb_plane_get_hw_state(struct intel_plane *plane,
        return ret;
 }
 
+static unsigned int
+g4x_sprite_max_stride(struct intel_plane *plane,
+                     u32 pixel_format, u64 modifier,
+                     unsigned int rotation)
+{
+       return 16384;
+}
+
 static u32 g4x_sprite_ctl(const struct intel_crtc_state *crtc_state,
                          const struct intel_plane_state *plane_state)
 {
@@ -868,15 +970,15 @@ g4x_update_plane(struct intel_plane *plane,
        const struct drm_framebuffer *fb = plane_state->base.fb;
        enum pipe pipe = plane->pipe;
        u32 dvscntr = plane_state->ctl, dvsscale = 0;
-       u32 dvssurf_offset = plane_state->main.offset;
+       u32 dvssurf_offset = plane_state->color_plane[0].offset;
        u32 linear_offset;
        const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
        int crtc_x = plane_state->base.dst.x1;
        int crtc_y = plane_state->base.dst.y1;
        uint32_t crtc_w = drm_rect_width(&plane_state->base.dst);
        uint32_t crtc_h = drm_rect_height(&plane_state->base.dst);
-       uint32_t x = plane_state->main.x;
-       uint32_t y = plane_state->main.y;
+       uint32_t x = plane_state->color_plane[0].x;
+       uint32_t y = plane_state->color_plane[0].y;
        uint32_t src_w = drm_rect_width(&plane_state->base.src) >> 16;
        uint32_t src_h = drm_rect_height(&plane_state->base.src) >> 16;
        unsigned long irqflags;
@@ -900,7 +1002,7 @@ g4x_update_plane(struct intel_plane *plane,
                I915_WRITE_FW(DVSKEYMSK(pipe), key->channel_mask);
        }
 
-       I915_WRITE_FW(DVSSTRIDE(pipe), fb->pitches[0]);
+       I915_WRITE_FW(DVSSTRIDE(pipe), plane_state->color_plane[0].stride);
        I915_WRITE_FW(DVSPOS(pipe), (crtc_y << 16) | crtc_x);
 
        if (fb->modifier == I915_FORMAT_MOD_X_TILED)
@@ -959,144 +1061,315 @@ g4x_plane_get_hw_state(struct intel_plane *plane,
 }
 
 static int
-intel_check_sprite_plane(struct intel_crtc_state *crtc_state,
-                        struct intel_plane_state *state)
+g4x_sprite_check_scaling(struct intel_crtc_state *crtc_state,
+                        struct intel_plane_state *plane_state)
 {
-       struct intel_plane *plane = to_intel_plane(state->base.plane);
-       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
-       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
-       struct drm_framebuffer *fb = state->base.fb;
-       int max_stride = INTEL_GEN(dev_priv) >= 9 ? 32768 : 16384;
-       int max_scale, min_scale;
-       bool can_scale;
-       int ret;
-       uint32_t pixel_format = 0;
-
-       if (!fb) {
-               state->base.visible = false;
+       const struct drm_framebuffer *fb = plane_state->base.fb;
+       const struct drm_rect *src = &plane_state->base.src;
+       const struct drm_rect *dst = &plane_state->base.dst;
+       int src_x, src_y, src_w, src_h, crtc_w, crtc_h;
+       const struct drm_display_mode *adjusted_mode =
+               &crtc_state->base.adjusted_mode;
+       unsigned int cpp = fb->format->cpp[0];
+       unsigned int width_bytes;
+       int min_width, min_height;
+
+       crtc_w = drm_rect_width(dst);
+       crtc_h = drm_rect_height(dst);
+
+       src_x = src->x1 >> 16;
+       src_y = src->y1 >> 16;
+       src_w = drm_rect_width(src) >> 16;
+       src_h = drm_rect_height(src) >> 16;
+
+       if (src_w == crtc_w && src_h == crtc_h)
                return 0;
+
+       min_width = 3;
+
+       if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
+               if (src_h & 1) {
+                       DRM_DEBUG_KMS("Source height must be even with interlaced modes\n");
+                       return -EINVAL;
+               }
+               min_height = 6;
+       } else {
+               min_height = 3;
        }
 
-       /* Don't modify another pipe's plane */
-       if (plane->pipe != crtc->pipe) {
-               DRM_DEBUG_KMS("Wrong plane <-> crtc mapping\n");
+       width_bytes = ((src_x * cpp) & 63) + src_w * cpp;
+
+       if (src_w < min_width || src_h < min_height ||
+           src_w > 2048 || src_h > 2048) {
+               DRM_DEBUG_KMS("Source dimensions (%dx%d) exceed hardware limits (%dx%d - %dx%d)\n",
+                             src_w, src_h, min_width, min_height, 2048, 2048);
                return -EINVAL;
        }
 
-       /* FIXME check all gen limits */
-       if (fb->width < 3 || fb->height < 3 || fb->pitches[0] > max_stride) {
-               DRM_DEBUG_KMS("Unsuitable framebuffer for plane\n");
+       if (width_bytes > 4096) {
+               DRM_DEBUG_KMS("Fetch width (%d) exceeds hardware max with scaling (%u)\n",
+                             width_bytes, 4096);
                return -EINVAL;
        }
 
-       /* setup can_scale, min_scale, max_scale */
-       if (INTEL_GEN(dev_priv) >= 9) {
-               if (state->base.fb)
-                       pixel_format = state->base.fb->format->format;
-               /* use scaler when colorkey is not required */
-               if (!state->ckey.flags) {
-                       can_scale = 1;
-                       min_scale = 1;
-                       max_scale =
-                               skl_max_scale(crtc, crtc_state, pixel_format);
-               } else {
-                       can_scale = 0;
-                       min_scale = DRM_PLANE_HELPER_NO_SCALING;
-                       max_scale = DRM_PLANE_HELPER_NO_SCALING;
-               }
+       if (width_bytes > 4096 || fb->pitches[0] > 4096) {
+               DRM_DEBUG_KMS("Stride (%u) exceeds hardware max with scaling (%u)\n",
+                             fb->pitches[0], 4096);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int
+g4x_sprite_check(struct intel_crtc_state *crtc_state,
+                struct intel_plane_state *plane_state)
+{
+       struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
+       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
+       int max_scale, min_scale;
+       int ret;
+
+       if (INTEL_GEN(dev_priv) < 7) {
+               min_scale = 1;
+               max_scale = 16 << 16;
+       } else if (IS_IVYBRIDGE(dev_priv)) {
+               min_scale = 1;
+               max_scale = 2 << 16;
        } else {
-               can_scale = plane->can_scale;
-               max_scale = plane->max_downscale << 16;
-               min_scale = plane->can_scale ? 1 : (1 << 16);
+               min_scale = DRM_PLANE_HELPER_NO_SCALING;
+               max_scale = DRM_PLANE_HELPER_NO_SCALING;
        }
 
-       ret = drm_atomic_helper_check_plane_state(&state->base,
+       ret = drm_atomic_helper_check_plane_state(&plane_state->base,
                                                  &crtc_state->base,
                                                  min_scale, max_scale,
                                                  true, true);
        if (ret)
                return ret;
 
-       if (state->base.visible) {
-               struct drm_rect *src = &state->base.src;
-               struct drm_rect *dst = &state->base.dst;
-               unsigned int crtc_w = drm_rect_width(dst);
-               unsigned int crtc_h = drm_rect_height(dst);
-               uint32_t src_x, src_y, src_w, src_h;
+       if (!plane_state->base.visible)
+               return 0;
+
+       ret = intel_plane_check_src_coordinates(plane_state);
+       if (ret)
+               return ret;
+
+       ret = g4x_sprite_check_scaling(crtc_state, plane_state);
+       if (ret)
+               return ret;
+
+       ret = i9xx_check_plane_surface(plane_state);
+       if (ret)
+               return ret;
+
+       if (INTEL_GEN(dev_priv) >= 7)
+               plane_state->ctl = ivb_sprite_ctl(crtc_state, plane_state);
+       else
+               plane_state->ctl = g4x_sprite_ctl(crtc_state, plane_state);
+
+       return 0;
+}
+
+int chv_plane_check_rotation(const struct intel_plane_state *plane_state)
+{
+       struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
+       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
+       unsigned int rotation = plane_state->base.rotation;
+
+       /* CHV ignores the mirror bit when the rotate bit is set :( */
+       if (IS_CHERRYVIEW(dev_priv) &&
+           rotation & DRM_MODE_ROTATE_180 &&
+           rotation & DRM_MODE_REFLECT_X) {
+               DRM_DEBUG_KMS("Cannot rotate and reflect at the same time\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int
+vlv_sprite_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,
+                                                 true, 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 = vlv_sprite_ctl(crtc_state, plane_state);
+
+       return 0;
+}
+
+static int skl_plane_check_fb(const struct intel_crtc_state *crtc_state,
+                             const struct intel_plane_state *plane_state)
+{
+       struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
+       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
+       const struct drm_framebuffer *fb = plane_state->base.fb;
+       unsigned int rotation = plane_state->base.rotation;
+       struct drm_format_name_buf format_name;
+
+       if (!fb)
+               return 0;
+
+       if (rotation & ~(DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180) &&
+           is_ccs_modifier(fb->modifier)) {
+               DRM_DEBUG_KMS("RC support only with 0/180 degree rotation (%x)\n",
+                             rotation);
+               return -EINVAL;
+       }
+
+       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;
+       }
+
+       if (drm_rotation_90_or_270(rotation)) {
+               if (fb->modifier != I915_FORMAT_MOD_Y_TILED &&
+                   fb->modifier != I915_FORMAT_MOD_Yf_TILED) {
+                       DRM_DEBUG_KMS("Y/Yf tiling required for 90/270!\n");
+                       return -EINVAL;
+               }
 
                /*
-                * Hardware doesn't handle subpixel coordinates.
-                * Adjust to (macro)pixel boundary, but be careful not to
-                * increase the source viewport size, because that could
-                * push the downscaling factor out of bounds.
+                * 90/270 is not allowed with RGB64 16:16:16:16 and
+                * Indexed 8-bit. RGB 16-bit 5:6:5 is allowed gen11 onwards.
+                * TBD: Add RGB64 case once its added in supported format
+                * list.
                 */
-               src_x = src->x1 >> 16;
-               src_w = drm_rect_width(src) >> 16;
-               src_y = src->y1 >> 16;
-               src_h = drm_rect_height(src) >> 16;
-
-               src->x1 = src_x << 16;
-               src->x2 = (src_x + src_w) << 16;
-               src->y1 = src_y << 16;
-               src->y2 = (src_y + src_h) << 16;
-
-               if (fb->format->is_yuv &&
-                   fb->format->format != DRM_FORMAT_NV12 &&
-                   (src_x % 2 || src_w % 2)) {
-                       DRM_DEBUG_KMS("src x/w (%u, %u) must be a multiple of 2 for YUV planes\n",
-                                     src_x, src_w);
+               switch (fb->format->format) {
+               case DRM_FORMAT_RGB565:
+                       if (INTEL_GEN(dev_priv) >= 11)
+                               break;
+                       /* fall through */
+               case DRM_FORMAT_C8:
+                       DRM_DEBUG_KMS("Unsupported pixel format %s for 90/270!\n",
+                                     drm_get_format_name(fb->format->format,
+                                                         &format_name));
                        return -EINVAL;
+               default:
+                       break;
                }
+       }
 
-               /* Check size restrictions when scaling */
-               if (src_w != crtc_w || src_h != crtc_h) {
-                       unsigned int width_bytes;
-                       int cpp = fb->format->cpp[0];
+       /* Y-tiling is not supported in IF-ID Interlace mode */
+       if (crtc_state->base.enable &&
+           crtc_state->base.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE &&
+           (fb->modifier == I915_FORMAT_MOD_Y_TILED ||
+            fb->modifier == I915_FORMAT_MOD_Yf_TILED ||
+            fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
+            fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS)) {
+               DRM_DEBUG_KMS("Y/Yf tiling not supported in IF-ID mode\n");
+               return -EINVAL;
+       }
 
-                       WARN_ON(!can_scale);
+       return 0;
+}
 
-                       width_bytes = ((src_x * cpp) & 63) + src_w * cpp;
+static int skl_plane_check_dst_coordinates(const struct intel_crtc_state *crtc_state,
+                                          const struct intel_plane_state *plane_state)
+{
+       struct drm_i915_private *dev_priv =
+               to_i915(plane_state->base.plane->dev);
+       int crtc_x = plane_state->base.dst.x1;
+       int crtc_w = drm_rect_width(&plane_state->base.dst);
+       int pipe_src_w = crtc_state->pipe_src_w;
 
-                       /* FIXME interlacing min height is 6 */
-                       if (INTEL_GEN(dev_priv) < 9 && (
-                            src_w < 3 || src_h < 3 ||
-                            src_w > 2048 || src_h > 2048 ||
-                            crtc_w < 3 || crtc_h < 3 ||
-                            width_bytes > 4096 || fb->pitches[0] > 4096)) {
-                               DRM_DEBUG_KMS("Source dimensions exceed hardware limits\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)) &&
+           (crtc_x + crtc_w < 4 || crtc_x > pipe_src_w - 4)) {
+               DRM_DEBUG_KMS("requested plane X %s position %d invalid (valid range %d-%d)\n",
+                             crtc_x + crtc_w < 4 ? "end" : "start",
+                             crtc_x + crtc_w < 4 ? crtc_x + crtc_w : crtc_x,
+                             4, pipe_src_w - 4);
+               return -ERANGE;
        }
 
-       if (INTEL_GEN(dev_priv) >= 9) {
-               ret = skl_check_plane_surface(crtc_state, state);
-               if (ret)
-                       return ret;
+       return 0;
+}
 
-               state->ctl = skl_plane_ctl(crtc_state, state);
-       } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
-               ret = i9xx_check_plane_surface(state);
-               if (ret)
-                       return ret;
+int skl_plane_check(struct intel_crtc_state *crtc_state,
+                   struct intel_plane_state *plane_state)
+{
+       struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
+       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
+       int max_scale, min_scale;
+       int ret;
 
-               state->ctl = vlv_sprite_ctl(crtc_state, state);
-       } else if (INTEL_GEN(dev_priv) >= 7) {
-               ret = i9xx_check_plane_surface(state);
-               if (ret)
-                       return ret;
+       ret = skl_plane_check_fb(crtc_state, plane_state);
+       if (ret)
+               return ret;
 
-               state->ctl = ivb_sprite_ctl(crtc_state, state);
-       } else {
-               ret = i9xx_check_plane_surface(state);
-               if (ret)
-                       return ret;
+       /* use scaler when colorkey is not required */
+       if (!plane_state->ckey.flags) {
+               const struct drm_framebuffer *fb = plane_state->base.fb;
 
-               state->ctl = g4x_sprite_ctl(crtc_state, state);
+               min_scale = 1;
+               max_scale = skl_max_scale(crtc_state,
+                                         fb ? fb->format->format : 0);
+       } else {
+               min_scale = DRM_PLANE_HELPER_NO_SCALING;
+               max_scale = DRM_PLANE_HELPER_NO_SCALING;
        }
 
+       ret = drm_atomic_helper_check_plane_state(&plane_state->base,
+                                                 &crtc_state->base,
+                                                 min_scale, max_scale,
+                                                 true, true);
+       if (ret)
+               return ret;
+
+       if (!plane_state->base.visible)
+               return 0;
+
+       ret = skl_plane_check_dst_coordinates(crtc_state, plane_state);
+       if (ret)
+               return ret;
+
+       ret = intel_plane_check_src_coordinates(plane_state);
+       if (ret)
+               return ret;
+
+       ret = skl_check_plane_surface(plane_state);
+       if (ret)
+               return ret;
+
+       plane_state->ctl = skl_plane_ctl(crtc_state, plane_state);
+
        if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
-               state->color_ctl = glk_plane_color_ctl(crtc_state, state);
+               plane_state->color_ctl = glk_plane_color_ctl(crtc_state,
+                                                            plane_state);
 
        return 0;
 }
@@ -1523,15 +1796,16 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv,
        intel_plane->base.state = &state->base;
 
        if (INTEL_GEN(dev_priv) >= 9) {
-               intel_plane->can_scale = true;
                state->scaler_id = -1;
 
                intel_plane->has_ccs = skl_plane_has_ccs(dev_priv, pipe,
                                                         PLANE_SPRITE0 + plane);
 
+               intel_plane->max_stride = skl_plane_max_stride;
                intel_plane->update_plane = skl_update_plane;
                intel_plane->disable_plane = skl_disable_plane;
                intel_plane->get_hw_state = skl_plane_get_hw_state;
+               intel_plane->check_plane = skl_plane_check;
 
                if (skl_plane_has_planar(dev_priv, pipe,
                                         PLANE_SPRITE0 + plane)) {
@@ -1549,12 +1823,11 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv,
 
                plane_funcs = &skl_plane_funcs;
        } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
-               intel_plane->can_scale = false;
-               intel_plane->max_downscale = 1;
-
+               intel_plane->max_stride = i9xx_plane_max_stride;
                intel_plane->update_plane = vlv_update_plane;
                intel_plane->disable_plane = vlv_disable_plane;
                intel_plane->get_hw_state = vlv_plane_get_hw_state;
+               intel_plane->check_plane = vlv_sprite_check;
 
                plane_formats = vlv_plane_formats;
                num_plane_formats = ARRAY_SIZE(vlv_plane_formats);
@@ -1562,17 +1835,11 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv,
 
                plane_funcs = &vlv_sprite_funcs;
        } else if (INTEL_GEN(dev_priv) >= 7) {
-               if (IS_IVYBRIDGE(dev_priv)) {
-                       intel_plane->can_scale = true;
-                       intel_plane->max_downscale = 2;
-               } else {
-                       intel_plane->can_scale = false;
-                       intel_plane->max_downscale = 1;
-               }
-
+               intel_plane->max_stride = g4x_sprite_max_stride;
                intel_plane->update_plane = ivb_update_plane;
                intel_plane->disable_plane = ivb_disable_plane;
                intel_plane->get_hw_state = ivb_plane_get_hw_state;
+               intel_plane->check_plane = g4x_sprite_check;
 
                plane_formats = snb_plane_formats;
                num_plane_formats = ARRAY_SIZE(snb_plane_formats);
@@ -1580,12 +1847,11 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv,
 
                plane_funcs = &snb_sprite_funcs;
        } else {
-               intel_plane->can_scale = true;
-               intel_plane->max_downscale = 16;
-
+               intel_plane->max_stride = g4x_sprite_max_stride;
                intel_plane->update_plane = g4x_update_plane;
                intel_plane->disable_plane = g4x_disable_plane;
                intel_plane->get_hw_state = g4x_plane_get_hw_state;
+               intel_plane->check_plane = g4x_sprite_check;
 
                modifiers = i9xx_plane_format_modifiers;
                if (IS_GEN6(dev_priv)) {
@@ -1618,7 +1884,6 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv,
        intel_plane->i9xx_plane = plane;
        intel_plane->id = PLANE_SPRITE0 + plane;
        intel_plane->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, intel_plane->id);
-       intel_plane->check_plane = intel_check_sprite_plane;
 
        possible_crtcs = (1 << pipe);
 
index 7c95697..b1b3e81 100644 (file)
@@ -401,6 +401,10 @@ int intel_uc_init_hw(struct drm_i915_private *i915)
                ret = intel_guc_submission_enable(guc);
                if (ret)
                        goto err_communication;
+       } else if (INTEL_GEN(i915) < 11) {
+               ret = intel_guc_sample_forcewake(guc);
+               if (ret)
+                       goto err_communication;
        }
 
        dev_info(i915->drm.dev, "GuC firmware version %u.%u\n",
index e272127..8d03f64 100644 (file)
@@ -235,6 +235,8 @@ static int fake_get_huge_pages(struct drm_i915_gem_object *obj)
                sg = sg_next(sg);
        } while (1);
 
+       i915_sg_trim(st);
+
        obj->mm.madv = I915_MADV_DONTNEED;
 
        __i915_gem_object_set_pages(obj, st, sg_page_sizes);
index 4e6a221..f7392c1 100644 (file)
@@ -298,6 +298,7 @@ static int igt_gem_coherency(void *arg)
        values = offsets + ncachelines;
 
        mutex_lock(&i915->drm.struct_mutex);
+       intel_runtime_pm_get(i915);
        for (over = igt_coherency_mode; over->name; over++) {
                if (!over->set)
                        continue;
@@ -375,6 +376,7 @@ static int igt_gem_coherency(void *arg)
                }
        }
 unlock:
+       intel_runtime_pm_put(i915);
        mutex_unlock(&i915->drm.struct_mutex);
        kfree(offsets);
        return err;
index 1c92560..76df25a 100644 (file)
@@ -22,6 +22,8 @@
  *
  */
 
+#include <linux/prime_numbers.h>
+
 #include "../i915_selftest.h"
 #include "i915_random.h"
 #include "igt_flush_test.h"
 
 #define DW_PER_PAGE (PAGE_SIZE / sizeof(u32))
 
+struct live_test {
+       struct drm_i915_private *i915;
+       const char *func;
+       const char *name;
+
+       unsigned int reset_count;
+};
+
+static int begin_live_test(struct live_test *t,
+                          struct drm_i915_private *i915,
+                          const char *func,
+                          const char *name)
+{
+       int err;
+
+       t->i915 = i915;
+       t->func = func;
+       t->name = name;
+
+       err = i915_gem_wait_for_idle(i915,
+                                    I915_WAIT_LOCKED,
+                                    MAX_SCHEDULE_TIMEOUT);
+       if (err) {
+               pr_err("%s(%s): failed to idle before, with err=%d!",
+                      func, name, err);
+               return err;
+       }
+
+       i915->gpu_error.missed_irq_rings = 0;
+       t->reset_count = i915_reset_count(&i915->gpu_error);
+
+       return 0;
+}
+
+static int end_live_test(struct live_test *t)
+{
+       struct drm_i915_private *i915 = t->i915;
+
+       if (igt_flush_test(i915, I915_WAIT_LOCKED))
+               return -EIO;
+
+       if (t->reset_count != i915_reset_count(&i915->gpu_error)) {
+               pr_err("%s(%s): GPU was reset %d times!\n",
+                      t->func, t->name,
+                      i915_reset_count(&i915->gpu_error) - t->reset_count);
+               return -EIO;
+       }
+
+       if (i915->gpu_error.missed_irq_rings) {
+               pr_err("%s(%s): Missed interrupts on engines %lx\n",
+                      t->func, t->name, i915->gpu_error.missed_irq_rings);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int live_nop_switch(void *arg)
+{
+       const unsigned int nctx = 1024;
+       struct drm_i915_private *i915 = arg;
+       struct intel_engine_cs *engine;
+       struct i915_gem_context **ctx;
+       enum intel_engine_id id;
+       struct drm_file *file;
+       struct live_test t;
+       unsigned long n;
+       int err = -ENODEV;
+
+       /*
+        * Create as many contexts as we can feasibly get away with
+        * and check we can switch between them rapidly.
+        *
+        * Serves as very simple stress test for submission and HW switching
+        * between contexts.
+        */
+
+       if (!DRIVER_CAPS(i915)->has_logical_contexts)
+               return 0;
+
+       file = mock_file(i915);
+       if (IS_ERR(file))
+               return PTR_ERR(file);
+
+       mutex_lock(&i915->drm.struct_mutex);
+       intel_runtime_pm_get(i915);
+
+       ctx = kcalloc(nctx, sizeof(*ctx), GFP_KERNEL);
+       if (!ctx) {
+               err = -ENOMEM;
+               goto out_unlock;
+       }
+
+       for (n = 0; n < nctx; n++) {
+               ctx[n] = i915_gem_create_context(i915, file->driver_priv);
+               if (IS_ERR(ctx[n])) {
+                       err = PTR_ERR(ctx[n]);
+                       goto out_unlock;
+               }
+       }
+
+       for_each_engine(engine, i915, id) {
+               struct i915_request *rq;
+               unsigned long end_time, prime;
+               ktime_t times[2] = {};
+
+               times[0] = ktime_get_raw();
+               for (n = 0; n < nctx; n++) {
+                       rq = i915_request_alloc(engine, ctx[n]);
+                       if (IS_ERR(rq)) {
+                               err = PTR_ERR(rq);
+                               goto out_unlock;
+                       }
+                       i915_request_add(rq);
+               }
+               if (i915_request_wait(rq,
+                                     I915_WAIT_LOCKED,
+                                     HZ / 5) < 0) {
+                       pr_err("Failed to populated %d contexts\n", nctx);
+                       i915_gem_set_wedged(i915);
+                       err = -EIO;
+                       goto out_unlock;
+               }
+
+               times[1] = ktime_get_raw();
+
+               pr_info("Populated %d contexts on %s in %lluns\n",
+                       nctx, engine->name, ktime_to_ns(times[1] - times[0]));
+
+               err = begin_live_test(&t, i915, __func__, engine->name);
+               if (err)
+                       goto out_unlock;
+
+               end_time = jiffies + i915_selftest.timeout_jiffies;
+               for_each_prime_number_from(prime, 2, 8192) {
+                       times[1] = ktime_get_raw();
+
+                       for (n = 0; n < prime; n++) {
+                               rq = i915_request_alloc(engine, ctx[n % nctx]);
+                               if (IS_ERR(rq)) {
+                                       err = PTR_ERR(rq);
+                                       goto out_unlock;
+                               }
+
+                               /*
+                                * This space is left intentionally blank.
+                                *
+                                * We do not actually want to perform any
+                                * action with this request, we just want
+                                * to measure the latency in allocation
+                                * and submission of our breadcrumbs -
+                                * ensuring that the bare request is sufficient
+                                * for the system to work (i.e. proper HEAD
+                                * tracking of the rings, interrupt handling,
+                                * etc). It also gives us the lowest bounds
+                                * for latency.
+                                */
+
+                               i915_request_add(rq);
+                       }
+                       if (i915_request_wait(rq,
+                                             I915_WAIT_LOCKED,
+                                             HZ / 5) < 0) {
+                               pr_err("Switching between %ld contexts timed out\n",
+                                      prime);
+                               i915_gem_set_wedged(i915);
+                               break;
+                       }
+
+                       times[1] = ktime_sub(ktime_get_raw(), times[1]);
+                       if (prime == 2)
+                               times[0] = times[1];
+
+                       if (__igt_timeout(end_time, NULL))
+                               break;
+               }
+
+               err = end_live_test(&t);
+               if (err)
+                       goto out_unlock;
+
+               pr_info("Switch latencies on %s: 1 = %lluns, %lu = %lluns\n",
+                       engine->name,
+                       ktime_to_ns(times[0]),
+                       prime - 1, div64_u64(ktime_to_ns(times[1]), prime - 1));
+       }
+
+out_unlock:
+       intel_runtime_pm_put(i915);
+       mutex_unlock(&i915->drm.struct_mutex);
+       mock_file_free(i915, file);
+       return err;
+}
+
 static struct i915_vma *
 gpu_fill_dw(struct i915_vma *vma, u64 offset, unsigned long count, u32 value)
 {
@@ -195,6 +391,7 @@ err_request:
        i915_request_add(rq);
 err_batch:
        i915_vma_unpin(batch);
+       i915_vma_put(batch);
 err_vma:
        i915_vma_unpin(vma);
        return err;
@@ -636,6 +833,8 @@ static int igt_switch_to_kernel_context(void *arg)
         */
 
        mutex_lock(&i915->drm.struct_mutex);
+       intel_runtime_pm_get(i915);
+
        ctx = kernel_context(i915);
        if (IS_ERR(ctx)) {
                mutex_unlock(&i915->drm.struct_mutex);
@@ -658,6 +857,8 @@ out_unlock:
        GEM_TRACE_DUMP_ON(err);
        if (igt_flush_test(i915, I915_WAIT_LOCKED))
                err = -EIO;
+
+       intel_runtime_pm_put(i915);
        mutex_unlock(&i915->drm.struct_mutex);
 
        kernel_context_close(ctx);
@@ -713,6 +914,7 @@ int i915_gem_context_live_selftests(struct drm_i915_private *dev_priv)
 {
        static const struct i915_subtest tests[] = {
                SUBTEST(igt_switch_to_kernel_context),
+               SUBTEST(live_nop_switch),
                SUBTEST(igt_ctx_exec),
                SUBTEST(igt_ctx_readonly),
        };
index c4aac61..07e5578 100644 (file)
@@ -342,6 +342,7 @@ static int live_nop_request(void *arg)
         */
 
        mutex_lock(&i915->drm.struct_mutex);
+       intel_runtime_pm_get(i915);
 
        for_each_engine(engine, i915, id) {
                struct i915_request *request = NULL;
@@ -402,6 +403,7 @@ static int live_nop_request(void *arg)
        }
 
 out_unlock:
+       intel_runtime_pm_put(i915);
        mutex_unlock(&i915->drm.struct_mutex);
        return err;
 }
@@ -487,6 +489,7 @@ static int live_empty_request(void *arg)
         */
 
        mutex_lock(&i915->drm.struct_mutex);
+       intel_runtime_pm_get(i915);
 
        batch = empty_batch(i915);
        if (IS_ERR(batch)) {
@@ -550,6 +553,7 @@ out_batch:
        i915_vma_unpin(batch);
        i915_vma_put(batch);
 out_unlock:
+       intel_runtime_pm_put(i915);
        mutex_unlock(&i915->drm.struct_mutex);
        return err;
 }
@@ -644,6 +648,7 @@ static int live_all_engines(void *arg)
         */
 
        mutex_lock(&i915->drm.struct_mutex);
+       intel_runtime_pm_get(i915);
 
        err = begin_live_test(&t, i915, __func__, "");
        if (err)
@@ -726,6 +731,7 @@ out_request:
        i915_vma_unpin(batch);
        i915_vma_put(batch);
 out_unlock:
+       intel_runtime_pm_put(i915);
        mutex_unlock(&i915->drm.struct_mutex);
        return err;
 }
@@ -747,6 +753,7 @@ static int live_sequential_engines(void *arg)
         */
 
        mutex_lock(&i915->drm.struct_mutex);
+       intel_runtime_pm_get(i915);
 
        err = begin_live_test(&t, i915, __func__, "");
        if (err)
@@ -853,6 +860,7 @@ out_request:
                i915_request_put(request[id]);
        }
 out_unlock:
+       intel_runtime_pm_put(i915);
        mutex_unlock(&i915->drm.struct_mutex);
        return err;
 }
index 90ba88c..0c0ab82 100644 (file)
@@ -142,6 +142,7 @@ static int igt_guc_clients(void *args)
 
        GEM_BUG_ON(!HAS_GUC(dev_priv));
        mutex_lock(&dev_priv->drm.struct_mutex);
+       intel_runtime_pm_get(dev_priv);
 
        guc = &dev_priv->guc;
        if (!guc) {
@@ -269,6 +270,7 @@ out:
        guc_clients_create(guc);
        guc_clients_doorbell_init(guc);
 unlock:
+       intel_runtime_pm_put(dev_priv);
        mutex_unlock(&dev_priv->drm.struct_mutex);
        return err;
 }
@@ -287,6 +289,7 @@ static int igt_guc_doorbells(void *arg)
 
        GEM_BUG_ON(!HAS_GUC(dev_priv));
        mutex_lock(&dev_priv->drm.struct_mutex);
+       intel_runtime_pm_get(dev_priv);
 
        guc = &dev_priv->guc;
        if (!guc) {
@@ -379,6 +382,7 @@ out:
                        guc_client_free(clients[i]);
                }
 unlock:
+       intel_runtime_pm_put(dev_priv);
        mutex_unlock(&dev_priv->drm.struct_mutex);
        return err;
 }
index 582566f..1aea7a8 100644 (file)
@@ -221,6 +221,7 @@ static int live_sanitycheck(void *arg)
                return 0;
 
        mutex_lock(&i915->drm.struct_mutex);
+       intel_runtime_pm_get(i915);
 
        if (spinner_init(&spin, i915))
                goto err_unlock;
@@ -261,6 +262,7 @@ err_spin:
        spinner_fini(&spin);
 err_unlock:
        igt_flush_test(i915, I915_WAIT_LOCKED);
+       intel_runtime_pm_put(i915);
        mutex_unlock(&i915->drm.struct_mutex);
        return err;
 }
@@ -278,6 +280,7 @@ static int live_preempt(void *arg)
                return 0;
 
        mutex_lock(&i915->drm.struct_mutex);
+       intel_runtime_pm_get(i915);
 
        if (spinner_init(&spin_hi, i915))
                goto err_unlock;
@@ -350,6 +353,7 @@ err_spin_hi:
        spinner_fini(&spin_hi);
 err_unlock:
        igt_flush_test(i915, I915_WAIT_LOCKED);
+       intel_runtime_pm_put(i915);
        mutex_unlock(&i915->drm.struct_mutex);
        return err;
 }
@@ -368,6 +372,7 @@ static int live_late_preempt(void *arg)
                return 0;
 
        mutex_lock(&i915->drm.struct_mutex);
+       intel_runtime_pm_get(i915);
 
        if (spinner_init(&spin_hi, i915))
                goto err_unlock;
@@ -440,6 +445,7 @@ err_spin_hi:
        spinner_fini(&spin_hi);
 err_unlock:
        igt_flush_test(i915, I915_WAIT_LOCKED);
+       intel_runtime_pm_put(i915);
        mutex_unlock(&i915->drm.struct_mutex);
        return err;
 
@@ -467,6 +473,7 @@ static int live_preempt_hang(void *arg)
                return 0;
 
        mutex_lock(&i915->drm.struct_mutex);
+       intel_runtime_pm_get(i915);
 
        if (spinner_init(&spin_hi, i915))
                goto err_unlock;
@@ -561,6 +568,7 @@ err_spin_hi:
        spinner_fini(&spin_hi);
 err_unlock:
        igt_flush_test(i915, I915_WAIT_LOCKED);
+       intel_runtime_pm_put(i915);
        mutex_unlock(&i915->drm.struct_mutex);
        return err;
 }
index 0d39b3b..d1a0923 100644 (file)
@@ -44,7 +44,9 @@ read_nonprivs(struct i915_gem_context *ctx, struct intel_engine_cs *engine)
        if (err)
                goto err_obj;
 
+       intel_runtime_pm_get(engine->i915);
        rq = i915_request_alloc(engine, ctx);
+       intel_runtime_pm_put(engine->i915);
        if (IS_ERR(rq)) {
                err = PTR_ERR(rq);
                goto err_pin;
@@ -175,7 +177,10 @@ static int switch_to_scratch_context(struct intel_engine_cs *engine)
        if (IS_ERR(ctx))
                return PTR_ERR(ctx);
 
+       intel_runtime_pm_get(engine->i915);
        rq = i915_request_alloc(engine, ctx);
+       intel_runtime_pm_put(engine->i915);
+
        kernel_context_close(ctx);
        if (IS_ERR(rq))
                return PTR_ERR(rq);