Merge remote-tracking branch 'airlied/drm-next' into drm-intel-next-queued
authorDaniel Vetter <daniel.vetter@ffwll.ch>
Mon, 15 Aug 2016 08:41:47 +0000 (10:41 +0200)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Mon, 15 Aug 2016 08:41:47 +0000 (10:41 +0200)
Backmerge because too many conflicts, and also we need to get at the
latest struct fence patches from Gustavo. Requested by Chris Wilson.

Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
1  2 
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/i915/intel_sprite.c

@@@ -787,6 -787,8 +787,6 @@@ static void i915_ring_seqno_info(struc
  
        seq_printf(m, "Current sequence (%s): %x\n",
                   engine->name, intel_engine_get_seqno(engine));
 -      seq_printf(m, "Current user interrupts (%s): %lx\n",
 -                 engine->name, READ_ONCE(engine->breadcrumbs.irq_wakeups));
  
        spin_lock(&b->lock);
        for (rb = rb_first(&b->waiters); rb; rb = rb_next(rb)) {
@@@ -1432,10 -1434,11 +1432,10 @@@ static int i915_hangcheck_info(struct s
                           engine->hangcheck.seqno,
                           seqno[id],
                           engine->last_submitted_seqno);
 -              seq_printf(m, "\twaiters? %d\n",
 -                         intel_engine_has_waiter(engine));
 -              seq_printf(m, "\tuser interrupts = %lx [current %lx]\n",
 -                         engine->hangcheck.user_interrupts,
 -                         READ_ONCE(engine->breadcrumbs.irq_wakeups));
 +              seq_printf(m, "\twaiters? %s, fake irq active? %s\n",
 +                         yesno(intel_engine_has_waiter(engine)),
 +                         yesno(test_bit(engine->id,
 +                                        &dev_priv->gpu_error.missed_irq_rings)));
                seq_printf(m, "\tACTHD = 0x%08llx [current 0x%08llx]\n",
                           (long long)engine->hangcheck.acthd,
                           (long long)acthd[id]);
@@@ -2544,7 -2547,6 +2544,7 @@@ static void i915_guc_client_info(struc
                                 struct i915_guc_client *client)
  {
        struct intel_engine_cs *engine;
 +      enum intel_engine_id id;
        uint64_t tot = 0;
  
        seq_printf(m, "\tPriority %d, GuC ctx index: %u, PD offset 0x%x\n",
                client->wq_size, client->wq_offset, client->wq_tail);
  
        seq_printf(m, "\tWork queue full: %u\n", client->no_wq_space);
 -      seq_printf(m, "\tFailed to queue: %u\n", client->q_fail);
        seq_printf(m, "\tFailed doorbell: %u\n", client->b_fail);
        seq_printf(m, "\tLast submission result: %d\n", client->retcode);
  
 -      for_each_engine(engine, dev_priv) {
 +      for_each_engine_id(engine, dev_priv, id) {
 +              u64 submissions = client->submissions[id];
 +              tot += submissions;
                seq_printf(m, "\tSubmissions: %llu %s\n",
 -                              client->submissions[engine->id],
 -                              engine->name);
 -              tot += client->submissions[engine->id];
 +                              submissions, engine->name);
        }
        seq_printf(m, "\tTotal: %llu\n", tot);
  }
@@@ -2575,7 -2578,6 +2575,7 @@@ static int i915_guc_info(struct seq_fil
        struct intel_guc guc;
        struct i915_guc_client client = {};
        struct intel_engine_cs *engine;
 +      enum intel_engine_id id;
        u64 total = 0;
  
        if (!HAS_GUC_SCHED(dev_priv))
        seq_printf(m, "GuC last action error code: %d\n", guc.action_err);
  
        seq_printf(m, "\nGuC submissions:\n");
 -      for_each_engine(engine, dev_priv) {
 +      for_each_engine_id(engine, dev_priv, id) {
 +              u64 submissions = guc.submissions[id];
 +              total += submissions;
                seq_printf(m, "\t%-24s: %10llu, last seqno 0x%08x\n",
 -                      engine->name, guc.submissions[engine->id],
 -                      guc.last_seqno[engine->id]);
 -              total += guc.submissions[engine->id];
 +                      engine->name, submissions, guc.last_seqno[id]);
        }
        seq_printf(m, "\t%s: %llu\n", "Total", total);
  
@@@ -3091,12 -3093,12 +3091,12 @@@ static const char *plane_rotation(unsig
         */
        snprintf(buf, sizeof(buf),
                 "%s%s%s%s%s%s(0x%08x)",
-                (rotation & BIT(DRM_ROTATE_0)) ? "0 " : "",
-                (rotation & BIT(DRM_ROTATE_90)) ? "90 " : "",
-                (rotation & BIT(DRM_ROTATE_180)) ? "180 " : "",
-                (rotation & BIT(DRM_ROTATE_270)) ? "270 " : "",
-                (rotation & BIT(DRM_REFLECT_X)) ? "FLIPX " : "",
-                (rotation & BIT(DRM_REFLECT_Y)) ? "FLIPY " : "",
+                (rotation & DRM_ROTATE_0) ? "0 " : "",
+                (rotation & DRM_ROTATE_90) ? "90 " : "",
+                (rotation & DRM_ROTATE_180) ? "180 " : "",
+                (rotation & DRM_ROTATE_270) ? "270 " : "",
+                (rotation & DRM_REFLECT_X) ? "FLIPX " : "",
+                (rotation & DRM_REFLECT_Y) ? "FLIPY " : "",
                 rotation);
  
        return buf;
@@@ -3226,7 -3228,7 +3226,7 @@@ static int i915_semaphore_status(struc
        struct drm_device *dev = node->minor->dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_engine_cs *engine;
 -      int num_rings = hweight32(INTEL_INFO(dev)->ring_mask);
 +      int num_rings = INTEL_INFO(dev)->num_rings;
        enum intel_engine_id id;
        int j, ret;
  
@@@ -685,7 -685,7 +685,7 @@@ static int i915_kick_out_firmware_fb(st
        primary =
                pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
  
-       ret = remove_conflicting_framebuffers(ap, "inteldrmfb", primary);
+       ret = drm_fb_helper_remove_conflicting_framebuffers(ap, "inteldrmfb", primary);
  
        kfree(ap);
  
@@@ -827,8 -827,6 +827,8 @@@ static int i915_driver_init_early(struc
        mutex_init(&dev_priv->wm.wm_mutex);
        mutex_init(&dev_priv->pps_mutex);
  
 +      i915_memcpy_init_early(dev_priv);
 +
        ret = i915_workqueues_init(dev_priv);
        if (ret < 0)
                return ret;
@@@ -1562,7 -1560,6 +1562,7 @@@ static int i915_drm_resume(struct drm_d
        i915_gem_resume(dev);
  
        i915_restore_state(dev);
 +      intel_pps_unlock_regs_wa(dev_priv);
        intel_opregion_setup(dev_priv);
  
        intel_init_pch_refclk(dev);
@@@ -170,7 -170,7 +170,7 @@@ i915_gem_get_aperture_ioctl(struct drm_
  static int
  i915_gem_object_get_pages_phys(struct drm_i915_gem_object *obj)
  {
-       struct address_space *mapping = file_inode(obj->base.filp)->i_mapping;
+       struct address_space *mapping = obj->base.filp->f_mapping;
        char *vaddr = obj->phys_handle->vaddr;
        struct sg_table *st;
        struct scatterlist *sg;
@@@ -237,7 -237,7 +237,7 @@@ i915_gem_object_put_pages_phys(struct d
                obj->dirty = 0;
  
        if (obj->dirty) {
-               struct address_space *mapping = file_inode(obj->base.filp)->i_mapping;
+               struct address_space *mapping = obj->base.filp->f_mapping;
                char *vaddr = obj->phys_handle->vaddr;
                int i;
  
@@@ -279,25 -279,16 +279,25 @@@ static const struct drm_i915_gem_object
        .release = i915_gem_object_release_phys,
  };
  
 -int
 -i915_gem_object_unbind(struct drm_i915_gem_object *obj)
 +int i915_gem_object_unbind(struct drm_i915_gem_object *obj)
  {
        struct i915_vma *vma;
        LIST_HEAD(still_in_list);
        int ret;
  
 -      /* The vma will only be freed if it is marked as closed, and if we wait
 -       * upon rendering to the vma, we may unbind anything in the list.
 +      lockdep_assert_held(&obj->base.dev->struct_mutex);
 +
 +      /* Closed vma are removed from the obj->vma_list - but they may
 +       * still have an active binding on the object. To remove those we
 +       * must wait for all rendering to complete to the object (as unbinding
 +       * must anyway), and retire the requests.
         */
 +      ret = i915_gem_object_wait_rendering(obj, false);
 +      if (ret)
 +              return ret;
 +
 +      i915_gem_retire_requests(to_i915(obj->base.dev));
 +
        while ((vma = list_first_entry_or_null(&obj->vma_list,
                                               struct i915_vma,
                                               obj_link))) {
@@@ -2022,7 -2013,7 +2022,7 @@@ i915_gem_object_invalidate(struct drm_i
        if (obj->base.filp == NULL)
                return;
  
-       mapping = file_inode(obj->base.filp)->i_mapping,
+       mapping = obj->base.filp->f_mapping,
        invalidate_mapping_pages(mapping, 0, (loff_t)-1);
  }
  
@@@ -2086,7 -2077,6 +2086,7 @@@ i915_gem_object_put_pages(struct drm_i9
        list_del(&obj->global_list);
  
        if (obj->mapping) {
 +              /* low bits are ignored by is_vmalloc_addr and kmap_to_page */
                if (is_vmalloc_addr(obj->mapping))
                        vunmap(obj->mapping);
                else
@@@ -2138,7 -2128,7 +2138,7 @@@ i915_gem_object_get_pages_gtt(struct dr
         *
         * Fail silently without starting the shrinker
         */
-       mapping = file_inode(obj->base.filp)->i_mapping;
+       mapping = obj->base.filp->f_mapping;
        gfp = mapping_gfp_constraint(mapping, ~(__GFP_IO | __GFP_RECLAIM));
        gfp |= __GFP_NORETRY | __GFP_NOWARN;
        sg = st->sgl;
@@@ -2263,8 -2253,7 +2263,8 @@@ i915_gem_object_get_pages(struct drm_i9
  }
  
  /* The 'mapping' part of i915_gem_object_pin_map() below */
 -static void *i915_gem_object_map(const struct drm_i915_gem_object *obj)
 +static void *i915_gem_object_map(const struct drm_i915_gem_object *obj,
 +                               enum i915_map_type type)
  {
        unsigned long n_pages = obj->base.size >> PAGE_SHIFT;
        struct sg_table *sgt = obj->pages;
        struct page *stack_pages[32];
        struct page **pages = stack_pages;
        unsigned long i = 0;
 +      pgprot_t pgprot;
        void *addr;
  
        /* A single page can always be kmapped */
 -      if (n_pages == 1)
 +      if (n_pages == 1 && type == I915_MAP_WB)
                return kmap(sg_page(sgt->sgl));
  
        if (n_pages > ARRAY_SIZE(stack_pages)) {
        /* Check that we have the expected number of pages */
        GEM_BUG_ON(i != n_pages);
  
 -      addr = vmap(pages, n_pages, 0, PAGE_KERNEL);
 +      switch (type) {
 +      case I915_MAP_WB:
 +              pgprot = PAGE_KERNEL;
 +              break;
 +      case I915_MAP_WC:
 +              pgprot = pgprot_writecombine(PAGE_KERNEL_IO);
 +              break;
 +      }
 +      addr = vmap(pages, n_pages, 0, pgprot);
  
        if (pages != stack_pages)
                drm_free_large(pages);
  }
  
  /* get, pin, and map the pages of the object into kernel space */
 -void *i915_gem_object_pin_map(struct drm_i915_gem_object *obj)
 +void *i915_gem_object_pin_map(struct drm_i915_gem_object *obj,
 +                            enum i915_map_type type)
  {
 +      enum i915_map_type has_type;
 +      bool pinned;
 +      void *ptr;
        int ret;
  
        lockdep_assert_held(&obj->base.dev->struct_mutex);
 +      GEM_BUG_ON(!i915_gem_object_has_struct_page(obj));
  
        ret = i915_gem_object_get_pages(obj);
        if (ret)
                return ERR_PTR(ret);
  
        i915_gem_object_pin_pages(obj);
 +      pinned = obj->pages_pin_count > 1;
 +
 +      ptr = ptr_unpack_bits(obj->mapping, has_type);
 +      if (ptr && has_type != type) {
 +              if (pinned) {
 +                      ret = -EBUSY;
 +                      goto err;
 +              }
 +
 +              if (is_vmalloc_addr(ptr))
 +                      vunmap(ptr);
 +              else
 +                      kunmap(kmap_to_page(ptr));
  
 -      if (!obj->mapping) {
 -              obj->mapping = i915_gem_object_map(obj);
 -              if (!obj->mapping) {
 -                      i915_gem_object_unpin_pages(obj);
 -                      return ERR_PTR(-ENOMEM);
 +              ptr = obj->mapping = NULL;
 +      }
 +
 +      if (!ptr) {
 +              ptr = i915_gem_object_map(obj, type);
 +              if (!ptr) {
 +                      ret = -ENOMEM;
 +                      goto err;
                }
 +
 +              obj->mapping = ptr_pack_bits(ptr, type);
        }
  
 -      return obj->mapping;
 +      return ptr;
 +
 +err:
 +      i915_gem_object_unpin_pages(obj);
 +      return ERR_PTR(ret);
  }
  
  static void
@@@ -2470,11 -2423,15 +2470,11 @@@ static void i915_gem_reset_engine_clean
        struct drm_i915_gem_request *request;
        struct intel_ring *ring;
  
 -      request = i915_gem_active_peek(&engine->last_request,
 -                                     &engine->i915->drm.struct_mutex);
 -
        /* Mark all pending requests as complete so that any concurrent
         * (lockless) lookup doesn't try and wait upon the request as we
         * reset it.
         */
 -      if (request)
 -              intel_engine_init_seqno(engine, request->fence.seqno);
 +      intel_engine_init_seqno(engine, engine->last_submitted_seqno);
  
        /*
         * Clear the execlists queue up before freeing the requests, as those
         * implicit references on things like e.g. ppgtt address spaces through
         * the request.
         */
 +      request = i915_gem_active_raw(&engine->last_request,
 +                                    &engine->i915->drm.struct_mutex);
        if (request)
                i915_gem_request_retire_upto(request);
        GEM_BUG_ON(intel_engine_is_active(engine));
@@@ -2571,6 -2526,7 +2571,6 @@@ i915_gem_idle_work_handler(struct work_
                container_of(work, typeof(*dev_priv), gt.idle_work.work);
        struct drm_device *dev = &dev_priv->drm;
        struct intel_engine_cs *engine;
 -      unsigned int stuck_engines;
        bool rearm_hangcheck;
  
        if (!READ_ONCE(dev_priv->gt.awake))
        dev_priv->gt.awake = false;
        rearm_hangcheck = false;
  
 -      /* As we have disabled hangcheck, we need to unstick any waiters still
 -       * hanging around. However, as we may be racing against the interrupt
 -       * handler or the waiters themselves, we skip enabling the fake-irq.
 -       */
 -      stuck_engines = intel_kick_waiters(dev_priv);
 -      if (unlikely(stuck_engines))
 -              DRM_DEBUG_DRIVER("kicked stuck waiters (%x)...missed irq?\n",
 -                               stuck_engines);
 -
        if (INTEL_GEN(dev_priv) >= 6)
                gen6_rps_idle(dev_priv);
        intel_runtime_pm_put(dev_priv);
@@@ -3770,7 -3735,7 +3770,7 @@@ i915_gem_object_ggtt_unpin_view(struct 
        i915_vma_unpin(i915_gem_obj_to_ggtt_view(obj, view));
  }
  
 -static __always_inline unsigned __busy_read_flag(unsigned int id)
 +static __always_inline unsigned int __busy_read_flag(unsigned int id)
  {
        /* Note that we could alias engines in the execbuf API, but
         * that would be very unwise as it prevents userspace from
  
  static __always_inline unsigned int __busy_write_id(unsigned int id)
  {
 -      return id;
 +      /* The uABI guarantees an active writer is also amongst the read
 +       * engines. This would be true if we accessed the activity tracking
 +       * under the lock, but as we perform the lookup of the object and
 +       * its activity locklessly we can not guarantee that the last_write
 +       * being active implies that we have set the same engine flag from
 +       * last_read - hence we always set both read and write busy for
 +       * last_write.
 +       */
 +      return id | __busy_read_flag(id);
  }
  
 -static __always_inline unsigned
 +static __always_inline unsigned int
  __busy_set_if_active(const struct i915_gem_active *active,
                     unsigned int (*flag)(unsigned int id))
  {
  
                id = request->engine->exec_id;
  
 -              /* Check that the pointer wasn't reassigned and overwritten. */
 +              /* Check that the pointer wasn't reassigned and overwritten.
 +               *
 +               * In __i915_gem_active_get_rcu(), we enforce ordering between
 +               * the first rcu pointer dereference (imposing a
 +               * read-dependency only on access through the pointer) and
 +               * the second lockless access through the memory barrier
 +               * following a successful atomic_inc_not_zero(). Here there
 +               * is no such barrier, and so we must manually insert an
 +               * explicit read barrier to ensure that the following
 +               * access occurs after all the loads through the first
 +               * pointer.
 +               *
 +               * It is worth comparing this sequence with
 +               * raw_write_seqcount_latch() which operates very similarly.
 +               * The challenge here is the visibility of the other CPU
 +               * writes to the reallocated request vs the local CPU ordering.
 +               * Before the other CPU can overwrite the request, it will
 +               * have updated our active->request and gone through a wmb.
 +               * During the read here, we want to make sure that the values
 +               * we see have not been overwritten as we do so - and we do
 +               * that by serialising the second pointer check with the writes
 +               * on other other CPUs.
 +               *
 +               * The corresponding write barrier is part of
 +               * rcu_assign_pointer().
 +               */
 +              smp_rmb();
                if (request == rcu_access_pointer(active->request))
                        return flag(id);
        } while (1);
  }
  
 -static inline unsigned
 +static __always_inline unsigned int
  busy_check_reader(const struct i915_gem_active *active)
  {
        return __busy_set_if_active(active, __busy_read_flag);
  }
  
 -static inline unsigned
 +static __always_inline unsigned int
  busy_check_writer(const struct i915_gem_active *active)
  {
        return __busy_set_if_active(active, __busy_write_id);
@@@ -3902,11 -3833,9 +3902,11 @@@ i915_gem_busy_ioctl(struct drm_device *
                        args->busy |= busy_check_reader(&obj->last_read[idx]);
  
                /* For ABI sanity, we only care that the write engine is in
 -               * the set of read engines. This is ensured by the ordering
 -               * of setting last_read/last_write in i915_vma_move_to_active,
 -               * and then in reverse in retire.
 +               * the set of read engines. This should be ensured by the
 +               * ordering of setting last_read/last_write in
 +               * i915_vma_move_to_active(), and then in reverse in retire.
 +               * However, for good measure, we always report the last_write
 +               * request as a busy read as well as being a busy write.
                 *
                 * We don't care that the set of active read/write engines
                 * may change during construction of the result, as it is
@@@ -4033,7 -3962,7 +4033,7 @@@ struct drm_i915_gem_object *i915_gem_ob
                mask |= __GFP_DMA32;
        }
  
-       mapping = file_inode(obj->base.filp)->i_mapping;
+       mapping = obj->base.filp->f_mapping;
        mapping_set_gfp_mask(mapping, mask);
  
        i915_gem_object_init(obj, &i915_gem_object_ops);
@@@ -1202,8 -1202,8 +1202,8 @@@ void assert_panel_unlocked(struct drm_i
        if (HAS_PCH_SPLIT(dev)) {
                u32 port_sel;
  
 -              pp_reg = PCH_PP_CONTROL;
 -              port_sel = I915_READ(PCH_PP_ON_DELAYS) & PANEL_PORT_SELECT_MASK;
 +              pp_reg = PP_CONTROL(0);
 +              port_sel = I915_READ(PP_ON_DELAYS(0)) & PANEL_PORT_SELECT_MASK;
  
                if (port_sel == PANEL_PORT_SELECT_LVDS &&
                    I915_READ(PCH_LVDS) & LVDS_PIPEB_SELECT)
                /* XXX: else fix for eDP */
        } else if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
                /* presumably write lock depends on pipe, not port select */
 -              pp_reg = VLV_PIPE_PP_CONTROL(pipe);
 +              pp_reg = PP_CONTROL(pipe);
                panel_pipe = pipe;
        } else {
 -              pp_reg = PP_CONTROL;
 +              pp_reg = PP_CONTROL(0);
                if (I915_READ(LVDS) & LVDS_PIPEB_SELECT)
                        panel_pipe = PIPE_B;
        }
@@@ -1959,12 -1959,12 +1959,12 @@@ static void intel_enable_pipe(struct in
         * a plane.  On ILK+ the pipe PLLs are integrated, so we don't
         * need the check.
         */
 -      if (HAS_GMCH_DISPLAY(dev_priv))
 +      if (HAS_GMCH_DISPLAY(dev_priv)) {
                if (intel_crtc_has_type(crtc->config, INTEL_OUTPUT_DSI))
                        assert_dsi_pll_enabled(dev_priv);
                else
                        assert_pll_enabled(dev_priv, pipe);
 -      else {
 +      else {
                if (crtc->config->has_pch_encoder) {
                        /* if driving the PCH, we need FDI enabled */
                        assert_fdi_rx_pll_enabled(dev_priv, pch_transcoder);
@@@ -2147,6 -2147,33 +2147,6 @@@ intel_fill_fb_ggtt_view(struct i915_ggt
        }
  }
  
 -static void
 -intel_fill_fb_info(struct drm_i915_private *dev_priv,
 -                 struct drm_framebuffer *fb)
 -{
 -      struct intel_rotation_info *info = &to_intel_framebuffer(fb)->rot_info;
 -      unsigned int tile_size, tile_width, tile_height, cpp;
 -
 -      tile_size = intel_tile_size(dev_priv);
 -
 -      cpp = drm_format_plane_cpp(fb->pixel_format, 0);
 -      intel_tile_dims(dev_priv, &tile_width, &tile_height,
 -                      fb->modifier[0], cpp);
 -
 -      info->plane[0].width = DIV_ROUND_UP(fb->pitches[0], tile_width * cpp);
 -      info->plane[0].height = DIV_ROUND_UP(fb->height, tile_height);
 -
 -      if (info->pixel_format == DRM_FORMAT_NV12) {
 -              cpp = drm_format_plane_cpp(fb->pixel_format, 1);
 -              intel_tile_dims(dev_priv, &tile_width, &tile_height,
 -                              fb->modifier[1], cpp);
 -
 -              info->uv_offset = fb->offsets[1];
 -              info->plane[1].width = DIV_ROUND_UP(fb->pitches[1], tile_width * cpp);
 -              info->plane[1].height = DIV_ROUND_UP(fb->height / 2, tile_height);
 -      }
 -}
 -
  static unsigned int intel_linear_alignment(const struct drm_i915_private *dev_priv)
  {
        if (INTEL_INFO(dev_priv)->gen >= 9)
@@@ -2267,67 -2294,21 +2267,67 @@@ void intel_unpin_fb_obj(struct drm_fram
        i915_gem_object_unpin_from_display_plane(obj, &view);
  }
  
 +static int intel_fb_pitch(const struct drm_framebuffer *fb, int plane,
 +                        unsigned int rotation)
 +{
 +      if (intel_rotation_90_or_270(rotation))
 +              return to_intel_framebuffer(fb)->rotated[plane].pitch;
 +      else
 +              return fb->pitches[plane];
 +}
 +
 +/*
 + * Convert the x/y offsets into a linear offset.
 + * Only valid with 0/180 degree rotation, which is fine since linear
 + * offset is only used with linear buffers on pre-hsw and tiled buffers
 + * with gen2/3, and 90/270 degree rotations isn't supported on any of them.
 + */
 +u32 intel_fb_xy_to_linear(int x, int y,
 +                        const struct intel_plane_state *state,
 +                        int plane)
 +{
 +      const struct drm_framebuffer *fb = state->base.fb;
 +      unsigned int cpp = drm_format_plane_cpp(fb->pixel_format, plane);
 +      unsigned int pitch = fb->pitches[plane];
 +
 +      return y * pitch + x * cpp;
 +}
 +
 +/*
 + * Add the x/y offsets derived from fb->offsets[] to the user
 + * specified plane src x/y offsets. The resulting x/y offsets
 + * specify the start of scanout from the beginning of the gtt mapping.
 + */
 +void intel_add_fb_offsets(int *x, int *y,
 +                        const struct intel_plane_state *state,
 +                        int plane)
 +
 +{
 +      const struct intel_framebuffer *intel_fb = to_intel_framebuffer(state->base.fb);
 +      unsigned int rotation = state->base.rotation;
 +
 +      if (intel_rotation_90_or_270(rotation)) {
 +              *x += intel_fb->rotated[plane].x;
 +              *y += intel_fb->rotated[plane].y;
 +      } else {
 +              *x += intel_fb->normal[plane].x;
 +              *y += intel_fb->normal[plane].y;
 +      }
 +}
 +
  /*
 - * Adjust the tile offset by moving the difference into
 - * the x/y offsets.
 - *
   * Input tile dimensions and pitch must already be
   * rotated to match x and y, and in pixel units.
   */
 -static u32 intel_adjust_tile_offset(int *x, int *y,
 -                                  unsigned int tile_width,
 -                                  unsigned int tile_height,
 -                                  unsigned int tile_size,
 -                                  unsigned int pitch_tiles,
 -                                  u32 old_offset,
 -                                  u32 new_offset)
 -{
 +static u32 _intel_adjust_tile_offset(int *x, int *y,
 +                                   unsigned int tile_width,
 +                                   unsigned int tile_height,
 +                                   unsigned int tile_size,
 +                                   unsigned int pitch_tiles,
 +                                   u32 old_offset,
 +                                   u32 new_offset)
 +{
 +      unsigned int pitch_pixels = pitch_tiles * tile_width;
        unsigned int tiles;
  
        WARN_ON(old_offset & (tile_size - 1));
        *y += tiles / pitch_tiles * tile_height;
        *x += tiles % pitch_tiles * tile_width;
  
 +      /* minimize x in case it got needlessly big */
 +      *y += *x / pitch_pixels * tile_height;
 +      *x %= pitch_pixels;
 +
 +      return new_offset;
 +}
 +
 +/*
 + * Adjust the tile offset by moving the difference into
 + * the x/y offsets.
 + */
 +static u32 intel_adjust_tile_offset(int *x, int *y,
 +                                  const struct intel_plane_state *state, int plane,
 +                                  u32 old_offset, u32 new_offset)
 +{
 +      const struct drm_i915_private *dev_priv = to_i915(state->base.plane->dev);
 +      const struct drm_framebuffer *fb = state->base.fb;
 +      unsigned int cpp = drm_format_plane_cpp(fb->pixel_format, plane);
 +      unsigned int rotation = state->base.rotation;
 +      unsigned int pitch = intel_fb_pitch(fb, plane, rotation);
 +
 +      WARN_ON(new_offset > old_offset);
 +
 +      if (fb->modifier[plane] != DRM_FORMAT_MOD_NONE) {
 +              unsigned int tile_size, tile_width, tile_height;
 +              unsigned int pitch_tiles;
 +
 +              tile_size = intel_tile_size(dev_priv);
 +              intel_tile_dims(dev_priv, &tile_width, &tile_height,
 +                              fb->modifier[plane], cpp);
 +
 +              if (intel_rotation_90_or_270(rotation)) {
 +                      pitch_tiles = pitch / tile_height;
 +                      swap(tile_width, tile_height);
 +              } else {
 +                      pitch_tiles = pitch / (tile_width * cpp);
 +              }
 +
 +              _intel_adjust_tile_offset(x, y, tile_width, tile_height,
 +                                        tile_size, pitch_tiles,
 +                                        old_offset, new_offset);
 +      } else {
 +              old_offset += *y * pitch + *x * cpp;
 +
 +              *y = (old_offset - new_offset) / pitch;
 +              *x = ((old_offset - new_offset) - *y * pitch) / cpp;
 +      }
 +
        return new_offset;
  }
  
   * In the 90/270 rotated case, x and y are assumed
   * to be already rotated to match the rotated GTT view, and
   * pitch is the tile_height aligned framebuffer height.
 + *
 + * This function is used when computing the derived information
 + * under intel_framebuffer, so using any of that information
 + * here is not allowed. Anything under drm_framebuffer can be
 + * used. This is why the user has to pass in the pitch since it
 + * is specified in the rotated orientation.
   */
 -u32 intel_compute_tile_offset(int *x, int *y,
 -                            const struct drm_framebuffer *fb, int plane,
 -                            unsigned int pitch,
 -                            unsigned int rotation)
 +static u32 _intel_compute_tile_offset(const struct drm_i915_private *dev_priv,
 +                                    int *x, int *y,
 +                                    const struct drm_framebuffer *fb, int plane,
 +                                    unsigned int pitch,
 +                                    unsigned int rotation,
 +                                    u32 alignment)
  {
 -      const struct drm_i915_private *dev_priv = to_i915(fb->dev);
        uint64_t fb_modifier = fb->modifier[plane];
        unsigned int cpp = drm_format_plane_cpp(fb->pixel_format, plane);
 -      u32 offset, offset_aligned, alignment;
 +      u32 offset, offset_aligned;
  
 -      alignment = intel_surf_alignment(dev_priv, fb_modifier);
        if (alignment)
                alignment--;
  
                offset = (tile_rows * pitch_tiles + tiles) * tile_size;
                offset_aligned = offset & ~alignment;
  
 -              intel_adjust_tile_offset(x, y, tile_width, tile_height,
 -                                       tile_size, pitch_tiles,
 -                                       offset, offset_aligned);
 +              _intel_adjust_tile_offset(x, y, tile_width, tile_height,
 +                                        tile_size, pitch_tiles,
 +                                        offset, offset_aligned);
        } else {
                offset = *y * pitch + *x * cpp;
                offset_aligned = offset & ~alignment;
        return offset_aligned;
  }
  
-                                                   BIT(DRM_ROTATE_0), tile_size);
 +u32 intel_compute_tile_offset(int *x, int *y,
 +                            const struct intel_plane_state *state,
 +                            int plane)
 +{
 +      const struct drm_i915_private *dev_priv = to_i915(state->base.plane->dev);
 +      const struct drm_framebuffer *fb = state->base.fb;
 +      unsigned int rotation = state->base.rotation;
 +      int pitch = intel_fb_pitch(fb, plane, rotation);
 +      u32 alignment;
 +
 +      /* AUX_DIST needs only 4K alignment */
 +      if (fb->pixel_format == DRM_FORMAT_NV12 && plane == 1)
 +              alignment = 4096;
 +      else
 +              alignment = intel_surf_alignment(dev_priv, fb->modifier[plane]);
 +
 +      return _intel_compute_tile_offset(dev_priv, x, y, fb, plane, pitch,
 +                                        rotation, alignment);
 +}
 +
 +/* Convert the fb->offset[] linear offset into x/y offsets */
 +static void intel_fb_offset_to_xy(int *x, int *y,
 +                                const struct drm_framebuffer *fb, int plane)
 +{
 +      unsigned int cpp = drm_format_plane_cpp(fb->pixel_format, plane);
 +      unsigned int pitch = fb->pitches[plane];
 +      u32 linear_offset = fb->offsets[plane];
 +
 +      *y = linear_offset / pitch;
 +      *x = linear_offset % pitch / cpp;
 +}
 +
 +static unsigned int intel_fb_modifier_to_tiling(uint64_t fb_modifier)
 +{
 +      switch (fb_modifier) {
 +      case I915_FORMAT_MOD_X_TILED:
 +              return I915_TILING_X;
 +      case I915_FORMAT_MOD_Y_TILED:
 +              return I915_TILING_Y;
 +      default:
 +              return I915_TILING_NONE;
 +      }
 +}
 +
 +static int
 +intel_fill_fb_info(struct drm_i915_private *dev_priv,
 +                 struct drm_framebuffer *fb)
 +{
 +      struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
 +      struct intel_rotation_info *rot_info = &intel_fb->rot_info;
 +      u32 gtt_offset_rotated = 0;
 +      unsigned int max_size = 0;
 +      uint32_t format = fb->pixel_format;
 +      int i, num_planes = drm_format_num_planes(format);
 +      unsigned int tile_size = intel_tile_size(dev_priv);
 +
 +      for (i = 0; i < num_planes; i++) {
 +              unsigned int width, height;
 +              unsigned int cpp, size;
 +              u32 offset;
 +              int x, y;
 +
 +              cpp = drm_format_plane_cpp(format, i);
 +              width = drm_format_plane_width(fb->width, format, i);
 +              height = drm_format_plane_height(fb->height, format, i);
 +
 +              intel_fb_offset_to_xy(&x, &y, fb, i);
 +
 +              /*
 +               * The fence (if used) is aligned to the start of the object
 +               * so having the framebuffer wrap around across the edge of the
 +               * fenced region doesn't really work. We have no API to configure
 +               * the fence start offset within the object (nor could we probably
 +               * on gen2/3). So it's just easier if we just require that the
 +               * fb layout agrees with the fence layout. We already check that the
 +               * fb stride matches the fence stride elsewhere.
 +               */
 +              if (i915_gem_object_is_tiled(intel_fb->obj) &&
 +                  (x + width) * cpp > fb->pitches[i]) {
 +                      DRM_DEBUG("bad fb plane %d offset: 0x%x\n",
 +                                i, fb->offsets[i]);
 +                      return -EINVAL;
 +              }
 +
 +              /*
 +               * First pixel of the framebuffer from
 +               * the start of the normal gtt mapping.
 +               */
 +              intel_fb->normal[i].x = x;
 +              intel_fb->normal[i].y = y;
 +
 +              offset = _intel_compute_tile_offset(dev_priv, &x, &y,
 +                                                  fb, 0, fb->pitches[i],
-                                       BIT(DRM_ROTATE_270));
++                                                  DRM_ROTATE_0, tile_size);
 +              offset /= tile_size;
 +
 +              if (fb->modifier[i] != DRM_FORMAT_MOD_NONE) {
 +                      unsigned int tile_width, tile_height;
 +                      unsigned int pitch_tiles;
 +                      struct drm_rect r;
 +
 +                      intel_tile_dims(dev_priv, &tile_width, &tile_height,
 +                                      fb->modifier[i], cpp);
 +
 +                      rot_info->plane[i].offset = offset;
 +                      rot_info->plane[i].stride = DIV_ROUND_UP(fb->pitches[i], tile_width * cpp);
 +                      rot_info->plane[i].width = DIV_ROUND_UP(x + width, tile_width);
 +                      rot_info->plane[i].height = DIV_ROUND_UP(y + height, tile_height);
 +
 +                      intel_fb->rotated[i].pitch =
 +                              rot_info->plane[i].height * tile_height;
 +
 +                      /* how many tiles does this plane need */
 +                      size = rot_info->plane[i].stride * rot_info->plane[i].height;
 +                      /*
 +                       * If the plane isn't horizontally tile aligned,
 +                       * we need one more tile.
 +                       */
 +                      if (x != 0)
 +                              size++;
 +
 +                      /* 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,
 +                                      rot_info->plane[i].width * tile_width,
 +                                      rot_info->plane[i].height * tile_height,
++                                      DRM_ROTATE_270);
 +                      x = r.x1;
 +                      y = r.y1;
 +
 +                      /* rotate the tile dimensions to match the GTT view */
 +                      pitch_tiles = intel_fb->rotated[i].pitch / tile_height;
 +                      swap(tile_width, tile_height);
 +
 +                      /*
 +                       * 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_size,
 +                                                tile_width, tile_height, pitch_tiles,
 +                                                gtt_offset_rotated * tile_size, 0);
 +
 +                      gtt_offset_rotated += rot_info->plane[i].width * rot_info->plane[i].height;
 +
 +                      /*
 +                       * First pixel of the framebuffer from
 +                       * the start of the rotated gtt mapping.
 +                       */
 +                      intel_fb->rotated[i].x = x;
 +                      intel_fb->rotated[i].y = y;
 +              } else {
 +                      size = DIV_ROUND_UP((y + height) * fb->pitches[i] +
 +                                          x * cpp, tile_size);
 +              }
 +
 +              /* how many tiles in total needed in the bo */
 +              max_size = max(max_size, offset + size);
 +      }
 +
 +      if (max_size * tile_size > to_intel_framebuffer(fb)->obj->base.size) {
 +              DRM_DEBUG("fb too big for bo (need %u bytes, have %zu bytes)\n",
 +                        max_size * tile_size, to_intel_framebuffer(fb)->obj->base.size);
 +              return -EINVAL;
 +      }
 +
 +      return 0;
 +}
 +
  static int i9xx_format_to_fourcc(int format)
  {
        switch (format) {
@@@ -2809,7 -2565,7 +2809,7 @@@ intel_find_initial_plane_obj(struct int
         * simplest solution is to just disable the primary plane now and
         * pretend the BIOS never had it enabled.
         */
-       to_intel_plane_state(plane_state)->visible = false;
+       to_intel_plane_state(plane_state)->base.visible = false;
        crtc_state->plane_mask &= ~(1 << drm_plane_index(primary));
        intel_pre_disable_primary_noatomic(&intel_crtc->base);
        intel_plane->disable_plane(primary, &intel_crtc->base);
@@@ -2827,14 -2583,14 +2827,14 @@@ valid_fb
        plane_state->crtc_w = fb->width;
        plane_state->crtc_h = fb->height;
  
-       intel_state->src.x1 = plane_state->src_x;
-       intel_state->src.y1 = plane_state->src_y;
-       intel_state->src.x2 = plane_state->src_x + plane_state->src_w;
-       intel_state->src.y2 = plane_state->src_y + plane_state->src_h;
-       intel_state->dst.x1 = plane_state->crtc_x;
-       intel_state->dst.y1 = plane_state->crtc_y;
-       intel_state->dst.x2 = plane_state->crtc_x + plane_state->crtc_w;
-       intel_state->dst.y2 = plane_state->crtc_y + plane_state->crtc_h;
+       intel_state->base.src.x1 = plane_state->src_x;
+       intel_state->base.src.y1 = plane_state->src_y;
+       intel_state->base.src.x2 = plane_state->src_x + plane_state->src_w;
+       intel_state->base.src.y2 = plane_state->src_y + plane_state->src_h;
+       intel_state->base.dst.x1 = plane_state->crtc_x;
+       intel_state->base.dst.y1 = plane_state->crtc_y;
+       intel_state->base.dst.x2 = plane_state->crtc_x + plane_state->crtc_w;
+       intel_state->base.dst.y2 = plane_state->crtc_y + plane_state->crtc_h;
  
        obj = intel_fb_obj(fb);
        if (i915_gem_object_is_tiled(obj))
                  &obj->frontbuffer_bits);
  }
  
-       int x = plane_state->src.x1 >> 16;
-       int y = plane_state->src.y1 >> 16;
-       int w = drm_rect_width(&plane_state->src) >> 16;
-       int h = drm_rect_height(&plane_state->src) >> 16;
 +static int skl_max_plane_width(const struct drm_framebuffer *fb, int plane,
 +                             unsigned int rotation)
 +{
 +      int cpp = drm_format_plane_cpp(fb->pixel_format, plane);
 +
 +      switch (fb->modifier[plane]) {
 +      case DRM_FORMAT_MOD_NONE:
 +      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;
 +      case I915_FORMAT_MOD_Y_TILED:
 +      case I915_FORMAT_MOD_Yf_TILED:
 +              switch (cpp) {
 +              case 8:
 +                      return 2048;
 +              case 4:
 +                      return 4096;
 +              case 2:
 +              case 1:
 +                      return 8192;
 +              default:
 +                      MISSING_CASE(cpp);
 +                      break;
 +              }
 +              break;
 +      default:
 +              MISSING_CASE(fb->modifier[plane]);
 +      }
 +
 +      return 2048;
 +}
 +
 +static int skl_check_main_surface(struct intel_plane_state *plane_state)
 +{
 +      const 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->src.x1 >> 17;
-       int y = plane_state->src.y1 >> 17;
-       int w = drm_rect_width(&plane_state->src) >> 17;
-       int h = drm_rect_height(&plane_state->src) >> 17;
++      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_height = 4096;
 +      u32 alignment, offset, aux_offset = plane_state->aux.offset;
 +
 +      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);
 +              return -EINVAL;
 +      }
 +
 +      intel_add_fb_offsets(&x, &y, plane_state, 0);
 +      offset = intel_compute_tile_offset(&x, &y, plane_state, 0);
 +
 +      alignment = intel_surf_alignment(dev_priv, fb->modifier[0]);
 +
 +      /*
 +       * AUX surface offset is specified as the distance from the
 +       * main surface offset, and it must be non-negative. Make
 +       * sure that is what we will get.
 +       */
 +      if (offset > aux_offset)
 +              offset = intel_adjust_tile_offset(&x, &y, plane_state, 0,
 +                                                offset, aux_offset & ~(alignment - 1));
 +
 +      /*
 +       * When using an X-tiled surface, the plane blows up
 +       * if the x offset + width exceed the stride.
 +       *
 +       * TODO: linear and Y-tiled seem fine, Yf untested,
 +       */
 +      if (fb->modifier[0] == I915_FORMAT_MOD_X_TILED) {
 +              int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
 +
 +              while ((x + w) * cpp > fb->pitches[0]) {
 +                      if (offset == 0) {
 +                              DRM_DEBUG_KMS("Unable to find suitable display surface offset\n");
 +                              return -EINVAL;
 +                      }
 +
 +                      offset = intel_adjust_tile_offset(&x, &y, plane_state, 0,
 +                                                        offset, offset - alignment);
 +              }
 +      }
 +
 +      plane_state->main.offset = offset;
 +      plane_state->main.x = x;
 +      plane_state->main.y = y;
 +
 +      return 0;
 +}
 +
 +static int skl_check_nv12_aux_surface(struct intel_plane_state *plane_state)
 +{
 +      const struct drm_framebuffer *fb = plane_state->base.fb;
 +      unsigned int rotation = plane_state->base.rotation;
 +      int max_width = skl_max_plane_width(fb, 1, rotation);
 +      int max_height = 4096;
-               drm_rect_rotate(&plane_state->src,
-                               fb->width, fb->height, BIT(DRM_ROTATE_270));
++      int x = plane_state->base.src.x1 >> 17;
++      int y = plane_state->base.src.y1 >> 17;
++      int w = drm_rect_width(&plane_state->base.src) >> 17;
++      int h = drm_rect_height(&plane_state->base.src) >> 17;
 +      u32 offset;
 +
 +      intel_add_fb_offsets(&x, &y, plane_state, 1);
 +      offset = intel_compute_tile_offset(&x, &y, plane_state, 1);
 +
 +      /* FIXME not quite sure how/if these apply to the chroma plane */
 +      if (w > max_width || h > max_height) {
 +              DRM_DEBUG_KMS("CbCr source size %dx%d too big (limit %dx%d)\n",
 +                            w, h, max_width, max_height);
 +              return -EINVAL;
 +      }
 +
 +      plane_state->aux.offset = offset;
 +      plane_state->aux.x = x;
 +      plane_state->aux.y = y;
 +
 +      return 0;
 +}
 +
 +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;
 +
 +      /* Rotate src coordinates to match rotated GTT view */
 +      if (intel_rotation_90_or_270(rotation))
++              drm_rect_rotate(&plane_state->base.src,
++                              fb->width, fb->height, DRM_ROTATE_270);
 +
 +      /*
 +       * Handle the AUX surface first since
 +       * the main surface setup depends on it.
 +       */
 +      if (fb->pixel_format == DRM_FORMAT_NV12) {
 +              ret = skl_check_nv12_aux_surface(plane_state);
 +              if (ret)
 +                      return ret;
 +      } else {
 +              plane_state->aux.offset = ~0xfff;
 +              plane_state->aux.x = 0;
 +              plane_state->aux.y = 0;
 +      }
 +
 +      ret = skl_check_main_surface(plane_state);
 +      if (ret)
 +              return ret;
 +
 +      return 0;
 +}
 +
  static void i9xx_update_primary_plane(struct drm_plane *primary,
                                      const struct intel_crtc_state *crtc_state,
                                      const struct intel_plane_state *plane_state)
        u32 dspcntr;
        i915_reg_t reg = DSPCNTR(plane);
        unsigned int rotation = plane_state->base.rotation;
-       int x = plane_state->src.x1 >> 16;
-       int y = plane_state->src.y1 >> 16;
 -      int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
+       int x = plane_state->base.src.x1 >> 16;
+       int y = plane_state->base.src.y1 >> 16;
  
        dspcntr = DISPPLANE_GAMMA_ENABLE;
  
                BUG();
        }
  
 -      if (INTEL_INFO(dev)->gen >= 4 && i915_gem_object_is_tiled(obj))
 +      if (INTEL_GEN(dev_priv) >= 4 &&
 +          fb->modifier[0] == I915_FORMAT_MOD_X_TILED)
                dspcntr |= DISPPLANE_TILED;
  
        if (IS_G4X(dev))
                dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
  
 -      linear_offset = y * fb->pitches[0] + x * cpp;
 +      intel_add_fb_offsets(&x, &y, plane_state, 0);
  
 -      if (INTEL_INFO(dev)->gen >= 4) {
 +      if (INTEL_INFO(dev)->gen >= 4)
                intel_crtc->dspaddr_offset =
 -                      intel_compute_tile_offset(&x, &y, fb, 0,
 -                                                fb->pitches[0], rotation);
 -              linear_offset -= intel_crtc->dspaddr_offset;
 -      } else {
 -              intel_crtc->dspaddr_offset = linear_offset;
 -      }
 +                      intel_compute_tile_offset(&x, &y, plane_state, 0);
  
-       if (rotation == BIT(DRM_ROTATE_180)) {
+       if (rotation == DRM_ROTATE_180) {
                dspcntr |= DISPPLANE_ROTATE_180;
  
                x += (crtc_state->pipe_src_w - 1);
                y += (crtc_state->pipe_src_h - 1);
 -
 -              /* Finding the last pixel of the last line of the display
 -              data and adding to linear_offset*/
 -              linear_offset +=
 -                      (crtc_state->pipe_src_h - 1) * fb->pitches[0] +
 -                      (crtc_state->pipe_src_w - 1) * cpp;
        }
  
 +      linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0);
 +
 +      if (INTEL_INFO(dev)->gen < 4)
 +              intel_crtc->dspaddr_offset = linear_offset;
 +
        intel_crtc->adjusted_x = x;
        intel_crtc->adjusted_y = y;
  
        I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]);
        if (INTEL_INFO(dev)->gen >= 4) {
                I915_WRITE(DSPSURF(plane),
 -                         i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);
 +                         intel_fb_gtt_offset(fb, rotation) +
 +                         intel_crtc->dspaddr_offset);
                I915_WRITE(DSPTILEOFF(plane), (y << 16) | x);
                I915_WRITE(DSPLINOFF(plane), linear_offset);
        } else
@@@ -3143,13 -2741,15 +3143,13 @@@ static void ironlake_update_primary_pla
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
        struct drm_framebuffer *fb = plane_state->base.fb;
 -      struct drm_i915_gem_object *obj = intel_fb_obj(fb);
        int plane = intel_crtc->plane;
        u32 linear_offset;
        u32 dspcntr;
        i915_reg_t reg = DSPCNTR(plane);
        unsigned int rotation = plane_state->base.rotation;
-       int x = plane_state->src.x1 >> 16;
-       int y = plane_state->src.y1 >> 16;
 -      int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
+       int x = plane_state->base.src.x1 >> 16;
+       int y = plane_state->base.src.y1 >> 16;
  
        dspcntr = DISPPLANE_GAMMA_ENABLE;
        dspcntr |= DISPLAY_PLANE_ENABLE;
                BUG();
        }
  
 -      if (i915_gem_object_is_tiled(obj))
 +      if (fb->modifier[0] == I915_FORMAT_MOD_X_TILED)
                dspcntr |= DISPPLANE_TILED;
  
        if (!IS_HASWELL(dev) && !IS_BROADWELL(dev))
                dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
  
 -      linear_offset = y * fb->pitches[0] + x * cpp;
 +      intel_add_fb_offsets(&x, &y, plane_state, 0);
 +
        intel_crtc->dspaddr_offset =
 -              intel_compute_tile_offset(&x, &y, fb, 0,
 -                                        fb->pitches[0], rotation);
 -      linear_offset -= intel_crtc->dspaddr_offset;
 +              intel_compute_tile_offset(&x, &y, plane_state, 0);
 +
-       if (rotation == BIT(DRM_ROTATE_180)) {
+       if (rotation == DRM_ROTATE_180) {
                dspcntr |= DISPPLANE_ROTATE_180;
  
                if (!IS_HASWELL(dev) && !IS_BROADWELL(dev)) {
                        x += (crtc_state->pipe_src_w - 1);
                        y += (crtc_state->pipe_src_h - 1);
 -
 -                      /* Finding the last pixel of the last line of the display
 -                      data and adding to linear_offset*/
 -                      linear_offset +=
 -                              (crtc_state->pipe_src_h - 1) * fb->pitches[0] +
 -                              (crtc_state->pipe_src_w - 1) * cpp;
                }
        }
  
 +      linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0);
 +
        intel_crtc->adjusted_x = x;
        intel_crtc->adjusted_y = y;
  
  
        I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]);
        I915_WRITE(DSPSURF(plane),
 -                 i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);
 +                 intel_fb_gtt_offset(fb, rotation) +
 +                 intel_crtc->dspaddr_offset);
        if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
                I915_WRITE(DSPOFFSET(plane), (y << 16) | x);
        } else {
@@@ -3232,16 -2835,28 +3232,16 @@@ u32 intel_fb_stride_alignment(const str
        }
  }
  
 -u32 intel_plane_obj_offset(struct intel_plane *intel_plane,
 -                         struct drm_i915_gem_object *obj,
 -                         unsigned int plane)
 +u32 intel_fb_gtt_offset(struct drm_framebuffer *fb,
 +                      unsigned int rotation)
  {
 +      struct drm_i915_gem_object *obj = intel_fb_obj(fb);
        struct i915_ggtt_view view;
 -      struct i915_vma *vma;
        u64 offset;
  
 -      intel_fill_fb_ggtt_view(&view, intel_plane->base.state->fb,
 -                              intel_plane->base.state->rotation);
 -
 -      vma = i915_gem_obj_to_ggtt_view(obj, &view);
 -      if (WARN(!vma, "ggtt vma for display object not found! (view=%u)\n",
 -              view.type))
 -              return -1;
 -
 -      offset = vma->node.start;
 +      intel_fill_fb_ggtt_view(&view, fb, rotation);
  
 -      if (plane == 1) {
 -              offset += vma->ggtt_view.params.rotated.uv_start_page *
 -                        PAGE_SIZE;
 -      }
 +      offset = i915_gem_obj_ggtt_offset_view(obj, &view);
  
        WARN_ON(upper_32_bits(offset));
  
@@@ -3275,28 -2890,6 +3275,28 @@@ static void skl_detach_scalers(struct i
        }
  }
  
 +u32 skl_plane_stride(const struct drm_framebuffer *fb, int plane,
 +                   unsigned int rotation)
 +{
 +      const struct drm_i915_private *dev_priv = to_i915(fb->dev);
 +      u32 stride = intel_fb_pitch(fb, plane, rotation);
 +
 +      /*
 +       * The stride is either expressed as a multiple of 64 bytes chunks for
 +       * linear buffers or in number of tiles for tiled buffers.
 +       */
 +      if (intel_rotation_90_or_270(rotation)) {
 +              int cpp = drm_format_plane_cpp(fb->pixel_format, plane);
 +
 +              stride /= intel_tile_height(dev_priv, fb->modifier[0], cpp);
 +      } else {
 +              stride /= intel_fb_stride_alignment(dev_priv, fb->modifier[0],
 +                                                  fb->pixel_format);
 +      }
 +
 +      return stride;
 +}
 +
  u32 skl_plane_ctl_format(uint32_t pixel_format)
  {
        switch (pixel_format) {
@@@ -3359,17 -2952,17 +3359,17 @@@ u32 skl_plane_ctl_tiling(uint64_t fb_mo
  u32 skl_plane_ctl_rotation(unsigned int rotation)
  {
        switch (rotation) {
-       case BIT(DRM_ROTATE_0):
+       case DRM_ROTATE_0:
                break;
        /*
         * DRM_ROTATE_ is counter clockwise to stay compatible with Xrandr
         * while i915 HW rotation is clockwise, thats why this swapping.
         */
-       case BIT(DRM_ROTATE_90):
+       case DRM_ROTATE_90:
                return PLANE_CTL_ROTATE_270;
-       case BIT(DRM_ROTATE_180):
+       case DRM_ROTATE_180:
                return PLANE_CTL_ROTATE_180;
-       case BIT(DRM_ROTATE_270):
+       case DRM_ROTATE_270:
                return PLANE_CTL_ROTATE_90;
        default:
                MISSING_CASE(rotation);
@@@ -3386,20 -2979,22 +3386,20 @@@ static void skylake_update_primary_plan
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
        struct drm_framebuffer *fb = plane_state->base.fb;
 -      struct drm_i915_gem_object *obj = intel_fb_obj(fb);
        int pipe = intel_crtc->pipe;
 -      u32 plane_ctl, stride_div, stride;
 -      u32 tile_height, plane_offset, plane_size;
 +      u32 plane_ctl;
        unsigned int rotation = plane_state->base.rotation;
 -      int x_offset, y_offset;
 -      u32 surf_addr;
 +      u32 stride = skl_plane_stride(fb, 0, rotation);
 +      u32 surf_addr = plane_state->main.offset;
        int scaler_id = plane_state->scaler_id;
 -      int src_x = plane_state->base.src.x1 >> 16;
 -      int src_y = plane_state->base.src.y1 >> 16;
 +      int src_x = plane_state->main.x;
 +      int src_y = plane_state->main.y;
-       int src_w = drm_rect_width(&plane_state->src) >> 16;
-       int src_h = drm_rect_height(&plane_state->src) >> 16;
-       int dst_x = plane_state->dst.x1;
-       int dst_y = plane_state->dst.y1;
-       int dst_w = drm_rect_width(&plane_state->dst);
-       int dst_h = drm_rect_height(&plane_state->dst);
+       int src_w = drm_rect_width(&plane_state->base.src) >> 16;
+       int src_h = drm_rect_height(&plane_state->base.src) >> 16;
+       int dst_x = plane_state->base.dst.x1;
+       int dst_y = plane_state->base.dst.y1;
+       int dst_w = drm_rect_width(&plane_state->base.dst);
+       int dst_h = drm_rect_height(&plane_state->base.dst);
  
        plane_ctl = PLANE_CTL_ENABLE |
                    PLANE_CTL_PIPE_GAMMA_ENABLE |
        plane_ctl |= PLANE_CTL_PLANE_GAMMA_DISABLE;
        plane_ctl |= skl_plane_ctl_rotation(rotation);
  
 -      stride_div = intel_fb_stride_alignment(dev_priv, fb->modifier[0],
 -                                             fb->pixel_format);
 -      surf_addr = intel_plane_obj_offset(to_intel_plane(plane), obj, 0);
 +      /* Sizes are 0 based */
 +      src_w--;
 +      src_h--;
 +      dst_w--;
 +      dst_h--;
  
 -      WARN_ON(drm_rect_width(&plane_state->base.src) == 0);
 -
 -      if (intel_rotation_90_or_270(rotation)) {
 -              int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
 -
 -              /* stride = Surface height in tiles */
 -              tile_height = intel_tile_height(dev_priv, fb->modifier[0], cpp);
 -              stride = DIV_ROUND_UP(fb->height, tile_height);
 -              x_offset = stride * tile_height - src_y - src_h;
 -              y_offset = src_x;
 -              plane_size = (src_w - 1) << 16 | (src_h - 1);
 -      } else {
 -              stride = fb->pitches[0] / stride_div;
 -              x_offset = src_x;
 -              y_offset = src_y;
 -              plane_size = (src_h - 1) << 16 | (src_w - 1);
 -      }
 -      plane_offset = y_offset << 16 | x_offset;
 -
 -      intel_crtc->adjusted_x = x_offset;
 -      intel_crtc->adjusted_y = y_offset;
 +      intel_crtc->adjusted_x = src_x;
 +      intel_crtc->adjusted_y = src_y;
  
        I915_WRITE(PLANE_CTL(pipe, 0), plane_ctl);
 -      I915_WRITE(PLANE_OFFSET(pipe, 0), plane_offset);
 -      I915_WRITE(PLANE_SIZE(pipe, 0), plane_size);
 +      I915_WRITE(PLANE_OFFSET(pipe, 0), (src_y << 16) | src_x);
        I915_WRITE(PLANE_STRIDE(pipe, 0), stride);
 +      I915_WRITE(PLANE_SIZE(pipe, 0), (src_h << 16) | src_w);
  
        if (scaler_id >= 0) {
                uint32_t ps_ctrl = 0;
                I915_WRITE(PLANE_POS(pipe, 0), (dst_y << 16) | dst_x);
        }
  
 -      I915_WRITE(PLANE_SURF(pipe, 0), surf_addr);
 +      I915_WRITE(PLANE_SURF(pipe, 0),
 +                 intel_fb_gtt_offset(fb, rotation) + surf_addr);
  
        POSTING_READ(PLANE_SURF(pipe, 0));
  }
@@@ -3482,113 -3093,40 +3482,113 @@@ static void intel_update_primary_planes
  
        for_each_crtc(dev, crtc) {
                struct intel_plane *plane = to_intel_plane(crtc->primary);
 -              struct intel_plane_state *plane_state;
 -
 -              drm_modeset_lock_crtc(crtc, &plane->base);
 -              plane_state = to_intel_plane_state(plane->base.state);
 +              struct intel_plane_state *plane_state =
 +                      to_intel_plane_state(plane->base.state);
  
-               if (plane_state->visible)
+               if (plane_state->base.visible)
                        plane->update_plane(&plane->base,
                                            to_intel_crtc_state(crtc->state),
                                            plane_state);
 +      }
 +}
 +
 +static int
 +__intel_display_resume(struct drm_device *dev,
 +                     struct drm_atomic_state *state)
 +{
 +      struct drm_crtc_state *crtc_state;
 +      struct drm_crtc *crtc;
 +      int i, ret;
  
 -              drm_modeset_unlock_crtc(crtc);
 +      intel_modeset_setup_hw_state(dev);
 +      i915_redisable_vga(dev);
 +
 +      if (!state)
 +              return 0;
 +
 +      for_each_crtc_in_state(state, crtc, crtc_state, i) {
 +              /*
 +               * Force recalculation even if we restore
 +               * current state. With fast modeset this may not result
 +               * in a modeset when the state is compatible.
 +               */
 +              crtc_state->mode_changed = true;
        }
 +
 +      /* ignore any reset values/BIOS leftovers in the WM registers */
 +      to_intel_atomic_state(state)->skip_intermediate_wm = true;
 +
 +      ret = drm_atomic_commit(state);
 +
 +      WARN_ON(ret == -EDEADLK);
 +      return ret;
 +}
 +
 +static bool gpu_reset_clobbers_display(struct drm_i915_private *dev_priv)
 +{
 +      return intel_has_gpu_reset(dev_priv) &&
 +              INTEL_GEN(dev_priv) < 5 && !IS_G4X(dev_priv);
  }
  
  void intel_prepare_reset(struct drm_i915_private *dev_priv)
  {
 -      /* no reset support for gen2 */
 -      if (IS_GEN2(dev_priv))
 -              return;
 +      struct drm_device *dev = &dev_priv->drm;
 +      struct drm_modeset_acquire_ctx *ctx = &dev_priv->reset_ctx;
 +      struct drm_atomic_state *state;
 +      int ret;
  
 -      /* reset doesn't touch the display */
 -      if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
 +      /*
 +       * Need mode_config.mutex so that we don't
 +       * trample ongoing ->detect() and whatnot.
 +       */
 +      mutex_lock(&dev->mode_config.mutex);
 +      drm_modeset_acquire_init(ctx, 0);
 +      while (1) {
 +              ret = drm_modeset_lock_all_ctx(dev, ctx);
 +              if (ret != -EDEADLK)
 +                      break;
 +
 +              drm_modeset_backoff(ctx);
 +      }
 +
 +      /* reset doesn't touch the display, but flips might get nuked anyway, */
 +      if (!i915.force_reset_modeset_test &&
 +          !gpu_reset_clobbers_display(dev_priv))
                return;
  
 -      drm_modeset_lock_all(&dev_priv->drm);
        /*
         * Disabling the crtcs gracefully seems nicer. Also the
         * g33 docs say we should at least disable all the planes.
         */
 -      intel_display_suspend(&dev_priv->drm);
 +      state = drm_atomic_helper_duplicate_state(dev, ctx);
 +      if (IS_ERR(state)) {
 +              ret = PTR_ERR(state);
 +              state = NULL;
 +              DRM_ERROR("Duplicating state failed with %i\n", ret);
 +              goto err;
 +      }
 +
 +      ret = drm_atomic_helper_disable_all(dev, ctx);
 +      if (ret) {
 +              DRM_ERROR("Suspending crtc's failed with %i\n", ret);
 +              goto err;
 +      }
 +
 +      dev_priv->modeset_restore_state = state;
 +      state->acquire_ctx = ctx;
 +      return;
 +
 +err:
 +      drm_atomic_state_free(state);
  }
  
  void intel_finish_reset(struct drm_i915_private *dev_priv)
  {
 +      struct drm_device *dev = &dev_priv->drm;
 +      struct drm_modeset_acquire_ctx *ctx = &dev_priv->reset_ctx;
 +      struct drm_atomic_state *state = dev_priv->modeset_restore_state;
 +      int ret;
 +
        /*
         * Flips in the rings will be nuked by the reset,
         * so complete all pending flips so that user space
         */
        intel_complete_page_flips(dev_priv);
  
 -      /* no reset support for gen2 */
 -      if (IS_GEN2(dev_priv))
 -              return;
 +      dev_priv->modeset_restore_state = NULL;
  
        /* reset doesn't touch the display */
 -      if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv)) {
 +      if (!gpu_reset_clobbers_display(dev_priv)) {
 +              if (!state) {
 +                      /*
 +                       * Flips in the rings have been nuked by the reset,
 +                       * so update the base address of all primary
 +                       * planes to the the last fb to make sure we're
 +                       * showing the correct fb after a reset.
 +                       *
 +                       * FIXME: Atomic will make this obsolete since we won't schedule
 +                       * CS-based flips (which might get lost in gpu resets) any more.
 +                       */
 +                      intel_update_primary_planes(dev);
 +              } else {
 +                      ret = __intel_display_resume(dev, state);
 +                      if (ret)
 +                              DRM_ERROR("Restoring old state failed with %i\n", ret);
 +              }
 +      } else {
                /*
 -               * Flips in the rings have been nuked by the reset,
 -               * so update the base address of all primary
 -               * planes to the the last fb to make sure we're
 -               * showing the correct fb after a reset.
 -               *
 -               * FIXME: Atomic will make this obsolete since we won't schedule
 -               * CS-based flips (which might get lost in gpu resets) any more.
 +               * The display has been reset as well,
 +               * so need a full re-initialization.
                 */
 -              intel_update_primary_planes(&dev_priv->drm);
 -              return;
 -      }
 +              intel_runtime_pm_disable_interrupts(dev_priv);
 +              intel_runtime_pm_enable_interrupts(dev_priv);
  
 -      /*
 -       * The display has been reset as well,
 -       * so need a full re-initialization.
 -       */
 -      intel_runtime_pm_disable_interrupts(dev_priv);
 -      intel_runtime_pm_enable_interrupts(dev_priv);
 +              intel_modeset_init_hw(dev);
  
 -      intel_modeset_init_hw(&dev_priv->drm);
 +              spin_lock_irq(&dev_priv->irq_lock);
 +              if (dev_priv->display.hpd_irq_setup)
 +                      dev_priv->display.hpd_irq_setup(dev_priv);
 +              spin_unlock_irq(&dev_priv->irq_lock);
  
 -      spin_lock_irq(&dev_priv->irq_lock);
 -      if (dev_priv->display.hpd_irq_setup)
 -              dev_priv->display.hpd_irq_setup(dev_priv);
 -      spin_unlock_irq(&dev_priv->irq_lock);
 -
 -      intel_display_resume(&dev_priv->drm);
 +              ret = __intel_display_resume(dev, state);
 +              if (ret)
 +                      DRM_ERROR("Restoring old state failed with %i\n", ret);
  
 -      intel_hpd_init(dev_priv);
 +              intel_hpd_init(dev_priv);
 +      }
  
 -      drm_modeset_unlock_all(&dev_priv->drm);
 +      drm_modeset_drop_locks(ctx);
 +      drm_modeset_acquire_fini(ctx);
 +      mutex_unlock(&dev->mode_config.mutex);
  }
  
  static bool intel_crtc_has_pending_flip(struct drm_crtc *crtc)
@@@ -4717,7 -4248,7 +4717,7 @@@ int skl_update_scaler_crtc(struct intel
                      intel_crtc->pipe, SKL_CRTC_INDEX);
  
        return skl_update_scaler(state, !state->base.active, SKL_CRTC_INDEX,
-               &state->scaler_state.scaler_id, BIT(DRM_ROTATE_0),
+               &state->scaler_state.scaler_id, DRM_ROTATE_0,
                state->pipe_src_w, state->pipe_src_h,
                adjusted_mode->crtc_hdisplay, adjusted_mode->crtc_vdisplay);
  }
@@@ -4742,7 -4273,7 +4742,7 @@@ static int skl_update_scaler_plane(stru
        struct drm_framebuffer *fb = plane_state->base.fb;
        int ret;
  
-       bool force_detach = !fb || !plane_state->visible;
+       bool force_detach = !fb || !plane_state->base.visible;
  
        DRM_DEBUG_KMS("Updating scaler for [PLANE:%d:%s] scaler_user index %u.%u\n",
                      intel_plane->base.base.id, intel_plane->base.name,
                                drm_plane_index(&intel_plane->base),
                                &plane_state->scaler_id,
                                plane_state->base.rotation,
-                               drm_rect_width(&plane_state->src) >> 16,
-                               drm_rect_height(&plane_state->src) >> 16,
-                               drm_rect_width(&plane_state->dst),
-                               drm_rect_height(&plane_state->dst));
+                               drm_rect_width(&plane_state->base.src) >> 16,
+                               drm_rect_height(&plane_state->base.src) >> 16,
+                               drm_rect_width(&plane_state->base.dst),
+                               drm_rect_height(&plane_state->base.dst));
  
        if (ret || plane_state->scaler_id < 0)
                return ret;
@@@ -5052,9 -4583,9 +5052,9 @@@ static void intel_post_plane_update(str
  
                intel_fbc_post_update(crtc);
  
-               if (primary_state->visible &&
+               if (primary_state->base.visible &&
                    (needs_modeset(&pipe_config->base) ||
-                    !old_primary_state->visible))
+                    !old_primary_state->base.visible))
                        intel_post_enable_primary(&crtc->base);
        }
  }
@@@ -5080,8 -4611,8 +5080,8 @@@ static void intel_pre_plane_update(stru
  
                intel_fbc_pre_update(crtc, pipe_config, primary_state);
  
-               if (old_primary_state->visible &&
-                   (modeset || !primary_state->visible))
+               if (old_primary_state->base.visible &&
+                   (modeset || !primary_state->base.visible))
                        intel_pre_disable_primary(&crtc->base);
        }
  
@@@ -6758,13 -6289,13 +6758,13 @@@ static void intel_crtc_disable_noatomic
        if (!intel_crtc->active)
                return;
  
-       if (to_intel_plane_state(crtc->primary->state)->visible) {
+       if (to_intel_plane_state(crtc->primary->state)->base.visible) {
                WARN_ON(intel_crtc->flip_work);
  
                intel_pre_disable_primary_noatomic(crtc);
  
                intel_crtc_disable_planes(crtc, 1 << drm_plane_index(crtc->primary));
-               to_intel_plane_state(crtc->primary->state)->visible = false;
+               to_intel_plane_state(crtc->primary->state)->base.visible = false;
        }
  
        dev_priv->display.crtc_disable(crtc);
@@@ -9880,7 -9411,7 +9880,7 @@@ static void assert_can_disable_lcpll(st
        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(PCH_PP_STATUS) & PP_ON, "Panel power on\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))
@@@ -10638,7 -10169,7 +10638,7 @@@ static void i845_update_cursor(struct d
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        uint32_t cntl = 0, size = 0;
  
-       if (plane_state && plane_state->visible) {
+       if (plane_state && plane_state->base.visible) {
                unsigned int width = plane_state->base.crtc_w;
                unsigned int height = plane_state->base.crtc_h;
                unsigned int stride = roundup_pow_of_two(width) * 4;
@@@ -10702,7 -10233,7 +10702,7 @@@ static void i9xx_update_cursor(struct d
        int pipe = intel_crtc->pipe;
        uint32_t cntl = 0;
  
-       if (plane_state && plane_state->visible) {
+       if (plane_state && plane_state->base.visible) {
                cntl = MCURSOR_GAMMA_ENABLE;
                switch (plane_state->base.crtc_w) {
                        case 64:
                if (HAS_DDI(dev))
                        cntl |= CURSOR_PIPE_CSC_ENABLE;
  
-               if (plane_state->base.rotation == BIT(DRM_ROTATE_180))
+               if (plane_state->base.rotation == DRM_ROTATE_180)
                        cntl |= CURSOR_ROTATE_180;
        }
  
@@@ -10769,7 -10300,7 +10769,7 @@@ static void intel_crtc_update_cursor(st
  
                /* ILK+ do this automagically */
                if (HAS_GMCH_DISPLAY(dev) &&
-                   plane_state->base.rotation == BIT(DRM_ROTATE_180)) {
+                   plane_state->base.rotation == DRM_ROTATE_180) {
                        base += (plane_state->base.crtc_h *
                                 plane_state->base.crtc_w - 1) * 4;
                }
@@@ -11667,7 -11198,7 +11667,7 @@@ static int intel_gen4_queue_flip(struc
                        MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
        intel_ring_emit(ring, fb->pitches[0]);
        intel_ring_emit(ring, intel_crtc->flip_work->gtt_offset |
 -                      i915_gem_object_get_tiling(obj));
 +                      intel_fb_modifier_to_tiling(fb->modifier[0]));
  
        /* XXX Enabling the panel-fitter across page-flip is so far
         * untested on non-native modes, so ignore it for now.
@@@ -11699,8 -11230,7 +11699,8 @@@ static int intel_gen6_queue_flip(struc
  
        intel_ring_emit(ring, MI_DISPLAY_FLIP |
                        MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
 -      intel_ring_emit(ring, fb->pitches[0] | i915_gem_object_get_tiling(obj));
 +      intel_ring_emit(ring, fb->pitches[0] |
 +                      intel_fb_modifier_to_tiling(fb->modifier[0]));
        intel_ring_emit(ring, intel_crtc->flip_work->gtt_offset);
  
        /* Contrary to the suggestions in the documentation,
@@@ -11803,8 -11333,7 +11803,8 @@@ static int intel_gen7_queue_flip(struc
        }
  
        intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 | plane_bit);
 -      intel_ring_emit(ring, fb->pitches[0] | i915_gem_object_get_tiling(obj));
 +      intel_ring_emit(ring, fb->pitches[0] |
 +                      intel_fb_modifier_to_tiling(fb->modifier[0]));
        intel_ring_emit(ring, intel_crtc->flip_work->gtt_offset);
        intel_ring_emit(ring, (MI_NOOP));
  
@@@ -11853,7 -11382,7 +11853,7 @@@ static void skl_do_mmio_flip(struct int
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct drm_framebuffer *fb = intel_crtc->base.primary->fb;
        const enum pipe pipe = intel_crtc->pipe;
 -      u32 ctl, stride, tile_height;
 +      u32 ctl, stride = skl_plane_stride(fb, 0, rotation);
  
        ctl = I915_READ(PLANE_CTL(pipe, 0));
        ctl &= ~PLANE_CTL_TILED_MASK;
                MISSING_CASE(fb->modifier[0]);
        }
  
 -      /*
 -       * The stride is either expressed as a multiple of 64 bytes chunks for
 -       * linear buffers or in number of tiles for tiled buffers.
 -       */
 -      if (intel_rotation_90_or_270(rotation)) {
 -              /* stride = Surface height in tiles */
 -              tile_height = intel_tile_height(dev_priv, fb->modifier[0], 0);
 -              stride = DIV_ROUND_UP(fb->height, tile_height);
 -      } else {
 -              stride = fb->pitches[0] /
 -                      intel_fb_stride_alignment(dev_priv, fb->modifier[0],
 -                                                fb->pixel_format);
 -      }
 -
        /*
         * Both PLANE_CTL and PLANE_STRIDE are not updated on vblank but on
         * PLANE_SURF updates, the update is then guaranteed to be atomic.
@@@ -11889,13 -11432,15 +11889,13 @@@ static void ilk_do_mmio_flip(struct int
  {
        struct drm_device *dev = intel_crtc->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
 -      struct intel_framebuffer *intel_fb =
 -              to_intel_framebuffer(intel_crtc->base.primary->fb);
 -      struct drm_i915_gem_object *obj = intel_fb->obj;
 +      struct drm_framebuffer *fb = intel_crtc->base.primary->fb;
        i915_reg_t reg = DSPCNTR(intel_crtc->plane);
        u32 dspcntr;
  
        dspcntr = I915_READ(reg);
  
 -      if (i915_gem_object_is_tiled(obj))
 +      if (fb->modifier[0] == I915_FORMAT_MOD_X_TILED)
                dspcntr |= DISPPLANE_TILED;
        else
                dspcntr &= ~DISPPLANE_TILED;
@@@ -12123,7 -11668,8 +12123,7 @@@ static int intel_crtc_page_flip(struct 
  
        if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
                engine = &dev_priv->engine[BCS];
 -              if (i915_gem_object_get_tiling(obj) !=
 -                  i915_gem_object_get_tiling(intel_fb_obj(work->old_fb)))
 +              if (fb->modifier[0] != old_fb->modifier[0])
                        /* vlv: DISPLAY_FLIP fails to change tiling */
                        engine = NULL;
        } else if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) {
        if (ret)
                goto cleanup_pending;
  
 -      work->gtt_offset = intel_plane_obj_offset(to_intel_plane(primary),
 -                                                obj, 0);
 +      work->gtt_offset = intel_fb_gtt_offset(fb, primary->state->rotation);
        work->gtt_offset += intel_crtc->dspaddr_offset;
        work->rotation = crtc->primary->state->rotation;
  
@@@ -12265,7 -11812,7 +12265,7 @@@ static bool intel_wm_need_update(struc
        struct intel_plane_state *cur = to_intel_plane_state(plane->state);
  
        /* Update watermarks on tiling or size changes. */
-       if (new->visible != cur->visible)
+       if (new->base.visible != cur->base.visible)
                return true;
  
        if (!cur->base.fb || !new->base.fb)
  
        if (cur->base.fb->modifier[0] != new->base.fb->modifier[0] ||
            cur->base.rotation != new->base.rotation ||
-           drm_rect_width(&new->src) != drm_rect_width(&cur->src) ||
-           drm_rect_height(&new->src) != drm_rect_height(&cur->src) ||
-           drm_rect_width(&new->dst) != drm_rect_width(&cur->dst) ||
-           drm_rect_height(&new->dst) != drm_rect_height(&cur->dst))
+           drm_rect_width(&new->base.src) != drm_rect_width(&cur->base.src) ||
+           drm_rect_height(&new->base.src) != drm_rect_height(&cur->base.src) ||
+           drm_rect_width(&new->base.dst) != drm_rect_width(&cur->base.dst) ||
+           drm_rect_height(&new->base.dst) != drm_rect_height(&cur->base.dst))
                return true;
  
        return false;
  
  static bool needs_scaling(struct intel_plane_state *state)
  {
-       int src_w = drm_rect_width(&state->src) >> 16;
-       int src_h = drm_rect_height(&state->src) >> 16;
-       int dst_w = drm_rect_width(&state->dst);
-       int dst_h = drm_rect_height(&state->dst);
+       int src_w = drm_rect_width(&state->base.src) >> 16;
+       int src_h = drm_rect_height(&state->base.src) >> 16;
+       int dst_w = drm_rect_width(&state->base.dst);
+       int dst_h = drm_rect_height(&state->base.dst);
  
        return (src_w != dst_w || src_h != dst_h);
  }
@@@ -12318,8 -11865,8 +12318,8 @@@ int intel_plane_atomic_calc_changes(str
                        return ret;
        }
  
-       was_visible = old_plane_state->visible;
-       visible = to_intel_plane_state(plane_state)->visible;
+       was_visible = old_plane_state->base.visible;
+       visible = to_intel_plane_state(plane_state)->base.visible;
  
        if (!was_crtc_enabled && WARN_ON(was_visible))
                was_visible = false;
         * only combine the results from all planes in the current place?
         */
        if (!is_crtc_enabled)
-               to_intel_plane_state(plane_state)->visible = visible = false;
+               to_intel_plane_state(plane_state)->base.visible = visible = false;
  
        if (!was_visible && !visible)
                return 0;
@@@ -12553,21 -12100,11 +12553,11 @@@ connected_sink_compute_bpp(struct intel
                pipe_config->pipe_bpp = connector->base.display_info.bpc*3;
        }
  
-       /* Clamp bpp to default limit on screens without EDID 1.4 */
-       if (connector->base.display_info.bpc == 0) {
-               int type = connector->base.connector_type;
-               int clamp_bpp = 24;
-               /* Fall back to 18 bpp when DP sink capability is unknown. */
-               if (type == DRM_MODE_CONNECTOR_DisplayPort ||
-                   type == DRM_MODE_CONNECTOR_eDP)
-                       clamp_bpp = 18;
-               if (bpp > clamp_bpp) {
-                       DRM_DEBUG_KMS("clamping display bpp (was %d) to default limit of %d\n",
-                                     bpp, clamp_bpp);
-                       pipe_config->pipe_bpp = clamp_bpp;
-               }
+       /* Clamp bpp to 8 on screens without EDID 1.4 */
+       if (connector->base.display_info.bpc == 0 && bpp > 24) {
+               DRM_DEBUG_KMS("clamping display bpp (was %d) to default limit of 24\n",
+                             bpp);
+               pipe_config->pipe_bpp = 24;
        }
  }
  
@@@ -12740,12 -12277,13 +12730,13 @@@ static void intel_dump_pipe_config(stru
                              drm_get_format_name(fb->pixel_format));
                DRM_DEBUG_KMS("\tscaler:%d src %dx%d+%d+%d dst %dx%d+%d+%d\n",
                              state->scaler_id,
-                             state->src.x1 >> 16, state->src.y1 >> 16,
-                             drm_rect_width(&state->src) >> 16,
-                             drm_rect_height(&state->src) >> 16,
-                             state->dst.x1, state->dst.y1,
-                             drm_rect_width(&state->dst),
-                             drm_rect_height(&state->dst));
+                             state->base.src.x1 >> 16,
+                             state->base.src.y1 >> 16,
+                             drm_rect_width(&state->base.src) >> 16,
+                             drm_rect_height(&state->base.src) >> 16,
+                             state->base.dst.x1, state->base.dst.y1,
+                             drm_rect_width(&state->base.dst),
+                             drm_rect_height(&state->base.dst));
        }
  }
  
@@@ -14568,15 -14106,12 +14559,14 @@@ intel_check_primary_plane(struct drm_pl
                          struct intel_crtc_state *crtc_state,
                          struct intel_plane_state *state)
  {
 +      struct drm_i915_private *dev_priv = to_i915(plane->dev);
        struct drm_crtc *crtc = state->base.crtc;
-       struct drm_framebuffer *fb = state->base.fb;
        int min_scale = DRM_PLANE_HELPER_NO_SCALING;
        int max_scale = DRM_PLANE_HELPER_NO_SCALING;
        bool can_position = false;
 +      int ret;
  
 -      if (INTEL_INFO(plane->dev)->gen >= 9) {
 +      if (INTEL_GEN(dev_priv) >= 9) {
                /* use scaler when colorkey is not required */
                if (state->ckey.flags == I915_SET_COLORKEY_NONE) {
                        min_scale = 1;
                can_position = true;
        }
  
-       ret = drm_plane_helper_check_update(plane, crtc, fb, &state->src,
-                                           &state->dst, &state->clip,
-                                           state->base.rotation,
 -      return drm_plane_helper_check_state(&state->base,
 -                                          &state->clip,
--                                          min_scale, max_scale,
-                                           can_position, true,
-                                           &state->visible);
 -                                          can_position, true);
++      ret = drm_plane_helper_check_state(&state->base,
++                                         &state->clip,
++                                         min_scale, max_scale,
++                                         can_position, true);
 +      if (ret)
 +              return ret;
 +
-       if (!fb)
++      if (!state->base.fb)
 +              return 0;
 +
 +      if (INTEL_GEN(dev_priv) >= 9) {
 +              ret = skl_check_plane_surface(state);
 +              if (ret)
 +                      return ret;
 +      }
 +
 +      return 0;
  }
  
  static void intel_begin_crtc_commit(struct drm_crtc *crtc,
  void intel_create_rotation_property(struct drm_device *dev, struct intel_plane *plane)
  {
        if (!dev->mode_config.rotation_property) {
-               unsigned long flags = BIT(DRM_ROTATE_0) |
-                       BIT(DRM_ROTATE_180);
+               unsigned long flags = DRM_ROTATE_0 |
+                       DRM_ROTATE_180;
  
                if (INTEL_INFO(dev)->gen >= 9)
-                       flags |= BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270);
+                       flags |= DRM_ROTATE_90 | DRM_ROTATE_270;
  
                dev->mode_config.rotation_property =
                        drm_mode_create_rotation_property(dev, flags);
@@@ -14783,19 -14303,17 +14771,17 @@@ intel_check_cursor_plane(struct drm_pla
                         struct intel_crtc_state *crtc_state,
                         struct intel_plane_state *state)
  {
-       struct drm_crtc *crtc = crtc_state->base.crtc;
        struct drm_framebuffer *fb = state->base.fb;
        struct drm_i915_gem_object *obj = intel_fb_obj(fb);
        enum pipe pipe = to_intel_plane(plane)->pipe;
        unsigned stride;
        int ret;
  
-       ret = drm_plane_helper_check_update(plane, crtc, fb, &state->src,
-                                           &state->dst, &state->clip,
-                                           state->base.rotation,
-                                           DRM_PLANE_HELPER_NO_SCALING,
-                                           DRM_PLANE_HELPER_NO_SCALING,
-                                           true, true, &state->visible);
+       ret = drm_plane_helper_check_state(&state->base,
+                                          &state->clip,
+                                          DRM_PLANE_HELPER_NO_SCALING,
+                                          DRM_PLANE_HELPER_NO_SCALING,
+                                          true, true);
        if (ret)
                return ret;
  
         * Refuse the put the cursor into that compromised position.
         */
        if (IS_CHERRYVIEW(plane->dev) && pipe == PIPE_C &&
-           state->visible && state->base.crtc_x < 0) {
+           state->base.visible && state->base.crtc_x < 0) {
                DRM_DEBUG_KMS("CHV cursor C not allowed to straddle the left screen edge\n");
                return -EINVAL;
        }
@@@ -14910,8 -14428,8 +14896,8 @@@ static struct drm_plane *intel_cursor_p
                if (!dev->mode_config.rotation_property)
                        dev->mode_config.rotation_property =
                                drm_mode_create_rotation_property(dev,
-                                                       BIT(DRM_ROTATE_0) |
-                                                       BIT(DRM_ROTATE_180));
+                                                       DRM_ROTATE_0 |
+                                                       DRM_ROTATE_180);
                if (dev->mode_config.rotation_property)
                        drm_object_attach_property(&cursor->base.base,
                                dev->mode_config.rotation_property,
@@@ -15117,50 -14635,12 +15103,50 @@@ static bool intel_crt_present(struct dr
        return true;
  }
  
 +void intel_pps_unlock_regs_wa(struct drm_i915_private *dev_priv)
 +{
 +      int pps_num;
 +      int pps_idx;
 +
 +      if (HAS_DDI(dev_priv))
 +              return;
 +      /*
 +       * This w/a is needed at least on CPT/PPT, but to be sure apply it
 +       * everywhere where registers can be write protected.
 +       */
 +      if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
 +              pps_num = 2;
 +      else
 +              pps_num = 1;
 +
 +      for (pps_idx = 0; pps_idx < pps_num; pps_idx++) {
 +              u32 val = I915_READ(PP_CONTROL(pps_idx));
 +
 +              val = (val & ~PANEL_UNLOCK_MASK) | PANEL_UNLOCK_REGS;
 +              I915_WRITE(PP_CONTROL(pps_idx), val);
 +      }
 +}
 +
 +static void intel_pps_init(struct drm_i915_private *dev_priv)
 +{
 +      if (HAS_PCH_SPLIT(dev_priv) || IS_BROXTON(dev_priv))
 +              dev_priv->pps_mmio_base = PCH_PPS_BASE;
 +      else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
 +              dev_priv->pps_mmio_base = VLV_PPS_BASE;
 +      else
 +              dev_priv->pps_mmio_base = PPS_BASE;
 +
 +      intel_pps_unlock_regs_wa(dev_priv);
 +}
 +
  static void intel_setup_outputs(struct drm_device *dev)
  {
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_encoder *encoder;
        bool dpd_is_edp = false;
  
 +      intel_pps_init(dev_priv);
 +
        /*
         * intel_edp_init_connector() depends on this completing first, to
         * prevent the registeration of both eDP and LVDS and the incorrect
@@@ -15428,26 -14908,24 +15414,26 @@@ static int intel_framebuffer_init(struc
                                  struct drm_i915_gem_object *obj)
  {
        struct drm_i915_private *dev_priv = to_i915(dev);
 -      unsigned int aligned_height;
 +      unsigned int tiling = i915_gem_object_get_tiling(obj);
        int ret;
        u32 pitch_limit, stride_alignment;
  
        WARN_ON(!mutex_is_locked(&dev->struct_mutex));
  
        if (mode_cmd->flags & DRM_MODE_FB_MODIFIERS) {
 -              /* Enforce that fb modifier and tiling mode match, but only for
 -               * X-tiled. This is needed for FBC. */
 -              if (!!(i915_gem_object_get_tiling(obj) == I915_TILING_X) !=
 -                  !!(mode_cmd->modifier[0] == I915_FORMAT_MOD_X_TILED)) {
 +              /*
 +               * If there's a fence, enforce that
 +               * the fb modifier and tiling mode match.
 +               */
 +              if (tiling != I915_TILING_NONE &&
 +                  tiling != intel_fb_modifier_to_tiling(mode_cmd->modifier[0])) {
                        DRM_DEBUG("tiling_mode doesn't match fb modifier\n");
                        return -EINVAL;
                }
        } else {
 -              if (i915_gem_object_get_tiling(obj) == I915_TILING_X)
 +              if (tiling == I915_TILING_X) {
                        mode_cmd->modifier[0] = I915_FORMAT_MOD_X_TILED;
 -              else if (i915_gem_object_get_tiling(obj) == I915_TILING_Y) {
 +              } else if (tiling == I915_TILING_Y) {
                        DRM_DEBUG("No Y tiling for legacy addfb\n");
                        return -EINVAL;
                }
                return -EINVAL;
        }
  
 +      /*
 +       * gen2/3 display engine uses the fence if present,
 +       * so the tiling mode must match the fb modifier exactly.
 +       */
 +      if (INTEL_INFO(dev_priv)->gen < 4 &&
 +          tiling != intel_fb_modifier_to_tiling(mode_cmd->modifier[0])) {
 +              DRM_DEBUG("tiling_mode must match fb modifier exactly on gen2/3\n");
 +              return -EINVAL;
 +      }
 +
        stride_alignment = intel_fb_stride_alignment(dev_priv,
                                                     mode_cmd->modifier[0],
                                                     mode_cmd->pixel_format);
                return -EINVAL;
        }
  
 -      if (mode_cmd->modifier[0] == I915_FORMAT_MOD_X_TILED &&
 +      /*
 +       * If there's a fence, enforce that
 +       * the fb pitch and fence stride match.
 +       */
 +      if (tiling != I915_TILING_NONE &&
            mode_cmd->pitches[0] != i915_gem_object_get_stride(obj)) {
                DRM_DEBUG("pitch (%d) must match tiling stride (%d)\n",
                          mode_cmd->pitches[0],
        if (mode_cmd->offsets[0] != 0)
                return -EINVAL;
  
 -      aligned_height = intel_fb_align_height(dev, mode_cmd->height,
 -                                             mode_cmd->pixel_format,
 -                                             mode_cmd->modifier[0]);
 -      /* FIXME drm helper for size checks (especially planar formats)? */
 -      if (obj->base.size < aligned_height * mode_cmd->pitches[0])
 -              return -EINVAL;
 -
        drm_helper_mode_fill_fb_struct(&intel_fb->base, mode_cmd);
        intel_fb->obj = obj;
  
 -      intel_fill_fb_info(dev_priv, &intel_fb->base);
 +      ret = intel_fill_fb_info(dev_priv, &intel_fb->base);
 +      if (ret)
 +              return ret;
  
        ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs);
        if (ret) {
@@@ -16288,13 -15757,6 +16274,13 @@@ static bool intel_encoder_has_connector
        return false;
  }
  
 +static bool has_pch_trancoder(struct drm_i915_private *dev_priv,
 +                            enum transcoder pch_transcoder)
 +{
 +      return HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv) ||
 +              (HAS_PCH_LPT_H(dev_priv) && pch_transcoder == TRANSCODER_A);
 +}
 +
  static void intel_sanitize_crtc(struct intel_crtc *crtc)
  {
        struct drm_device *dev = crtc->base.dev;
                 * Temporarily change the plane mapping and disable everything
                 * ...  */
                plane = crtc->plane;
-               to_intel_plane_state(crtc->base.primary->state)->visible = true;
+               to_intel_plane_state(crtc->base.primary->state)->base.visible = true;
                crtc->plane = !plane;
                intel_crtc_disable_noatomic(&crtc->base);
                crtc->plane = plane;
                 * worst a fifo underrun happens which also sets this to false.
                 */
                crtc->cpu_fifo_underrun_disabled = true;
 -              crtc->pch_fifo_underrun_disabled = true;
 +              /*
 +               * We track the PCH trancoder underrun reporting state
 +               * within the crtc. With crtc for pipe A housing the underrun
 +               * reporting state for PCH transcoder A, crtc for pipe B housing
 +               * it for PCH transcoder B, etc. LPT-H has only PCH transcoder A,
 +               * and marking underrun reporting as disabled for the non-existing
 +               * PCH transcoders B and C would prevent enabling the south
 +               * error interrupt (see cpt_can_enable_serr_int()).
 +               */
 +              if (has_pch_trancoder(dev_priv, (enum transcoder)crtc->pipe))
 +                      crtc->pch_fifo_underrun_disabled = true;
        }
  }
  
@@@ -16475,10 -15927,10 +16461,10 @@@ static void readout_plane_state(struct 
        struct intel_plane_state *plane_state =
                to_intel_plane_state(primary->state);
  
-       plane_state->visible = crtc->active &&
+       plane_state->base.visible = crtc->active &&
                primary_get_hw_state(to_intel_plane(primary));
  
-       if (plane_state->visible)
+       if (plane_state->base.visible)
                crtc->base.state->plane_mask |= 1 << drm_plane_index(primary);
  }
  
@@@ -16697,10 -16149,9 +16683,10 @@@ void intel_display_resume(struct drm_de
        struct drm_atomic_state *state = dev_priv->modeset_restore_state;
        struct drm_modeset_acquire_ctx ctx;
        int ret;
 -      bool setup = false;
  
        dev_priv->modeset_restore_state = NULL;
 +      if (state)
 +              state->acquire_ctx = &ctx;
  
        /*
         * This is a cludge because with real atomic modeset mode_config.mutex
        mutex_lock(&dev->mode_config.mutex);
        drm_modeset_acquire_init(&ctx, 0);
  
 -retry:
 -      ret = drm_modeset_lock_all_ctx(dev, &ctx);
 -
 -      if (ret == 0 && !setup) {
 -              setup = true;
 -
 -              intel_modeset_setup_hw_state(dev);
 -              i915_redisable_vga(dev);
 -      }
 -
 -      if (ret == 0 && state) {
 -              struct drm_crtc_state *crtc_state;
 -              struct drm_crtc *crtc;
 -              int i;
 -
 -              state->acquire_ctx = &ctx;
 -
 -              /* ignore any reset values/BIOS leftovers in the WM registers */
 -              to_intel_atomic_state(state)->skip_intermediate_wm = true;
 -
 -              for_each_crtc_in_state(state, crtc, crtc_state, i) {
 -                      /*
 -                       * Force recalculation even if we restore
 -                       * current state. With fast modeset this may not result
 -                       * in a modeset when the state is compatible.
 -                       */
 -                      crtc_state->mode_changed = true;
 -              }
 -
 -              ret = drm_atomic_commit(state);
 -      }
 +      while (1) {
 +              ret = drm_modeset_lock_all_ctx(dev, &ctx);
 +              if (ret != -EDEADLK)
 +                      break;
  
 -      if (ret == -EDEADLK) {
                drm_modeset_backoff(&ctx);
 -              goto retry;
        }
  
 +      if (!ret)
 +              ret = __intel_display_resume(dev, state);
 +
        drm_modeset_drop_locks(&ctx);
        drm_modeset_acquire_fini(&ctx);
        mutex_unlock(&dev->mode_config.mutex);
@@@ -178,16 -178,6 +178,16 @@@ struct intel_framebuffer 
        struct drm_framebuffer base;
        struct drm_i915_gem_object *obj;
        struct intel_rotation_info rot_info;
 +
 +      /* for each plane in the normal GTT view */
 +      struct {
 +              unsigned int x, y;
 +      } normal[2];
 +      /* for each plane in the rotated GTT view */
 +      struct {
 +              unsigned int x, y;
 +              unsigned int pitch; /* pixels */
 +      } rotated[2];
  };
  
  struct intel_fbdev {
@@@ -348,20 -338,8 +348,17 @@@ struct intel_atomic_state 
  
  struct intel_plane_state {
        struct drm_plane_state base;
-       struct drm_rect src;
-       struct drm_rect dst;
        struct drm_rect clip;
-       bool visible;
  
 +      struct {
 +              u32 offset;
 +              int x, y;
 +      } main;
 +      struct {
 +              u32 offset;
 +              int x, y;
 +      } aux;
 +
        /*
         * scaler_id
         *    = -1 : not using a scaler
@@@ -1175,18 -1153,12 +1172,18 @@@ int vlv_get_cck_clock(struct drm_i915_p
                      const char *name, u32 reg, int ref_freq);
  extern const struct drm_plane_funcs intel_plane_funcs;
  void intel_init_display_hooks(struct drm_i915_private *dev_priv);
 +unsigned int intel_fb_xy_to_linear(int x, int y,
 +                                 const struct intel_plane_state *state,
 +                                 int plane);
 +void intel_add_fb_offsets(int *x, int *y,
 +                        const struct intel_plane_state *state, int plane);
  unsigned int intel_rotation_info_size(const struct intel_rotation_info *rot_info);
  bool intel_has_pending_fb_unpin(struct drm_device *dev);
  void intel_mark_busy(struct drm_i915_private *dev_priv);
  void intel_mark_idle(struct drm_i915_private *dev_priv);
  void intel_crtc_restore_mode(struct drm_crtc *crtc);
  int intel_display_suspend(struct drm_device *dev);
 +void intel_pps_unlock_regs_wa(struct drm_i915_private *dev_priv);
  void intel_encoder_destroy(struct drm_encoder *encoder);
  int intel_connector_init(struct intel_connector *);
  struct intel_connector *intel_connector_alloc(void);
@@@ -1273,7 -1245,7 +1270,7 @@@ unsigned int intel_tile_height(const st
  static inline bool
  intel_rotation_90_or_270(unsigned int rotation)
  {
-       return rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270));
+       return rotation & (DRM_ROTATE_90 | DRM_ROTATE_270);
  }
  
  void intel_create_rotation_property(struct drm_device *dev,
@@@ -1305,7 -1277,9 +1302,7 @@@ void assert_pipe(struct drm_i915_privat
  #define assert_pipe_enabled(d, p) assert_pipe(d, p, true)
  #define assert_pipe_disabled(d, p) assert_pipe(d, p, false)
  u32 intel_compute_tile_offset(int *x, int *y,
 -                            const struct drm_framebuffer *fb, int plane,
 -                            unsigned int pitch,
 -                            unsigned int rotation);
 +                            const struct intel_plane_state *state, int plane);
  void intel_prepare_reset(struct drm_i915_private *dev_priv);
  void intel_finish_reset(struct drm_i915_private *dev_priv);
  void hsw_enable_pc8(struct drm_i915_private *dev_priv);
@@@ -1348,14 -1322,13 +1345,14 @@@ void intel_mode_from_pipe_config(struc
  int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state);
  int skl_max_scale(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state);
  
 -u32 intel_plane_obj_offset(struct intel_plane *intel_plane,
 -                         struct drm_i915_gem_object *obj,
 -                         unsigned int plane);
 +u32 intel_fb_gtt_offset(struct drm_framebuffer *fb, unsigned int rotation);
  
  u32 skl_plane_ctl_format(uint32_t pixel_format);
  u32 skl_plane_ctl_tiling(uint64_t fb_modifier);
  u32 skl_plane_ctl_rotation(unsigned int rotation);
 +u32 skl_plane_stride(const struct drm_framebuffer *fb, int plane,
 +                   unsigned int rotation);
 +int skl_check_plane_surface(struct intel_plane_state *plane_state);
  
  /* intel_csr.c */
  void intel_csr_ucode_init(struct drm_i915_private *);
@@@ -1738,6 -1711,8 +1735,8 @@@ bool intel_sdvo_init(struct drm_device 
  
  
  /* intel_sprite.c */
+ int intel_usecs_to_scanlines(const struct drm_display_mode *adjusted_mode,
+                            int usecs);
  int intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane);
  int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
                              struct drm_file *file_priv);
@@@ -965,7 -965,7 +965,7 @@@ static uint16_t vlv_compute_wm_level(st
        if (dev_priv->wm.pri_latency[level] == 0)
                return USHRT_MAX;
  
-       if (!state->visible)
+       if (!state->base.visible)
                return 0;
  
        cpp = drm_format_plane_cpp(state->base.fb->pixel_format, 0);
@@@ -1007,7 -1007,7 +1007,7 @@@ static void vlv_compute_fifo(struct int
                if (plane->base.type == DRM_PLANE_TYPE_CURSOR)
                        continue;
  
-               if (state->visible) {
+               if (state->base.visible) {
                        wm_state->num_active_planes++;
                        total_rate += drm_format_plane_cpp(state->base.fb->pixel_format, 0);
                }
                        continue;
                }
  
-               if (!state->visible) {
+               if (!state->base.visible) {
                        plane->wm.fifo_size = 0;
                        continue;
                }
@@@ -1123,7 -1123,7 +1123,7 @@@ static void vlv_compute_wm(struct intel
                struct intel_plane_state *state =
                        to_intel_plane_state(plane->base.state);
  
-               if (!state->visible)
+               if (!state->base.visible)
                        continue;
  
                /* normal watermarks */
@@@ -1775,7 -1775,7 +1775,7 @@@ static uint32_t ilk_compute_pri_wm(cons
                drm_format_plane_cpp(pstate->base.fb->pixel_format, 0) : 0;
        uint32_t method1, method2;
  
-       if (!cstate->base.active || !pstate->visible)
+       if (!cstate->base.active || !pstate->base.visible)
                return 0;
  
        method1 = ilk_wm_method1(ilk_pipe_pixel_rate(cstate), cpp, mem_value);
  
        method2 = ilk_wm_method2(ilk_pipe_pixel_rate(cstate),
                                 cstate->base.adjusted_mode.crtc_htotal,
-                                drm_rect_width(&pstate->dst),
+                                drm_rect_width(&pstate->base.dst),
                                 cpp, mem_value);
  
        return min(method1, method2);
@@@ -1803,13 -1803,13 +1803,13 @@@ static uint32_t ilk_compute_spr_wm(cons
                drm_format_plane_cpp(pstate->base.fb->pixel_format, 0) : 0;
        uint32_t method1, method2;
  
-       if (!cstate->base.active || !pstate->visible)
+       if (!cstate->base.active || !pstate->base.visible)
                return 0;
  
        method1 = ilk_wm_method1(ilk_pipe_pixel_rate(cstate), cpp, mem_value);
        method2 = ilk_wm_method2(ilk_pipe_pixel_rate(cstate),
                                 cstate->base.adjusted_mode.crtc_htotal,
-                                drm_rect_width(&pstate->dst),
+                                drm_rect_width(&pstate->base.dst),
                                 cpp, mem_value);
        return min(method1, method2);
  }
@@@ -1828,7 -1828,7 +1828,7 @@@ static uint32_t ilk_compute_cur_wm(cons
         * this is necessary to avoid flickering.
         */
        int cpp = 4;
-       int width = pstate->visible ? pstate->base.crtc_w : 64;
+       int width = pstate->base.visible ? pstate->base.crtc_w : 64;
  
        if (!cstate->base.active)
                return 0;
@@@ -1846,10 -1846,10 +1846,10 @@@ static uint32_t ilk_compute_fbc_wm(cons
        int cpp = pstate->base.fb ?
                drm_format_plane_cpp(pstate->base.fb->pixel_format, 0) : 0;
  
-       if (!cstate->base.active || !pstate->visible)
+       if (!cstate->base.active || !pstate->base.visible)
                return 0;
  
-       return ilk_wm_fbc(pri_val, drm_rect_width(&pstate->dst), cpp);
+       return ilk_wm_fbc(pri_val, drm_rect_width(&pstate->base.dst), cpp);
  }
  
  static unsigned int ilk_display_fifo_size(const struct drm_device *dev)
@@@ -2366,10 -2366,10 +2366,10 @@@ static int ilk_compute_pipe_wm(struct i
  
        pipe_wm->pipe_enabled = cstate->base.active;
        if (sprstate) {
-               pipe_wm->sprites_enabled = sprstate->visible;
-               pipe_wm->sprites_scaled = sprstate->visible &&
-                       (drm_rect_width(&sprstate->dst) != drm_rect_width(&sprstate->src) >> 16 ||
-                        drm_rect_height(&sprstate->dst) != drm_rect_height(&sprstate->src) >> 16);
+               pipe_wm->sprites_enabled = sprstate->base.visible;
+               pipe_wm->sprites_scaled = sprstate->base.visible &&
+                       (drm_rect_width(&sprstate->base.dst) != drm_rect_width(&sprstate->base.src) >> 16 ||
+                        drm_rect_height(&sprstate->base.dst) != drm_rect_height(&sprstate->base.src) >> 16);
        }
  
        usable_level = max_level;
@@@ -3004,14 -3004,14 +3004,14 @@@ skl_plane_downscale_amount(const struc
        uint32_t downscale_h, downscale_w;
        uint32_t src_w, src_h, dst_w, dst_h;
  
-       if (WARN_ON(!pstate->visible))
+       if (WARN_ON(!pstate->base.visible))
                return DRM_PLANE_HELPER_NO_SCALING;
  
        /* n.b., src is 16.16 fixed point, dst is whole integer */
-       src_w = drm_rect_width(&pstate->src);
-       src_h = drm_rect_height(&pstate->src);
-       dst_w = drm_rect_width(&pstate->dst);
-       dst_h = drm_rect_height(&pstate->dst);
+       src_w = drm_rect_width(&pstate->base.src);
+       src_h = drm_rect_height(&pstate->base.src);
+       dst_w = drm_rect_width(&pstate->base.dst);
+       dst_h = drm_rect_height(&pstate->base.dst);
        if (intel_rotation_90_or_270(pstate->base.rotation))
                swap(dst_w, dst_h);
  
@@@ -3033,15 -3033,15 +3033,15 @@@ skl_plane_relative_data_rate(const stru
        uint32_t width = 0, height = 0;
        unsigned format = fb ? fb->pixel_format : DRM_FORMAT_XRGB8888;
  
-       if (!intel_pstate->visible)
+       if (!intel_pstate->base.visible)
                return 0;
        if (pstate->plane->type == DRM_PLANE_TYPE_CURSOR)
                return 0;
        if (y && format != DRM_FORMAT_NV12)
                return 0;
  
-       width = drm_rect_width(&intel_pstate->src) >> 16;
-       height = drm_rect_height(&intel_pstate->src) >> 16;
+       width = drm_rect_width(&intel_pstate->base.src) >> 16;
+       height = drm_rect_height(&intel_pstate->base.src) >> 16;
  
        if (intel_rotation_90_or_270(pstate->rotation))
                swap(width, height);
@@@ -3142,8 -3142,8 +3142,8 @@@ skl_ddb_min_alloc(const struct drm_plan
            fb->modifier[0] != I915_FORMAT_MOD_Yf_TILED)
                return 8;
  
-       src_w = drm_rect_width(&intel_pstate->src) >> 16;
-       src_h = drm_rect_height(&intel_pstate->src) >> 16;
+       src_w = drm_rect_width(&intel_pstate->base.src) >> 16;
+       src_h = drm_rect_height(&intel_pstate->base.src) >> 16;
  
        if (intel_rotation_90_or_270(pstate->rotation))
                swap(src_w, src_h);
@@@ -3234,7 -3234,7 +3234,7 @@@ skl_allocate_pipe_ddb(struct intel_crtc
                if (intel_plane->pipe != pipe)
                        continue;
  
-               if (!to_intel_plane_state(pstate)->visible) {
+               if (!to_intel_plane_state(pstate)->base.visible) {
                        minimum[id] = 0;
                        y_minimum[id] = 0;
                        continue;
@@@ -3373,7 -3373,7 +3373,7 @@@ static uint32_t skl_adjusted_plane_pixe
        uint64_t pixel_rate;
  
        /* Shouldn't reach here on disabled planes... */
-       if (WARN_ON(!pstate->visible))
+       if (WARN_ON(!pstate->base.visible))
                return 0;
  
        /*
@@@ -3409,13 -3409,13 +3409,13 @@@ static int skl_compute_plane_wm(const s
        uint32_t width = 0, height = 0;
        uint32_t plane_pixel_rate;
  
-       if (latency == 0 || !cstate->base.active || !intel_pstate->visible) {
+       if (latency == 0 || !cstate->base.active || !intel_pstate->base.visible) {
                *enabled = false;
                return 0;
        }
  
-       width = drm_rect_width(&intel_pstate->src) >> 16;
-       height = drm_rect_height(&intel_pstate->src) >> 16;
+       width = drm_rect_width(&intel_pstate->base.src) >> 16;
+       height = drm_rect_height(&intel_pstate->base.src) >> 16;
  
        if (intel_rotation_90_or_270(pstate->rotation))
                swap(width, height);
@@@ -5675,6 -5675,8 +5675,6 @@@ static void valleyview_setup_pctx(struc
        u32 pcbr;
        int pctx_size = 24*1024;
  
 -      mutex_lock(&dev_priv->drm.struct_mutex);
 -
        pcbr = I915_READ(VLV_PCBR);
        if (pcbr) {
                /* BIOS set it up already, grab the pre-alloc'd space */
  out:
        DRM_DEBUG_DRIVER("PCBR: 0x%08x\n", I915_READ(VLV_PCBR));
        dev_priv->vlv_pctx = pctx;
 -      mutex_unlock(&dev_priv->drm.struct_mutex);
  }
  
  static void valleyview_cleanup_pctx(struct drm_i915_private *dev_priv)
@@@ -6485,7 -6488,6 +6485,7 @@@ void intel_init_gt_powersave(struct drm
                intel_runtime_pm_get(dev_priv);
        }
  
 +      mutex_lock(&dev_priv->drm.struct_mutex);
        mutex_lock(&dev_priv->rps.hw_lock);
  
        /* Initialize RPS limits (for userspace) */
        dev_priv->rps.boost_freq = dev_priv->rps.max_freq;
  
        mutex_unlock(&dev_priv->rps.hw_lock);
 +      mutex_unlock(&dev_priv->drm.struct_mutex);
  
        intel_autoenable_gt_powersave(dev_priv);
  }
@@@ -54,8 -54,8 +54,8 @@@ format_is_yuv(uint32_t format
        }
  }
  
static int usecs_to_scanlines(const struct drm_display_mode *adjusted_mode,
-                             int usecs)
int intel_usecs_to_scanlines(const struct drm_display_mode *adjusted_mode,
+                            int usecs)
  {
        /* paranoia */
        if (!adjusted_mode->crtc_htotal)
@@@ -92,7 -92,7 +92,7 @@@ void intel_pipe_update_start(struct int
                vblank_start = DIV_ROUND_UP(vblank_start, 2);
  
        /* FIXME needs to be calibrated sensibly */
-       min = vblank_start - usecs_to_scanlines(adjusted_mode, 100);
+       min = vblank_start - intel_usecs_to_scanlines(adjusted_mode, 100);
        max = vblank_start - 1;
  
        local_irq_disable();
@@@ -203,21 -203,23 +203,21 @@@ skl_update_plane(struct drm_plane *drm_
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_plane *intel_plane = to_intel_plane(drm_plane);
        struct drm_framebuffer *fb = plane_state->base.fb;
 -      struct drm_i915_gem_object *obj = intel_fb_obj(fb);
        const int pipe = intel_plane->pipe;
        const int plane = intel_plane->plane + 1;
 -      u32 plane_ctl, stride_div, stride;
 +      u32 plane_ctl;
        const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
 -      u32 surf_addr;
 -      u32 tile_height, plane_offset, plane_size;
 +      u32 surf_addr = plane_state->main.offset;
        unsigned int rotation = plane_state->base.rotation;
 -      int x_offset, y_offset;
 +      u32 stride = skl_plane_stride(fb, 0, rotation);
-       int crtc_x = plane_state->dst.x1;
-       int crtc_y = plane_state->dst.y1;
-       uint32_t crtc_w = drm_rect_width(&plane_state->dst);
-       uint32_t crtc_h = drm_rect_height(&plane_state->dst);
+       int crtc_x = plane_state->base.dst.x1;
+       int crtc_y = plane_state->base.dst.y1;
+       uint32_t crtc_w = drm_rect_width(&plane_state->base.dst);
+       uint32_t crtc_h = drm_rect_height(&plane_state->base.dst);
 -      uint32_t x = plane_state->base.src.x1 >> 16;
 -      uint32_t y = plane_state->base.src.y1 >> 16;
 +      uint32_t x = plane_state->main.x;
 +      uint32_t y = plane_state->main.y;
-       uint32_t src_w = drm_rect_width(&plane_state->src) >> 16;
-       uint32_t src_h = drm_rect_height(&plane_state->src) >> 16;
+       uint32_t src_w = drm_rect_width(&plane_state->base.src) >> 16;
+       uint32_t src_h = drm_rect_height(&plane_state->base.src) >> 16;
  
        plane_ctl = PLANE_CTL_ENABLE |
                PLANE_CTL_PIPE_GAMMA_ENABLE |
  
        plane_ctl |= skl_plane_ctl_rotation(rotation);
  
 -      stride_div = intel_fb_stride_alignment(dev_priv, fb->modifier[0],
 -                                             fb->pixel_format);
 -
 -      /* Sizes are 0 based */
 -      src_w--;
 -      src_h--;
 -      crtc_w--;
 -      crtc_h--;
 -
        if (key->flags) {
                I915_WRITE(PLANE_KEYVAL(pipe, plane), key->min_value);
                I915_WRITE(PLANE_KEYMAX(pipe, plane), key->max_value);
        else if (key->flags & I915_SET_COLORKEY_SOURCE)
                plane_ctl |= PLANE_CTL_KEY_ENABLE_SOURCE;
  
 -      surf_addr = intel_plane_obj_offset(intel_plane, obj, 0);
 -
 -      if (intel_rotation_90_or_270(rotation)) {
 -              int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
 -
 -              /* stride: Surface height in tiles */
 -              tile_height = intel_tile_height(dev_priv, fb->modifier[0], cpp);
 -              stride = DIV_ROUND_UP(fb->height, tile_height);
 -              plane_size = (src_w << 16) | src_h;
 -              x_offset = stride * tile_height - y - (src_h + 1);
 -              y_offset = x;
 -      } else {
 -              stride = fb->pitches[0] / stride_div;
 -              plane_size = (src_h << 16) | src_w;
 -              x_offset = x;
 -              y_offset = y;
 -      }
 -      plane_offset = y_offset << 16 | x_offset;
 +      /* Sizes are 0 based */
 +      src_w--;
 +      src_h--;
 +      crtc_w--;
 +      crtc_h--;
  
 -      I915_WRITE(PLANE_OFFSET(pipe, plane), plane_offset);
 +      I915_WRITE(PLANE_OFFSET(pipe, plane), (y << 16) | x);
        I915_WRITE(PLANE_STRIDE(pipe, plane), stride);
 -      I915_WRITE(PLANE_SIZE(pipe, plane), plane_size);
 +      I915_WRITE(PLANE_SIZE(pipe, plane), (src_h << 16) | src_w);
  
        /* program plane scaler */
        if (plane_state->scaler_id >= 0) {
        }
  
        I915_WRITE(PLANE_CTL(pipe, plane), plane_ctl);
 -      I915_WRITE(PLANE_SURF(pipe, plane), surf_addr);
 +      I915_WRITE(PLANE_SURF(pipe, plane),
 +                 intel_fb_gtt_offset(fb, rotation) + surf_addr);
        POSTING_READ(PLANE_SURF(pipe, plane));
  }
  
@@@ -340,20 -363,22 +340,20 @@@ vlv_update_plane(struct drm_plane *dpla
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_plane *intel_plane = to_intel_plane(dplane);
        struct drm_framebuffer *fb = plane_state->base.fb;
 -      struct drm_i915_gem_object *obj = intel_fb_obj(fb);
        int pipe = intel_plane->pipe;
        int plane = intel_plane->plane;
        u32 sprctl;
        u32 sprsurf_offset, linear_offset;
        unsigned int rotation = dplane->state->rotation;
 -      int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
        const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
-       int crtc_x = plane_state->dst.x1;
-       int crtc_y = plane_state->dst.y1;
-       uint32_t crtc_w = drm_rect_width(&plane_state->dst);
-       uint32_t crtc_h = drm_rect_height(&plane_state->dst);
-       uint32_t x = plane_state->src.x1 >> 16;
-       uint32_t y = plane_state->src.y1 >> 16;
-       uint32_t src_w = drm_rect_width(&plane_state->src) >> 16;
-       uint32_t src_h = drm_rect_height(&plane_state->src) >> 16;
+       int crtc_x = plane_state->base.dst.x1;
+       int crtc_y = plane_state->base.dst.y1;
+       uint32_t crtc_w = drm_rect_width(&plane_state->base.dst);
+       uint32_t crtc_h = drm_rect_height(&plane_state->base.dst);
+       uint32_t x = plane_state->base.src.x1 >> 16;
+       uint32_t y = plane_state->base.src.y1 >> 16;
+       uint32_t src_w = drm_rect_width(&plane_state->base.src) >> 16;
+       uint32_t src_h = drm_rect_height(&plane_state->base.src) >> 16;
  
        sprctl = SP_ENABLE;
  
         */
        sprctl |= SP_GAMMA_ENABLE;
  
 -      if (i915_gem_object_is_tiled(obj))
 +      if (fb->modifier[0] == I915_FORMAT_MOD_X_TILED)
                sprctl |= SP_TILED;
  
        /* Sizes are 0 based */
        crtc_w--;
        crtc_h--;
  
 -      linear_offset = y * fb->pitches[0] + x * cpp;
 -      sprsurf_offset = intel_compute_tile_offset(&x, &y, fb, 0,
 -                                                 fb->pitches[0], rotation);
 -      linear_offset -= sprsurf_offset;
 +      intel_add_fb_offsets(&x, &y, plane_state, 0);
 +      sprsurf_offset = intel_compute_tile_offset(&x, &y, plane_state, 0);
  
-       if (rotation == BIT(DRM_ROTATE_180)) {
+       if (rotation == DRM_ROTATE_180) {
                sprctl |= SP_ROTATE_180;
  
                x += src_w;
                y += src_h;
 -              linear_offset += src_h * fb->pitches[0] + src_w * cpp;
        }
  
 +      linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0);
 +
        if (key->flags) {
                I915_WRITE(SPKEYMINVAL(pipe, plane), key->min_value);
                I915_WRITE(SPKEYMAXVAL(pipe, plane), key->max_value);
        I915_WRITE(SPSTRIDE(pipe, plane), fb->pitches[0]);
        I915_WRITE(SPPOS(pipe, plane), (crtc_y << 16) | crtc_x);
  
 -      if (i915_gem_object_is_tiled(obj))
 +      if (fb->modifier[0] == I915_FORMAT_MOD_X_TILED)
                I915_WRITE(SPTILEOFF(pipe, plane), (y << 16) | x);
        else
                I915_WRITE(SPLINOFF(pipe, plane), linear_offset);
  
        I915_WRITE(SPSIZE(pipe, plane), (crtc_h << 16) | crtc_w);
        I915_WRITE(SPCNTR(pipe, plane), sprctl);
 -      I915_WRITE(SPSURF(pipe, plane), i915_gem_obj_ggtt_offset(obj) +
 -                 sprsurf_offset);
 +      I915_WRITE(SPSURF(pipe, plane),
 +                 intel_fb_gtt_offset(fb, rotation) + sprsurf_offset);
        POSTING_READ(SPSURF(pipe, plane));
  }
  
@@@ -480,19 -506,21 +480,19 @@@ ivb_update_plane(struct drm_plane *plan
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_plane *intel_plane = to_intel_plane(plane);
        struct drm_framebuffer *fb = plane_state->base.fb;
 -      struct drm_i915_gem_object *obj = intel_fb_obj(fb);
        enum pipe pipe = intel_plane->pipe;
        u32 sprctl, sprscale = 0;
        u32 sprsurf_offset, linear_offset;
        unsigned int rotation = plane_state->base.rotation;
 -      int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
        const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
-       int crtc_x = plane_state->dst.x1;
-       int crtc_y = plane_state->dst.y1;
-       uint32_t crtc_w = drm_rect_width(&plane_state->dst);
-       uint32_t crtc_h = drm_rect_height(&plane_state->dst);
-       uint32_t x = plane_state->src.x1 >> 16;
-       uint32_t y = plane_state->src.y1 >> 16;
-       uint32_t src_w = drm_rect_width(&plane_state->src) >> 16;
-       uint32_t src_h = drm_rect_height(&plane_state->src) >> 16;
+       int crtc_x = plane_state->base.dst.x1;
+       int crtc_y = plane_state->base.dst.y1;
+       uint32_t crtc_w = drm_rect_width(&plane_state->base.dst);
+       uint32_t crtc_h = drm_rect_height(&plane_state->base.dst);
+       uint32_t x = plane_state->base.src.x1 >> 16;
+       uint32_t y = plane_state->base.src.y1 >> 16;
+       uint32_t src_w = drm_rect_width(&plane_state->base.src) >> 16;
+       uint32_t src_h = drm_rect_height(&plane_state->base.src) >> 16;
  
        sprctl = SPRITE_ENABLE;
  
         */
        sprctl |= SPRITE_GAMMA_ENABLE;
  
 -      if (i915_gem_object_is_tiled(obj))
 +      if (fb->modifier[0] == I915_FORMAT_MOD_X_TILED)
                sprctl |= SPRITE_TILED;
  
        if (IS_HASWELL(dev) || IS_BROADWELL(dev))
        if (crtc_w != src_w || crtc_h != src_h)
                sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h;
  
 -      linear_offset = y * fb->pitches[0] + x * cpp;
 -      sprsurf_offset = intel_compute_tile_offset(&x, &y, fb, 0,
 -                                                 fb->pitches[0], rotation);
 -      linear_offset -= sprsurf_offset;
 +      intel_add_fb_offsets(&x, &y, plane_state, 0);
 +      sprsurf_offset = intel_compute_tile_offset(&x, &y, plane_state, 0);
  
-       if (rotation == BIT(DRM_ROTATE_180)) {
+       if (rotation == DRM_ROTATE_180) {
                sprctl |= SPRITE_ROTATE_180;
  
                /* HSW and BDW does this automagically in hardware */
                if (!IS_HASWELL(dev) && !IS_BROADWELL(dev)) {
                        x += src_w;
                        y += src_h;
 -                      linear_offset += src_h * fb->pitches[0] + src_w * cpp;
                }
        }
  
 +      linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0);
 +
        if (key->flags) {
                I915_WRITE(SPRKEYVAL(pipe), key->min_value);
                I915_WRITE(SPRKEYMAX(pipe), key->max_value);
         * register */
        if (IS_HASWELL(dev) || IS_BROADWELL(dev))
                I915_WRITE(SPROFFSET(pipe), (y << 16) | x);
 -      else if (i915_gem_object_is_tiled(obj))
 +      else if (fb->modifier[0] == I915_FORMAT_MOD_X_TILED)
                I915_WRITE(SPRTILEOFF(pipe), (y << 16) | x);
        else
                I915_WRITE(SPRLINOFF(pipe), linear_offset);
                I915_WRITE(SPRSCALE(pipe), sprscale);
        I915_WRITE(SPRCTL(pipe), sprctl);
        I915_WRITE(SPRSURF(pipe),
 -                 i915_gem_obj_ggtt_offset(obj) + sprsurf_offset);
 +                 intel_fb_gtt_offset(fb, rotation) + sprsurf_offset);
        POSTING_READ(SPRSURF(pipe));
  }
  
@@@ -618,19 -647,21 +618,19 @@@ ilk_update_plane(struct drm_plane *plan
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_plane *intel_plane = to_intel_plane(plane);
        struct drm_framebuffer *fb = plane_state->base.fb;
 -      struct drm_i915_gem_object *obj = intel_fb_obj(fb);
        int pipe = intel_plane->pipe;
        u32 dvscntr, dvsscale;
        u32 dvssurf_offset, linear_offset;
        unsigned int rotation = plane_state->base.rotation;
 -      int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
        const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
-       int crtc_x = plane_state->dst.x1;
-       int crtc_y = plane_state->dst.y1;
-       uint32_t crtc_w = drm_rect_width(&plane_state->dst);
-       uint32_t crtc_h = drm_rect_height(&plane_state->dst);
-       uint32_t x = plane_state->src.x1 >> 16;
-       uint32_t y = plane_state->src.y1 >> 16;
-       uint32_t src_w = drm_rect_width(&plane_state->src) >> 16;
-       uint32_t src_h = drm_rect_height(&plane_state->src) >> 16;
+       int crtc_x = plane_state->base.dst.x1;
+       int crtc_y = plane_state->base.dst.y1;
+       uint32_t crtc_w = drm_rect_width(&plane_state->base.dst);
+       uint32_t crtc_h = drm_rect_height(&plane_state->base.dst);
+       uint32_t x = plane_state->base.src.x1 >> 16;
+       uint32_t y = plane_state->base.src.y1 >> 16;
+       uint32_t src_w = drm_rect_width(&plane_state->base.src) >> 16;
+       uint32_t src_h = drm_rect_height(&plane_state->base.src) >> 16;
  
        dvscntr = DVS_ENABLE;
  
         */
        dvscntr |= DVS_GAMMA_ENABLE;
  
 -      if (i915_gem_object_is_tiled(obj))
 +      if (fb->modifier[0] == I915_FORMAT_MOD_X_TILED)
                dvscntr |= DVS_TILED;
  
        if (IS_GEN6(dev))
        if (crtc_w != src_w || crtc_h != src_h)
                dvsscale = DVS_SCALE_ENABLE | (src_w << 16) | src_h;
  
 -      linear_offset = y * fb->pitches[0] + x * cpp;
 -      dvssurf_offset = intel_compute_tile_offset(&x, &y, fb, 0,
 -                                                 fb->pitches[0], rotation);
 -      linear_offset -= dvssurf_offset;
 +      intel_add_fb_offsets(&x, &y, plane_state, 0);
 +      dvssurf_offset = intel_compute_tile_offset(&x, &y, plane_state, 0);
  
-       if (rotation == BIT(DRM_ROTATE_180)) {
+       if (rotation == DRM_ROTATE_180) {
                dvscntr |= DVS_ROTATE_180;
  
                x += src_w;
                y += src_h;
 -              linear_offset += src_h * fb->pitches[0] + src_w * cpp;
        }
  
 +      linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0);
 +
        if (key->flags) {
                I915_WRITE(DVSKEYVAL(pipe), key->min_value);
                I915_WRITE(DVSKEYMAX(pipe), key->max_value);
        I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]);
        I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x);
  
 -      if (i915_gem_object_is_tiled(obj))
 +      if (fb->modifier[0] == I915_FORMAT_MOD_X_TILED)
                I915_WRITE(DVSTILEOFF(pipe), (y << 16) | x);
        else
                I915_WRITE(DVSLINOFF(pipe), linear_offset);
        I915_WRITE(DVSSCALE(pipe), dvsscale);
        I915_WRITE(DVSCNTR(pipe), dvscntr);
        I915_WRITE(DVSSURF(pipe),
 -                 i915_gem_obj_ggtt_offset(obj) + dvssurf_offset);
 +                 intel_fb_gtt_offset(fb, rotation) + dvssurf_offset);
        POSTING_READ(DVSSURF(pipe));
  }
  
@@@ -747,16 -779,25 +747,26 @@@ intel_check_sprite_plane(struct drm_pla
        int crtc_x, crtc_y;
        unsigned int crtc_w, crtc_h;
        uint32_t src_x, src_y, src_w, src_h;
-       struct drm_rect *src = &state->src;
-       struct drm_rect *dst = &state->dst;
+       struct drm_rect *src = &state->base.src;
+       struct drm_rect *dst = &state->base.dst;
        const struct drm_rect *clip = &state->clip;
        int hscale, vscale;
        int max_scale, min_scale;
        bool can_scale;
 +      int ret;
  
+       src->x1 = state->base.src_x;
+       src->y1 = state->base.src_y;
+       src->x2 = state->base.src_x + state->base.src_w;
+       src->y2 = state->base.src_y + state->base.src_h;
+       dst->x1 = state->base.crtc_x;
+       dst->y1 = state->base.crtc_y;
+       dst->x2 = state->base.crtc_x + state->base.crtc_w;
+       dst->y2 = state->base.crtc_y + state->base.crtc_h;
        if (!fb) {
-               state->visible = false;
+               state->base.visible = false;
                return 0;
        }
  
        vscale = drm_rect_calc_vscale_relaxed(src, dst, min_scale, max_scale);
        BUG_ON(vscale < 0);
  
-       state->visible = drm_rect_clip_scaled(src, dst, clip, hscale, vscale);
+       state->base.visible = drm_rect_clip_scaled(src, dst, clip, hscale, vscale);
  
        crtc_x = dst->x1;
        crtc_y = dst->y1;
        crtc_w = drm_rect_width(dst);
        crtc_h = drm_rect_height(dst);
  
-       if (state->visible) {
+       if (state->base.visible) {
                /* check again in case clipping clamped the results */
                hscale = drm_rect_calc_hscale(src, dst, min_scale, max_scale);
                if (hscale < 0) {
                                crtc_w &= ~1;
  
                        if (crtc_w == 0)
-                               state->visible = false;
+                               state->base.visible = false;
                }
        }
  
        /* Check size restrictions when scaling */
-       if (state->visible && (src_w != crtc_w || src_h != crtc_h)) {
+       if (state->base.visible && (src_w != crtc_w || src_h != crtc_h)) {
                unsigned int width_bytes;
                int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
  
                /* FIXME interlacing min height is 6 */
  
                if (crtc_w < 3 || crtc_h < 3)
-                       state->visible = false;
+                       state->base.visible = false;
  
                if (src_w < 3 || src_h < 3)
-                       state->visible = false;
+                       state->base.visible = false;
  
                width_bytes = ((src_x * cpp) & 63) + src_w * cpp;
  
                }
        }
  
-       if (state->visible) {
+       if (state->base.visible) {
                src->x1 = src_x << 16;
                src->x2 = (src_x + src_w) << 16;
                src->y1 = src_y << 16;
        dst->y1 = crtc_y;
        dst->y2 = crtc_y + crtc_h;
  
 +      if (INTEL_GEN(dev) >= 9) {
 +              ret = skl_check_plane_surface(state);
 +              if (ret)
 +                      return ret;
 +      }
 +
        return 0;
  }