Merge tag 'drm-intel-next-2019-05-24' of git://anongit.freedesktop.org/drm/drm-intel...
authorDave Airlie <airlied@redhat.com>
Mon, 27 May 2019 23:03:58 +0000 (09:03 +1000)
committerDave Airlie <airlied@redhat.com>
Mon, 27 May 2019 23:26:52 +0000 (09:26 +1000)
Features:
- Engine discovery query (Tvrtko)
- Support for DP YCbCr4:2:0 outputs (Gwan-gyeong)
- HDCP revocation support, refactoring (Ramalingam)
- Remove DRM_AUTH from IOCTLs which also have DRM_RENDER_ALLOW (Christian König)
- Asynchronous display power disabling (Imre)
- Perma-pin uC firmware and re-enable global reset (Fernando)
- GTT remapping for display, for bigger fb size and stride (Ville)
- Enable pipe HDR mode on ICL if only HDR planes are used (Ville)
- Kconfig to tweak the busyspin durations for i915_wait_request (Chris)
- Allow multiple user handles to the same VM (Chris)
- GT/GEM runtime pm improvements using wakerefs (Chris)
- Gen 4&5 render context support (Chris)
- Allow userspace to clone contexts on creation (Chris)
- SINGLE_TIMELINE flags for context creation (Chris)
- Allow specification of parallel execbuf (Chris)

Refactoring:
- Header refactoring (Jani)
- Move GraphicsTechnology files under gt/ (Chris)
- Sideband code refactoring (Chris)

Fixes:
- ICL DSI state readout and checker fixes (Vandita)
- GLK DSI picture corruption fix (Stanislav)
- HDMI deep color fixes (Clinton, Aditya)
- Fix driver unbinding from a device in use (Janusz)
- Fix clock gating with pipe scaling (Radhakrishna)
- Disable broken FBC on GLK (Daniel Drake)
- Miscellaneous GuC fixes (Michal)
- Fix MG PHY DP register programming (Imre)
- Add missing combo PHY lane power setup (Imre)
- Workarounds for early ICL VBT issues (Imre)
- Fix fastset vs. pfit on/off on HSW EDP transcoder (Ville)
- Add readout and state check for pch_pfit.force_thru (Ville)
- Miscellaneous display fixes and refactoring (Ville)
- Display workaround fixes (Ville)
- Enable audio even if ELD is bogus (Ville)
- Fix use-after-free in reporting create.size (Chris)
- Sideband fixes to avoid BYT hard lockups (Chris)
- Workaround fixes and improvements (Chris)

Maintainer shortcomings:
- Failure to adequately describe and give credit for all changes (Jani)

Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/87sgt3n45z.fsf@intel.com
17 files changed:
1  2 
drivers/gpu/drm/Makefile
drivers/gpu/drm/drm_atomic_uapi.c
drivers/gpu/drm/drm_connector.c
drivers/gpu/drm/drm_internal.h
drivers/gpu/drm/i915/Kconfig
drivers/gpu/drm/i915/gvt/mmio_context.c
drivers/gpu/drm/i915/gvt/scheduler.c
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_execbuffer.c
drivers/gpu/drm/i915/i915_vma.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_runtime_pm.c
drivers/gpu/drm/i915/intel_sprite.c
drivers/misc/mei/hdcp/mei_hdcp.c
include/drm/drm_connector.h
include/drm/drm_mode_config.h

diff --combined drivers/gpu/drm/Makefile
@@@ -17,7 -17,7 +17,7 @@@ drm-y       :=        drm_auth.o drm_cache.o 
                drm_plane.o drm_color_mgmt.o drm_print.o \
                drm_dumb_buffers.o drm_mode_config.o drm_vblank.o \
                drm_syncobj.o drm_lease.o drm_writeback.o drm_client.o \
-               drm_atomic_uapi.o
+               drm_atomic_uapi.o drm_hdcp.o
  
  drm-$(CONFIG_DRM_LEGACY) += drm_legacy_misc.o drm_bufs.o drm_context.o drm_dma.o drm_scatter.o drm_lock.o
  drm-$(CONFIG_DRM_LIB_RANDOM) += lib/drm_random.o
@@@ -32,11 -32,6 +32,11 @@@ drm-$(CONFIG_AGP) += drm_agpsupport.
  drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o
  drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
  
 +drm_vram_helper-y := drm_gem_vram_helper.o \
 +                   drm_vram_helper_common.o \
 +                   drm_vram_mm_helper.o
 +obj-$(CONFIG_DRM_VRAM_HELPER) += drm_vram_helper.o
 +
  drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_dsc.o drm_probe_helper.o \
                drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \
                drm_kms_helper_common.o drm_dp_dual_mode_helper.o \
@@@ -676,8 -676,6 +676,8 @@@ static int drm_atomic_connector_set_pro
  {
        struct drm_device *dev = connector->dev;
        struct drm_mode_config *config = &dev->mode_config;
 +      bool replaced = false;
 +      int ret;
  
        if (property == config->prop_crtc_id) {
                struct drm_crtc *crtc = drm_crtc_find(dev, file_priv, val);
                 */
                if (state->link_status != DRM_LINK_STATUS_GOOD)
                        state->link_status = val;
 +      } else if (property == config->hdr_output_metadata_property) {
 +              ret = drm_atomic_replace_property_blob_from_id(dev,
 +                              &state->hdr_output_metadata,
 +                              val,
 +                              sizeof(struct hdr_output_metadata), -1,
 +                              &replaced);
 +              return ret;
        } else if (property == config->aspect_ratio_property) {
                state->picture_aspect_ratio = val;
        } else if (property == config->content_type_property) {
                state->content_type = val;
        } else if (property == connector->scaling_mode_property) {
                state->scaling_mode = val;
-       } else if (property == connector->content_protection_property) {
+       } else if (property == config->content_protection_property) {
                if (val == DRM_MODE_CONTENT_PROTECTION_ENABLED) {
                        DRM_DEBUG_KMS("only drivers can set CP Enabled\n");
                        return -EINVAL;
@@@ -823,10 -814,7 +823,10 @@@ drm_atomic_connector_get_property(struc
                *val = state->colorspace;
        } else if (property == connector->scaling_mode_property) {
                *val = state->scaling_mode;
-       } else if (property == connector->content_protection_property) {
 +      } else if (property == config->hdr_output_metadata_property) {
 +              *val = state->hdr_output_metadata ?
 +                      state->hdr_output_metadata->base.id : 0;
+       } else if (property == config->content_protection_property) {
                *val = state->content_protection;
        } else if (property == config->writeback_fb_id_property) {
                /* Writeback framebuffer is one-shot, write and forget */
@@@ -823,13 -823,6 +823,6 @@@ static const struct drm_prop_enum_list 
  DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name,
                 drm_tv_subconnector_enum_list)
  
- static struct drm_prop_enum_list drm_cp_enum_list[] = {
-       { DRM_MODE_CONTENT_PROTECTION_UNDESIRED, "Undesired" },
-       { DRM_MODE_CONTENT_PROTECTION_DESIRED, "Desired" },
-       { DRM_MODE_CONTENT_PROTECTION_ENABLED, "Enabled" },
- };
- DRM_ENUM_NAME_FN(drm_get_content_protection_name, drm_cp_enum_list)
  static const struct drm_prop_enum_list hdmi_colorspaces[] = {
        /* For Default case, driver will set the colorspace */
        { DRM_MODE_COLORIMETRY_DEFAULT, "Default" },
@@@ -1058,12 -1051,6 +1051,12 @@@ int drm_connector_create_standard_prope
                return -ENOMEM;
        dev->mode_config.non_desktop_property = prop;
  
 +      prop = drm_property_create(dev, DRM_MODE_PROP_BLOB,
 +                                 "HDR_OUTPUT_METADATA", 0);
 +      if (!prop)
 +              return -ENOMEM;
 +      dev->mode_config.hdr_output_metadata_property = prop;
 +
        return 0;
  }
  
@@@ -1422,6 -1409,12 +1415,6 @@@ EXPORT_SYMBOL(drm_mode_create_scaling_m
   *
   *    The driver may place further restrictions within these minimum
   *    and maximum bounds.
 - *
 - *    The semantics for the vertical blank timestamp differ when
 - *    variable refresh rate is active. The vertical blank timestamp
 - *    is defined to be an estimate using the current mode's fixed
 - *    refresh rate timings. The semantics for the page-flip event
 - *    timestamp remain the same.
   */
  
  /**
@@@ -1515,42 -1508,6 +1508,6 @@@ int drm_connector_attach_scaling_mode_p
  }
  EXPORT_SYMBOL(drm_connector_attach_scaling_mode_property);
  
- /**
-  * drm_connector_attach_content_protection_property - attach content protection
-  * property
-  *
-  * @connector: connector to attach CP property on.
-  *
-  * This is used to add support for content protection on select connectors.
-  * Content Protection is intentionally vague to allow for different underlying
-  * technologies, however it is most implemented by HDCP.
-  *
-  * The content protection will be set to &drm_connector_state.content_protection
-  *
-  * Returns:
-  * Zero on success, negative errno on failure.
-  */
- int drm_connector_attach_content_protection_property(
-               struct drm_connector *connector)
- {
-       struct drm_device *dev = connector->dev;
-       struct drm_property *prop;
-       prop = drm_property_create_enum(dev, 0, "Content Protection",
-                                       drm_cp_enum_list,
-                                       ARRAY_SIZE(drm_cp_enum_list));
-       if (!prop)
-               return -ENOMEM;
-       drm_object_attach_property(&connector->base, prop,
-                                  DRM_MODE_CONTENT_PROTECTION_UNDESIRED);
-       connector->content_protection_property = prop;
-       return 0;
- }
- EXPORT_SYMBOL(drm_connector_attach_content_protection_property);
  /**
   * drm_mode_create_aspect_ratio_property - create aspect ratio property
   * @dev: DRM device
@@@ -93,8 -93,6 +93,8 @@@ int drm_dropmaster_ioctl(struct drm_dev
                         struct drm_file *file_priv);
  int drm_master_open(struct drm_file *file_priv);
  void drm_master_release(struct drm_file *file_priv);
 +bool drm_master_internal_acquire(struct drm_device *dev);
 +void drm_master_internal_release(struct drm_device *dev);
  
  /* drm_sysfs.c */
  extern struct class *drm_class;
@@@ -108,6 -106,7 +108,7 @@@ void drm_sysfs_connector_remove(struct 
  void drm_sysfs_lease_event(struct drm_device *dev);
  
  /* drm_gem.c */
+ struct drm_gem_object;
  int drm_gem_init(struct drm_device *dev);
  void drm_gem_destroy(struct drm_device *dev);
  int drm_gem_handle_create_tail(struct drm_file *file_priv,
@@@ -203,3 -202,7 +204,7 @@@ int drm_syncobj_query_ioctl(struct drm_
  void drm_framebuffer_print_info(struct drm_printer *p, unsigned int indent,
                                const struct drm_framebuffer *fb);
  int drm_framebuffer_debugfs_init(struct drm_minor *minor);
+ /* drm_hdcp.c */
+ int drm_setup_hdcp_srm(struct class *drm_class);
+ void drm_teardown_hdcp_srm(struct class *drm_class);
@@@ -1,4 -1,3 +1,4 @@@
 +# SPDX-License-Identifier: GPL-2.0-only
  config DRM_I915
        tristate "Intel 8xx/9xx/G3x/G4x/HD Graphics"
        depends on DRM
@@@ -16,6 -15,7 +16,6 @@@
        select IRQ_WORK
        # i915 depends on ACPI_VIDEO when ACPI is enabled
        # but for select to work, need to select ACPI_VIDEO's dependencies, ick
 -      select BACKLIGHT_LCD_SUPPORT if ACPI
        select BACKLIGHT_CLASS_DEVICE if ACPI
        select INPUT if ACPI
        select ACPI_VIDEO if ACPI
@@@ -133,3 -133,9 +133,9 @@@ depends on DRM_I91
  depends on EXPERT
  source "drivers/gpu/drm/i915/Kconfig.debug"
  endmenu
+ menu "drm/i915 Profile Guided Optimisation"
+       visible if EXPERT
+       depends on DRM_I915
+       source "drivers/gpu/drm/i915/Kconfig.profile"
+ endmenu
@@@ -108,13 -108,12 +108,13 @@@ static struct engine_mmio gen9_engine_m
        {RCS0, GEN9_HALF_SLICE_CHICKEN5, 0xffff, true}, /* 0xe188 */
        {RCS0, GEN9_HALF_SLICE_CHICKEN7, 0xffff, true}, /* 0xe194 */
        {RCS0, GEN8_ROW_CHICKEN, 0xffff, true}, /* 0xe4f0 */
 -      {RCS0, TRVATTL3PTRDW(0), 0, false}, /* 0x4de0 */
 -      {RCS0, TRVATTL3PTRDW(1), 0, false}, /* 0x4de4 */
 -      {RCS0, TRNULLDETCT, 0, false}, /* 0x4de8 */
 -      {RCS0, TRINVTILEDETCT, 0, false}, /* 0x4dec */
 -      {RCS0, TRVADR, 0, false}, /* 0x4df0 */
 -      {RCS0, TRTTE, 0, false}, /* 0x4df4 */
 +      {RCS0, TRVATTL3PTRDW(0), 0, true}, /* 0x4de0 */
 +      {RCS0, TRVATTL3PTRDW(1), 0, true}, /* 0x4de4 */
 +      {RCS0, TRNULLDETCT, 0, true}, /* 0x4de8 */
 +      {RCS0, TRINVTILEDETCT, 0, true}, /* 0x4dec */
 +      {RCS0, TRVADR, 0, true}, /* 0x4df0 */
 +      {RCS0, TRTTE, 0, true}, /* 0x4df4 */
 +      {RCS0, _MMIO(0x4dfc), 0, true},
  
        {BCS0, RING_GFX_MODE(BLT_RING_BASE), 0xffff, false}, /* 0x2229c */
        {BCS0, RING_MI_MODE(BLT_RING_BASE), 0xffff, false}, /* 0x2209c */
  
        {RCS0, GEN9_GAMT_ECO_REG_RW_IA, 0x0, false}, /* 0x4ab0 */
        {RCS0, GEN9_CSFE_CHICKEN1_RCS, 0xffff, false}, /* 0x20d4 */
 +      {RCS0, _MMIO(0x20D8), 0xffff, true}, /* 0x20d8 */
  
        {RCS0, GEN8_GARBCNTL, 0x0, false}, /* 0xb004 */
        {RCS0, GEN7_FF_THREAD_MODE, 0x0, false}, /* 0x20a0 */
@@@ -393,7 -391,10 +393,7 @@@ static void switch_mocs(struct intel_vg
        if (WARN_ON(ring_id >= ARRAY_SIZE(regs)))
                return;
  
 -      if (ring_id == RCS0 &&
 -          (IS_KABYLAKE(dev_priv) ||
 -           IS_BROXTON(dev_priv) ||
 -           IS_COFFEELAKE(dev_priv)))
 +      if (ring_id == RCS0 && IS_GEN(dev_priv, 9))
                return;
  
        if (!pre && !gen9_render_mocs.initialized)
@@@ -468,10 -469,11 +468,10 @@@ static void switch_mmio(struct intel_vg
                        continue;
                /*
                 * No need to do save or restore of the mmio which is in context
 -               * state image on kabylake, it's initialized by lri command and
 +               * state image on gen9, it's initialized by lri command and
                 * save or restore with context together.
                 */
 -              if ((IS_KABYLAKE(dev_priv) || IS_BROXTON(dev_priv)
 -                      || IS_COFFEELAKE(dev_priv)) && mmio->in_context)
 +              if (IS_GEN(dev_priv, 9) && mmio->in_context)
                        continue;
  
                // save
                         * itself.
                         */
                        if (mmio->in_context &&
-                           !is_inhibit_context(intel_context_lookup(s->shadow_ctx,
-                                                                    dev_priv->engine[ring_id])))
+                           !is_inhibit_context(s->shadow[ring_id]))
                                continue;
  
                        if (mmio->mask)
@@@ -36,6 -36,7 +36,7 @@@
  #include <linux/kthread.h>
  
  #include "i915_drv.h"
+ #include "i915_gem_pm.h"
  #include "gvt.h"
  
  #define RING_CTX_OFF(x) \
@@@ -277,18 -278,23 +278,23 @@@ static int shadow_context_status_change
        return NOTIFY_OK;
  }
  
- static void shadow_context_descriptor_update(struct intel_context *ce)
+ static void
+ shadow_context_descriptor_update(struct intel_context *ce,
+                                struct intel_vgpu_workload *workload)
  {
-       u64 desc = 0;
-       desc = ce->lrc_desc;
+       u64 desc = ce->lrc_desc;
  
-       /* Update bits 0-11 of the context descriptor which includes flags
+       /*
+        * Update bits 0-11 of the context descriptor which includes flags
         * like GEN8_CTX_* cached in desc_template
         */
        desc &= U64_MAX << 12;
        desc |= ce->gem_context->desc_template & ((1ULL << 12) - 1);
  
+       desc &= ~(0x3 << GEN8_CTX_ADDRESSING_MODE_SHIFT);
+       desc |= workload->ctx_desc.addressing_mode <<
+               GEN8_CTX_ADDRESSING_MODE_SHIFT;
        ce->lrc_desc = desc;
  }
  
@@@ -298,29 -304,12 +304,29 @@@ static int copy_workload_to_ring_buffer
        struct i915_request *req = workload->req;
        void *shadow_ring_buffer_va;
        u32 *cs;
 +      int err;
  
 -      if ((IS_KABYLAKE(req->i915) || IS_BROXTON(req->i915)
 -              || IS_COFFEELAKE(req->i915))
 -              && is_inhibit_context(req->hw_context))
 +      if (IS_GEN(req->i915, 9) && is_inhibit_context(req->hw_context))
                intel_vgpu_restore_inhibit_context(vgpu, req);
  
 +      /*
 +       * To track whether a request has started on HW, we can emit a
 +       * breadcrumb at the beginning of the request and check its
 +       * timeline's HWSP to see if the breadcrumb has advanced past the
 +       * start of this request. Actually, the request must have the
 +       * init_breadcrumb if its timeline set has_init_bread_crumb, or the
 +       * scheduler might get a wrong state of it during reset. Since the
 +       * requests from gvt always set the has_init_breadcrumb flag, here
 +       * need to do the emit_init_breadcrumb for all the requests.
 +       */
 +      if (req->engine->emit_init_breadcrumb) {
 +              err = req->engine->emit_init_breadcrumb(req);
 +              if (err) {
 +                      gvt_vgpu_err("fail to emit init breadcrumb\n");
 +                      return err;
 +              }
 +      }
 +
        /* allocate shadow ring buffer */
        cs = intel_ring_begin(workload->req, workload->rb_len / sizeof(u32));
        if (IS_ERR(cs)) {
@@@ -382,26 -371,22 +388,22 @@@ intel_gvt_workload_req_alloc(struct int
  {
        struct intel_vgpu *vgpu = workload->vgpu;
        struct intel_vgpu_submission *s = &vgpu->submission;
-       struct i915_gem_context *shadow_ctx = s->shadow_ctx;
        struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
-       struct intel_engine_cs *engine = dev_priv->engine[workload->ring_id];
        struct i915_request *rq;
-       int ret = 0;
  
        lockdep_assert_held(&dev_priv->drm.struct_mutex);
  
        if (workload->req)
-               goto out;
+               return 0;
  
-       rq = i915_request_alloc(engine, shadow_ctx);
+       rq = i915_request_create(s->shadow[workload->ring_id]);
        if (IS_ERR(rq)) {
                gvt_vgpu_err("fail to allocate gem request\n");
-               ret = PTR_ERR(rq);
-               goto out;
+               return PTR_ERR(rq);
        }
        workload->req = i915_request_get(rq);
- out:
-       return ret;
+       return 0;
  }
  
  /**
@@@ -416,10 -401,7 +418,7 @@@ int intel_gvt_scan_and_shadow_workload(
  {
        struct intel_vgpu *vgpu = workload->vgpu;
        struct intel_vgpu_submission *s = &vgpu->submission;
-       struct i915_gem_context *shadow_ctx = s->shadow_ctx;
        struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
-       struct intel_engine_cs *engine = dev_priv->engine[workload->ring_id];
-       struct intel_context *ce;
        int ret;
  
        lockdep_assert_held(&dev_priv->drm.struct_mutex);
        if (workload->shadow)
                return 0;
  
-       /* pin shadow context by gvt even the shadow context will be pinned
-        * when i915 alloc request. That is because gvt will update the guest
-        * context from shadow context when workload is completed, and at that
-        * moment, i915 may already unpined the shadow context to make the
-        * shadow_ctx pages invalid. So gvt need to pin itself. After update
-        * the guest context, gvt can unpin the shadow_ctx safely.
-        */
-       ce = intel_context_pin(shadow_ctx, engine);
-       if (IS_ERR(ce)) {
-               gvt_vgpu_err("fail to pin shadow context\n");
-               return PTR_ERR(ce);
-       }
-       shadow_ctx->desc_template &= ~(0x3 << GEN8_CTX_ADDRESSING_MODE_SHIFT);
-       shadow_ctx->desc_template |= workload->ctx_desc.addressing_mode <<
-                                   GEN8_CTX_ADDRESSING_MODE_SHIFT;
        if (!test_and_set_bit(workload->ring_id, s->shadow_ctx_desc_updated))
-               shadow_context_descriptor_update(ce);
+               shadow_context_descriptor_update(s->shadow[workload->ring_id],
+                                                workload);
  
        ret = intel_gvt_scan_and_shadow_ringbuffer(workload);
        if (ret)
-               goto err_unpin;
+               return ret;
  
        if (workload->ring_id == RCS0 && workload->wa_ctx.indirect_ctx.size) {
                ret = intel_gvt_scan_and_shadow_wa_ctx(&workload->wa_ctx);
        return 0;
  err_shadow:
        release_shadow_wa_ctx(&workload->wa_ctx);
- err_unpin:
-       intel_context_unpin(ce);
        return ret;
  }
  
@@@ -689,7 -653,6 +670,6 @@@ static int dispatch_workload(struct int
        struct intel_vgpu *vgpu = workload->vgpu;
        struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
        struct intel_vgpu_submission *s = &vgpu->submission;
-       struct i915_gem_context *shadow_ctx = s->shadow_ctx;
        struct i915_request *rq;
        int ring_id = workload->ring_id;
        int ret;
        mutex_lock(&vgpu->vgpu_lock);
        mutex_lock(&dev_priv->drm.struct_mutex);
  
-       ret = set_context_ppgtt_from_shadow(workload, shadow_ctx);
+       ret = set_context_ppgtt_from_shadow(workload,
+                                           s->shadow[ring_id]->gem_context);
        if (ret < 0) {
                gvt_vgpu_err("workload shadow ppgtt isn't ready\n");
                goto err_req;
@@@ -928,11 -892,6 +909,6 @@@ static void complete_current_workload(s
                                intel_vgpu_trigger_virtual_event(vgpu, event);
                }
  
-               /* unpin shadow ctx as the shadow_ctx update is done */
-               mutex_lock(&rq->i915->drm.struct_mutex);
-               intel_context_unpin(rq->hw_context);
-               mutex_unlock(&rq->i915->drm.struct_mutex);
                i915_request_put(fetch_and_zero(&workload->req));
        }
  
@@@ -1011,8 -970,6 +987,6 @@@ static int workload_thread(void *priv
                                workload->ring_id, workload,
                                workload->vgpu->id);
  
-               intel_runtime_pm_get(gvt->dev_priv);
                gvt_dbg_sched("ring id %d will dispatch workload %p\n",
                                workload->ring_id, workload);
  
@@@ -1042,7 -999,6 +1016,6 @@@ complete
                        intel_uncore_forcewake_put(&gvt->dev_priv->uncore,
                                        FORCEWAKE_ALL);
  
-               intel_runtime_pm_put_unchecked(gvt->dev_priv);
                if (ret && (vgpu_is_vm_unhealthy(ret)))
                        enter_failsafe_mode(vgpu, GVT_FAILSAFE_GUEST_ERR);
        }
  }
  
  static void
- i915_context_ppgtt_root_restore(struct intel_vgpu_submission *s)
+ i915_context_ppgtt_root_restore(struct intel_vgpu_submission *s,
+                               struct i915_hw_ppgtt *ppgtt)
  {
-       struct i915_hw_ppgtt *i915_ppgtt = s->shadow_ctx->ppgtt;
        int i;
  
-       if (i915_vm_is_4lvl(&i915_ppgtt->vm)) {
-               px_dma(&i915_ppgtt->pml4) = s->i915_context_pml4;
+       if (i915_vm_is_4lvl(&ppgtt->vm)) {
+               px_dma(&ppgtt->pml4) = s->i915_context_pml4;
        } else {
                for (i = 0; i < GEN8_3LVL_PDPES; i++)
-                       px_dma(i915_ppgtt->pdp.page_directory[i]) =
-                                               s->i915_context_pdps[i];
+                       px_dma(ppgtt->pdp.page_directory[i]) =
+                               s->i915_context_pdps[i];
        }
  }
  
  void intel_vgpu_clean_submission(struct intel_vgpu *vgpu)
  {
        struct intel_vgpu_submission *s = &vgpu->submission;
+       struct intel_engine_cs *engine;
+       enum intel_engine_id id;
  
        intel_vgpu_select_submission_ops(vgpu, ALL_ENGINES, 0);
-       i915_context_ppgtt_root_restore(s);
-       i915_gem_context_put(s->shadow_ctx);
+       i915_context_ppgtt_root_restore(s, s->shadow[0]->gem_context->ppgtt);
+       for_each_engine(engine, vgpu->gvt->dev_priv, id)
+               intel_context_unpin(s->shadow[id]);
        kmem_cache_destroy(s->workloads);
  }
  
@@@ -1178,17 -1139,17 +1156,17 @@@ void intel_vgpu_reset_submission(struc
  }
  
  static void
- i915_context_ppgtt_root_save(struct intel_vgpu_submission *s)
+ i915_context_ppgtt_root_save(struct intel_vgpu_submission *s,
+                            struct i915_hw_ppgtt *ppgtt)
  {
-       struct i915_hw_ppgtt *i915_ppgtt = s->shadow_ctx->ppgtt;
        int i;
  
-       if (i915_vm_is_4lvl(&i915_ppgtt->vm))
-               s->i915_context_pml4 = px_dma(&i915_ppgtt->pml4);
-       else {
+       if (i915_vm_is_4lvl(&ppgtt->vm)) {
+               s->i915_context_pml4 = px_dma(&ppgtt->pml4);
+       else {
                for (i = 0; i < GEN8_3LVL_PDPES; i++)
                        s->i915_context_pdps[i] =
-                               px_dma(i915_ppgtt->pdp.page_directory[i]);
+                               px_dma(ppgtt->pdp.page_directory[i]);
        }
  }
  
  int intel_vgpu_setup_submission(struct intel_vgpu *vgpu)
  {
        struct intel_vgpu_submission *s = &vgpu->submission;
-       enum intel_engine_id i;
        struct intel_engine_cs *engine;
+       struct i915_gem_context *ctx;
+       enum intel_engine_id i;
        int ret;
  
-       s->shadow_ctx = i915_gem_context_create_gvt(
-                       &vgpu->gvt->dev_priv->drm);
-       if (IS_ERR(s->shadow_ctx))
-               return PTR_ERR(s->shadow_ctx);
+       ctx = i915_gem_context_create_gvt(&vgpu->gvt->dev_priv->drm);
+       if (IS_ERR(ctx))
+               return PTR_ERR(ctx);
+       i915_context_ppgtt_root_save(s, ctx->ppgtt);
+       for_each_engine(engine, vgpu->gvt->dev_priv, i) {
+               struct intel_context *ce;
+               INIT_LIST_HEAD(&s->workload_q_head[i]);
+               s->shadow[i] = ERR_PTR(-EINVAL);
+               ce = i915_gem_context_get_engine(ctx, i);
+               if (IS_ERR(ce)) {
+                       ret = PTR_ERR(ce);
+                       goto out_shadow_ctx;
+               }
  
-       i915_context_ppgtt_root_save(s);
+               ret = intel_context_pin(ce);
+               intel_context_put(ce);
+               if (ret)
+                       goto out_shadow_ctx;
+               s->shadow[i] = ce;
+       }
  
        bitmap_zero(s->shadow_ctx_desc_updated, I915_NUM_ENGINES);
  
                goto out_shadow_ctx;
        }
  
-       for_each_engine(engine, vgpu->gvt->dev_priv, i)
-               INIT_LIST_HEAD(&s->workload_q_head[i]);
        atomic_set(&s->running_workload_num, 0);
        bitmap_zero(s->tlb_handle_pending, I915_NUM_ENGINES);
  
+       i915_gem_context_put(ctx);
        return 0;
  
  out_shadow_ctx:
-       i915_gem_context_put(s->shadow_ctx);
+       i915_context_ppgtt_root_restore(s, ctx->ppgtt);
+       for_each_engine(engine, vgpu->gvt->dev_priv, i) {
+               if (IS_ERR(s->shadow[i]))
+                       break;
+               intel_context_unpin(s->shadow[i]);
+       }
+       i915_gem_context_put(ctx);
        return ret;
  }
  
@@@ -1360,7 -1346,7 +1363,7 @@@ static int prepare_mm(struct intel_vgpu
        struct execlist_ctx_descriptor_format *desc = &workload->ctx_desc;
        struct intel_vgpu_mm *mm;
        struct intel_vgpu *vgpu = workload->vgpu;
 -      intel_gvt_gtt_type_t root_entry_type;
 +      enum intel_gvt_gtt_type root_entry_type;
        u64 pdps[GVT_RING_CTX_NR_PDPS];
  
        switch (desc->addressing_mode) {
  #include <linux/dma-buf.h>
  #include <linux/mman.h>
  
+ #include "gt/intel_engine_pm.h"
+ #include "gt/intel_gt_pm.h"
+ #include "gt/intel_mocs.h"
+ #include "gt/intel_reset.h"
+ #include "gt/intel_workarounds.h"
  #include "i915_drv.h"
  #include "i915_gem_clflush.h"
  #include "i915_gemfs.h"
- #include "i915_globals.h"
- #include "i915_reset.h"
+ #include "i915_gem_pm.h"
  #include "i915_trace.h"
  #include "i915_vgpu.h"
  
+ #include "intel_display.h"
  #include "intel_drv.h"
  #include "intel_frontbuffer.h"
- #include "intel_mocs.h"
  #include "intel_pm.h"
- #include "intel_workarounds.h"
  
  static void i915_gem_flush_free_objects(struct drm_i915_private *i915);
  
@@@ -102,105 -106,6 +106,6 @@@ static void i915_gem_info_remove_obj(st
        spin_unlock(&dev_priv->mm.object_stat_lock);
  }
  
- static void __i915_gem_park(struct drm_i915_private *i915)
- {
-       intel_wakeref_t wakeref;
-       GEM_TRACE("\n");
-       lockdep_assert_held(&i915->drm.struct_mutex);
-       GEM_BUG_ON(i915->gt.active_requests);
-       GEM_BUG_ON(!list_empty(&i915->gt.active_rings));
-       if (!i915->gt.awake)
-               return;
-       /*
-        * Be paranoid and flush a concurrent interrupt to make sure
-        * we don't reactivate any irq tasklets after parking.
-        *
-        * FIXME: Note that even though we have waited for execlists to be idle,
-        * there may still be an in-flight interrupt even though the CSB
-        * is now empty. synchronize_irq() makes sure that a residual interrupt
-        * is completed before we continue, but it doesn't prevent the HW from
-        * raising a spurious interrupt later. To complete the shield we should
-        * coordinate disabling the CS irq with flushing the interrupts.
-        */
-       synchronize_irq(i915->drm.irq);
-       intel_engines_park(i915);
-       i915_timelines_park(i915);
-       i915_pmu_gt_parked(i915);
-       i915_vma_parked(i915);
-       wakeref = fetch_and_zero(&i915->gt.awake);
-       GEM_BUG_ON(!wakeref);
-       if (INTEL_GEN(i915) >= 6)
-               gen6_rps_idle(i915);
-       intel_display_power_put(i915, POWER_DOMAIN_GT_IRQ, wakeref);
-       i915_globals_park();
- }
- void i915_gem_park(struct drm_i915_private *i915)
- {
-       GEM_TRACE("\n");
-       lockdep_assert_held(&i915->drm.struct_mutex);
-       GEM_BUG_ON(i915->gt.active_requests);
-       if (!i915->gt.awake)
-               return;
-       /* Defer the actual call to __i915_gem_park() to prevent ping-pongs */
-       mod_delayed_work(i915->wq, &i915->gt.idle_work, msecs_to_jiffies(100));
- }
- void i915_gem_unpark(struct drm_i915_private *i915)
- {
-       GEM_TRACE("\n");
-       lockdep_assert_held(&i915->drm.struct_mutex);
-       GEM_BUG_ON(!i915->gt.active_requests);
-       assert_rpm_wakelock_held(i915);
-       if (i915->gt.awake)
-               return;
-       /*
-        * It seems that the DMC likes to transition between the DC states a lot
-        * when there are no connected displays (no active power domains) during
-        * command submission.
-        *
-        * This activity has negative impact on the performance of the chip with
-        * huge latencies observed in the interrupt handler and elsewhere.
-        *
-        * Work around it by grabbing a GT IRQ power domain whilst there is any
-        * GT activity, preventing any DC state transitions.
-        */
-       i915->gt.awake = intel_display_power_get(i915, POWER_DOMAIN_GT_IRQ);
-       GEM_BUG_ON(!i915->gt.awake);
-       i915_globals_unpark();
-       intel_enable_gt_powersave(i915);
-       i915_update_gfx_val(i915);
-       if (INTEL_GEN(i915) >= 6)
-               gen6_rps_busy(i915);
-       i915_pmu_gt_unparked(i915);
-       intel_engines_unpark(i915);
-       i915_queue_hangcheck(i915);
-       queue_delayed_work(i915->wq,
-                          &i915->gt.retire_work,
-                          round_jiffies_up_relative(HZ));
- }
  int
  i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data,
                            struct drm_file *file)
@@@ -656,8 -561,31 +561,31 @@@ i915_gem_dumb_create(struct drm_file *f
                     struct drm_device *dev,
                     struct drm_mode_create_dumb *args)
  {
+       int cpp = DIV_ROUND_UP(args->bpp, 8);
+       u32 format;
+       switch (cpp) {
+       case 1:
+               format = DRM_FORMAT_C8;
+               break;
+       case 2:
+               format = DRM_FORMAT_RGB565;
+               break;
+       case 4:
+               format = DRM_FORMAT_XRGB8888;
+               break;
+       default:
+               return -EINVAL;
+       }
        /* have to work out size/pitch and return them */
-       args->pitch = ALIGN(args->width * DIV_ROUND_UP(args->bpp, 8), 64);
+       args->pitch = ALIGN(args->width * cpp, 64);
+       /* align stride to page size so that we can remap */
+       if (args->pitch > intel_plane_fb_max_stride(to_i915(dev), format,
+                                                   DRM_FORMAT_MOD_LINEAR))
+               args->pitch = ALIGN(args->pitch, 4096);
        args->size = args->pitch * args->height;
        return i915_gem_create(file, to_i915(dev),
                               &args->size, &args->handle);
@@@ -2087,7 -2015,7 +2015,7 @@@ static int i915_gem_object_create_mmap_
                if (!err)
                        break;
  
-       } while (flush_delayed_work(&dev_priv->gt.retire_work));
+       } while (flush_delayed_work(&dev_priv->gem.retire_work));
  
        return err;
  }
@@@ -2143,8 -2071,7 +2071,7 @@@ i915_gem_mmap_gtt_ioctl(struct drm_devi
  }
  
  /* Immediately discard the backing storage */
- static void
- i915_gem_object_truncate(struct drm_i915_gem_object *obj)
+ void __i915_gem_object_truncate(struct drm_i915_gem_object *obj)
  {
        i915_gem_object_free_mmap_offset(obj);
  
        obj->mm.pages = ERR_PTR(-EFAULT);
  }
  
- /* Try to discard unwanted pages */
- void __i915_gem_object_invalidate(struct drm_i915_gem_object *obj)
- {
-       struct address_space *mapping;
-       lockdep_assert_held(&obj->mm.lock);
-       GEM_BUG_ON(i915_gem_object_has_pages(obj));
-       switch (obj->mm.madv) {
-       case I915_MADV_DONTNEED:
-               i915_gem_object_truncate(obj);
-       case __I915_MADV_PURGED:
-               return;
-       }
-       if (obj->base.filp == NULL)
-               return;
-       mapping = obj->base.filp->f_mapping,
-       invalidate_mapping_pages(mapping, 0, (loff_t)-1);
- }
  /*
   * Move pages to appropriate lru and release the pagevec, decrementing the
   * ref count of those pages.
@@@ -2870,132 -2775,6 +2775,6 @@@ i915_gem_object_pwrite_gtt(struct drm_i
        return 0;
  }
  
- static void
- i915_gem_retire_work_handler(struct work_struct *work)
- {
-       struct drm_i915_private *dev_priv =
-               container_of(work, typeof(*dev_priv), gt.retire_work.work);
-       struct drm_device *dev = &dev_priv->drm;
-       /* Come back later if the device is busy... */
-       if (mutex_trylock(&dev->struct_mutex)) {
-               i915_retire_requests(dev_priv);
-               mutex_unlock(&dev->struct_mutex);
-       }
-       /*
-        * Keep the retire handler running until we are finally idle.
-        * We do not need to do this test under locking as in the worst-case
-        * we queue the retire worker once too often.
-        */
-       if (READ_ONCE(dev_priv->gt.awake))
-               queue_delayed_work(dev_priv->wq,
-                                  &dev_priv->gt.retire_work,
-                                  round_jiffies_up_relative(HZ));
- }
- static bool switch_to_kernel_context_sync(struct drm_i915_private *i915,
-                                         unsigned long mask)
- {
-       bool result = true;
-       /*
-        * Even if we fail to switch, give whatever is running a small chance
-        * to save itself before we report the failure. Yes, this may be a
-        * false positive due to e.g. ENOMEM, caveat emptor!
-        */
-       if (i915_gem_switch_to_kernel_context(i915, mask))
-               result = false;
-       if (i915_gem_wait_for_idle(i915,
-                                  I915_WAIT_LOCKED |
-                                  I915_WAIT_FOR_IDLE_BOOST,
-                                  I915_GEM_IDLE_TIMEOUT))
-               result = false;
-       if (!result) {
-               if (i915_modparams.reset) { /* XXX hide warning from gem_eio */
-                       dev_err(i915->drm.dev,
-                               "Failed to idle engines, declaring wedged!\n");
-                       GEM_TRACE_DUMP();
-               }
-               /* Forcibly cancel outstanding work and leave the gpu quiet. */
-               i915_gem_set_wedged(i915);
-       }
-       i915_retire_requests(i915); /* ensure we flush after wedging */
-       return result;
- }
- static bool load_power_context(struct drm_i915_private *i915)
- {
-       /* Force loading the kernel context on all engines */
-       if (!switch_to_kernel_context_sync(i915, ALL_ENGINES))
-               return false;
-       /*
-        * 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);
-       return true;
- }
- static void
- i915_gem_idle_work_handler(struct work_struct *work)
- {
-       struct drm_i915_private *i915 =
-               container_of(work, typeof(*i915), gt.idle_work.work);
-       bool rearm_hangcheck;
-       if (!READ_ONCE(i915->gt.awake))
-               return;
-       if (READ_ONCE(i915->gt.active_requests))
-               return;
-       rearm_hangcheck =
-               cancel_delayed_work_sync(&i915->gpu_error.hangcheck_work);
-       if (!mutex_trylock(&i915->drm.struct_mutex)) {
-               /* Currently busy, come back later */
-               mod_delayed_work(i915->wq,
-                                &i915->gt.idle_work,
-                                msecs_to_jiffies(50));
-               goto out_rearm;
-       }
-       /*
-        * Flush out the last user context, leaving only the pinned
-        * kernel context resident. Should anything unfortunate happen
-        * while we are idle (such as the GPU being power cycled), no users
-        * will be harmed.
-        */
-       if (!work_pending(&i915->gt.idle_work.work) &&
-           !i915->gt.active_requests) {
-               ++i915->gt.active_requests; /* don't requeue idle */
-               switch_to_kernel_context_sync(i915, i915->gt.active_engines);
-               if (!--i915->gt.active_requests) {
-                       __i915_gem_park(i915);
-                       rearm_hangcheck = false;
-               }
-       }
-       mutex_unlock(&i915->drm.struct_mutex);
- out_rearm:
-       if (rearm_hangcheck) {
-               GEM_BUG_ON(!i915->gt.awake);
-               i915_queue_hangcheck(i915);
-       }
- }
  void i915_gem_close_object(struct drm_gem_object *gem, struct drm_file *file)
  {
        struct drm_i915_private *i915 = to_i915(gem->dev);
@@@ -3135,9 -2914,6 +2914,6 @@@ wait_for_timelines(struct drm_i915_priv
        struct i915_gt_timelines *gt = &i915->gt.timelines;
        struct i915_timeline *tl;
  
-       if (!READ_ONCE(i915->gt.active_requests))
-               return timeout;
        mutex_lock(&gt->mutex);
        list_for_each_entry(tl, &gt->active_list, link) {
                struct i915_request *rq;
  int i915_gem_wait_for_idle(struct drm_i915_private *i915,
                           unsigned int flags, long timeout)
  {
-       GEM_TRACE("flags=%x (%s), timeout=%ld%s\n",
+       GEM_TRACE("flags=%x (%s), timeout=%ld%s, awake?=%s\n",
                  flags, flags & I915_WAIT_LOCKED ? "locked" : "unlocked",
-                 timeout, timeout == MAX_SCHEDULE_TIMEOUT ? " (forever)" : "");
+                 timeout, timeout == MAX_SCHEDULE_TIMEOUT ? " (forever)" : "",
+                 yesno(i915->gt.awake));
  
        /* If the device is asleep, we have no requests outstanding */
        if (!READ_ONCE(i915->gt.awake))
@@@ -4023,7 -3800,7 +3800,7 @@@ i915_gem_madvise_ioctl(struct drm_devic
        /* if the object is no longer attached, discard its backing storage */
        if (obj->mm.madv == I915_MADV_DONTNEED &&
            !i915_gem_object_has_pages(obj))
-               i915_gem_object_truncate(obj);
+               __i915_gem_object_truncate(obj);
  
        args->retained = obj->mm.madv != __I915_MADV_PURGED;
        mutex_unlock(&obj->mm.lock);
@@@ -4199,7 -3976,7 +3976,7 @@@ static bool discard_backing_storage(str
         * acquiring such a reference whilst we are in the middle of
         * freeing the object.
         */
 -      return atomic_long_read(&obj->base.filp->f_count) == 1;
 +      return file_count(obj->base.filp) == 1;
  }
  
  static void __i915_gem_free_objects(struct drm_i915_private *i915,
@@@ -4401,7 -4178,7 +4178,7 @@@ void i915_gem_sanitize(struct drm_i915_
         * it may impact the display and we are uncertain about the stability
         * of the reset, so this could be applied to even earlier gen.
         */
-       intel_engines_sanitize(i915, false);
+       intel_gt_sanitize(i915, false);
  
        intel_uncore_forcewake_put(&i915->uncore, FORCEWAKE_ALL);
        intel_runtime_pm_put(i915, wakeref);
        mutex_unlock(&i915->drm.struct_mutex);
  }
  
- void i915_gem_suspend(struct drm_i915_private *i915)
- {
-       intel_wakeref_t wakeref;
-       GEM_TRACE("\n");
-       wakeref = intel_runtime_pm_get(i915);
-       flush_workqueue(i915->wq);
-       mutex_lock(&i915->drm.struct_mutex);
-       /*
-        * We have to flush all the executing contexts to main memory so
-        * that they can saved in the hibernation image. To ensure the last
-        * context image is coherent, we have to switch away from it. That
-        * leaves the i915->kernel_context still active when
-        * we actually suspend, and its image in memory may not match the GPU
-        * state. Fortunately, the kernel_context is disposable and we do
-        * not rely on its state.
-        */
-       switch_to_kernel_context_sync(i915, i915->gt.active_engines);
-       mutex_unlock(&i915->drm.struct_mutex);
-       i915_reset_flush(i915);
-       drain_delayed_work(&i915->gt.retire_work);
-       /*
-        * As the idle_work is rearming if it detects a race, play safe and
-        * repeat the flush until it is definitely idle.
-        */
-       drain_delayed_work(&i915->gt.idle_work);
-       /*
-        * Assert that we successfully flushed all the work and
-        * reset the GPU back to its idle, low power state.
-        */
-       GEM_BUG_ON(i915->gt.awake);
-       intel_uc_suspend(i915);
-       intel_runtime_pm_put(i915, wakeref);
- }
- void i915_gem_suspend_late(struct drm_i915_private *i915)
- {
-       struct drm_i915_gem_object *obj;
-       struct list_head *phases[] = {
-               &i915->mm.unbound_list,
-               &i915->mm.bound_list,
-               NULL
-       }, **phase;
-       /*
-        * Neither the BIOS, ourselves or any other kernel
-        * expects the system to be in execlists mode on startup,
-        * so we need to reset the GPU back to legacy mode. And the only
-        * known way to disable logical contexts is through a GPU reset.
-        *
-        * So in order to leave the system in a known default configuration,
-        * always reset the GPU upon unload and suspend. Afterwards we then
-        * clean up the GEM state tracking, flushing off the requests and
-        * leaving the system in a known idle state.
-        *
-        * Note that is of the upmost importance that the GPU is idle and
-        * all stray writes are flushed *before* we dismantle the backing
-        * storage for the pinned objects.
-        *
-        * However, since we are uncertain that resetting the GPU on older
-        * machines is a good idea, we don't - just in case it leaves the
-        * machine in an unusable condition.
-        */
-       mutex_lock(&i915->drm.struct_mutex);
-       for (phase = phases; *phase; phase++) {
-               list_for_each_entry(obj, *phase, mm.link)
-                       WARN_ON(i915_gem_object_set_to_gtt_domain(obj, false));
-       }
-       mutex_unlock(&i915->drm.struct_mutex);
-       intel_uc_sanitize(i915);
-       i915_gem_sanitize(i915);
- }
- void i915_gem_resume(struct drm_i915_private *i915)
- {
-       GEM_TRACE("\n");
-       WARN_ON(i915->gt.awake);
-       mutex_lock(&i915->drm.struct_mutex);
-       intel_uncore_forcewake_get(&i915->uncore, FORCEWAKE_ALL);
-       i915_gem_restore_gtt_mappings(i915);
-       i915_gem_restore_fences(i915);
-       /*
-        * As we didn't flush the kernel context before suspend, we cannot
-        * guarantee that the context image is complete. So let's just reset
-        * it and start again.
-        */
-       intel_gt_resume(i915);
-       if (i915_gem_init_hw(i915))
-               goto err_wedged;
-       intel_uc_resume(i915);
-       /* Always reload a context for powersaving. */
-       if (!load_power_context(i915))
-               goto err_wedged;
- out_unlock:
-       intel_uncore_forcewake_put(&i915->uncore, FORCEWAKE_ALL);
-       mutex_unlock(&i915->drm.struct_mutex);
-       return;
- err_wedged:
-       if (!i915_reset_failed(i915)) {
-               dev_err(i915->drm.dev,
-                       "Failed to re-initialize GPU, declaring it wedged!\n");
-               i915_gem_set_wedged(i915);
-       }
-       goto out_unlock;
- }
  void i915_gem_init_swizzling(struct drm_i915_private *dev_priv)
  {
        if (INTEL_GEN(dev_priv) < 5 ||
@@@ -4586,27 -4236,6 +4236,6 @@@ static void init_unused_rings(struct dr
        }
  }
  
- static int __i915_gem_restart_engines(void *data)
- {
-       struct drm_i915_private *i915 = data;
-       struct intel_engine_cs *engine;
-       enum intel_engine_id id;
-       int err;
-       for_each_engine(engine, i915, id) {
-               err = engine->init_hw(engine);
-               if (err) {
-                       DRM_ERROR("Failed to restart %s (%d)\n",
-                                 engine->name, err);
-                       return err;
-               }
-       }
-       intel_engines_set_scheduler_caps(i915);
-       return 0;
- }
  int i915_gem_init_hw(struct drm_i915_private *dev_priv)
  {
        int ret;
        intel_mocs_init_l3cc_table(dev_priv);
  
        /* Only when the HW is re-initialised, can we replay the requests */
-       ret = __i915_gem_restart_engines(dev_priv);
+       ret = intel_engines_resume(dev_priv);
        if (ret)
                goto cleanup_uc;
  
        intel_uncore_forcewake_put(&dev_priv->uncore, FORCEWAKE_ALL);
  
+       intel_engines_set_scheduler_caps(dev_priv);
        return 0;
  
  cleanup_uc:
@@@ -4683,8 -4313,9 +4313,9 @@@ out
  
  static int __intel_engines_record_defaults(struct drm_i915_private *i915)
  {
-       struct i915_gem_context *ctx;
        struct intel_engine_cs *engine;
+       struct i915_gem_context *ctx;
+       struct i915_gem_engines *e;
        enum intel_engine_id id;
        int err = 0;
  
        if (IS_ERR(ctx))
                return PTR_ERR(ctx);
  
+       e = i915_gem_context_lock_engines(ctx);
        for_each_engine(engine, i915, id) {
+               struct intel_context *ce = e->engines[id];
                struct i915_request *rq;
  
-               rq = i915_request_alloc(engine, ctx);
+               rq = intel_context_create_request(ce);
                if (IS_ERR(rq)) {
                        err = PTR_ERR(rq);
-                       goto out_ctx;
+                       goto err_active;
                }
  
                err = 0;
-               if (engine->init_context)
-                       err = engine->init_context(rq);
+               if (rq->engine->init_context)
+                       err = rq->engine->init_context(rq);
  
                i915_request_add(rq);
                if (err)
        }
  
        /* Flush the default context image to memory, and enable powersaving. */
-       if (!load_power_context(i915)) {
+       if (!i915_gem_load_power_context(i915)) {
                err = -EIO;
                goto err_active;
        }
  
        for_each_engine(engine, i915, id) {
-               struct intel_context *ce;
-               struct i915_vma *state;
+               struct intel_context *ce = e->engines[id];
+               struct i915_vma *state = ce->state;
                void *vaddr;
  
-               ce = intel_context_lookup(ctx, engine);
-               if (!ce)
-                       continue;
-               state = ce->state;
                if (!state)
                        continue;
  
        }
  
  out_ctx:
+       i915_gem_context_unlock_engines(ctx);
        i915_gem_context_set_closed(ctx);
        i915_gem_context_put(ctx);
        return err;
@@@ -4842,6 -4472,23 +4472,23 @@@ static void i915_gem_fini_scratch(struc
        i915_vma_unpin_and_release(&i915->gt.scratch, 0);
  }
  
+ static int intel_engines_verify_workarounds(struct drm_i915_private *i915)
+ {
+       struct intel_engine_cs *engine;
+       enum intel_engine_id id;
+       int err = 0;
+       if (!IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM))
+               return 0;
+       for_each_engine(engine, i915, id) {
+               if (intel_engine_verify_workarounds(engine, "load"))
+                       err = -EIO;
+       }
+       return err;
+ }
  int i915_gem_init(struct drm_i915_private *dev_priv)
  {
        int ret;
  
        dev_priv->mm.unordered_timeline = dma_fence_context_alloc(1);
  
-       if (HAS_LOGICAL_RING_CONTEXTS(dev_priv))
-               dev_priv->gt.cleanup_engine = intel_logical_ring_cleanup;
-       else
-               dev_priv->gt.cleanup_engine = intel_engine_cleanup;
        i915_timelines_init(dev_priv);
  
        ret = i915_gem_init_userptr(dev_priv);
                goto err_ggtt;
        }
  
+       ret = intel_engines_setup(dev_priv);
+       if (ret) {
+               GEM_BUG_ON(ret == -EIO);
+               goto err_unlock;
+       }
        ret = i915_gem_contexts_init(dev_priv);
        if (ret) {
                GEM_BUG_ON(ret == -EIO);
         */
        intel_init_clock_gating(dev_priv);
  
+       ret = intel_engines_verify_workarounds(dev_priv);
+       if (ret)
+               goto err_init_hw;
        ret = __intel_engines_record_defaults(dev_priv);
        if (ret)
                goto err_init_hw;
  err_init_hw:
        mutex_unlock(&dev_priv->drm.struct_mutex);
  
+       i915_gem_set_wedged(dev_priv);
        i915_gem_suspend(dev_priv);
        i915_gem_suspend_late(dev_priv);
  
@@@ -4967,7 -4620,7 +4620,7 @@@ err_uc_init
  err_pm:
        if (ret != -EIO) {
                intel_cleanup_gt_powersave(dev_priv);
-               i915_gem_cleanup_engines(dev_priv);
+               intel_engines_cleanup(dev_priv);
        }
  err_context:
        if (ret != -EIO)
@@@ -5016,6 -4669,8 +4669,8 @@@ err_uc_misc
  
  void i915_gem_fini(struct drm_i915_private *dev_priv)
  {
+       GEM_BUG_ON(dev_priv->gt.awake);
        i915_gem_suspend_late(dev_priv);
        intel_disable_gt_powersave(dev_priv);
  
        mutex_lock(&dev_priv->drm.struct_mutex);
        intel_uc_fini_hw(dev_priv);
        intel_uc_fini(dev_priv);
-       i915_gem_cleanup_engines(dev_priv);
+       intel_engines_cleanup(dev_priv);
        i915_gem_contexts_fini(dev_priv);
        i915_gem_fini_scratch(dev_priv);
        mutex_unlock(&dev_priv->drm.struct_mutex);
@@@ -5048,16 -4703,6 +4703,6 @@@ void i915_gem_init_mmio(struct drm_i915
        i915_gem_sanitize(i915);
  }
  
- void
- i915_gem_cleanup_engines(struct drm_i915_private *dev_priv)
- {
-       struct intel_engine_cs *engine;
-       enum intel_engine_id id;
-       for_each_engine(engine, dev_priv, id)
-               dev_priv->gt.cleanup_engine(engine);
- }
  void
  i915_gem_load_init_fences(struct drm_i915_private *dev_priv)
  {
@@@ -5110,15 -4755,14 +4755,14 @@@ int i915_gem_init_early(struct drm_i915
  {
        int err;
  
+       intel_gt_pm_init(dev_priv);
        INIT_LIST_HEAD(&dev_priv->gt.active_rings);
        INIT_LIST_HEAD(&dev_priv->gt.closed_vma);
  
        i915_gem_init__mm(dev_priv);
+       i915_gem_init__pm(dev_priv);
  
-       INIT_DELAYED_WORK(&dev_priv->gt.retire_work,
-                         i915_gem_retire_work_handler);
-       INIT_DELAYED_WORK(&dev_priv->gt.idle_work,
-                         i915_gem_idle_work_handler);
        init_waitqueue_head(&dev_priv->gpu_error.wait_queue);
        init_waitqueue_head(&dev_priv->gpu_error.reset_queue);
        mutex_init(&dev_priv->gpu_error.wedge_mutex);
@@@ -5461,16 -5105,29 +5105,29 @@@ i915_gem_object_get_dirty_page(struct d
  }
  
  dma_addr_t
- i915_gem_object_get_dma_address(struct drm_i915_gem_object *obj,
-                               unsigned long n)
+ i915_gem_object_get_dma_address_len(struct drm_i915_gem_object *obj,
+                                   unsigned long n,
+                                   unsigned int *len)
  {
        struct scatterlist *sg;
        unsigned int offset;
  
        sg = i915_gem_object_get_sg(obj, n, &offset);
+       if (len)
+               *len = sg_dma_len(sg) - (offset << PAGE_SHIFT);
        return sg_dma_address(sg) + (offset << PAGE_SHIFT);
  }
  
+ dma_addr_t
+ i915_gem_object_get_dma_address(struct drm_i915_gem_object *obj,
+                               unsigned long n)
+ {
+       return i915_gem_object_get_dma_address_len(obj, n, NULL);
+ }
  int i915_gem_object_attach_phys(struct drm_i915_gem_object *obj, int align)
  {
        struct sg_table *pages;
@@@ -34,6 -34,8 +34,8 @@@
  #include <drm/drm_syncobj.h>
  #include <drm/i915_drm.h>
  
+ #include "gt/intel_gt_pm.h"
  #include "i915_drv.h"
  #include "i915_gem_clflush.h"
  #include "i915_trace.h"
@@@ -236,7 -238,8 +238,8 @@@ struct i915_execbuffer 
        unsigned int *flags;
  
        struct intel_engine_cs *engine; /** engine to queue the request to */
-       struct i915_gem_context *ctx; /** context for building the request */
+       struct intel_context *context; /* logical state for the request */
+       struct i915_gem_context *gem_context; /** caller's context */
        struct i915_address_space *vm; /** GTT and vma for the request */
  
        struct i915_request *request; /** our request to build */
@@@ -738,7 -741,7 +741,7 @@@ static int eb_select_context(struct i91
        if (unlikely(!ctx))
                return -ENOENT;
  
-       eb->ctx = ctx;
+       eb->gem_context = ctx;
        if (ctx->ppgtt) {
                eb->vm = &ctx->ppgtt->vm;
                eb->invalid_flags |= EXEC_OBJECT_NEEDS_GTT;
@@@ -784,7 -787,6 +787,6 @@@ static struct i915_request *__eb_wait_f
  
  static int eb_wait_for_ring(const struct i915_execbuffer *eb)
  {
-       const struct intel_context *ce;
        struct i915_request *rq;
        int ret = 0;
  
         * keeping all of their resources pinned.
         */
  
-       ce = intel_context_lookup(eb->ctx, eb->engine);
-       if (!ce || !ce->ring) /* first use, assume empty! */
-               return 0;
-       rq = __eb_wait_for_ring(ce->ring);
+       rq = __eb_wait_for_ring(eb->context->ring);
        if (rq) {
                mutex_unlock(&eb->i915->drm.struct_mutex);
  
  
  static int eb_lookup_vmas(struct i915_execbuffer *eb)
  {
-       struct radix_tree_root *handles_vma = &eb->ctx->handles_vma;
+       struct radix_tree_root *handles_vma = &eb->gem_context->handles_vma;
        struct drm_i915_gem_object *obj;
        unsigned int i, batch;
        int err;
  
-       if (unlikely(i915_gem_context_is_closed(eb->ctx)))
+       if (unlikely(i915_gem_context_is_closed(eb->gem_context)))
                return -ENOENT;
  
-       if (unlikely(i915_gem_context_is_banned(eb->ctx)))
+       if (unlikely(i915_gem_context_is_banned(eb->gem_context)))
                return -EIO;
  
        INIT_LIST_HEAD(&eb->relocs);
                if (!vma->open_count++)
                        i915_vma_reopen(vma);
                list_add(&lut->obj_link, &obj->lut_list);
-               list_add(&lut->ctx_link, &eb->ctx->handles_list);
-               lut->ctx = eb->ctx;
+               list_add(&lut->ctx_link, &eb->gem_context->handles_list);
+               lut->ctx = eb->gem_context;
                lut->handle = handle;
  
  add_vma:
@@@ -1227,7 -1225,7 +1225,7 @@@ static int __reloc_gpu_alloc(struct i91
        if (err)
                goto err_unmap;
  
-       rq = i915_request_alloc(eb->engine, eb->ctx);
+       rq = i915_request_create(eb->context);
        if (IS_ERR(rq)) {
                err = PTR_ERR(rq);
                goto err_unpin;
@@@ -1666,7 -1664,6 +1664,7 @@@ static int eb_copy_relocations(const st
                                             len)) {
  end_user:
                                user_access_end();
 +end:
                                kvfree(relocs);
                                err = -EFAULT;
                                goto err;
                 * relocations were valid.
                 */
                if (!user_access_begin(urelocs, size))
 -                      goto end_user;
 +                      goto end;
  
                for (copied = 0; copied < nreloc; copied++)
                        unsafe_put_user(-1,
@@@ -2079,9 -2076,7 +2077,7 @@@ gen8_dispatch_bsd_engine(struct drm_i91
        return file_priv->bsd_engine;
  }
  
- #define I915_USER_RINGS (4)
- static const enum intel_engine_id user_ring_map[I915_USER_RINGS + 1] = {
+ static const enum intel_engine_id user_ring_map[] = {
        [I915_EXEC_DEFAULT]     = RCS0,
        [I915_EXEC_RENDER]      = RCS0,
        [I915_EXEC_BLT]         = BCS0,
        [I915_EXEC_VEBOX]       = VECS0
  };
  
- static struct intel_engine_cs *
- eb_select_engine(struct drm_i915_private *dev_priv,
-                struct drm_file *file,
-                struct drm_i915_gem_execbuffer2 *args)
+ static int eb_pin_context(struct i915_execbuffer *eb, struct intel_context *ce)
  {
-       unsigned int user_ring_id = args->flags & I915_EXEC_RING_MASK;
-       struct intel_engine_cs *engine;
+       int err;
  
-       if (user_ring_id > I915_USER_RINGS) {
-               DRM_DEBUG("execbuf with unknown ring: %u\n", user_ring_id);
-               return NULL;
-       }
+       /*
+        * ABI: Before userspace accesses the GPU (e.g. execbuffer), report
+        * EIO if the GPU is already wedged.
+        */
+       err = i915_terminally_wedged(eb->i915);
+       if (err)
+               return err;
+       /*
+        * Pinning the contexts may generate requests in order to acquire
+        * GGTT space, so do this first before we reserve a seqno for
+        * ourselves.
+        */
+       err = intel_context_pin(ce);
+       if (err)
+               return err;
+       eb->engine = ce->engine;
+       eb->context = ce;
+       return 0;
+ }
+ static void eb_unpin_context(struct i915_execbuffer *eb)
+ {
+       intel_context_unpin(eb->context);
+ }
  
-       if ((user_ring_id != I915_EXEC_BSD) &&
-           ((args->flags & I915_EXEC_BSD_MASK) != 0)) {
+ static unsigned int
+ eb_select_legacy_ring(struct i915_execbuffer *eb,
+                     struct drm_file *file,
+                     struct drm_i915_gem_execbuffer2 *args)
+ {
+       struct drm_i915_private *i915 = eb->i915;
+       unsigned int user_ring_id = args->flags & I915_EXEC_RING_MASK;
+       if (user_ring_id != I915_EXEC_BSD &&
+           (args->flags & I915_EXEC_BSD_MASK)) {
                DRM_DEBUG("execbuf with non bsd ring but with invalid "
                          "bsd dispatch flags: %d\n", (int)(args->flags));
-               return NULL;
+               return -1;
        }
  
-       if (user_ring_id == I915_EXEC_BSD && HAS_ENGINE(dev_priv, VCS1)) {
+       if (user_ring_id == I915_EXEC_BSD && HAS_ENGINE(i915, VCS1)) {
                unsigned int bsd_idx = args->flags & I915_EXEC_BSD_MASK;
  
                if (bsd_idx == I915_EXEC_BSD_DEFAULT) {
-                       bsd_idx = gen8_dispatch_bsd_engine(dev_priv, file);
+                       bsd_idx = gen8_dispatch_bsd_engine(i915, file);
                } else if (bsd_idx >= I915_EXEC_BSD_RING1 &&
                           bsd_idx <= I915_EXEC_BSD_RING2) {
                        bsd_idx >>= I915_EXEC_BSD_SHIFT;
                } else {
                        DRM_DEBUG("execbuf with unknown bsd ring: %u\n",
                                  bsd_idx);
-                       return NULL;
+                       return -1;
                }
  
-               engine = dev_priv->engine[_VCS(bsd_idx)];
-       } else {
-               engine = dev_priv->engine[user_ring_map[user_ring_id]];
+               return _VCS(bsd_idx);
        }
  
-       if (!engine) {
-               DRM_DEBUG("execbuf with invalid ring: %u\n", user_ring_id);
-               return NULL;
+       if (user_ring_id >= ARRAY_SIZE(user_ring_map)) {
+               DRM_DEBUG("execbuf with unknown ring: %u\n", user_ring_id);
+               return -1;
        }
  
-       return engine;
+       return user_ring_map[user_ring_id];
+ }
+ static int
+ eb_select_engine(struct i915_execbuffer *eb,
+                struct drm_file *file,
+                struct drm_i915_gem_execbuffer2 *args)
+ {
+       struct intel_context *ce;
+       unsigned int idx;
+       int err;
+       if (i915_gem_context_user_engines(eb->gem_context))
+               idx = args->flags & I915_EXEC_RING_MASK;
+       else
+               idx = eb_select_legacy_ring(eb, file, args);
+       ce = i915_gem_context_get_engine(eb->gem_context, idx);
+       if (IS_ERR(ce))
+               return PTR_ERR(ce);
+       err = eb_pin_context(eb, ce);
+       intel_context_put(ce);
+       return err;
  }
  
  static void
@@@ -2275,8 -2318,8 +2319,8 @@@ i915_gem_do_execbuffer(struct drm_devic
  {
        struct i915_execbuffer eb;
        struct dma_fence *in_fence = NULL;
+       struct dma_fence *exec_fence = NULL;
        struct sync_file *out_fence = NULL;
-       intel_wakeref_t wakeref;
        int out_fence_fd = -1;
        int err;
  
                        return -EINVAL;
        }
  
+       if (args->flags & I915_EXEC_FENCE_SUBMIT) {
+               if (in_fence) {
+                       err = -EINVAL;
+                       goto err_in_fence;
+               }
+               exec_fence = sync_file_get_fence(lower_32_bits(args->rsvd2));
+               if (!exec_fence) {
+                       err = -EINVAL;
+                       goto err_in_fence;
+               }
+       }
        if (args->flags & I915_EXEC_FENCE_OUT) {
                out_fence_fd = get_unused_fd_flags(O_CLOEXEC);
                if (out_fence_fd < 0) {
                        err = out_fence_fd;
-                       goto err_in_fence;
+                       goto err_exec_fence;
                }
        }
  
        if (unlikely(err))
                goto err_destroy;
  
-       eb.engine = eb_select_engine(eb.i915, file, args);
-       if (!eb.engine) {
-               err = -EINVAL;
-               goto err_engine;
-       }
        /*
         * Take a local wakeref for preparing to dispatch the execbuf as
         * we expect to access the hardware fairly frequently in the
         * wakeref that we hold until the GPU has been idle for at least
         * 100ms.
         */
-       wakeref = intel_runtime_pm_get(eb.i915);
+       intel_gt_pm_get(eb.i915);
  
        err = i915_mutex_lock_interruptible(dev);
        if (err)
                goto err_rpm;
  
-       err = eb_wait_for_ring(&eb); /* may temporarily drop struct_mutex */
+       err = eb_select_engine(&eb, file, args);
        if (unlikely(err))
                goto err_unlock;
  
+       err = eb_wait_for_ring(&eb); /* may temporarily drop struct_mutex */
+       if (unlikely(err))
+               goto err_engine;
        err = eb_relocate(&eb);
        if (err) {
                /*
        GEM_BUG_ON(eb.reloc_cache.rq);
  
        /* Allocate a request for this batch buffer nice and early. */
-       eb.request = i915_request_alloc(eb.engine, eb.ctx);
+       eb.request = i915_request_create(eb.context);
        if (IS_ERR(eb.request)) {
                err = PTR_ERR(eb.request);
                goto err_batch_unpin;
                        goto err_request;
        }
  
+       if (exec_fence) {
+               err = i915_request_await_execution(eb.request, exec_fence,
+                                                  eb.engine->bond_execute);
+               if (err < 0)
+                       goto err_request;
+       }
        if (fences) {
                err = await_fence_array(&eb, fences);
                if (err)
        trace_i915_request_queue(eb.request, eb.batch_flags);
        err = eb_submit(&eb);
  err_request:
-       i915_request_add(eb.request);
        add_to_client(eb.request, file);
+       i915_request_add(eb.request);
  
        if (fences)
                signal_fence_array(&eb, fences);
@@@ -2503,17 -2564,20 +2565,20 @@@ err_batch_unpin
  err_vma:
        if (eb.exec)
                eb_release_vmas(&eb);
+ err_engine:
+       eb_unpin_context(&eb);
  err_unlock:
        mutex_unlock(&dev->struct_mutex);
  err_rpm:
-       intel_runtime_pm_put(eb.i915, wakeref);
- err_engine:
-       i915_gem_context_put(eb.ctx);
+       intel_gt_pm_put(eb.i915);
+       i915_gem_context_put(eb.gem_context);
  err_destroy:
        eb_destroy(&eb);
  err_out_fence:
        if (out_fence_fd != -1)
                put_unused_fd(out_fence_fd);
+ err_exec_fence:
+       dma_fence_put(exec_fence);
  err_in_fence:
        dma_fence_put(in_fence);
        return err;
@@@ -2698,7 -2762,7 +2763,7 @@@ i915_gem_execbuffer2_ioctl(struct drm_d
                 * when we did the "copy_from_user()" above.
                 */
                if (!user_access_begin(user_exec_list, count * sizeof(*user_exec_list)))
 -                      goto end_user;
 +                      goto end;
  
                for (i = 0; i < args->buffer_count; i++) {
                        if (!(exec2_list[i].offset & UPDATE))
                }
  end_user:
                user_access_end();
 +end:;
        }
  
        args->flags &= ~__I915_EXEC_UNKNOWN_FLAGS;
   *
   */
  
+ #include "gt/intel_engine.h"
  #include "i915_vma.h"
  
  #include "i915_drv.h"
  #include "i915_globals.h"
- #include "intel_ringbuffer.h"
  #include "intel_frontbuffer.h"
  
  #include <drm/drm_gem.h>
@@@ -52,8 -53,11 +53,8 @@@ void i915_vma_free(struct i915_vma *vma
  
  static void vma_print_allocator(struct i915_vma *vma, const char *reason)
  {
 -      unsigned long entries[12];
 -      struct stack_trace trace = {
 -              .entries = entries,
 -              .max_entries = ARRAY_SIZE(entries),
 -      };
 +      unsigned long *entries;
 +      unsigned int nr_entries;
        char buf[512];
  
        if (!vma->node.stack) {
@@@ -62,8 -66,8 +63,8 @@@
                return;
        }
  
 -      depot_fetch_stack(vma->node.stack, &trace);
 -      snprint_stack_trace(buf, sizeof(buf), &trace, 0);
 +      nr_entries = stack_depot_fetch(vma->node.stack, &entries);
 +      stack_trace_snprint(buf, sizeof(buf), entries, nr_entries, 0);
        DRM_DEBUG_DRIVER("vma.node [%08llx + %08llx] %s: inserted at %s\n",
                         vma->node.start, vma->node.size, reason, buf);
  }
@@@ -155,6 -159,9 +156,9 @@@ vma_create(struct drm_i915_gem_object *
                } else if (view->type == I915_GGTT_VIEW_ROTATED) {
                        vma->size = intel_rotation_info_size(&view->rotated);
                        vma->size <<= PAGE_SHIFT;
+               } else if (view->type == I915_GGTT_VIEW_REMAPPED) {
+                       vma->size = intel_remapped_info_size(&view->remapped);
+                       vma->size <<= PAGE_SHIFT;
                }
        }
  
@@@ -476,13 -483,6 +480,6 @@@ void __i915_vma_set_map_and_fenceable(s
        GEM_BUG_ON(!i915_vma_is_ggtt(vma));
        GEM_BUG_ON(!vma->fence_size);
  
-       /*
-        * Explicitly disable for rotated VMA since the display does not
-        * need the fence and the VMA is not accessible to other users.
-        */
-       if (vma->ggtt_view.type == I915_GGTT_VIEW_ROTATED)
-               return;
        fenceable = (vma->node.size >= vma->fence_size &&
                     IS_ALIGNED(vma->node.start, vma->fence_alignment));
  
@@@ -46,8 -46,9 +46,9 @@@
  
  #include "i915_drv.h"
  #include "i915_gem_clflush.h"
- #include "i915_reset.h"
  #include "i915_trace.h"
+ #include "intel_acpi.h"
+ #include "intel_atomic.h"
  #include "intel_atomic_plane.h"
  #include "intel_color.h"
  #include "intel_cdclk.h"
  #include "intel_dvo.h"
  #include "intel_fbc.h"
  #include "intel_fbdev.h"
+ #include "intel_fifo_underrun.h"
  #include "intel_frontbuffer.h"
+ #include "intel_gmbus.h"
  #include "intel_hdcp.h"
  #include "intel_hdmi.h"
+ #include "intel_hotplug.h"
  #include "intel_lvds.h"
+ #include "intel_overlay.h"
  #include "intel_pipe_crc.h"
  #include "intel_pm.h"
  #include "intel_psr.h"
+ #include "intel_quirks.h"
  #include "intel_sdvo.h"
+ #include "intel_sideband.h"
  #include "intel_sprite.h"
  #include "intel_tv.h"
+ #include "intel_vdsc.h"
  
  /* Primary plane formats for gen <= 3 */
  static const u32 i8xx_primary_formats[] = {
@@@ -120,7 -128,7 +128,7 @@@ static void intel_cpu_transcoder_set_m_
  static void i9xx_set_pipeconf(const struct intel_crtc_state *crtc_state);
  static void ironlake_set_pipeconf(const struct intel_crtc_state *crtc_state);
  static void haswell_set_pipeconf(const struct intel_crtc_state *crtc_state);
- static void haswell_set_pipemisc(const struct intel_crtc_state *crtc_state);
+ static void bdw_set_pipemisc(const struct intel_crtc_state *crtc_state);
  static void vlv_prepare_pll(struct intel_crtc *crtc,
                            const struct intel_crtc_state *pipe_config);
  static void chv_prepare_pll(struct intel_crtc *crtc,
@@@ -153,10 -161,8 +161,8 @@@ int vlv_get_hpll_vco(struct drm_i915_pr
        int hpll_freq, vco_freq[] = { 800, 1600, 2000, 2400 };
  
        /* Obtain SKU information */
-       mutex_lock(&dev_priv->sb_lock);
        hpll_freq = vlv_cck_read(dev_priv, CCK_FUSE_REG) &
                CCK_FUSE_HPLL_FREQ_MASK;
-       mutex_unlock(&dev_priv->sb_lock);
  
        return vco_freq[hpll_freq] * 1000;
  }
@@@ -167,10 -173,7 +173,7 @@@ int vlv_get_cck_clock(struct drm_i915_p
        u32 val;
        int divider;
  
-       mutex_lock(&dev_priv->sb_lock);
        val = vlv_cck_read(dev_priv, reg);
-       mutex_unlock(&dev_priv->sb_lock);
        divider = val & CCK_FREQUENCY_VALUES;
  
        WARN((val & CCK_FREQUENCY_STATUS) !=
  int vlv_get_cck_clock_hpll(struct drm_i915_private *dev_priv,
                           const char *name, u32 reg)
  {
+       int hpll;
+       vlv_cck_get(dev_priv);
        if (dev_priv->hpll_freq == 0)
                dev_priv->hpll_freq = vlv_get_hpll_vco(dev_priv);
  
-       return vlv_get_cck_clock(dev_priv, name, reg,
-                                dev_priv->hpll_freq);
+       hpll = vlv_get_cck_clock(dev_priv, name, reg, dev_priv->hpll_freq);
+       vlv_cck_put(dev_priv);
+       return hpll;
  }
  
  static void intel_update_czclk(struct drm_i915_private *dev_priv)
@@@ -476,6 -486,7 +486,7 @@@ static const struct intel_limit intel_l
        .p2 = { .p2_slow = 1, .p2_fast = 20 },
  };
  
+ /* WA Display #0827: Gen9:all */
  static void
  skl_wa_827(struct drm_i915_private *dev_priv, int pipe, bool enable)
  {
                           ~(DUPS1_GATING_DIS | DUPS2_GATING_DIS));
  }
  
+ /* Wa_2006604312:icl */
+ static void
+ icl_wa_scalerclkgating(struct drm_i915_private *dev_priv, enum pipe pipe,
+                      bool enable)
+ {
+       if (enable)
+               I915_WRITE(CLKGATE_DIS_PSL(pipe),
+                          I915_READ(CLKGATE_DIS_PSL(pipe)) | DPFR_GATING_DIS);
+       else
+               I915_WRITE(CLKGATE_DIS_PSL(pipe),
+                          I915_READ(CLKGATE_DIS_PSL(pipe)) & ~DPFR_GATING_DIS);
+ }
  static bool
  needs_modeset(const struct drm_crtc_state *state)
  {
@@@ -551,7 -575,7 +575,7 @@@ int chv_calc_dpll_params(int refclk, st
        clock->p = clock->p1 * clock->p2;
        if (WARN_ON(clock->n == 0 || clock->p == 0))
                return 0;
-       clock->vco = DIV_ROUND_CLOSEST_ULL((u64)refclk * clock->m,
+       clock->vco = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(refclk, clock->m),
                                           clock->n << 22);
        clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p);
  
@@@ -936,8 -960,8 +960,8 @@@ chv_find_best_dpll(const struct intel_l
  
                        clock.p = clock.p1 * clock.p2;
  
-                       m2 = DIV_ROUND_CLOSEST_ULL(((u64)target * clock.p *
-                                       clock.n) << 22, refclk * clock.m1);
+                       m2 = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(target, clock.p * clock.n) << 22,
+                                                  refclk * clock.m1);
  
                        if (m2 > INT_MAX/clock.m1)
                                continue;
@@@ -1080,9 -1104,9 +1104,9 @@@ void assert_dsi_pll(struct drm_i915_pri
        u32 val;
        bool cur_state;
  
-       mutex_lock(&dev_priv->sb_lock);
+       vlv_cck_get(dev_priv);
        val = vlv_cck_read(dev_priv, CCK_REG_DSI_PLL_CONTROL);
-       mutex_unlock(&dev_priv->sb_lock);
+       vlv_cck_put(dev_priv);
  
        cur_state = val & DSI_PLL_VCO_EN;
        I915_STATE_WARN(cur_state != state,
@@@ -1392,14 -1416,14 +1416,14 @@@ static void _chv_enable_pll(struct inte
        enum dpio_channel port = vlv_pipe_to_channel(pipe);
        u32 tmp;
  
-       mutex_lock(&dev_priv->sb_lock);
+       vlv_dpio_get(dev_priv);
  
        /* Enable back the 10bit clock to display controller */
        tmp = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW14(port));
        tmp |= DPIO_DCLKP_EN;
        vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW14(port), tmp);
  
-       mutex_unlock(&dev_priv->sb_lock);
+       vlv_dpio_put(dev_priv);
  
        /*
         * Need to wait > 100ns between dclkp clock enable bit and PLL enable.
@@@ -1556,14 -1580,14 +1580,14 @@@ static void chv_disable_pll(struct drm_
        I915_WRITE(DPLL(pipe), val);
        POSTING_READ(DPLL(pipe));
  
-       mutex_lock(&dev_priv->sb_lock);
+       vlv_dpio_get(dev_priv);
  
        /* Disable 10bit clock to display controller */
        val = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW14(port));
        val &= ~DPIO_DCLKP_EN;
        vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW14(port), val);
  
-       mutex_unlock(&dev_priv->sb_lock);
+       vlv_dpio_put(dev_priv);
  }
  
  void vlv_wait_port_ready(struct drm_i915_private *dev_priv,
@@@ -1891,7 -1915,7 +1915,7 @@@ intel_tile_width_bytes(const struct drm
  
        switch (fb->modifier) {
        case DRM_FORMAT_MOD_LINEAR:
-               return cpp;
+               return intel_tile_size(dev_priv);
        case I915_FORMAT_MOD_X_TILED:
                if (IS_GEN(dev_priv, 2))
                        return 128;
  static unsigned int
  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, color_plane);
+       return intel_tile_size(to_i915(fb->dev)) /
+               intel_tile_width_bytes(fb, color_plane);
  }
  
  /* Return the tile dimensions in pixel units */
@@@ -1973,6 -1994,17 +1994,17 @@@ unsigned int intel_rotation_info_size(c
        return size;
  }
  
+ unsigned int intel_remapped_info_size(const struct intel_remapped_info *rem_info)
+ {
+       unsigned int size = 0;
+       int i;
+       for (i = 0 ; i < ARRAY_SIZE(rem_info->plane); i++)
+               size += rem_info->plane[i].width * rem_info->plane[i].height;
+       return size;
+ }
  static void
  intel_fill_fb_ggtt_view(struct i915_ggtt_view *view,
                        const struct drm_framebuffer *fb,
@@@ -2042,7 -2074,9 +2074,9 @@@ static bool intel_plane_uses_fence(cons
        struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
        struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
  
-       return INTEL_GEN(dev_priv) < 4 || plane->has_fbc;
+       return INTEL_GEN(dev_priv) < 4 ||
+               (plane->has_fbc &&
+                plane_state->view.type == I915_GGTT_VIEW_NORMAL);
  }
  
  struct i915_vma *
@@@ -2183,16 -2217,8 +2217,8 @@@ void intel_add_fb_offsets(int *x, int *
                          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[color_plane].x;
-               *y += intel_fb->rotated[color_plane].y;
-       } else {
-               *x += intel_fb->normal[color_plane].x;
-               *y += intel_fb->normal[color_plane].y;
-       }
+       *x += state->color_plane[color_plane].x;
+       *y += state->color_plane[color_plane].y;
  }
  
  static u32 intel_adjust_tile_offset(int *x, int *y,
@@@ -2472,6 -2498,134 +2498,134 @@@ bool is_ccs_modifier(u64 modifier
               modifier == I915_FORMAT_MOD_Yf_TILED_CCS;
  }
  
+ u32 intel_plane_fb_max_stride(struct drm_i915_private *dev_priv,
+                             u32 pixel_format, u64 modifier)
+ {
+       struct intel_crtc *crtc;
+       struct intel_plane *plane;
+       /*
+        * 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);
+       return plane->max_stride(plane, pixel_format, modifier,
+                                DRM_MODE_ROTATE_0);
+ }
+ static
+ u32 intel_fb_max_stride(struct drm_i915_private *dev_priv,
+                       u32 pixel_format, u64 modifier)
+ {
+       /*
+        * Arbitrary limit for gen4+ chosen to match the
+        * render engine max stride.
+        *
+        * The new CCS hash mode makes remapping impossible
+        */
+       if (!is_ccs_modifier(modifier)) {
+               if (INTEL_GEN(dev_priv) >= 7)
+                       return 256*1024;
+               else if (INTEL_GEN(dev_priv) >= 4)
+                       return 128*1024;
+       }
+       return intel_plane_fb_max_stride(dev_priv, pixel_format, modifier);
+ }
+ static u32
+ intel_fb_stride_alignment(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) {
+               u32 max_stride = intel_plane_fb_max_stride(dev_priv,
+                                                          fb->format->format,
+                                                          fb->modifier);
+               /*
+                * To make remapping with linear generally feasible
+                * we need the stride to be page aligned.
+                */
+               if (fb->pitches[color_plane] > max_stride)
+                       return intel_tile_size(dev_priv);
+               else
+                       return 64;
+       } else {
+               return intel_tile_width_bytes(fb, color_plane);
+       }
+ }
+ bool intel_plane_can_remap(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;
+       int i;
+       /* We don't want to deal with remapping with cursors */
+       if (plane->id == PLANE_CURSOR)
+               return false;
+       /*
+        * The display engine limits already match/exceed the
+        * render engine limits, so not much point in remapping.
+        * Would also need to deal with the fence POT alignment
+        * and gen2 2KiB GTT tile size.
+        */
+       if (INTEL_GEN(dev_priv) < 4)
+               return false;
+       /*
+        * The new CCS hash mode isn't compatible with remapping as
+        * the virtual address of the pages affects the compressed data.
+        */
+       if (is_ccs_modifier(fb->modifier))
+               return false;
+       /* Linear needs a page aligned stride for remapping */
+       if (fb->modifier == DRM_FORMAT_MOD_LINEAR) {
+               unsigned int alignment = intel_tile_size(dev_priv) - 1;
+               for (i = 0; i < fb->format->num_planes; i++) {
+                       if (fb->pitches[i] & alignment)
+                               return false;
+               }
+       }
+       return true;
+ }
+ static bool intel_plane_needs_remap(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;
+       /*
+        * No remapping for invisible planes since we don't have
+        * an actual source viewport to remap.
+        */
+       if (!plane_state->base.visible)
+               return false;
+       if (!intel_plane_can_remap(plane_state))
+               return false;
+       /*
+        * FIXME: aux plane limits on gen9+ are
+        * unclear in Bspec, for now no checking.
+        */
+       stride = intel_fb_pitch(fb, 0, rotation);
+       max_stride = plane->max_stride(plane, fb->format->format,
+                                      fb->modifier, rotation);
+       return stride > max_stride;
+ }
  static int
  intel_fill_fb_info(struct drm_i915_private *dev_priv,
                   struct drm_framebuffer *fb)
        return 0;
  }
  
+ static void
+ intel_plane_remap_gtt(struct intel_plane_state *plane_state)
+ {
+       struct drm_i915_private *dev_priv =
+               to_i915(plane_state->base.plane->dev);
+       struct drm_framebuffer *fb = plane_state->base.fb;
+       struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
+       struct intel_rotation_info *info = &plane_state->view.rotated;
+       unsigned int rotation = plane_state->base.rotation;
+       int i, num_planes = fb->format->num_planes;
+       unsigned int tile_size = intel_tile_size(dev_priv);
+       unsigned int src_x, src_y;
+       unsigned int src_w, src_h;
+       u32 gtt_offset = 0;
+       memset(&plane_state->view, 0, sizeof(plane_state->view));
+       plane_state->view.type = drm_rotation_90_or_270(rotation) ?
+               I915_GGTT_VIEW_ROTATED : I915_GGTT_VIEW_REMAPPED;
+       src_x = plane_state->base.src.x1 >> 16;
+       src_y = plane_state->base.src.y1 >> 16;
+       src_w = drm_rect_width(&plane_state->base.src) >> 16;
+       src_h = drm_rect_height(&plane_state->base.src) >> 16;
+       WARN_ON(is_ccs_modifier(fb->modifier));
+       /* Make src coordinates relative to the viewport */
+       drm_rect_translate(&plane_state->base.src,
+                          -(src_x << 16), -(src_y << 16));
+       /* Rotate src coordinates to match rotated GTT view */
+       if (drm_rotation_90_or_270(rotation))
+               drm_rect_rotate(&plane_state->base.src,
+                               src_w << 16, src_h << 16,
+                               DRM_MODE_ROTATE_270);
+       for (i = 0; i < num_planes; i++) {
+               unsigned int hsub = i ? fb->format->hsub : 1;
+               unsigned int vsub = i ? fb->format->vsub : 1;
+               unsigned int cpp = fb->format->cpp[i];
+               unsigned int tile_width, tile_height;
+               unsigned int width, height;
+               unsigned int pitch_tiles;
+               unsigned int x, y;
+               u32 offset;
+               intel_tile_dims(fb, i, &tile_width, &tile_height);
+               x = src_x / hsub;
+               y = src_y / vsub;
+               width = src_w / hsub;
+               height = src_h / vsub;
+               /*
+                * First pixel of the src viewport from the
+                * start of the normal gtt mapping.
+                */
+               x += intel_fb->normal[i].x;
+               y += intel_fb->normal[i].y;
+               offset = intel_compute_aligned_offset(dev_priv, &x, &y,
+                                                     fb, i, fb->pitches[i],
+                                                     DRM_MODE_ROTATE_0, tile_size);
+               offset /= tile_size;
+               info->plane[i].offset = offset;
+               info->plane[i].stride = DIV_ROUND_UP(fb->pitches[i],
+                                                    tile_width * cpp);
+               info->plane[i].width = DIV_ROUND_UP(x + width, tile_width);
+               info->plane[i].height = DIV_ROUND_UP(y + height, tile_height);
+               if (drm_rotation_90_or_270(rotation)) {
+                       struct drm_rect r;
+                       /* rotate the x/y offsets to match the GTT view */
+                       r.x1 = x;
+                       r.y1 = y;
+                       r.x2 = x + width;
+                       r.y2 = y + height;
+                       drm_rect_rotate(&r,
+                                       info->plane[i].width * tile_width,
+                                       info->plane[i].height * tile_height,
+                                       DRM_MODE_ROTATE_270);
+                       x = r.x1;
+                       y = r.y1;
+                       pitch_tiles = info->plane[i].height;
+                       plane_state->color_plane[i].stride = pitch_tiles * tile_height;
+                       /* rotate the tile dimensions to match the GTT view */
+                       swap(tile_width, tile_height);
+               } else {
+                       pitch_tiles = info->plane[i].width;
+                       plane_state->color_plane[i].stride = pitch_tiles * tile_width * cpp;
+               }
+               /*
+                * 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 * tile_size, 0);
+               gtt_offset += info->plane[i].width * info->plane[i].height;
+               plane_state->color_plane[i].offset = 0;
+               plane_state->color_plane[i].x = x;
+               plane_state->color_plane[i].y = y;
+       }
+ }
+ static int
+ intel_plane_compute_gtt(struct intel_plane_state *plane_state)
+ {
+       const struct intel_framebuffer *fb =
+               to_intel_framebuffer(plane_state->base.fb);
+       unsigned int rotation = plane_state->base.rotation;
+       int i, num_planes;
+       if (!fb)
+               return 0;
+       num_planes = fb->base.format->num_planes;
+       if (intel_plane_needs_remap(plane_state)) {
+               intel_plane_remap_gtt(plane_state);
+               /*
+                * Sometimes even remapping can't overcome
+                * the stride limitations :( Can happen with
+                * big plane sizes and suitably misaligned
+                * offsets.
+                */
+               return intel_plane_check_stride(plane_state);
+       }
+       intel_fill_fb_ggtt_view(&plane_state->view, &fb->base, rotation);
+       for (i = 0; i < num_planes; i++) {
+               plane_state->color_plane[i].stride = intel_fb_pitch(&fb->base, i, rotation);
+               plane_state->color_plane[i].offset = 0;
+               if (drm_rotation_90_or_270(rotation)) {
+                       plane_state->color_plane[i].x = fb->rotated[i].x;
+                       plane_state->color_plane[i].y = fb->rotated[i].y;
+               } else {
+                       plane_state->color_plane[i].x = fb->normal[i].x;
+                       plane_state->color_plane[i].y = fb->normal[i].y;
+               }
+       }
+       /* Rotate src coordinates to match rotated GTT view */
+       if (drm_rotation_90_or_270(rotation))
+               drm_rect_rotate(&plane_state->base.src,
+                               fb->base.width << 16, fb->base.height << 16,
+                               DRM_MODE_ROTATE_270);
+       return intel_plane_check_stride(plane_state);
+ }
  static int i9xx_format_to_fourcc(int format)
  {
        switch (format) {
@@@ -2964,41 -3280,55 +3280,55 @@@ static int skl_max_plane_width(const st
        switch (fb->modifier) {
        case DRM_FORMAT_MOD_LINEAR:
        case I915_FORMAT_MOD_X_TILED:
-               switch (cpp) {
-               case 8:
-                       return 4096;
-               case 4:
-               case 2:
-               case 1:
-                       return 8192;
-               default:
-                       MISSING_CASE(cpp);
-                       break;
-               }
-               break;
+               return 4096;
        case I915_FORMAT_MOD_Y_TILED_CCS:
        case I915_FORMAT_MOD_Yf_TILED_CCS:
                /* FIXME AUX plane? */
        case I915_FORMAT_MOD_Y_TILED:
        case I915_FORMAT_MOD_Yf_TILED:
-               switch (cpp) {
-               case 8:
+               if (cpp == 8)
                        return 2048;
-               case 4:
+               else
                        return 4096;
-               case 2:
-               case 1:
-                       return 8192;
-               default:
-                       MISSING_CASE(cpp);
-                       break;
-               }
-               break;
        default:
                MISSING_CASE(fb->modifier);
+               return 2048;
        }
+ }
  
-       return 2048;
+ static int glk_max_plane_width(const struct drm_framebuffer *fb,
+                              int color_plane,
+                              unsigned int rotation)
+ {
+       int cpp = fb->format->cpp[color_plane];
+       switch (fb->modifier) {
+       case DRM_FORMAT_MOD_LINEAR:
+       case I915_FORMAT_MOD_X_TILED:
+               if (cpp == 8)
+                       return 4096;
+               else
+                       return 5120;
+       case I915_FORMAT_MOD_Y_TILED_CCS:
+       case I915_FORMAT_MOD_Yf_TILED_CCS:
+               /* FIXME AUX plane? */
+       case I915_FORMAT_MOD_Y_TILED:
+       case I915_FORMAT_MOD_Yf_TILED:
+               if (cpp == 8)
+                       return 2048;
+               else
+                       return 5120;
+       default:
+               MISSING_CASE(fb->modifier);
+               return 2048;
+       }
+ }
+ static int icl_max_plane_width(const struct drm_framebuffer *fb,
+                              int color_plane,
+                              unsigned int rotation)
+ {
+       return 5120;
  }
  
  static bool skl_check_main_ccs_coordinates(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 max_width = skl_max_plane_width(fb, 0, rotation);
+       int max_width;
        int max_height = 4096;
        u32 alignment, offset, aux_offset = plane_state->color_plane[1].offset;
  
+       if (INTEL_GEN(dev_priv) >= 11)
+               max_width = icl_max_plane_width(fb, 0, rotation);
+       else if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
+               max_width = glk_max_plane_width(fb, 0, rotation);
+       else
+               max_width = skl_max_plane_width(fb, 0, rotation);
        if (w > max_width || h > max_height) {
                DRM_DEBUG_KMS("requested Y/RGB source size %dx%d too big (limit %dx%d)\n",
                              w, h, max_width, max_height);
        plane_state->color_plane[0].x = x;
        plane_state->color_plane[0].y = y;
  
+       /*
+        * Put the final coordinates back so that the src
+        * coordinate checks will see the right values.
+        */
+       drm_rect_translate(&plane_state->base.src,
+                          (x << 16) - plane_state->base.src.x1,
+                          (y << 16) - plane_state->base.src.y1);
        return 0;
  }
  
@@@ -3169,26 -3515,15 +3515,15 @@@ static int skl_check_ccs_aux_surface(st
  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;
  
-       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);
+       ret = intel_plane_compute_gtt(plane_state);
        if (ret)
                return ret;
  
        if (!plane_state->base.visible)
                return 0;
  
-       /* Rotate src coordinates to match rotated GTT view */
-       if (drm_rotation_90_or_270(rotation))
-               drm_rect_rotate(&plane_state->base.src,
-                               fb->width << 16, fb->height << 16,
-                               DRM_MODE_ROTATE_270);
        /*
         * Handle the AUX surface first since
         * the main surface setup depends on it.
@@@ -3318,20 -3653,20 +3653,20 @@@ int i9xx_check_plane_surface(struct int
  {
        struct drm_i915_private *dev_priv =
                to_i915(plane_state->base.plane->dev);
-       const struct drm_framebuffer *fb = plane_state->base.fb;
-       unsigned int rotation = plane_state->base.rotation;
-       int src_x = plane_state->base.src.x1 >> 16;
-       int src_y = plane_state->base.src.y1 >> 16;
+       int src_x, src_y;
        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);
+       ret = intel_plane_compute_gtt(plane_state);
        if (ret)
                return ret;
  
+       if (!plane_state->base.visible)
+               return 0;
+       src_x = plane_state->base.src.x1 >> 16;
+       src_y = plane_state->base.src.y1 >> 16;
        intel_add_fb_offsets(&src_x, &src_y, plane_state, 0);
  
        if (INTEL_GEN(dev_priv) >= 4)
        else
                offset = 0;
  
+       /*
+        * Put the final coordinates back so that the src
+        * coordinate checks will see the right values.
+        */
+       drm_rect_translate(&plane_state->base.src,
+                          (src_x << 16) - plane_state->base.src.x1,
+                          (src_y << 16) - plane_state->base.src.y1);
        /* 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;
  
@@@ -3378,6 -3722,10 +3722,10 @@@ i9xx_plane_check(struct intel_crtc_stat
        if (ret)
                return ret;
  
+       ret = i9xx_check_plane_surface(plane_state);
+       if (ret)
+               return ret;
        if (!plane_state->base.visible)
                return 0;
  
        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;
@@@ -3527,15 -3871,6 +3871,6 @@@ static bool i9xx_plane_get_hw_state(str
        return ret;
  }
  
- static u32
- 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, color_plane);
- }
  static void skl_detach_scaler(struct intel_crtc *intel_crtc, int id)
  {
        struct drm_device *dev = intel_crtc->base.dev;
@@@ -5015,6 -5350,21 +5350,21 @@@ u16 skl_scaler_calc_phase(int sub, int 
        return ((phase >> 2) & PS_PHASE_MASK) | trip;
  }
  
+ #define SKL_MIN_SRC_W 8
+ #define SKL_MAX_SRC_W 4096
+ #define SKL_MIN_SRC_H 8
+ #define SKL_MAX_SRC_H 4096
+ #define SKL_MIN_DST_W 8
+ #define SKL_MAX_DST_W 4096
+ #define SKL_MIN_DST_H 8
+ #define SKL_MAX_DST_H 4096
+ #define ICL_MAX_SRC_W 5120
+ #define ICL_MAX_SRC_H 4096
+ #define ICL_MAX_DST_W 5120
+ #define ICL_MAX_DST_H 4096
+ #define SKL_MIN_YUV_420_SRC_W 16
+ #define SKL_MIN_YUV_420_SRC_H 16
  static int
  skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach,
                  unsigned int scaler_user, int *scaler_id,
@@@ -5294,10 -5644,8 +5644,8 @@@ void hsw_enable_ips(const struct intel_
        WARN_ON(!(crtc_state->active_planes & ~BIT(PLANE_CURSOR)));
  
        if (IS_BROADWELL(dev_priv)) {
-               mutex_lock(&dev_priv->pcu_lock);
                WARN_ON(sandybridge_pcode_write(dev_priv, DISPLAY_IPS_CONTROL,
                                                IPS_ENABLE | IPS_PCODE_CONTROL));
-               mutex_unlock(&dev_priv->pcu_lock);
                /* Quoting Art Runyan: "its not safe to expect any particular
                 * value in IPS_CTL bit 31 after enabling IPS through the
                 * mailbox." Moreover, the mailbox may return a bogus state,
@@@ -5327,9 -5675,7 +5675,7 @@@ void hsw_disable_ips(const struct intel
                return;
  
        if (IS_BROADWELL(dev_priv)) {
-               mutex_lock(&dev_priv->pcu_lock);
                WARN_ON(sandybridge_pcode_write(dev_priv, DISPLAY_IPS_CONTROL, 0));
-               mutex_unlock(&dev_priv->pcu_lock);
                /*
                 * Wait for PCODE to finish disabling IPS. The BSpec specified
                 * 42ms timeout value leads to occasional timeouts so use 100ms
@@@ -5505,6 -5851,16 +5851,16 @@@ static bool needs_nv12_wa(struct drm_i9
        return false;
  }
  
+ static bool needs_scalerclk_wa(struct drm_i915_private *dev_priv,
+                              const struct intel_crtc_state *crtc_state)
+ {
+       /* Wa_2006604312:icl */
+       if (crtc_state->scaler_state.scaler_users > 0 && IS_ICELAKE(dev_priv))
+               return true;
+       return false;
+ }
  static void intel_post_plane_update(struct intel_crtc_state *old_crtc_state)
  {
        struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc);
                        intel_post_enable_primary(&crtc->base, pipe_config);
        }
  
-       /* Display WA 827 */
        if (needs_nv12_wa(dev_priv, old_crtc_state) &&
-           !needs_nv12_wa(dev_priv, pipe_config)) {
+           !needs_nv12_wa(dev_priv, pipe_config))
                skl_wa_827(dev_priv, crtc->pipe, false);
-       }
+       if (needs_scalerclk_wa(dev_priv, old_crtc_state) &&
+           !needs_scalerclk_wa(dev_priv, pipe_config))
+               icl_wa_scalerclkgating(dev_priv, crtc->pipe, false);
  }
  
  static void intel_pre_plane_update(struct intel_crtc_state *old_crtc_state,
  
        /* Display WA 827 */
        if (!needs_nv12_wa(dev_priv, old_crtc_state) &&
-           needs_nv12_wa(dev_priv, pipe_config)) {
+           needs_nv12_wa(dev_priv, pipe_config))
                skl_wa_827(dev_priv, crtc->pipe, true);
-       }
+       /* Wa_2006604312:icl */
+       if (!needs_scalerclk_wa(dev_priv, old_crtc_state) &&
+           needs_scalerclk_wa(dev_priv, pipe_config))
+               icl_wa_scalerclkgating(dev_priv, crtc->pipe, true);
  
        /*
         * Vblank time updates from the shadow to live plane control register
@@@ -5987,7 -6349,8 +6349,8 @@@ static void haswell_crtc_enable(struct 
        if (!transcoder_is_dsi(cpu_transcoder))
                haswell_set_pipeconf(pipe_config);
  
-       haswell_set_pipemisc(pipe_config);
+       if (INTEL_GEN(dev_priv) >= 9 || IS_BROADWELL(dev_priv))
+               bdw_set_pipemisc(pipe_config);
  
        intel_crtc->active = true;
  
@@@ -6289,7 -6652,7 +6652,7 @@@ static u64 get_crtc_power_domains(struc
                mask |= BIT_ULL(POWER_DOMAIN_AUDIO);
  
        if (crtc_state->shared_dpll)
-               mask |= BIT_ULL(POWER_DOMAIN_PLLS);
+               mask |= BIT_ULL(POWER_DOMAIN_DISPLAY_CORE);
  
        return mask;
  }
@@@ -6872,7 -7235,7 +7235,7 @@@ static u32 ilk_pipe_pixel_rate(const st
                if (WARN_ON(!pfit_w || !pfit_h))
                        return pixel_rate;
  
-               pixel_rate = div_u64((u64)pixel_rate * pipe_w * pipe_h,
+               pixel_rate = div_u64(mul_u32_u32(pixel_rate, pipe_w * pipe_h),
                                     pfit_w * pfit_h);
        }
  
@@@ -6992,7 -7355,7 +7355,7 @@@ static void compute_m_n(unsigned int m
        else
                *ret_n = min_t(unsigned int, roundup_pow_of_two(n), DATA_LINK_N_MAX);
  
-       *ret_m = div_u64((u64)m * *ret_n, n);
+       *ret_m = div_u64(mul_u32_u32(m, *ret_n), n);
        intel_reduce_m_n_ratio(ret_m, ret_n);
  }
  
@@@ -7225,7 -7588,7 +7588,7 @@@ static void vlv_prepare_pll(struct inte
        if ((pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE) == 0)
                return;
  
-       mutex_lock(&dev_priv->sb_lock);
+       vlv_dpio_get(dev_priv);
  
        bestn = pipe_config->dpll.n;
        bestm1 = pipe_config->dpll.m1;
        vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW7(pipe), coreclk);
  
        vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW11(pipe), 0x87871000);
-       mutex_unlock(&dev_priv->sb_lock);
+       vlv_dpio_put(dev_priv);
  }
  
  static void chv_prepare_pll(struct intel_crtc *crtc,
        dpio_val = 0;
        loopfilter = 0;
  
-       mutex_lock(&dev_priv->sb_lock);
+       vlv_dpio_get(dev_priv);
  
        /* p1 and p2 divider */
        vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW13(port),
                        vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW14(port)) |
                        DPIO_AFC_RECAL);
  
-       mutex_unlock(&dev_priv->sb_lock);
+       vlv_dpio_put(dev_priv);
  }
  
  /**
@@@ -7675,9 -8039,14 +8039,14 @@@ static void intel_get_pipe_timings(stru
        tmp = I915_READ(HTOTAL(cpu_transcoder));
        pipe_config->base.adjusted_mode.crtc_hdisplay = (tmp & 0xffff) + 1;
        pipe_config->base.adjusted_mode.crtc_htotal = ((tmp >> 16) & 0xffff) + 1;
-       tmp = I915_READ(HBLANK(cpu_transcoder));
-       pipe_config->base.adjusted_mode.crtc_hblank_start = (tmp & 0xffff) + 1;
-       pipe_config->base.adjusted_mode.crtc_hblank_end = ((tmp >> 16) & 0xffff) + 1;
+       if (!transcoder_is_dsi(cpu_transcoder)) {
+               tmp = I915_READ(HBLANK(cpu_transcoder));
+               pipe_config->base.adjusted_mode.crtc_hblank_start =
+                                                       (tmp & 0xffff) + 1;
+               pipe_config->base.adjusted_mode.crtc_hblank_end =
+                                               ((tmp >> 16) & 0xffff) + 1;
+       }
        tmp = I915_READ(HSYNC(cpu_transcoder));
        pipe_config->base.adjusted_mode.crtc_hsync_start = (tmp & 0xffff) + 1;
        pipe_config->base.adjusted_mode.crtc_hsync_end = ((tmp >> 16) & 0xffff) + 1;
        tmp = I915_READ(VTOTAL(cpu_transcoder));
        pipe_config->base.adjusted_mode.crtc_vdisplay = (tmp & 0xffff) + 1;
        pipe_config->base.adjusted_mode.crtc_vtotal = ((tmp >> 16) & 0xffff) + 1;
-       tmp = I915_READ(VBLANK(cpu_transcoder));
-       pipe_config->base.adjusted_mode.crtc_vblank_start = (tmp & 0xffff) + 1;
-       pipe_config->base.adjusted_mode.crtc_vblank_end = ((tmp >> 16) & 0xffff) + 1;
+       if (!transcoder_is_dsi(cpu_transcoder)) {
+               tmp = I915_READ(VBLANK(cpu_transcoder));
+               pipe_config->base.adjusted_mode.crtc_vblank_start =
+                                                       (tmp & 0xffff) + 1;
+               pipe_config->base.adjusted_mode.crtc_vblank_end =
+                                               ((tmp >> 16) & 0xffff) + 1;
+       }
        tmp = I915_READ(VSYNC(cpu_transcoder));
        pipe_config->base.adjusted_mode.crtc_vsync_start = (tmp & 0xffff) + 1;
        pipe_config->base.adjusted_mode.crtc_vsync_end = ((tmp >> 16) & 0xffff) + 1;
@@@ -8033,9 -8407,9 +8407,9 @@@ static void vlv_crtc_clock_get(struct i
        if ((pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE) == 0)
                return;
  
-       mutex_lock(&dev_priv->sb_lock);
+       vlv_dpio_get(dev_priv);
        mdiv = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW3(pipe));
-       mutex_unlock(&dev_priv->sb_lock);
+       vlv_dpio_put(dev_priv);
  
        clock.m1 = (mdiv >> DPIO_M1DIV_SHIFT) & 7;
        clock.m2 = mdiv & DPIO_M2DIV_MASK;
@@@ -8144,13 -8518,13 +8518,13 @@@ static void chv_crtc_clock_get(struct i
        if ((pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE) == 0)
                return;
  
-       mutex_lock(&dev_priv->sb_lock);
+       vlv_dpio_get(dev_priv);
        cmn_dw13 = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW13(port));
        pll_dw0 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW0(port));
        pll_dw1 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW1(port));
        pll_dw2 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW2(port));
        pll_dw3 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW3(port));
-       mutex_unlock(&dev_priv->sb_lock);
+       vlv_dpio_put(dev_priv);
  
        clock.m1 = (pll_dw1 & 0x7) == DPIO_CHV_M1_DIV_BY_2 ? 2 : 0;
        clock.m2 = (pll_dw0 & 0xff) << 22;
@@@ -8650,7 -9024,7 +9024,7 @@@ static void lpt_enable_clkout_dp(struc
  }
  
  /* Sequence to disable CLKOUT_DP */
static void lpt_disable_clkout_dp(struct drm_i915_private *dev_priv)
+ void lpt_disable_clkout_dp(struct drm_i915_private *dev_priv)
  {
        u32 reg, tmp;
  
@@@ -8833,44 -9207,68 +9207,68 @@@ static void haswell_set_pipeconf(const 
        POSTING_READ(PIPECONF(cpu_transcoder));
  }
  
- static void haswell_set_pipemisc(const struct intel_crtc_state *crtc_state)
+ static void bdw_set_pipemisc(const struct intel_crtc_state *crtc_state)
  {
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
-       struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       u32 val = 0;
  
-       if (IS_BROADWELL(dev_priv) || INTEL_GEN(dev_priv) >= 9) {
-               u32 val = 0;
+       switch (crtc_state->pipe_bpp) {
+       case 18:
+               val |= PIPEMISC_DITHER_6_BPC;
+               break;
+       case 24:
+               val |= PIPEMISC_DITHER_8_BPC;
+               break;
+       case 30:
+               val |= PIPEMISC_DITHER_10_BPC;
+               break;
+       case 36:
+               val |= PIPEMISC_DITHER_12_BPC;
+               break;
+       default:
+               MISSING_CASE(crtc_state->pipe_bpp);
+               break;
+       }
  
-               switch (crtc_state->pipe_bpp) {
-               case 18:
-                       val |= PIPEMISC_DITHER_6_BPC;
-                       break;
-               case 24:
-                       val |= PIPEMISC_DITHER_8_BPC;
-                       break;
-               case 30:
-                       val |= PIPEMISC_DITHER_10_BPC;
-                       break;
-               case 36:
-                       val |= PIPEMISC_DITHER_12_BPC;
-                       break;
-               default:
-                       /* Case prevented by pipe_config_set_bpp. */
-                       BUG();
-               }
+       if (crtc_state->dither)
+               val |= PIPEMISC_DITHER_ENABLE | PIPEMISC_DITHER_TYPE_SP;
+       if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420 ||
+           crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444)
+               val |= PIPEMISC_OUTPUT_COLORSPACE_YUV;
  
-               if (crtc_state->dither)
-                       val |= PIPEMISC_DITHER_ENABLE | PIPEMISC_DITHER_TYPE_SP;
+       if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420)
+               val |= PIPEMISC_YUV420_ENABLE |
+                       PIPEMISC_YUV420_MODE_FULL_BLEND;
+       if (INTEL_GEN(dev_priv) >= 11 &&
+           (crtc_state->active_planes & ~(icl_hdr_plane_mask() |
+                                          BIT(PLANE_CURSOR))) == 0)
+               val |= PIPEMISC_HDR_MODE_PRECISION;
  
-               if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420 ||
-                   crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444)
-                       val |= PIPEMISC_OUTPUT_COLORSPACE_YUV;
+       I915_WRITE(PIPEMISC(crtc->pipe), val);
+ }
  
-               if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420)
-                       val |= PIPEMISC_YUV420_ENABLE |
-                               PIPEMISC_YUV420_MODE_FULL_BLEND;
+ int bdw_get_pipemisc_bpp(struct intel_crtc *crtc)
+ {
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       u32 tmp;
  
-               I915_WRITE(PIPEMISC(intel_crtc->pipe), val);
+       tmp = I915_READ(PIPEMISC(crtc->pipe));
+       switch (tmp & PIPEMISC_DITHER_BPC_MASK) {
+       case PIPEMISC_DITHER_6_BPC:
+               return 18;
+       case PIPEMISC_DITHER_8_BPC:
+               return 24;
+       case PIPEMISC_DITHER_10_BPC:
+               return 30;
+       case PIPEMISC_DITHER_12_BPC:
+               return 36;
+       default:
+               MISSING_CASE(tmp);
+               return 0;
        }
  }
  
  
        return ret;
  }
- static void assert_can_disable_lcpll(struct drm_i915_private *dev_priv)
- {
-       struct drm_device *dev = &dev_priv->drm;
-       struct intel_crtc *crtc;
-       for_each_intel_crtc(dev, crtc)
-               I915_STATE_WARN(crtc->active, "CRTC for pipe %c enabled\n",
-                    pipe_name(crtc->pipe));
-       I915_STATE_WARN(I915_READ(HSW_PWR_WELL_CTL2),
-                       "Display power well on\n");
-       I915_STATE_WARN(I915_READ(SPLL_CTL) & SPLL_PLL_ENABLE, "SPLL enabled\n");
-       I915_STATE_WARN(I915_READ(WRPLL_CTL(0)) & WRPLL_PLL_ENABLE, "WRPLL1 enabled\n");
-       I915_STATE_WARN(I915_READ(WRPLL_CTL(1)) & WRPLL_PLL_ENABLE, "WRPLL2 enabled\n");
-       I915_STATE_WARN(I915_READ(PP_STATUS(0)) & PP_ON, "Panel power on\n");
-       I915_STATE_WARN(I915_READ(BLC_PWM_CPU_CTL2) & BLM_PWM_ENABLE,
-            "CPU PWM1 enabled\n");
-       if (IS_HASWELL(dev_priv))
-               I915_STATE_WARN(I915_READ(HSW_BLC_PWM2_CTL) & BLM_PWM_ENABLE,
-                    "CPU PWM2 enabled\n");
-       I915_STATE_WARN(I915_READ(BLC_PWM_PCH_CTL1) & BLM_PCH_PWM_ENABLE,
-            "PCH PWM1 enabled\n");
-       I915_STATE_WARN(I915_READ(UTIL_PIN_CTL) & UTIL_PIN_ENABLE,
-            "Utility pin enabled\n");
-       I915_STATE_WARN(I915_READ(PCH_GTC_CTL) & PCH_GTC_ENABLE, "PCH GTC enabled\n");
-       /*
-        * In theory we can still leave IRQs enabled, as long as only the HPD
-        * interrupts remain enabled. We used to check for that, but since it's
-        * gen-specific and since we only disable LCPLL after we fully disable
-        * the interrupts, the check below should be enough.
-        */
-       I915_STATE_WARN(intel_irqs_enabled(dev_priv), "IRQs enabled\n");
- }
- static u32 hsw_read_dcomp(struct drm_i915_private *dev_priv)
- {
-       if (IS_HASWELL(dev_priv))
-               return I915_READ(D_COMP_HSW);
-       else
-               return I915_READ(D_COMP_BDW);
- }
- static void hsw_write_dcomp(struct drm_i915_private *dev_priv, u32 val)
- {
-       if (IS_HASWELL(dev_priv)) {
-               mutex_lock(&dev_priv->pcu_lock);
-               if (sandybridge_pcode_write(dev_priv, GEN6_PCODE_WRITE_D_COMP,
-                                           val))
-                       DRM_DEBUG_KMS("Failed to write to D_COMP\n");
-               mutex_unlock(&dev_priv->pcu_lock);
-       } else {
-               I915_WRITE(D_COMP_BDW, val);
-               POSTING_READ(D_COMP_BDW);
-       }
- }
- /*
-  * This function implements pieces of two sequences from BSpec:
-  * - Sequence for display software to disable LCPLL
-  * - Sequence for display software to allow package C8+
-  * The steps implemented here are just the steps that actually touch the LCPLL
-  * register. Callers should take care of disabling all the display engine
-  * functions, doing the mode unset, fixing interrupts, etc.
-  */
- static void hsw_disable_lcpll(struct drm_i915_private *dev_priv,
-                             bool switch_to_fclk, bool allow_power_down)
- {
-       u32 val;
-       assert_can_disable_lcpll(dev_priv);
-       val = I915_READ(LCPLL_CTL);
-       if (switch_to_fclk) {
-               val |= LCPLL_CD_SOURCE_FCLK;
-               I915_WRITE(LCPLL_CTL, val);
-               if (wait_for_us(I915_READ(LCPLL_CTL) &
-                               LCPLL_CD_SOURCE_FCLK_DONE, 1))
-                       DRM_ERROR("Switching to FCLK failed\n");
-               val = I915_READ(LCPLL_CTL);
-       }
-       val |= LCPLL_PLL_DISABLE;
-       I915_WRITE(LCPLL_CTL, val);
-       POSTING_READ(LCPLL_CTL);
-       if (intel_wait_for_register(&dev_priv->uncore,
-                                   LCPLL_CTL, LCPLL_PLL_LOCK, 0, 1))
-               DRM_ERROR("LCPLL still locked\n");
-       val = hsw_read_dcomp(dev_priv);
-       val |= D_COMP_COMP_DISABLE;
-       hsw_write_dcomp(dev_priv, val);
-       ndelay(100);
-       if (wait_for((hsw_read_dcomp(dev_priv) & D_COMP_RCOMP_IN_PROGRESS) == 0,
-                    1))
-               DRM_ERROR("D_COMP RCOMP still in progress\n");
-       if (allow_power_down) {
-               val = I915_READ(LCPLL_CTL);
-               val |= LCPLL_POWER_DOWN_ALLOW;
-               I915_WRITE(LCPLL_CTL, val);
-               POSTING_READ(LCPLL_CTL);
-       }
- }
- /*
-  * Fully restores LCPLL, disallowing power down and switching back to LCPLL
-  * source.
-  */
- static void hsw_restore_lcpll(struct drm_i915_private *dev_priv)
- {
-       u32 val;
-       val = I915_READ(LCPLL_CTL);
-       if ((val & (LCPLL_PLL_LOCK | LCPLL_PLL_DISABLE | LCPLL_CD_SOURCE_FCLK |
-                   LCPLL_POWER_DOWN_ALLOW)) == LCPLL_PLL_LOCK)
-               return;
-       /*
-        * Make sure we're not on PC8 state before disabling PC8, otherwise
-        * we'll hang the machine. To prevent PC8 state, just enable force_wake.
-        */
-       intel_uncore_forcewake_get(&dev_priv->uncore, FORCEWAKE_ALL);
-       if (val & LCPLL_POWER_DOWN_ALLOW) {
-               val &= ~LCPLL_POWER_DOWN_ALLOW;
-               I915_WRITE(LCPLL_CTL, val);
-               POSTING_READ(LCPLL_CTL);
-       }
-       val = hsw_read_dcomp(dev_priv);
-       val |= D_COMP_COMP_FORCE;
-       val &= ~D_COMP_COMP_DISABLE;
-       hsw_write_dcomp(dev_priv, val);
-       val = I915_READ(LCPLL_CTL);
-       val &= ~LCPLL_PLL_DISABLE;
-       I915_WRITE(LCPLL_CTL, val);
-       if (intel_wait_for_register(&dev_priv->uncore,
-                                   LCPLL_CTL, LCPLL_PLL_LOCK, LCPLL_PLL_LOCK,
-                                   5))
-               DRM_ERROR("LCPLL not locked yet\n");
-       if (val & LCPLL_CD_SOURCE_FCLK) {
-               val = I915_READ(LCPLL_CTL);
-               val &= ~LCPLL_CD_SOURCE_FCLK;
-               I915_WRITE(LCPLL_CTL, val);
-               if (wait_for_us((I915_READ(LCPLL_CTL) &
-                                LCPLL_CD_SOURCE_FCLK_DONE) == 0, 1))
-                       DRM_ERROR("Switching back to LCPLL failed\n");
-       }
-       intel_uncore_forcewake_put(&dev_priv->uncore, FORCEWAKE_ALL);
-       intel_update_cdclk(dev_priv);
-       intel_dump_cdclk_state(&dev_priv->cdclk.hw, "Current CDCLK");
- }
- /*
-  * Package states C8 and deeper are really deep PC states that can only be
-  * reached when all the devices on the system allow it, so even if the graphics
-  * device allows PC8+, it doesn't mean the system will actually get to these
-  * states. Our driver only allows PC8+ when going into runtime PM.
-  *
-  * The requirements for PC8+ are that all the outputs are disabled, the power
-  * well is disabled and most interrupts are disabled, and these are also
-  * requirements for runtime PM. When these conditions are met, we manually do
-  * the other conditions: disable the interrupts, clocks and switch LCPLL refclk
-  * to Fclk. If we're in PC8+ and we get an non-hotplug interrupt, we can hard
-  * hang the machine.
-  *
-  * When we really reach PC8 or deeper states (not just when we allow it) we lose
-  * the state of some registers, so when we come back from PC8+ we need to
-  * restore this state. We don't get into PC8+ if we're not in RC6, so we don't
-  * need to take care of the registers kept by RC6. Notice that this happens even
-  * if we don't put the device in PCI D3 state (which is what currently happens
-  * because of the runtime PM support).
-  *
-  * For more, read "Display Sequences for Package C8" on the hardware
-  * documentation.
-  */
- void hsw_enable_pc8(struct drm_i915_private *dev_priv)
- {
-       u32 val;
-       DRM_DEBUG_KMS("Enabling package C8+\n");
-       if (HAS_PCH_LPT_LP(dev_priv)) {
-               val = I915_READ(SOUTH_DSPCLK_GATE_D);
-               val &= ~PCH_LP_PARTITION_LEVEL_DISABLE;
-               I915_WRITE(SOUTH_DSPCLK_GATE_D, val);
-       }
-       lpt_disable_clkout_dp(dev_priv);
-       hsw_disable_lcpll(dev_priv, true, true);
- }
- void hsw_disable_pc8(struct drm_i915_private *dev_priv)
- {
-       u32 val;
-       DRM_DEBUG_KMS("Disabling package C8+\n");
-       hsw_restore_lcpll(dev_priv);
-       lpt_init_pch_refclk(dev_priv);
-       if (HAS_PCH_LPT_LP(dev_priv)) {
-               val = I915_READ(SOUTH_DSPCLK_GATE_D);
-               val |= PCH_LP_PARTITION_LEVEL_DISABLE;
-               I915_WRITE(SOUTH_DSPCLK_GATE_D, val);
-       }
- }
  static int haswell_crtc_compute_clock(struct intel_crtc *crtc,
                                      struct intel_crtc_state *crtc_state)
  {
@@@ -9797,6 -9973,7 +9973,7 @@@ static bool hsw_get_transcoder_state(st
        for_each_set_bit(panel_transcoder,
                         &panel_transcoder_mask,
                         ARRAY_SIZE(INTEL_INFO(dev_priv)->trans_offsets)) {
+               bool force_thru = false;
                enum pipe trans_pipe;
  
                tmp = I915_READ(TRANS_DDI_FUNC_CTL(panel_transcoder));
                             transcoder_name(panel_transcoder));
                        /* fall through */
                case TRANS_DDI_EDP_INPUT_A_ONOFF:
+                       force_thru = true;
+                       /* fall through */
                case TRANS_DDI_EDP_INPUT_A_ON:
                        trans_pipe = PIPE_A;
                        break;
                        break;
                }
  
-               if (trans_pipe == crtc->pipe)
+               if (trans_pipe == crtc->pipe) {
                        pipe_config->cpu_transcoder = panel_transcoder;
+                       pipe_config->pch_pfit.force_thru = force_thru;
+               }
        }
  
        /*
@@@ -10115,19 -10296,17 +10296,17 @@@ static bool intel_cursor_size_ok(const 
  
  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;
  
-       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);
+       ret = intel_plane_compute_gtt(plane_state);
        if (ret)
                return ret;
  
+       if (!plane_state->base.visible)
+               return 0;
        src_x = plane_state->base.src_x >> 16;
        src_y = plane_state->base.src_y >> 16;
  
@@@ -10164,6 -10343,10 +10343,10 @@@ static int intel_check_cursor(struct in
        if (ret)
                return ret;
  
+       ret = intel_cursor_check_surface(plane_state);
+       if (ret)
+               return ret;
        if (!plane_state->base.visible)
                return 0;
  
        if (ret)
                return ret;
  
-       ret = intel_cursor_check_surface(plane_state);
-       if (ret)
-               return ret;
        return 0;
  }
  
@@@ -11665,10 -11844,11 +11844,11 @@@ static void intel_dump_pipe_config(stru
                              pipe_config->gmch_pfit.pgm_ratios,
                              pipe_config->gmch_pfit.lvds_border_bits);
        else
-               DRM_DEBUG_KMS("pch pfit: pos: 0x%08x, size: 0x%08x, %s\n",
+               DRM_DEBUG_KMS("pch pfit: pos: 0x%08x, size: 0x%08x, %s, force thru: %s\n",
                              pipe_config->pch_pfit.pos,
                              pipe_config->pch_pfit.size,
-                             enableddisabled(pipe_config->pch_pfit.enabled));
+                             enableddisabled(pipe_config->pch_pfit.enabled),
+                             yesno(pipe_config->pch_pfit.force_thru));
  
        DRM_DEBUG_KMS("ips: %i, double wide: %i\n",
                      pipe_config->ips_enabled, pipe_config->double_wide);
@@@ -11790,7 -11970,6 +11970,6 @@@ clear_intel_crtc_state(struct intel_crt
        saved_state->scaler_state = crtc_state->scaler_state;
        saved_state->shared_dpll = crtc_state->shared_dpll;
        saved_state->dpll_hw_state = crtc_state->dpll_hw_state;
-       saved_state->pch_pfit.force_thru = crtc_state->pch_pfit.force_thru;
        saved_state->crc_enabled = crtc_state->crc_enabled;
        if (IS_G4X(dev_priv) ||
            IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
@@@ -12082,7 -12261,6 +12261,6 @@@ intel_pipe_config_compare(struct drm_i9
                          struct intel_crtc_state *pipe_config,
                          bool adjust)
  {
-       struct intel_crtc *crtc = to_intel_crtc(current_config->base.crtc);
        bool ret = true;
        bool fixup_inherited = adjust &&
                (current_config->base.mode.private_flags & I915_MODE_FLAG_INHERITED) &&
         * Changing the EDP transcoder input mux
         * (A_ONOFF vs. A_ON) requires a full modeset.
         */
-       if (IS_HASWELL(dev_priv) && crtc->pipe == PIPE_A &&
-           current_config->cpu_transcoder == TRANSCODER_EDP)
-               PIPE_CONF_CHECK_BOOL(pch_pfit.enabled);
+       PIPE_CONF_CHECK_BOOL(pch_pfit.force_thru);
  
        if (!adjust) {
                PIPE_CONF_CHECK_I(pipe_src_w);
@@@ -14105,6 -14281,9 +14281,9 @@@ static void intel_begin_crtc_commit(str
        else if (INTEL_GEN(dev_priv) >= 9)
                skl_detach_scalers(new_crtc_state);
  
+       if (INTEL_GEN(dev_priv) >= 9 || IS_BROADWELL(dev_priv))
+               bdw_set_pipemisc(new_crtc_state);
  out:
        if (dev_priv->display.atomic_update_watermarks)
                dev_priv->display.atomic_update_watermarks(state,
@@@ -14605,8 -14784,9 +14784,8 @@@ static int intel_crtc_init(struct drm_i
                ret = -ENOMEM;
                goto fail;
        }
 +      __drm_atomic_helper_crtc_reset(&intel_crtc->base, &crtc_state->base);
        intel_crtc->config = crtc_state;
 -      intel_crtc->base.state = &crtc_state->base;
 -      crtc_state->base.crtc = &intel_crtc->base;
  
        primary = intel_primary_plane_create(dev_priv, pipe);
        if (IS_ERR(primary)) {
@@@ -15059,31 -15239,13 +15238,13 @@@ static const struct drm_framebuffer_fun
        .dirty = intel_user_framebuffer_dirty,
  };
  
- static
- u32 intel_fb_pitch_limit(struct drm_i915_private *dev_priv,
-                        u32 pixel_format, u64 fb_modifier)
- {
-       struct intel_crtc *crtc;
-       struct intel_plane *plane;
-       /*
-        * 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);
-       return plane->max_stride(plane, pixel_format, fb_modifier,
-                                DRM_MODE_ROTATE_0);
- }
  static int intel_framebuffer_init(struct intel_framebuffer *intel_fb,
                                  struct drm_i915_gem_object *obj,
                                  struct drm_mode_fb_cmd2 *mode_cmd)
  {
        struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
        struct drm_framebuffer *fb = &intel_fb->base;
-       u32 pitch_limit;
+       u32 max_stride;
        unsigned int tiling, stride;
        int ret = -EINVAL;
        int i;
                goto err;
        }
  
-       pitch_limit = intel_fb_pitch_limit(dev_priv, mode_cmd->pixel_format,
-                                          mode_cmd->modifier[0]);
-       if (mode_cmd->pitches[0] > pitch_limit) {
+       max_stride = intel_fb_max_stride(dev_priv, mode_cmd->pixel_format,
+                                        mode_cmd->modifier[0]);
+       if (mode_cmd->pitches[0] > max_stride) {
                DRM_DEBUG_KMS("%s pitch (%u) must be at most %d\n",
                              mode_cmd->modifier[0] != DRM_FORMAT_MOD_LINEAR ?
                              "tiled" : "linear",
-                             mode_cmd->pitches[0], pitch_limit);
+                             mode_cmd->pitches[0], max_stride);
                goto err;
        }
  
@@@ -15418,6 -15580,16 +15579,16 @@@ void intel_init_display_hooks(struct dr
                dev_priv->display.update_crtcs = intel_update_crtcs;
  }
  
+ static i915_reg_t i915_vgacntrl_reg(struct drm_i915_private *dev_priv)
+ {
+       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
+               return VLV_VGACNTRL;
+       else if (INTEL_GEN(dev_priv) >= 5)
+               return CPU_VGACNTRL;
+       else
+               return VGACNTRL;
+ }
  /* Disable the VGA plane that we never use */
  static void i915_disable_vga(struct drm_i915_private *dev_priv)
  {
@@@ -15655,16 -15827,22 +15826,22 @@@ int intel_modeset_init(struct drm_devic
                }
        }
  
-       /* maximum framebuffer dimensions */
-       if (IS_GEN(dev_priv, 2)) {
-               dev->mode_config.max_width = 2048;
-               dev->mode_config.max_height = 2048;
+       /*
+        * Maximum framebuffer dimensions, chosen to match
+        * the maximum render engine surface size on gen4+.
+        */
+       if (INTEL_GEN(dev_priv) >= 7) {
+               dev->mode_config.max_width = 16384;
+               dev->mode_config.max_height = 16384;
+       } else if (INTEL_GEN(dev_priv) >= 4) {
+               dev->mode_config.max_width = 8192;
+               dev->mode_config.max_height = 8192;
        } else if (IS_GEN(dev_priv, 3)) {
                dev->mode_config.max_width = 4096;
                dev->mode_config.max_height = 4096;
        } else {
-               dev->mode_config.max_width = 8192;
-               dev->mode_config.max_height = 8192;
+               dev->mode_config.max_width = 2048;
+               dev->mode_config.max_height = 2048;
        }
  
        if (IS_I845G(dev_priv) || IS_I865G(dev_priv)) {
@@@ -16148,7 -16326,7 +16325,7 @@@ static void intel_modeset_readout_hw_st
  
                __drm_atomic_helper_crtc_destroy_state(&crtc_state->base);
                memset(crtc_state, 0, sizeof(*crtc_state));
 -              crtc_state->base.crtc = &crtc->base;
 +              __drm_atomic_helper_crtc_reset(&crtc->base, &crtc_state->base);
  
                crtc_state->base.active = crtc_state->base.enable =
                        dev_priv->display.get_pipe_config(crtc, crtc_state);
@@@ -16563,7 -16741,7 +16740,7 @@@ void intel_modeset_cleanup(struct drm_d
  
        intel_overlay_cleanup(dev_priv);
  
-       intel_teardown_gmbus(dev_priv);
+       intel_gmbus_teardown(dev_priv);
  
        destroy_workqueue(dev_priv->modeset_wq);
  
  #include <drm/i915_drm.h>
  #include <drm/intel_lpe_audio.h>
  
+ #include "i915_debugfs.h"
  #include "i915_drv.h"
+ #include "intel_atomic.h"
  #include "intel_audio.h"
  #include "intel_connector.h"
  #include "intel_ddi.h"
  #include "intel_dp.h"
+ #include "intel_dpio_phy.h"
  #include "intel_drv.h"
+ #include "intel_fifo_underrun.h"
+ #include "intel_gmbus.h"
  #include "intel_hdcp.h"
  #include "intel_hdmi.h"
+ #include "intel_hotplug.h"
  #include "intel_lspcon.h"
  #include "intel_sdvo.h"
  #include "intel_panel.h"
+ #include "intel_sideband.h"
  
  static struct drm_device *intel_hdmi_to_dev(struct intel_hdmi *intel_hdmi)
  {
@@@ -207,6 -214,7 +214,6 @@@ static void g4x_write_infoframe(struct 
  
        I915_WRITE(VIDEO_DIP_CTL, val);
  
 -      mmiowb();
        for (i = 0; i < len; i += 4) {
                I915_WRITE(VIDEO_DIP_DATA, *data);
                data++;
        /* Write every possible data byte to force correct ECC calculation. */
        for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
                I915_WRITE(VIDEO_DIP_DATA, 0);
 -      mmiowb();
  
        val |= g4x_infoframe_enable(type);
        val &= ~VIDEO_DIP_FREQ_MASK;
@@@ -280,6 -289,7 +287,6 @@@ static void ibx_write_infoframe(struct 
  
        I915_WRITE(reg, val);
  
 -      mmiowb();
        for (i = 0; i < len; i += 4) {
                I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
                data++;
        /* Write every possible data byte to force correct ECC calculation. */
        for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
                I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), 0);
 -      mmiowb();
  
        val |= g4x_infoframe_enable(type);
        val &= ~VIDEO_DIP_FREQ_MASK;
@@@ -360,6 -371,7 +367,6 @@@ static void cpt_write_infoframe(struct 
  
        I915_WRITE(reg, val);
  
 -      mmiowb();
        for (i = 0; i < len; i += 4) {
                I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
                data++;
        /* Write every possible data byte to force correct ECC calculation. */
        for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
                I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), 0);
 -      mmiowb();
  
        val |= g4x_infoframe_enable(type);
        val &= ~VIDEO_DIP_FREQ_MASK;
@@@ -433,6 -446,7 +440,6 @@@ static void vlv_write_infoframe(struct 
  
        I915_WRITE(reg, val);
  
 -      mmiowb();
        for (i = 0; i < len; i += 4) {
                I915_WRITE(VLV_TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
                data++;
        /* Write every possible data byte to force correct ECC calculation. */
        for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
                I915_WRITE(VLV_TVIDEO_DIP_DATA(intel_crtc->pipe), 0);
 -      mmiowb();
  
        val |= g4x_infoframe_enable(type);
        val &= ~VIDEO_DIP_FREQ_MASK;
@@@ -506,6 -521,7 +513,6 @@@ static void hsw_write_infoframe(struct 
        val &= ~hsw_infoframe_enable(type);
        I915_WRITE(ctl_reg, val);
  
 -      mmiowb();
        for (i = 0; i < len; i += 4) {
                I915_WRITE(hsw_dip_data_reg(dev_priv, cpu_transcoder,
                                            type, i >> 2), *data);
        for (; i < data_size; i += 4)
                I915_WRITE(hsw_dip_data_reg(dev_priv, cpu_transcoder,
                                            type, i >> 2), 0);
 -      mmiowb();
  
        val |= hsw_infoframe_enable(type);
        I915_WRITE(ctl_reg, val);
@@@ -846,19 -863,6 +853,6 @@@ static void g4x_set_infoframes(struct i
                              &crtc_state->infoframes.hdmi);
  }
  
- static bool hdmi_sink_is_deep_color(const struct drm_connector_state *conn_state)
- {
-       struct drm_connector *connector = conn_state->connector;
-       /*
-        * HDMI cloning is only supported on g4x which doesn't
-        * support deep color or GCP infoframes anyway so no
-        * need to worry about multiple HDMI sinks here.
-        */
-       return connector->display_info.bpc > 8;
- }
  /*
   * Determine if default_phase=1 can be indicated in the GCP infoframe.
   *
@@@ -963,8 -967,8 +957,8 @@@ static void intel_hdmi_compute_gcp_info
        crtc_state->infoframes.enable |=
                intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_GENERAL_CONTROL);
  
-       /* Indicate color depth whenever the sink supports deep color */
-       if (hdmi_sink_is_deep_color(conn_state))
+       /* Indicate color indication for deep color mode */
+       if (crtc_state->pipe_bpp > 24)
                crtc_state->infoframes.gcp |= GCP_COLOR_INDICATION;
  
        /* Enable default_phase whenever the display mode is suitably aligned */
@@@ -2162,7 -2166,7 +2156,7 @@@ static bool hdmi_deep_color_possible(co
        if (bpc == 10 && INTEL_GEN(dev_priv) < 11)
                return false;
  
-       if (crtc_state->pipe_bpp <= 8*3)
+       if (crtc_state->pipe_bpp < bpc * 3)
                return false;
  
        if (!crtc_state->has_hdmi_sink)
@@@ -2620,12 -2624,12 +2614,12 @@@ static void chv_hdmi_post_disable(struc
        struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
  
-       mutex_lock(&dev_priv->sb_lock);
+       vlv_dpio_get(dev_priv);
  
        /* Assert data lane reset */
        chv_data_lane_soft_reset(encoder, old_crtc_state, true);
  
-       mutex_unlock(&dev_priv->sb_lock);
+       vlv_dpio_put(dev_priv);
  }
  
  static void chv_hdmi_pre_enable(struct intel_encoder *encoder,
  #include <drm/drm_print.h>
  
  #include "i915_drv.h"
+ #include "i915_irq.h"
  #include "intel_cdclk.h"
+ #include "intel_combo_phy.h"
  #include "intel_crt.h"
  #include "intel_csr.h"
  #include "intel_dp.h"
+ #include "intel_dpio_phy.h"
  #include "intel_drv.h"
+ #include "intel_hotplug.h"
+ #include "intel_sideband.h"
  
  /**
   * DOC: runtime pm
   * present for a given platform.
   */
  
+ static intel_wakeref_t intel_runtime_pm_get_raw(struct drm_i915_private *i915);
+ static void
+ __intel_runtime_pm_put(struct drm_i915_private *i915, intel_wakeref_t wref,
+                      bool wakelock);
+ #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM)
+ static void
+ intel_runtime_pm_put_raw(struct drm_i915_private *i915, intel_wakeref_t wref);
+ #else
+ static inline void intel_runtime_pm_put_raw(struct drm_i915_private *i915,
+                                           intel_wakeref_t wref)
+ {
+       __intel_runtime_pm_put(i915, -1, false);
+ }
+ #endif
  #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM)
  
  #include <linux/sort.h>
  static noinline depot_stack_handle_t __save_depot_stack(void)
  {
        unsigned long entries[STACKDEPTH];
 -      struct stack_trace trace = {
 -              .entries = entries,
 -              .max_entries = ARRAY_SIZE(entries),
 -              .skip = 1,
 -      };
 +      unsigned int n;
  
 -      save_stack_trace(&trace);
 -      if (trace.nr_entries &&
 -          trace.entries[trace.nr_entries - 1] == ULONG_MAX)
 -              trace.nr_entries--;
 -
 -      return depot_save_stack(&trace, GFP_NOWAIT | __GFP_NOWARN);
 +      n = stack_trace_save(entries, ARRAY_SIZE(entries), 1);
 +      return stack_depot_save(entries, n, GFP_NOWAIT | __GFP_NOWARN);
  }
  
  static void __print_depot_stack(depot_stack_handle_t stack,
                                char *buf, int sz, int indent)
  {
 -      unsigned long entries[STACKDEPTH];
 -      struct stack_trace trace = {
 -              .entries = entries,
 -              .max_entries = ARRAY_SIZE(entries),
 -      };
 +      unsigned long *entries;
 +      unsigned int nr_entries;
  
 -      depot_fetch_stack(stack, &trace);
 -      snprint_stack_trace(buf, sz, &trace, indent);
 +      nr_entries = stack_depot_fetch(stack, &entries);
 +      stack_trace_snprint(buf, sz, entries, nr_entries, indent);
  }
  
  static void init_intel_runtime_pm_wakeref(struct drm_i915_private *i915)
@@@ -94,9 -126,6 +115,6 @@@ track_intel_runtime_pm_wakeref(struct d
        depot_stack_handle_t stack, *stacks;
        unsigned long flags;
  
-       atomic_inc(&rpm->wakeref_count);
-       assert_rpm_wakelock_held(i915);
        if (!HAS_RUNTIME_PM(i915))
                return -1;
  
        return stack;
  }
  
- static void cancel_intel_runtime_pm_wakeref(struct drm_i915_private *i915,
-                                           depot_stack_handle_t stack)
+ static void untrack_intel_runtime_pm_wakeref(struct drm_i915_private *i915,
+                                            depot_stack_handle_t stack)
  {
        struct i915_runtime_pm *rpm = &i915->runtime_pm;
        unsigned long flags, n;
@@@ -220,32 -249,60 +238,60 @@@ __print_intel_runtime_pm_wakeref(struc
  }
  
  static noinline void
- untrack_intel_runtime_pm_wakeref(struct drm_i915_private *i915)
+ __untrack_all_wakerefs(struct intel_runtime_pm_debug *debug,
+                      struct intel_runtime_pm_debug *saved)
+ {
+       *saved = *debug;
+       debug->owners = NULL;
+       debug->count = 0;
+       debug->last_release = __save_depot_stack();
+ }
+ static void
+ dump_and_free_wakeref_tracking(struct intel_runtime_pm_debug *debug)
+ {
+       struct drm_printer p;
+       if (!debug->count)
+               return;
+       p = drm_debug_printer("i915");
+       __print_intel_runtime_pm_wakeref(&p, debug);
+       kfree(debug->owners);
+ }
+ static noinline void
+ __intel_wakeref_dec_and_check_tracking(struct drm_i915_private *i915)
  {
        struct i915_runtime_pm *rpm = &i915->runtime_pm;
        struct intel_runtime_pm_debug dbg = {};
-       struct drm_printer p;
        unsigned long flags;
  
-       assert_rpm_wakelock_held(i915);
-       if (atomic_dec_and_lock_irqsave(&rpm->wakeref_count,
-                                       &rpm->debug.lock,
-                                       flags)) {
-               dbg = rpm->debug;
+       if (!atomic_dec_and_lock_irqsave(&rpm->wakeref_count,
+                                        &rpm->debug.lock,
+                                        flags))
+               return;
  
-               rpm->debug.owners = NULL;
-               rpm->debug.count = 0;
-               rpm->debug.last_release = __save_depot_stack();
+       __untrack_all_wakerefs(&rpm->debug, &dbg);
+       spin_unlock_irqrestore(&rpm->debug.lock, flags);
  
-               spin_unlock_irqrestore(&rpm->debug.lock, flags);
-       }
-       if (!dbg.count)
-               return;
+       dump_and_free_wakeref_tracking(&dbg);
+ }
  
-       p = drm_debug_printer("i915");
-       __print_intel_runtime_pm_wakeref(&p, &dbg);
+ static noinline void
+ untrack_all_intel_runtime_pm_wakerefs(struct drm_i915_private *i915)
+ {
+       struct i915_runtime_pm *rpm = &i915->runtime_pm;
+       struct intel_runtime_pm_debug dbg = {};
+       unsigned long flags;
  
-       kfree(dbg.owners);
+       spin_lock_irqsave(&rpm->debug.lock, flags);
+       __untrack_all_wakerefs(&rpm->debug, &dbg);
+       spin_unlock_irqrestore(&rpm->debug.lock, flags);
+       dump_and_free_wakeref_tracking(&dbg);
  }
  
  void print_intel_runtime_pm_wakeref(struct drm_i915_private *i915,
@@@ -295,19 -352,56 +341,56 @@@ static void init_intel_runtime_pm_waker
  static depot_stack_handle_t
  track_intel_runtime_pm_wakeref(struct drm_i915_private *i915)
  {
-       atomic_inc(&i915->runtime_pm.wakeref_count);
-       assert_rpm_wakelock_held(i915);
        return -1;
  }
  
- static void untrack_intel_runtime_pm_wakeref(struct drm_i915_private *i915)
+ static void untrack_intel_runtime_pm_wakeref(struct drm_i915_private *i915,
+                                            intel_wakeref_t wref)
+ {
+ }
+ static void
+ __intel_wakeref_dec_and_check_tracking(struct drm_i915_private *i915)
  {
-       assert_rpm_wakelock_held(i915);
        atomic_dec(&i915->runtime_pm.wakeref_count);
  }
  
+ static void
+ untrack_all_intel_runtime_pm_wakerefs(struct drm_i915_private *i915)
+ {
+ }
  #endif
  
+ static void
+ intel_runtime_pm_acquire(struct drm_i915_private *i915, bool wakelock)
+ {
+       struct i915_runtime_pm *rpm = &i915->runtime_pm;
+       if (wakelock) {
+               atomic_add(1 + INTEL_RPM_WAKELOCK_BIAS, &rpm->wakeref_count);
+               assert_rpm_wakelock_held(i915);
+       } else {
+               atomic_inc(&rpm->wakeref_count);
+               assert_rpm_raw_wakeref_held(i915);
+       }
+ }
+ static void
+ intel_runtime_pm_release(struct drm_i915_private *i915, int wakelock)
+ {
+       struct i915_runtime_pm *rpm = &i915->runtime_pm;
+       if (wakelock) {
+               assert_rpm_wakelock_held(i915);
+               atomic_sub(INTEL_RPM_WAKELOCK_BIAS, &rpm->wakeref_count);
+       } else {
+               assert_rpm_raw_wakeref_held(i915);
+       }
+       __intel_wakeref_dec_and_check_tracking(i915);
+ }
  bool intel_display_power_well_is_enabled(struct drm_i915_private *dev_priv,
                                         enum i915_power_well_id power_well_id);
  
@@@ -315,6 -409,8 +398,8 @@@ const char 
  intel_display_power_domain_str(enum intel_display_power_domain domain)
  {
        switch (domain) {
+       case POWER_DOMAIN_DISPLAY_CORE:
+               return "DISPLAY_CORE";
        case POWER_DOMAIN_PIPE_A:
                return "PIPE_A";
        case POWER_DOMAIN_PIPE_B:
                return "VGA";
        case POWER_DOMAIN_AUDIO:
                return "AUDIO";
-       case POWER_DOMAIN_PLLS:
-               return "PLLS";
        case POWER_DOMAIN_AUX_A:
                return "AUX_A";
        case POWER_DOMAIN_AUX_B:
@@@ -1125,7 -1219,7 +1208,7 @@@ static void gen9_dc_off_power_well_enab
                 * PHY's HW context for port B is lost after DC transitions,
                 * so we need to restore it manually.
                 */
-               icl_combo_phys_init(dev_priv);
+               intel_combo_phy_init(dev_priv);
  }
  
  static void gen9_dc_off_power_well_disable(struct drm_i915_private *dev_priv,
@@@ -1200,7 -1294,7 +1283,7 @@@ static void vlv_set_power_well(struct d
        state = enable ? PUNIT_PWRGT_PWR_ON(pw_idx) :
                         PUNIT_PWRGT_PWR_GATE(pw_idx);
  
-       mutex_lock(&dev_priv->pcu_lock);
+       vlv_punit_get(dev_priv);
  
  #define COND \
        ((vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_STATUS) & mask) == state)
  #undef COND
  
  out:
-       mutex_unlock(&dev_priv->pcu_lock);
+       vlv_punit_put(dev_priv);
  }
  
  static void vlv_power_well_enable(struct drm_i915_private *dev_priv,
@@@ -1248,7 -1342,7 +1331,7 @@@ static bool vlv_power_well_enabled(stru
        mask = PUNIT_PWRGT_MASK(pw_idx);
        ctrl = PUNIT_PWRGT_PWR_ON(pw_idx);
  
-       mutex_lock(&dev_priv->pcu_lock);
+       vlv_punit_get(dev_priv);
  
        state = vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_STATUS) & mask;
        /*
        ctrl = vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_CTRL) & mask;
        WARN_ON(ctrl != state);
  
-       mutex_unlock(&dev_priv->pcu_lock);
+       vlv_punit_put(dev_priv);
  
        return enabled;
  }
@@@ -1558,7 -1652,7 +1641,7 @@@ static void chv_dpio_cmn_power_well_ena
                                    1))
                DRM_ERROR("Display PHY %d is not power up\n", phy);
  
-       mutex_lock(&dev_priv->sb_lock);
+       vlv_dpio_get(dev_priv);
  
        /* Enable dynamic power down */
        tmp = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW28);
                vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW30, tmp);
        }
  
-       mutex_unlock(&dev_priv->sb_lock);
+       vlv_dpio_put(dev_priv);
  
        dev_priv->chv_phy_control |= PHY_COM_LANE_RESET_DEASSERT(phy);
        I915_WRITE(DISPLAY_PHY_CONTROL, dev_priv->chv_phy_control);
@@@ -1644,9 -1738,9 +1727,9 @@@ static void assert_chv_phy_powergate(st
        else
                reg = _CHV_CMN_DW6_CH1;
  
-       mutex_lock(&dev_priv->sb_lock);
+       vlv_dpio_get(dev_priv);
        val = vlv_dpio_read(dev_priv, pipe, reg);
-       mutex_unlock(&dev_priv->sb_lock);
+       vlv_dpio_put(dev_priv);
  
        /*
         * This assumes !override is only used when the port is disabled.
@@@ -1753,7 -1847,7 +1836,7 @@@ static bool chv_pipe_power_well_enabled
        bool enabled;
        u32 state, ctrl;
  
-       mutex_lock(&dev_priv->pcu_lock);
+       vlv_punit_get(dev_priv);
  
        state = vlv_punit_read(dev_priv, PUNIT_REG_DSPSSPM) & DP_SSS_MASK(pipe);
        /*
        ctrl = vlv_punit_read(dev_priv, PUNIT_REG_DSPSSPM) & DP_SSC_MASK(pipe);
        WARN_ON(ctrl << 16 != state);
  
-       mutex_unlock(&dev_priv->pcu_lock);
+       vlv_punit_put(dev_priv);
  
        return enabled;
  }
@@@ -1785,7 -1879,7 +1868,7 @@@ static void chv_set_pipe_power_well(str
  
        state = enable ? DP_SSS_PWR_ON(pipe) : DP_SSS_PWR_GATE(pipe);
  
-       mutex_lock(&dev_priv->pcu_lock);
+       vlv_punit_get(dev_priv);
  
  #define COND \
        ((vlv_punit_read(dev_priv, PUNIT_REG_DSPSSPM) & DP_SSS_MASK(pipe)) == state)
  #undef COND
  
  out:
-       mutex_unlock(&dev_priv->pcu_lock);
+       vlv_punit_put(dev_priv);
  }
  
  static void chv_pipe_power_well_enable(struct drm_i915_private *dev_priv,
@@@ -1825,6 -1919,125 +1908,125 @@@ static void chv_pipe_power_well_disable
        chv_set_pipe_power_well(dev_priv, power_well, false);
  }
  
+ static u64 __async_put_domains_mask(struct i915_power_domains *power_domains)
+ {
+       return power_domains->async_put_domains[0] |
+              power_domains->async_put_domains[1];
+ }
+ #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM)
+ static bool
+ assert_async_put_domain_masks_disjoint(struct i915_power_domains *power_domains)
+ {
+       return !WARN_ON(power_domains->async_put_domains[0] &
+                       power_domains->async_put_domains[1]);
+ }
+ static bool
+ __async_put_domains_state_ok(struct i915_power_domains *power_domains)
+ {
+       enum intel_display_power_domain domain;
+       bool err = false;
+       err |= !assert_async_put_domain_masks_disjoint(power_domains);
+       err |= WARN_ON(!!power_domains->async_put_wakeref !=
+                      !!__async_put_domains_mask(power_domains));
+       for_each_power_domain(domain, __async_put_domains_mask(power_domains))
+               err |= WARN_ON(power_domains->domain_use_count[domain] != 1);
+       return !err;
+ }
+ static void print_power_domains(struct i915_power_domains *power_domains,
+                               const char *prefix, u64 mask)
+ {
+       enum intel_display_power_domain domain;
+       DRM_DEBUG_DRIVER("%s (%lu):\n", prefix, hweight64(mask));
+       for_each_power_domain(domain, mask)
+               DRM_DEBUG_DRIVER("%s use_count %d\n",
+                                intel_display_power_domain_str(domain),
+                                power_domains->domain_use_count[domain]);
+ }
+ static void
+ print_async_put_domains_state(struct i915_power_domains *power_domains)
+ {
+       DRM_DEBUG_DRIVER("async_put_wakeref %u\n",
+                        power_domains->async_put_wakeref);
+       print_power_domains(power_domains, "async_put_domains[0]",
+                           power_domains->async_put_domains[0]);
+       print_power_domains(power_domains, "async_put_domains[1]",
+                           power_domains->async_put_domains[1]);
+ }
+ static void
+ verify_async_put_domains_state(struct i915_power_domains *power_domains)
+ {
+       if (!__async_put_domains_state_ok(power_domains))
+               print_async_put_domains_state(power_domains);
+ }
+ #else
+ static void
+ assert_async_put_domain_masks_disjoint(struct i915_power_domains *power_domains)
+ {
+ }
+ static void
+ verify_async_put_domains_state(struct i915_power_domains *power_domains)
+ {
+ }
+ #endif /* CONFIG_DRM_I915_DEBUG_RUNTIME_PM */
+ static u64 async_put_domains_mask(struct i915_power_domains *power_domains)
+ {
+       assert_async_put_domain_masks_disjoint(power_domains);
+       return __async_put_domains_mask(power_domains);
+ }
+ static void
+ async_put_domains_clear_domain(struct i915_power_domains *power_domains,
+                              enum intel_display_power_domain domain)
+ {
+       assert_async_put_domain_masks_disjoint(power_domains);
+       power_domains->async_put_domains[0] &= ~BIT_ULL(domain);
+       power_domains->async_put_domains[1] &= ~BIT_ULL(domain);
+ }
+ static bool
+ intel_display_power_grab_async_put_ref(struct drm_i915_private *dev_priv,
+                                      enum intel_display_power_domain domain)
+ {
+       struct i915_power_domains *power_domains = &dev_priv->power_domains;
+       bool ret = false;
+       if (!(async_put_domains_mask(power_domains) & BIT_ULL(domain)))
+               goto out_verify;
+       async_put_domains_clear_domain(power_domains, domain);
+       ret = true;
+       if (async_put_domains_mask(power_domains))
+               goto out_verify;
+       cancel_delayed_work(&power_domains->async_put_work);
+       intel_runtime_pm_put_raw(dev_priv,
+                                fetch_and_zero(&power_domains->async_put_wakeref));
+ out_verify:
+       verify_async_put_domains_state(power_domains);
+       return ret;
+ }
  static void
  __intel_display_power_get_domain(struct drm_i915_private *dev_priv,
                                 enum intel_display_power_domain domain)
        struct i915_power_domains *power_domains = &dev_priv->power_domains;
        struct i915_power_well *power_well;
  
+       if (intel_display_power_grab_async_put_ref(dev_priv, domain))
+               return;
        for_each_power_domain_well(dev_priv, power_well, BIT_ULL(domain))
                intel_power_well_get(dev_priv, power_well);
  
@@@ -1857,9 -2073,7 +2062,7 @@@ intel_wakeref_t intel_display_power_get
        intel_wakeref_t wakeref = intel_runtime_pm_get(dev_priv);
  
        mutex_lock(&power_domains->lock);
        __intel_display_power_get_domain(dev_priv, domain);
        mutex_unlock(&power_domains->lock);
  
        return wakeref;
@@@ -1908,35 -2122,51 +2111,51 @@@ intel_display_power_get_if_enabled(stru
        return wakeref;
  }
  
- static void __intel_display_power_put(struct drm_i915_private *dev_priv,
-                                     enum intel_display_power_domain domain)
+ static void
+ __intel_display_power_put_domain(struct drm_i915_private *dev_priv,
+                                enum intel_display_power_domain domain)
  {
        struct i915_power_domains *power_domains;
        struct i915_power_well *power_well;
+       const char *name = intel_display_power_domain_str(domain);
  
        power_domains = &dev_priv->power_domains;
  
-       mutex_lock(&power_domains->lock);
        WARN(!power_domains->domain_use_count[domain],
             "Use count on domain %s is already zero\n",
-            intel_display_power_domain_str(domain));
+            name);
+       WARN(async_put_domains_mask(power_domains) & BIT_ULL(domain),
+            "Async disabling of domain %s is pending\n",
+            name);
        power_domains->domain_use_count[domain]--;
  
        for_each_power_domain_well_reverse(dev_priv, power_well, BIT_ULL(domain))
                intel_power_well_put(dev_priv, power_well);
+ }
  
+ static void __intel_display_power_put(struct drm_i915_private *dev_priv,
+                                     enum intel_display_power_domain domain)
+ {
+       struct i915_power_domains *power_domains = &dev_priv->power_domains;
+       mutex_lock(&power_domains->lock);
+       __intel_display_power_put_domain(dev_priv, domain);
        mutex_unlock(&power_domains->lock);
  }
  
  /**
-  * intel_display_power_put - release a power domain reference
+  * intel_display_power_put_unchecked - release an unchecked power domain reference
   * @dev_priv: i915 device instance
   * @domain: power domain to reference
   *
   * This function drops the power domain reference obtained by
   * intel_display_power_get() and might power down the corresponding hardware
   * block right away if this is the last reference.
+  *
+  * This function exists only for historical reasons and should be avoided in
+  * new code, as the correctness of its use cannot be checked. Always use
+  * intel_display_power_put() instead.
   */
  void intel_display_power_put_unchecked(struct drm_i915_private *dev_priv,
                                       enum intel_display_power_domain domain)
        intel_runtime_pm_put_unchecked(dev_priv);
  }
  
+ static void
+ queue_async_put_domains_work(struct i915_power_domains *power_domains,
+                            intel_wakeref_t wakeref)
+ {
+       WARN_ON(power_domains->async_put_wakeref);
+       power_domains->async_put_wakeref = wakeref;
+       WARN_ON(!queue_delayed_work(system_unbound_wq,
+                                   &power_domains->async_put_work,
+                                   msecs_to_jiffies(100)));
+ }
+ static void
+ release_async_put_domains(struct i915_power_domains *power_domains, u64 mask)
+ {
+       struct drm_i915_private *dev_priv =
+               container_of(power_domains, struct drm_i915_private,
+                            power_domains);
+       enum intel_display_power_domain domain;
+       intel_wakeref_t wakeref;
+       /*
+        * The caller must hold already raw wakeref, upgrade that to a proper
+        * wakeref to make the state checker happy about the HW access during
+        * power well disabling.
+        */
+       assert_rpm_raw_wakeref_held(dev_priv);
+       wakeref = intel_runtime_pm_get(dev_priv);
+       for_each_power_domain(domain, mask) {
+               /* Clear before put, so put's sanity check is happy. */
+               async_put_domains_clear_domain(power_domains, domain);
+               __intel_display_power_put_domain(dev_priv, domain);
+       }
+       intel_runtime_pm_put(dev_priv, wakeref);
+ }
+ static void
+ intel_display_power_put_async_work(struct work_struct *work)
+ {
+       struct drm_i915_private *dev_priv =
+               container_of(work, struct drm_i915_private,
+                            power_domains.async_put_work.work);
+       struct i915_power_domains *power_domains = &dev_priv->power_domains;
+       intel_wakeref_t new_work_wakeref = intel_runtime_pm_get_raw(dev_priv);
+       intel_wakeref_t old_work_wakeref = 0;
+       mutex_lock(&power_domains->lock);
+       /*
+        * Bail out if all the domain refs pending to be released were grabbed
+        * by subsequent gets or a flush_work.
+        */
+       old_work_wakeref = fetch_and_zero(&power_domains->async_put_wakeref);
+       if (!old_work_wakeref)
+               goto out_verify;
+       release_async_put_domains(power_domains,
+                                 power_domains->async_put_domains[0]);
+       /* Requeue the work if more domains were async put meanwhile. */
+       if (power_domains->async_put_domains[1]) {
+               power_domains->async_put_domains[0] =
+                       fetch_and_zero(&power_domains->async_put_domains[1]);
+               queue_async_put_domains_work(power_domains,
+                                            fetch_and_zero(&new_work_wakeref));
+       }
+ out_verify:
+       verify_async_put_domains_state(power_domains);
+       mutex_unlock(&power_domains->lock);
+       if (old_work_wakeref)
+               intel_runtime_pm_put_raw(dev_priv, old_work_wakeref);
+       if (new_work_wakeref)
+               intel_runtime_pm_put_raw(dev_priv, new_work_wakeref);
+ }
+ /**
+  * intel_display_power_put_async - release a power domain reference asynchronously
+  * @i915: i915 device instance
+  * @domain: power domain to reference
+  * @wakeref: wakeref acquired for the reference that is being released
+  *
+  * This function drops the power domain reference obtained by
+  * intel_display_power_get*() and schedules a work to power down the
+  * corresponding hardware block if this is the last reference.
+  */
+ void __intel_display_power_put_async(struct drm_i915_private *i915,
+                                    enum intel_display_power_domain domain,
+                                    intel_wakeref_t wakeref)
+ {
+       struct i915_power_domains *power_domains = &i915->power_domains;
+       intel_wakeref_t work_wakeref = intel_runtime_pm_get_raw(i915);
+       mutex_lock(&power_domains->lock);
+       if (power_domains->domain_use_count[domain] > 1) {
+               __intel_display_power_put_domain(i915, domain);
+               goto out_verify;
+       }
+       WARN_ON(power_domains->domain_use_count[domain] != 1);
+       /* Let a pending work requeue itself or queue a new one. */
+       if (power_domains->async_put_wakeref) {
+               power_domains->async_put_domains[1] |= BIT_ULL(domain);
+       } else {
+               power_domains->async_put_domains[0] |= BIT_ULL(domain);
+               queue_async_put_domains_work(power_domains,
+                                            fetch_and_zero(&work_wakeref));
+       }
+ out_verify:
+       verify_async_put_domains_state(power_domains);
+       mutex_unlock(&power_domains->lock);
+       if (work_wakeref)
+               intel_runtime_pm_put_raw(i915, work_wakeref);
+       intel_runtime_pm_put(i915, wakeref);
+ }
+ /**
+  * intel_display_power_flush_work - flushes the async display power disabling work
+  * @i915: i915 device instance
+  *
+  * Flushes any pending work that was scheduled by a preceding
+  * intel_display_power_put_async() call, completing the disabling of the
+  * corresponding power domains.
+  *
+  * Note that the work handler function may still be running after this
+  * function returns; to ensure that the work handler isn't running use
+  * intel_display_power_flush_work_sync() instead.
+  */
+ void intel_display_power_flush_work(struct drm_i915_private *i915)
+ {
+       struct i915_power_domains *power_domains = &i915->power_domains;
+       intel_wakeref_t work_wakeref;
+       mutex_lock(&power_domains->lock);
+       work_wakeref = fetch_and_zero(&power_domains->async_put_wakeref);
+       if (!work_wakeref)
+               goto out_verify;
+       release_async_put_domains(power_domains,
+                                 async_put_domains_mask(power_domains));
+       cancel_delayed_work(&power_domains->async_put_work);
+ out_verify:
+       verify_async_put_domains_state(power_domains);
+       mutex_unlock(&power_domains->lock);
+       if (work_wakeref)
+               intel_runtime_pm_put_raw(i915, work_wakeref);
+ }
+ /**
+  * intel_display_power_flush_work_sync - flushes and syncs the async display power disabling work
+  * @i915: i915 device instance
+  *
+  * Like intel_display_power_flush_work(), but also ensure that the work
+  * handler function is not running any more when this function returns.
+  */
+ static void
+ intel_display_power_flush_work_sync(struct drm_i915_private *i915)
+ {
+       struct i915_power_domains *power_domains = &i915->power_domains;
+       intel_display_power_flush_work(i915);
+       cancel_delayed_work_sync(&power_domains->async_put_work);
+       verify_async_put_domains_state(power_domains);
+       WARN_ON(power_domains->async_put_wakeref);
+ }
  #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM)
+ /**
+  * intel_display_power_put - release a power domain reference
+  * @dev_priv: i915 device instance
+  * @domain: power domain to reference
+  * @wakeref: wakeref acquired for the reference that is being released
+  *
+  * This function drops the power domain reference obtained by
+  * intel_display_power_get() and might power down the corresponding hardware
+  * block right away if this is the last reference.
+  */
  void intel_display_power_put(struct drm_i915_private *dev_priv,
                             enum intel_display_power_domain domain,
                             intel_wakeref_t wakeref)
        BIT_ULL(POWER_DOMAIN_INIT))
  
  #define VLV_DISPLAY_POWER_DOMAINS (           \
+       BIT_ULL(POWER_DOMAIN_DISPLAY_CORE) |    \
        BIT_ULL(POWER_DOMAIN_PIPE_A) |          \
        BIT_ULL(POWER_DOMAIN_PIPE_B) |          \
        BIT_ULL(POWER_DOMAIN_PIPE_A_PANEL_FITTER) |     \
        BIT_ULL(POWER_DOMAIN_INIT))
  
  #define CHV_DISPLAY_POWER_DOMAINS (           \
+       BIT_ULL(POWER_DOMAIN_DISPLAY_CORE) |    \
        BIT_ULL(POWER_DOMAIN_PIPE_A) |          \
        BIT_ULL(POWER_DOMAIN_PIPE_B) |          \
        BIT_ULL(POWER_DOMAIN_PIPE_C) |          \
@@@ -3433,6 -3857,9 +3846,9 @@@ int intel_power_domains_init(struct drm
  
        mutex_init(&power_domains->lock);
  
+       INIT_DELAYED_WORK(&power_domains->async_put_work,
+                         intel_display_power_put_async_work);
        /*
         * The enabling order will be from lower to higher indexed wells,
         * the disabling order is reversed.
@@@ -3609,6 -4036,246 +4025,246 @@@ static void icl_mbus_init(struct drm_i9
        I915_WRITE(MBUS_ABOX_CTL, val);
  }
  
+ static void hsw_assert_cdclk(struct drm_i915_private *dev_priv)
+ {
+       u32 val = I915_READ(LCPLL_CTL);
+       /*
+        * The LCPLL register should be turned on by the BIOS. For now
+        * let's just check its state and print errors in case
+        * something is wrong.  Don't even try to turn it on.
+        */
+       if (val & LCPLL_CD_SOURCE_FCLK)
+               DRM_ERROR("CDCLK source is not LCPLL\n");
+       if (val & LCPLL_PLL_DISABLE)
+               DRM_ERROR("LCPLL is disabled\n");
+ }
+ static void assert_can_disable_lcpll(struct drm_i915_private *dev_priv)
+ {
+       struct drm_device *dev = &dev_priv->drm;
+       struct intel_crtc *crtc;
+       for_each_intel_crtc(dev, crtc)
+               I915_STATE_WARN(crtc->active, "CRTC for pipe %c enabled\n",
+                               pipe_name(crtc->pipe));
+       I915_STATE_WARN(I915_READ(HSW_PWR_WELL_CTL2),
+                       "Display power well on\n");
+       I915_STATE_WARN(I915_READ(SPLL_CTL) & SPLL_PLL_ENABLE,
+                       "SPLL enabled\n");
+       I915_STATE_WARN(I915_READ(WRPLL_CTL(0)) & WRPLL_PLL_ENABLE,
+                       "WRPLL1 enabled\n");
+       I915_STATE_WARN(I915_READ(WRPLL_CTL(1)) & WRPLL_PLL_ENABLE,
+                       "WRPLL2 enabled\n");
+       I915_STATE_WARN(I915_READ(PP_STATUS(0)) & PP_ON,
+                       "Panel power on\n");
+       I915_STATE_WARN(I915_READ(BLC_PWM_CPU_CTL2) & BLM_PWM_ENABLE,
+                       "CPU PWM1 enabled\n");
+       if (IS_HASWELL(dev_priv))
+               I915_STATE_WARN(I915_READ(HSW_BLC_PWM2_CTL) & BLM_PWM_ENABLE,
+                               "CPU PWM2 enabled\n");
+       I915_STATE_WARN(I915_READ(BLC_PWM_PCH_CTL1) & BLM_PCH_PWM_ENABLE,
+                       "PCH PWM1 enabled\n");
+       I915_STATE_WARN(I915_READ(UTIL_PIN_CTL) & UTIL_PIN_ENABLE,
+                       "Utility pin enabled\n");
+       I915_STATE_WARN(I915_READ(PCH_GTC_CTL) & PCH_GTC_ENABLE,
+                       "PCH GTC enabled\n");
+       /*
+        * In theory we can still leave IRQs enabled, as long as only the HPD
+        * interrupts remain enabled. We used to check for that, but since it's
+        * gen-specific and since we only disable LCPLL after we fully disable
+        * the interrupts, the check below should be enough.
+        */
+       I915_STATE_WARN(intel_irqs_enabled(dev_priv), "IRQs enabled\n");
+ }
+ static u32 hsw_read_dcomp(struct drm_i915_private *dev_priv)
+ {
+       if (IS_HASWELL(dev_priv))
+               return I915_READ(D_COMP_HSW);
+       else
+               return I915_READ(D_COMP_BDW);
+ }
+ static void hsw_write_dcomp(struct drm_i915_private *dev_priv, u32 val)
+ {
+       if (IS_HASWELL(dev_priv)) {
+               if (sandybridge_pcode_write(dev_priv,
+                                           GEN6_PCODE_WRITE_D_COMP, val))
+                       DRM_DEBUG_KMS("Failed to write to D_COMP\n");
+       } else {
+               I915_WRITE(D_COMP_BDW, val);
+               POSTING_READ(D_COMP_BDW);
+       }
+ }
+ /*
+  * This function implements pieces of two sequences from BSpec:
+  * - Sequence for display software to disable LCPLL
+  * - Sequence for display software to allow package C8+
+  * The steps implemented here are just the steps that actually touch the LCPLL
+  * register. Callers should take care of disabling all the display engine
+  * functions, doing the mode unset, fixing interrupts, etc.
+  */
+ static void hsw_disable_lcpll(struct drm_i915_private *dev_priv,
+                             bool switch_to_fclk, bool allow_power_down)
+ {
+       u32 val;
+       assert_can_disable_lcpll(dev_priv);
+       val = I915_READ(LCPLL_CTL);
+       if (switch_to_fclk) {
+               val |= LCPLL_CD_SOURCE_FCLK;
+               I915_WRITE(LCPLL_CTL, val);
+               if (wait_for_us(I915_READ(LCPLL_CTL) &
+                               LCPLL_CD_SOURCE_FCLK_DONE, 1))
+                       DRM_ERROR("Switching to FCLK failed\n");
+               val = I915_READ(LCPLL_CTL);
+       }
+       val |= LCPLL_PLL_DISABLE;
+       I915_WRITE(LCPLL_CTL, val);
+       POSTING_READ(LCPLL_CTL);
+       if (intel_wait_for_register(&dev_priv->uncore, LCPLL_CTL,
+                                   LCPLL_PLL_LOCK, 0, 1))
+               DRM_ERROR("LCPLL still locked\n");
+       val = hsw_read_dcomp(dev_priv);
+       val |= D_COMP_COMP_DISABLE;
+       hsw_write_dcomp(dev_priv, val);
+       ndelay(100);
+       if (wait_for((hsw_read_dcomp(dev_priv) &
+                     D_COMP_RCOMP_IN_PROGRESS) == 0, 1))
+               DRM_ERROR("D_COMP RCOMP still in progress\n");
+       if (allow_power_down) {
+               val = I915_READ(LCPLL_CTL);
+               val |= LCPLL_POWER_DOWN_ALLOW;
+               I915_WRITE(LCPLL_CTL, val);
+               POSTING_READ(LCPLL_CTL);
+       }
+ }
+ /*
+  * Fully restores LCPLL, disallowing power down and switching back to LCPLL
+  * source.
+  */
+ static void hsw_restore_lcpll(struct drm_i915_private *dev_priv)
+ {
+       u32 val;
+       val = I915_READ(LCPLL_CTL);
+       if ((val & (LCPLL_PLL_LOCK | LCPLL_PLL_DISABLE | LCPLL_CD_SOURCE_FCLK |
+                   LCPLL_POWER_DOWN_ALLOW)) == LCPLL_PLL_LOCK)
+               return;
+       /*
+        * Make sure we're not on PC8 state before disabling PC8, otherwise
+        * we'll hang the machine. To prevent PC8 state, just enable force_wake.
+        */
+       intel_uncore_forcewake_get(&dev_priv->uncore, FORCEWAKE_ALL);
+       if (val & LCPLL_POWER_DOWN_ALLOW) {
+               val &= ~LCPLL_POWER_DOWN_ALLOW;
+               I915_WRITE(LCPLL_CTL, val);
+               POSTING_READ(LCPLL_CTL);
+       }
+       val = hsw_read_dcomp(dev_priv);
+       val |= D_COMP_COMP_FORCE;
+       val &= ~D_COMP_COMP_DISABLE;
+       hsw_write_dcomp(dev_priv, val);
+       val = I915_READ(LCPLL_CTL);
+       val &= ~LCPLL_PLL_DISABLE;
+       I915_WRITE(LCPLL_CTL, val);
+       if (intel_wait_for_register(&dev_priv->uncore, LCPLL_CTL,
+                                   LCPLL_PLL_LOCK, LCPLL_PLL_LOCK, 5))
+               DRM_ERROR("LCPLL not locked yet\n");
+       if (val & LCPLL_CD_SOURCE_FCLK) {
+               val = I915_READ(LCPLL_CTL);
+               val &= ~LCPLL_CD_SOURCE_FCLK;
+               I915_WRITE(LCPLL_CTL, val);
+               if (wait_for_us((I915_READ(LCPLL_CTL) &
+                                LCPLL_CD_SOURCE_FCLK_DONE) == 0, 1))
+                       DRM_ERROR("Switching back to LCPLL failed\n");
+       }
+       intel_uncore_forcewake_put(&dev_priv->uncore, FORCEWAKE_ALL);
+       intel_update_cdclk(dev_priv);
+       intel_dump_cdclk_state(&dev_priv->cdclk.hw, "Current CDCLK");
+ }
+ /*
+  * Package states C8 and deeper are really deep PC states that can only be
+  * reached when all the devices on the system allow it, so even if the graphics
+  * device allows PC8+, it doesn't mean the system will actually get to these
+  * states. Our driver only allows PC8+ when going into runtime PM.
+  *
+  * The requirements for PC8+ are that all the outputs are disabled, the power
+  * well is disabled and most interrupts are disabled, and these are also
+  * requirements for runtime PM. When these conditions are met, we manually do
+  * the other conditions: disable the interrupts, clocks and switch LCPLL refclk
+  * to Fclk. If we're in PC8+ and we get an non-hotplug interrupt, we can hard
+  * hang the machine.
+  *
+  * When we really reach PC8 or deeper states (not just when we allow it) we lose
+  * the state of some registers, so when we come back from PC8+ we need to
+  * restore this state. We don't get into PC8+ if we're not in RC6, so we don't
+  * need to take care of the registers kept by RC6. Notice that this happens even
+  * if we don't put the device in PCI D3 state (which is what currently happens
+  * because of the runtime PM support).
+  *
+  * For more, read "Display Sequences for Package C8" on the hardware
+  * documentation.
+  */
+ void hsw_enable_pc8(struct drm_i915_private *dev_priv)
+ {
+       u32 val;
+       DRM_DEBUG_KMS("Enabling package C8+\n");
+       if (HAS_PCH_LPT_LP(dev_priv)) {
+               val = I915_READ(SOUTH_DSPCLK_GATE_D);
+               val &= ~PCH_LP_PARTITION_LEVEL_DISABLE;
+               I915_WRITE(SOUTH_DSPCLK_GATE_D, val);
+       }
+       lpt_disable_clkout_dp(dev_priv);
+       hsw_disable_lcpll(dev_priv, true, true);
+ }
+ void hsw_disable_pc8(struct drm_i915_private *dev_priv)
+ {
+       u32 val;
+       DRM_DEBUG_KMS("Disabling package C8+\n");
+       hsw_restore_lcpll(dev_priv);
+       intel_init_pch_refclk(dev_priv);
+       if (HAS_PCH_LPT_LP(dev_priv)) {
+               val = I915_READ(SOUTH_DSPCLK_GATE_D);
+               val |= PCH_LP_PARTITION_LEVEL_DISABLE;
+               I915_WRITE(SOUTH_DSPCLK_GATE_D, val);
+       }
+ }
  static void intel_pch_reset_handshake(struct drm_i915_private *dev_priv,
                                      bool enable)
  {
@@@ -3764,7 -4431,7 +4420,7 @@@ static void cnl_display_core_init(struc
        intel_pch_reset_handshake(dev_priv, !HAS_PCH_NOP(dev_priv));
  
        /* 2-3. */
-       cnl_combo_phys_init(dev_priv);
+       intel_combo_phy_init(dev_priv);
  
        /*
         * 4. Enable Power Well 1 (PG1).
@@@ -3813,7 -4480,7 +4469,7 @@@ static void cnl_display_core_uninit(str
        usleep_range(10, 30);           /* 10 us delay per Bspec */
  
        /* 5. */
-       cnl_combo_phys_uninit(dev_priv);
+       intel_combo_phy_uninit(dev_priv);
  }
  
  void icl_display_core_init(struct drm_i915_private *dev_priv,
        /* 1. Enable PCH reset handshake. */
        intel_pch_reset_handshake(dev_priv, !HAS_PCH_NOP(dev_priv));
  
-       /* 2-3. */
-       icl_combo_phys_init(dev_priv);
+       /* 2. Initialize all combo phys */
+       intel_combo_phy_init(dev_priv);
  
        /*
-        * 4. Enable Power Well 1 (PG1).
+        * 3. Enable Power Well 1 (PG1).
         *    The AUX IO power wells will be enabled on demand.
         */
        mutex_lock(&power_domains->lock);
        intel_power_well_enable(dev_priv, well);
        mutex_unlock(&power_domains->lock);
  
-       /* 5. Enable CDCLK. */
+       /* 4. Enable CDCLK. */
        intel_cdclk_init(dev_priv);
  
-       /* 6. Enable DBUF. */
+       /* 5. Enable DBUF. */
        icl_dbuf_enable(dev_priv);
  
-       /* 7. Setup MBUS. */
+       /* 6. Setup MBUS. */
        icl_mbus_init(dev_priv);
  
        if (resume && dev_priv->csr.dmc_payload)
@@@ -3878,7 -4545,7 +4534,7 @@@ void icl_display_core_uninit(struct drm
        mutex_unlock(&power_domains->lock);
  
        /* 5. */
-       icl_combo_phys_uninit(dev_priv);
+       intel_combo_phy_uninit(dev_priv);
  }
  
  static void chv_phy_control_init(struct drm_i915_private *dev_priv)
@@@ -4000,9 -4667,9 +4656,9 @@@ static bool vlv_punit_is_power_gated(st
  {
        bool ret;
  
-       mutex_lock(&dev_priv->pcu_lock);
+       vlv_punit_get(dev_priv);
        ret = (vlv_punit_read(dev_priv, reg0) & SSPM0_SSC_MASK) == SSPM0_SSC_PWR_GATE;
-       mutex_unlock(&dev_priv->pcu_lock);
+       vlv_punit_put(dev_priv);
  
        return ret;
  }
@@@ -4069,7 -4736,10 +4725,10 @@@ void intel_power_domains_init_hw(struc
                mutex_unlock(&power_domains->lock);
                assert_ved_power_gated(i915);
                assert_isp_power_gated(i915);
-       } else if (IS_IVYBRIDGE(i915) || INTEL_GEN(i915) >= 7) {
+       } else if (IS_BROADWELL(i915) || IS_HASWELL(i915)) {
+               hsw_assert_cdclk(i915);
+               intel_pch_reset_handshake(i915, !HAS_PCH_NOP(i915));
+       } else if (IS_IVYBRIDGE(i915)) {
                intel_pch_reset_handshake(i915, !HAS_PCH_NOP(i915));
        }
  
@@@ -4110,6 -4780,8 +4769,8 @@@ void intel_power_domains_fini_hw(struc
        if (!i915_modparams.disable_power_well)
                intel_display_power_put_unchecked(i915, POWER_DOMAIN_INIT);
  
+       intel_display_power_flush_work_sync(i915);
        intel_power_domains_verify_state(i915);
  
        /* Keep the power well enabled, but cancel its rpm wakeref. */
@@@ -4185,6 -4857,7 +4846,7 @@@ void intel_power_domains_suspend(struc
        if (!(i915->csr.allowed_dc_mask & DC_STATE_EN_DC9) &&
            suspend_mode == I915_DRM_SUSPEND_IDLE &&
            i915->csr.dmc_payload) {
+               intel_display_power_flush_work(i915);
                intel_power_domains_verify_state(i915);
                return;
        }
         * Even if power well support was disabled we still want to disable
         * power wells if power domains must be deinitialized for suspend.
         */
-       if (!i915_modparams.disable_power_well) {
+       if (!i915_modparams.disable_power_well)
                intel_display_power_put_unchecked(i915, POWER_DOMAIN_INIT);
-               intel_power_domains_verify_state(i915);
-       }
+       intel_display_power_flush_work(i915);
+       intel_power_domains_verify_state(i915);
  
        if (INTEL_GEN(i915) >= 11)
                icl_display_core_uninit(i915);
@@@ -4274,6 -4948,8 +4937,8 @@@ static void intel_power_domains_verify_
  
        mutex_lock(&power_domains->lock);
  
+       verify_async_put_domains_state(power_domains);
        dump_domain_info = false;
        for_each_power_well(i915, power_well) {
                enum intel_display_power_domain domain;
@@@ -4320,6 -4996,26 +4985,26 @@@ static void intel_power_domains_verify_
  
  #endif
  
+ static intel_wakeref_t __intel_runtime_pm_get(struct drm_i915_private *i915,
+                                             bool wakelock)
+ {
+       struct pci_dev *pdev = i915->drm.pdev;
+       struct device *kdev = &pdev->dev;
+       int ret;
+       ret = pm_runtime_get_sync(kdev);
+       WARN_ONCE(ret < 0, "pm_runtime_get_sync() failed: %d\n", ret);
+       intel_runtime_pm_acquire(i915, wakelock);
+       return track_intel_runtime_pm_wakeref(i915);
+ }
+ static intel_wakeref_t intel_runtime_pm_get_raw(struct drm_i915_private *i915)
+ {
+       return __intel_runtime_pm_get(i915, false);
+ }
  /**
   * intel_runtime_pm_get - grab a runtime pm reference
   * @i915: i915 device instance
   */
  intel_wakeref_t intel_runtime_pm_get(struct drm_i915_private *i915)
  {
-       struct pci_dev *pdev = i915->drm.pdev;
-       struct device *kdev = &pdev->dev;
-       int ret;
-       ret = pm_runtime_get_sync(kdev);
-       WARN_ONCE(ret < 0, "pm_runtime_get_sync() failed: %d\n", ret);
-       return track_intel_runtime_pm_wakeref(i915);
+       return __intel_runtime_pm_get(i915, true);
  }
  
  /**
@@@ -4374,6 -5063,8 +5052,8 @@@ intel_wakeref_t intel_runtime_pm_get_if
                        return 0;
        }
  
+       intel_runtime_pm_acquire(i915, true);
        return track_intel_runtime_pm_wakeref(i915);
  }
  
@@@ -4404,33 -5095,64 +5084,64 @@@ intel_wakeref_t intel_runtime_pm_get_no
        assert_rpm_wakelock_held(i915);
        pm_runtime_get_noresume(kdev);
  
+       intel_runtime_pm_acquire(i915, true);
        return track_intel_runtime_pm_wakeref(i915);
  }
  
+ static void __intel_runtime_pm_put(struct drm_i915_private *i915,
+                                  intel_wakeref_t wref,
+                                  bool wakelock)
+ {
+       struct pci_dev *pdev = i915->drm.pdev;
+       struct device *kdev = &pdev->dev;
+       untrack_intel_runtime_pm_wakeref(i915, wref);
+       intel_runtime_pm_release(i915, wakelock);
+       pm_runtime_mark_last_busy(kdev);
+       pm_runtime_put_autosuspend(kdev);
+ }
+ #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM)
+ static void
+ intel_runtime_pm_put_raw(struct drm_i915_private *i915, intel_wakeref_t wref)
+ {
+       __intel_runtime_pm_put(i915, wref, false);
+ }
+ #endif
  /**
-  * intel_runtime_pm_put - release a runtime pm reference
+  * intel_runtime_pm_put_unchecked - release an unchecked runtime pm reference
   * @i915: i915 device instance
   *
   * This function drops the device-level runtime pm reference obtained by
   * intel_runtime_pm_get() and might power down the corresponding
   * hardware block right away if this is the last reference.
+  *
+  * This function exists only for historical reasons and should be avoided in
+  * new code, as the correctness of its use cannot be checked. Always use
+  * intel_runtime_pm_put() instead.
   */
  void intel_runtime_pm_put_unchecked(struct drm_i915_private *i915)
  {
-       struct pci_dev *pdev = i915->drm.pdev;
-       struct device *kdev = &pdev->dev;
-       untrack_intel_runtime_pm_wakeref(i915);
-       pm_runtime_mark_last_busy(kdev);
-       pm_runtime_put_autosuspend(kdev);
+       __intel_runtime_pm_put(i915, -1, true);
  }
  
  #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM)
+ /**
+  * intel_runtime_pm_put - release a runtime pm reference
+  * @i915: i915 device instance
+  * @wref: wakeref acquired for the reference that is being released
+  *
+  * This function drops the device-level runtime pm reference obtained by
+  * intel_runtime_pm_get() and might power down the corresponding
+  * hardware block right away if this is the last reference.
+  */
  void intel_runtime_pm_put(struct drm_i915_private *i915, intel_wakeref_t wref)
  {
-       cancel_intel_runtime_pm_wakeref(i915, wref);
-       intel_runtime_pm_put_unchecked(i915);
+       __intel_runtime_pm_put(i915, wref, true);
  }
  #endif
  
@@@ -4504,14 -5226,14 +5215,14 @@@ void intel_runtime_pm_disable(struct dr
  void intel_runtime_pm_cleanup(struct drm_i915_private *i915)
  {
        struct i915_runtime_pm *rpm = &i915->runtime_pm;
-       int count;
+       int count = atomic_read(&rpm->wakeref_count);
  
-       count = atomic_fetch_inc(&rpm->wakeref_count); /* balance untrack */
        WARN(count,
-            "i915->runtime_pm.wakeref_count=%d on cleanup\n",
-            count);
+            "i915 raw-wakerefs=%d wakelocks=%d on cleanup\n",
+            intel_rpm_raw_wakeref_count(count),
+            intel_rpm_wakelock_count(count));
  
-       untrack_intel_runtime_pm_wakeref(i915);
+       untrack_all_intel_runtime_pm_wakerefs(i915);
  }
  
  void intel_runtime_pm_init_early(struct drm_i915_private *i915)
@@@ -256,6 -256,16 +256,16 @@@ int intel_plane_check_stride(const stru
        unsigned int rotation = plane_state->base.rotation;
        u32 stride, max_stride;
  
+       /*
+        * We ignore stride for all invisible planes that
+        * can be remapped. Otherwise we could end up
+        * with a false positive when the remapping didn't
+        * kick in due the plane being invisible.
+        */
+       if (intel_plane_can_remap(plane_state) &&
+           !plane_state->base.visible)
+               return 0;
        /* FIXME other color planes? */
        stride = plane_state->color_plane[0].stride;
        max_stride = plane->max_stride(plane, fb->format->format,
@@@ -325,8 -335,7 +335,8 @@@ skl_plane_max_stride(struct intel_plan
                     u32 pixel_format, u64 modifier,
                     unsigned int rotation)
  {
 -      int cpp = drm_format_plane_cpp(pixel_format, 0);
 +      const struct drm_format_info *info = drm_format_info(pixel_format);
 +      int cpp = info->cpp[0];
  
        /*
         * "The stride in bytes must not exceed the
@@@ -1418,6 -1427,10 +1428,10 @@@ g4x_sprite_check(struct intel_crtc_stat
        if (ret)
                return ret;
  
+       ret = i9xx_check_plane_surface(plane_state);
+       if (ret)
+               return ret;
        if (!plane_state->base.visible)
                return 0;
  
        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
@@@ -1476,6 -1485,10 +1486,10 @@@ vlv_sprite_check(struct intel_crtc_stat
        if (ret)
                return ret;
  
+       ret = i9xx_check_plane_surface(plane_state);
+       if (ret)
+               return ret;
        if (!plane_state->base.visible)
                return 0;
  
        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;
@@@ -1640,6 -1649,10 +1650,10 @@@ static int skl_plane_check(struct intel
        if (ret)
                return ret;
  
+       ret = skl_check_plane_surface(plane_state);
+       if (ret)
+               return ret;
        if (!plane_state->base.visible)
                return 0;
  
        if (ret)
                return ret;
  
-       ret = skl_check_plane_surface(plane_state);
-       if (ret)
-               return ret;
        /* HW only has 8 bits pixel precision, disable plane if invisible */
        if (!(plane_state->base.alpha >> 8))
                plane_state->base.visible = false;
@@@ -1,4 -1,4 +1,4 @@@
 -// SPDX-License-Identifier: (GPL-2.0)
 +// SPDX-License-Identifier: GPL-2.0
  /*
   * Copyright © 2019 Intel Corporation
   *
@@@ -576,7 -576,7 +576,7 @@@ static int mei_hdcp_verify_mprime(struc
  
        memcpy(verify_mprime_in.m_prime, stream_ready->m_prime,
               HDCP_2_2_MPRIME_LEN);
-       drm_hdcp2_u32_to_seq_num(verify_mprime_in.seq_num_m, data->seq_num_m);
+       drm_hdcp_cpu_to_be24(verify_mprime_in.seq_num_m, data->seq_num_m);
        memcpy(verify_mprime_in.streams, data->streams,
               (data->k * sizeof(struct hdcp2_streamid_type)));
  
@@@ -517,10 -517,6 +517,10 @@@ struct drm_connector_state 
         * Used by the atomic helpers to select the encoder, through the
         * &drm_connector_helper_funcs.atomic_best_encoder or
         * &drm_connector_helper_funcs.best_encoder callbacks.
 +       *
 +       * NOTE: Atomic drivers must fill this out (either themselves or through
 +       * helpers), for otherwise the GETCONNECTOR and GETENCODER IOCTLs will
 +       * not return correct data to userspace.
         */
        struct drm_encoder *best_encoder;
  
         * and the connector bpc limitations obtained from edid.
         */
        u8 max_bpc;
 +
 +      /**
 +       * @hdr_output_metadata:
 +       * DRM blob property for HDR output metadata
 +       */
 +      struct drm_property_blob *hdr_output_metadata;
  };
  
  /**
@@@ -1071,12 -1061,6 +1071,6 @@@ struct drm_connector 
         */
        struct drm_property *vrr_capable_property;
  
-       /**
-        * @content_protection_property: DRM ENUM property for content
-        * protection. See drm_connector_attach_content_protection_property().
-        */
-       struct drm_property *content_protection_property;
        /**
         * @colorspace_property: Connector property to set the suitable
         * colorspace supported by the sink.
         * &drm_mode_config.connector_free_work.
         */
        struct llist_node free_node;
 +
 +      /* HDR metdata */
 +      struct hdr_output_metadata hdr_output_metadata;
 +      struct hdr_sink_metadata hdr_sink_metadata;
  };
  
  #define obj_to_connector(x) container_of(x, struct drm_connector, base)
@@@ -1359,8 -1339,6 +1353,6 @@@ int drm_connector_attach_scaling_mode_p
                                               u32 scaling_mode_mask);
  int drm_connector_attach_vrr_capable_property(
                struct drm_connector *connector);
- int drm_connector_attach_content_protection_property(
-               struct drm_connector *connector);
  int drm_mode_create_aspect_ratio_property(struct drm_device *dev);
  int drm_mode_create_colorspace_property(struct drm_connector *connector);
  int drm_mode_create_content_type_property(struct drm_device *dev);
@@@ -836,13 -836,12 +836,19 @@@ struct drm_mode_config 
         */
        struct drm_property *writeback_out_fence_ptr_property;
  
 +      /**
 +       * hdr_output_metadata_property: Connector property containing hdr
 +       * metatda. This will be provided by userspace compositors based
 +       * on HDR content
 +       */
 +      struct drm_property *hdr_output_metadata_property;
 +
+       /**
+        * @content_protection_property: DRM ENUM property for content
+        * protection. See drm_connector_attach_content_protection_property().
+        */
+       struct drm_property *content_protection_property;
        /* dumb ioctl parameters */
        uint32_t preferred_depth, prefer_shadow;