]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge remote-tracking branch 'drm-intel/for-linux-next'
authorStephen Rothwell <sfr@canb.auug.org.au>
Thu, 11 Feb 2016 01:15:05 +0000 (12:15 +1100)
committerStephen Rothwell <sfr@canb.auug.org.au>
Thu, 11 Feb 2016 01:15:05 +0000 (12:15 +1100)
1  2 
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_drv.h

index 1c3d2544fec4e817422153f1aa40465f91985eee,571d7e62953b93155d82f3fdd41323fef23983af..2df2fac04708be85f0b596ee07df82e894434b9c
@@@ -391,20 -391,13 +391,13 @@@ static int i915_load_modeset_init(struc
        if (ret)
                goto cleanup_vga_client;
  
-       /* Initialise stolen first so that we may reserve preallocated
-        * objects for the BIOS to KMS transition.
-        */
-       ret = i915_gem_init_stolen(dev);
-       if (ret)
-               goto cleanup_vga_switcheroo;
        intel_power_domains_init_hw(dev_priv, false);
  
        intel_csr_ucode_init(dev_priv);
  
        ret = intel_irq_install(dev_priv);
        if (ret)
-               goto cleanup_gem_stolen;
+               goto cleanup_csr;
  
        intel_setup_gmbus(dev);
  
  
  cleanup_gem:
        mutex_lock(&dev->struct_mutex);
-       i915_gem_cleanup_ringbuffer(dev);
        i915_gem_context_fini(dev);
+       i915_gem_cleanup_engines(dev);
        mutex_unlock(&dev->struct_mutex);
  cleanup_irq:
        intel_guc_ucode_fini(dev);
        drm_irq_uninstall(dev);
        intel_teardown_gmbus(dev);
- cleanup_gem_stolen:
-       i915_gem_cleanup_stolen(dev);
- cleanup_vga_switcheroo:
+ cleanup_csr:
+       intel_csr_ucode_fini(dev_priv);
        vga_switcheroo_unregister_client(dev->pdev);
  cleanup_vga_client:
        vga_client_register(dev->pdev, NULL, NULL, NULL);
@@@ -816,7 -808,41 +808,41 @@@ static void intel_device_info_runtime_i
                     !(sfuse_strap & SFUSE_STRAP_FUSE_LOCK))) {
                        DRM_INFO("Display fused off, disabling\n");
                        info->num_pipes = 0;
+               } else if (fuse_strap & IVB_PIPE_C_DISABLE) {
+                       DRM_INFO("PipeC fused off\n");
+                       info->num_pipes -= 1;
                }
+       } else if (info->num_pipes > 0 && INTEL_INFO(dev)->gen == 9) {
+               u32 dfsm = I915_READ(SKL_DFSM);
+               u8 disabled_mask = 0;
+               bool invalid;
+               int num_bits;
+               if (dfsm & SKL_DFSM_PIPE_A_DISABLE)
+                       disabled_mask |= BIT(PIPE_A);
+               if (dfsm & SKL_DFSM_PIPE_B_DISABLE)
+                       disabled_mask |= BIT(PIPE_B);
+               if (dfsm & SKL_DFSM_PIPE_C_DISABLE)
+                       disabled_mask |= BIT(PIPE_C);
+               num_bits = hweight8(disabled_mask);
+               switch (disabled_mask) {
+               case BIT(PIPE_A):
+               case BIT(PIPE_B):
+               case BIT(PIPE_A) | BIT(PIPE_B):
+               case BIT(PIPE_A) | BIT(PIPE_C):
+                       invalid = true;
+                       break;
+               default:
+                       invalid = false;
+               }
+               if (num_bits > info->num_pipes || invalid)
+                       DRM_ERROR("invalid pipe fuse configuration: 0x%x\n",
+                                 disabled_mask);
+               else
+                       info->num_pipes -= num_bits;
        }
  
        /* Initialize slice/subslice/EU info */
@@@ -855,6 -881,94 +881,94 @@@ static void intel_init_dpio(struct drm_
        }
  }
  
+ static int i915_workqueues_init(struct drm_i915_private *dev_priv)
+ {
+       /*
+        * The i915 workqueue is primarily used for batched retirement of
+        * requests (and thus managing bo) once the task has been completed
+        * by the GPU. i915_gem_retire_requests() is called directly when we
+        * need high-priority retirement, such as waiting for an explicit
+        * bo.
+        *
+        * It is also used for periodic low-priority events, such as
+        * idle-timers and recording error state.
+        *
+        * All tasks on the workqueue are expected to acquire the dev mutex
+        * so there is no point in running more than one instance of the
+        * workqueue at any time.  Use an ordered one.
+        */
+       dev_priv->wq = alloc_ordered_workqueue("i915", 0);
+       if (dev_priv->wq == NULL)
+               goto out_err;
+       dev_priv->hotplug.dp_wq = alloc_ordered_workqueue("i915-dp", 0);
+       if (dev_priv->hotplug.dp_wq == NULL)
+               goto out_free_wq;
+       dev_priv->gpu_error.hangcheck_wq =
+               alloc_ordered_workqueue("i915-hangcheck", 0);
+       if (dev_priv->gpu_error.hangcheck_wq == NULL)
+               goto out_free_dp_wq;
+       return 0;
+ out_free_dp_wq:
+       destroy_workqueue(dev_priv->hotplug.dp_wq);
+ out_free_wq:
+       destroy_workqueue(dev_priv->wq);
+ out_err:
+       DRM_ERROR("Failed to allocate workqueues.\n");
+       return -ENOMEM;
+ }
+ static void i915_workqueues_cleanup(struct drm_i915_private *dev_priv)
+ {
+       destroy_workqueue(dev_priv->gpu_error.hangcheck_wq);
+       destroy_workqueue(dev_priv->hotplug.dp_wq);
+       destroy_workqueue(dev_priv->wq);
+ }
+ static int i915_mmio_setup(struct drm_device *dev)
+ {
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       int mmio_bar;
+       int mmio_size;
+       mmio_bar = IS_GEN2(dev) ? 1 : 0;
+       /*
+        * Before gen4, the registers and the GTT are behind different BARs.
+        * However, from gen4 onwards, the registers and the GTT are shared
+        * in the same BAR, so we want to restrict this ioremap from
+        * clobbering the GTT which we want ioremap_wc instead. Fortunately,
+        * the register BAR remains the same size for all the earlier
+        * generations up to Ironlake.
+        */
+       if (INTEL_INFO(dev)->gen < 5)
+               mmio_size = 512 * 1024;
+       else
+               mmio_size = 2 * 1024 * 1024;
+       dev_priv->regs = pci_iomap(dev->pdev, mmio_bar, mmio_size);
+       if (dev_priv->regs == NULL) {
+               DRM_ERROR("failed to map registers\n");
+               return -EIO;
+       }
+       /* Try to make sure MCHBAR is enabled before poking at it */
+       intel_setup_mchbar(dev);
+       return 0;
+ }
+ static void i915_mmio_cleanup(struct drm_device *dev)
+ {
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       intel_teardown_mchbar(dev);
+       pci_iounmap(dev->pdev, dev_priv->regs);
+ }
  /**
   * i915_driver_load - setup chip and create an initial config
   * @dev: DRM device
@@@ -870,7 -984,7 +984,7 @@@ int i915_driver_load(struct drm_device 
  {
        struct drm_i915_private *dev_priv;
        struct intel_device_info *info, *device_info;
-       int ret = 0, mmio_bar, mmio_size;
+       int ret = 0;
        uint32_t aperture_size;
  
        info = (struct intel_device_info *) flags;
        mutex_init(&dev_priv->modeset_restore_lock);
        mutex_init(&dev_priv->av_mutex);
  
+       ret = i915_workqueues_init(dev_priv);
+       if (ret < 0)
+               goto out_free_priv;
        intel_pm_setup(dev);
  
        intel_runtime_pm_get(dev_priv);
  
        if (i915_get_bridge_dev(dev)) {
                ret = -EIO;
-               goto free_priv;
+               goto out_runtime_pm_put;
        }
  
-       mmio_bar = IS_GEN2(dev) ? 1 : 0;
-       /* Before gen4, the registers and the GTT are behind different BARs.
-        * However, from gen4 onwards, the registers and the GTT are shared
-        * in the same BAR, so we want to restrict this ioremap from
-        * clobbering the GTT which we want ioremap_wc instead. Fortunately,
-        * the register BAR remains the same size for all the earlier
-        * generations up to Ironlake.
-        */
-       if (info->gen < 5)
-               mmio_size = 512*1024;
-       else
-               mmio_size = 2*1024*1024;
-       dev_priv->regs = pci_iomap(dev->pdev, mmio_bar, mmio_size);
-       if (!dev_priv->regs) {
-               DRM_ERROR("failed to map registers\n");
-               ret = -EIO;
+       ret = i915_mmio_setup(dev);
+       if (ret < 0)
                goto put_bridge;
-       }
  
        /* This must be called before any calls to HAS_PCH_* */
        intel_detect_pch(dev);
  
        ret = i915_gem_gtt_init(dev);
        if (ret)
-               goto out_freecsr;
+               goto out_uncore_fini;
  
        /* WARNING: Apparently we must kick fbdev drivers before vgacon,
         * otherwise the vga fbdev driver falls over. */
        dev_priv->gtt.mtrr = arch_phys_wc_add(dev_priv->gtt.mappable_base,
                                              aperture_size);
  
-       /* The i915 workqueue is primarily used for batched retirement of
-        * requests (and thus managing bo) once the task has been completed
-        * by the GPU. i915_gem_retire_requests() is called directly when we
-        * need high-priority retirement, such as waiting for an explicit
-        * bo.
-        *
-        * It is also used for periodic low-priority events, such as
-        * idle-timers and recording error state.
-        *
-        * All tasks on the workqueue are expected to acquire the dev mutex
-        * so there is no point in running more than one instance of the
-        * workqueue at any time.  Use an ordered one.
-        */
-       dev_priv->wq = alloc_ordered_workqueue("i915", 0);
-       if (dev_priv->wq == NULL) {
-               DRM_ERROR("Failed to create our workqueue.\n");
-               ret = -ENOMEM;
-               goto out_mtrrfree;
-       }
-       dev_priv->hotplug.dp_wq = alloc_ordered_workqueue("i915-dp", 0);
-       if (dev_priv->hotplug.dp_wq == NULL) {
-               DRM_ERROR("Failed to create our dp workqueue.\n");
-               ret = -ENOMEM;
-               goto out_freewq;
-       }
-       dev_priv->gpu_error.hangcheck_wq =
-               alloc_ordered_workqueue("i915-hangcheck", 0);
-       if (dev_priv->gpu_error.hangcheck_wq == NULL) {
-               DRM_ERROR("Failed to create our hangcheck workqueue.\n");
-               ret = -ENOMEM;
-               goto out_freedpwq;
-       }
        intel_irq_init(dev_priv);
        intel_uncore_sanitize(dev);
  
-       /* Try to make sure MCHBAR is enabled before poking at it */
-       intel_setup_mchbar(dev);
        intel_opregion_setup(dev);
  
-       i915_gem_load(dev);
+       i915_gem_load_init(dev);
+       i915_gem_shrinker_init(dev_priv);
  
        /* On the 945G/GM, the chipset reports the MSI capability on the
         * integrated graphics even though the support isn't actually there
         * be lost or delayed, but we use them anyways to avoid
         * stuck interrupts on some machines.
         */
-       if (!IS_I945G(dev) && !IS_I945GM(dev))
-               pci_enable_msi(dev->pdev);
+       if (!IS_I945G(dev) && !IS_I945GM(dev)) {
+               if (pci_enable_msi(dev->pdev) < 0)
+                       DRM_DEBUG_DRIVER("can't enable MSI");
+       }
  
        intel_device_info_runtime_init(dev);
  
@@@ -1097,38 -1165,29 +1165,29 @@@ out_power_well
        intel_power_domains_fini(dev_priv);
        drm_vblank_cleanup(dev);
  out_gem_unload:
-       WARN_ON(unregister_oom_notifier(&dev_priv->mm.oom_notifier));
-       unregister_shrinker(&dev_priv->mm.shrinker);
+       i915_gem_shrinker_cleanup(dev_priv);
  
        if (dev->pdev->msi_enabled)
                pci_disable_msi(dev->pdev);
  
        intel_teardown_mchbar(dev);
        pm_qos_remove_request(&dev_priv->pm_qos);
-       destroy_workqueue(dev_priv->gpu_error.hangcheck_wq);
- out_freedpwq:
-       destroy_workqueue(dev_priv->hotplug.dp_wq);
- out_freewq:
-       destroy_workqueue(dev_priv->wq);
- out_mtrrfree:
        arch_phys_wc_del(dev_priv->gtt.mtrr);
        io_mapping_free(dev_priv->gtt.mappable);
  out_gtt:
        i915_global_gtt_cleanup(dev);
- out_freecsr:
-       intel_csr_ucode_fini(dev_priv);
+ out_uncore_fini:
        intel_uncore_fini(dev);
-       pci_iounmap(dev->pdev, dev_priv->regs);
+       i915_mmio_cleanup(dev);
  put_bridge:
        pci_dev_put(dev_priv->bridge_dev);
- free_priv:
-       kmem_cache_destroy(dev_priv->requests);
-       kmem_cache_destroy(dev_priv->vmas);
-       kmem_cache_destroy(dev_priv->objects);
+       i915_gem_load_cleanup(dev);
+ out_runtime_pm_put:
        intel_runtime_pm_put(dev_priv);
+       i915_workqueues_cleanup(dev_priv);
+ out_free_priv:
        kfree(dev_priv);
        return ret;
  }
  
@@@ -1153,8 -1212,7 +1212,7 @@@ int i915_driver_unload(struct drm_devic
  
        i915_teardown_sysfs(dev);
  
-       WARN_ON(unregister_oom_notifier(&dev_priv->mm.oom_notifier));
-       unregister_shrinker(&dev_priv->mm.shrinker);
+       i915_gem_shrinker_cleanup(dev_priv);
  
        io_mapping_free(dev_priv->gtt.mappable);
        arch_phys_wc_del(dev_priv->gtt.mtrr);
        vga_switcheroo_unregister_client(dev->pdev);
        vga_client_register(dev->pdev, NULL, NULL, NULL);
  
+       intel_csr_ucode_fini(dev_priv);
        /* Free error state after interrupts are fully disabled. */
        cancel_delayed_work_sync(&dev_priv->gpu_error.hangcheck_work);
        i915_destroy_error_state(dev);
  
        intel_guc_ucode_fini(dev);
        mutex_lock(&dev->struct_mutex);
-       i915_gem_cleanup_ringbuffer(dev);
        i915_gem_context_fini(dev);
+       i915_gem_cleanup_engines(dev);
        mutex_unlock(&dev->struct_mutex);
        intel_fbc_cleanup_cfb(dev_priv);
-       i915_gem_cleanup_stolen(dev);
  
-       intel_csr_ucode_fini(dev_priv);
-       intel_teardown_mchbar(dev);
-       destroy_workqueue(dev_priv->hotplug.dp_wq);
-       destroy_workqueue(dev_priv->wq);
-       destroy_workqueue(dev_priv->gpu_error.hangcheck_wq);
        pm_qos_remove_request(&dev_priv->pm_qos);
  
        i915_global_gtt_cleanup(dev);
  
        intel_uncore_fini(dev);
-       if (dev_priv->regs != NULL)
-               pci_iounmap(dev->pdev, dev_priv->regs);
+       i915_mmio_cleanup(dev);
  
-       kmem_cache_destroy(dev_priv->requests);
-       kmem_cache_destroy(dev_priv->vmas);
-       kmem_cache_destroy(dev_priv->objects);
+       i915_gem_load_cleanup(dev);
        pci_dev_put(dev_priv->bridge_dev);
+       i915_workqueues_cleanup(dev_priv);
        kfree(dev_priv);
  
        return 0;
@@@ -1261,6 -1311,8 +1311,6 @@@ void i915_driver_preclose(struct drm_de
        i915_gem_context_close(dev, file);
        i915_gem_release(dev, file);
        mutex_unlock(&dev->struct_mutex);
 -
 -      intel_modeset_preclose(dev, file);
  }
  
  void i915_driver_postclose(struct drm_device *dev, struct drm_file *file)
index 7a5ed95f2cd91c1b1debc975caf3751bb159d99e,76421c962216b40a536ece13c66f9a678b45ea8e..c04d57ac226674b3e04edff8c8cd98d16c13db0a
@@@ -2284,7 -2284,7 +2284,7 @@@ intel_fill_fb_ggtt_view(struct i915_ggt
                        const struct drm_plane_state *plane_state)
  {
        struct drm_i915_private *dev_priv = to_i915(fb->dev);
-       struct intel_rotation_info *info = &view->params.rotation_info;
+       struct intel_rotation_info *info = &view->params.rotated;
        unsigned int tile_size, tile_width, tile_height, cpp;
  
        *view = i915_ggtt_view_normal;
        tile_size = intel_tile_size(dev_priv);
  
        cpp = drm_format_plane_cpp(fb->pixel_format, 0);
-       tile_width = intel_tile_width(dev_priv, cpp, fb->modifier[0]);
+       tile_width = intel_tile_width(dev_priv, fb->modifier[0], cpp);
        tile_height = tile_size / tile_width;
  
        info->width_pages = DIV_ROUND_UP(fb->pitches[0], tile_width);
@@@ -2448,11 -2448,11 +2448,11 @@@ static void intel_unpin_fb_obj(struct d
  
  /* Computes the linear offset to the base tile and adjusts x, y. bytes per pixel
   * is assumed to be a power-of-two. */
- unsigned long intel_compute_tile_offset(struct drm_i915_private *dev_priv,
-                                       int *x, int *y,
-                                       uint64_t fb_modifier,
-                                       unsigned int cpp,
-                                       unsigned int pitch)
+ u32 intel_compute_tile_offset(struct drm_i915_private *dev_priv,
+                             int *x, int *y,
+                             uint64_t fb_modifier,
+                             unsigned int cpp,
+                             unsigned int pitch)
  {
        if (fb_modifier != DRM_FORMAT_MOD_NONE) {
                unsigned int tile_size, tile_width, tile_height;
@@@ -2706,14 -2706,12 +2706,12 @@@ static void i9xx_update_primary_plane(s
        struct drm_framebuffer *fb = plane_state->base.fb;
        struct drm_i915_gem_object *obj = intel_fb_obj(fb);
        int plane = intel_crtc->plane;
-       unsigned long linear_offset;
-       int x = plane_state->src.x1 >> 16;
-       int y = plane_state->src.y1 >> 16;
+       u32 linear_offset;
        u32 dspcntr;
        i915_reg_t reg = DSPCNTR(plane);
-       int pixel_size;
-       pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
+       int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
+       int x = plane_state->src.x1 >> 16;
+       int y = plane_state->src.y1 >> 16;
  
        dspcntr = DISPPLANE_GAMMA_ENABLE;
  
        if (IS_G4X(dev))
                dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
  
-       linear_offset = y * fb->pitches[0] + x * pixel_size;
+       linear_offset = y * fb->pitches[0] + x * cpp;
  
        if (INTEL_INFO(dev)->gen >= 4) {
                intel_crtc->dspaddr_offset =
                        intel_compute_tile_offset(dev_priv, &x, &y,
-                                                 fb->modifier[0],
-                                                 pixel_size,
+                                                 fb->modifier[0], cpp,
                                                  fb->pitches[0]);
                linear_offset -= intel_crtc->dspaddr_offset;
        } else {
                data and adding to linear_offset*/
                linear_offset +=
                        (crtc_state->pipe_src_h - 1) * fb->pitches[0] +
-                       (crtc_state->pipe_src_w - 1) * pixel_size;
+                       (crtc_state->pipe_src_w - 1) * cpp;
        }
  
        intel_crtc->adjusted_x = x;
@@@ -2839,10 -2836,10 +2836,10 @@@ static void ironlake_update_primary_pla
        struct drm_framebuffer *fb = plane_state->base.fb;
        struct drm_i915_gem_object *obj = intel_fb_obj(fb);
        int plane = intel_crtc->plane;
-       unsigned long linear_offset;
+       u32 linear_offset;
        u32 dspcntr;
        i915_reg_t reg = DSPCNTR(plane);
-       int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
+       int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
        int x = plane_state->src.x1 >> 16;
        int y = plane_state->src.y1 >> 16;
  
        if (!IS_HASWELL(dev) && !IS_BROADWELL(dev))
                dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
  
-       linear_offset = y * fb->pitches[0] + x * pixel_size;
+       linear_offset = y * fb->pitches[0] + x * cpp;
        intel_crtc->dspaddr_offset =
                intel_compute_tile_offset(dev_priv, &x, &y,
-                                         fb->modifier[0],
-                                         pixel_size,
+                                         fb->modifier[0], cpp,
                                          fb->pitches[0]);
        linear_offset -= intel_crtc->dspaddr_offset;
        if (plane_state->base.rotation == BIT(DRM_ROTATE_180)) {
                        data and adding to linear_offset*/
                        linear_offset +=
                                (crtc_state->pipe_src_h - 1) * fb->pitches[0] +
-                               (crtc_state->pipe_src_w - 1) * pixel_size;
+                               (crtc_state->pipe_src_w - 1) * cpp;
                }
        }
  
@@@ -2951,7 -2947,7 +2947,7 @@@ u32 intel_plane_obj_offset(struct intel
        offset = vma->node.start;
  
        if (plane == 1) {
-               offset += vma->ggtt_view.params.rotation_info.uv_start_page *
+               offset += vma->ggtt_view.params.rotated.uv_start_page *
                          PAGE_SIZE;
        }
  
@@@ -3160,9 -3156,6 +3156,6 @@@ static void skylake_disable_primary_pla
        struct drm_i915_private *dev_priv = dev->dev_private;
        int pipe = to_intel_crtc(crtc)->pipe;
  
-       if (dev_priv->fbc.deactivate)
-               dev_priv->fbc.deactivate(dev_priv);
        I915_WRITE(PLANE_CTL(pipe, 0), 0);
        I915_WRITE(PLANE_SURF(pipe, 0), 0);
        POSTING_READ(PLANE_SURF(pipe, 0));
@@@ -4803,7 -4796,7 +4796,7 @@@ static void intel_post_plane_update(str
                intel_update_watermarks(&crtc->base);
  
        if (atomic->update_fbc)
-               intel_fbc_update(crtc);
+               intel_fbc_post_update(crtc);
  
        if (atomic->post_enable_primary)
                intel_post_enable_primary(&crtc->base);
        memset(atomic, 0, sizeof(*atomic));
  }
  
- static void intel_pre_plane_update(struct intel_crtc *crtc)
+ static void intel_pre_plane_update(struct intel_crtc_state *old_crtc_state)
  {
+       struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc);
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc_atomic_commit *atomic = &crtc->atomic;
        struct intel_crtc_state *pipe_config =
                to_intel_crtc_state(crtc->base.state);
+       struct drm_atomic_state *old_state = old_crtc_state->base.state;
+       struct drm_plane *primary = crtc->base.primary;
+       struct drm_plane_state *old_pri_state =
+               drm_atomic_get_existing_plane_state(old_state, primary);
+       bool modeset = needs_modeset(&pipe_config->base);
  
-       if (atomic->disable_fbc)
-               intel_fbc_deactivate(crtc);
+       if (atomic->update_fbc)
+               intel_fbc_pre_update(crtc);
  
-       if (crtc->atomic.disable_ips)
-               hsw_disable_ips(crtc);
+       if (old_pri_state) {
+               struct intel_plane_state *primary_state =
+                       to_intel_plane_state(primary->state);
+               struct intel_plane_state *old_primary_state =
+                       to_intel_plane_state(old_pri_state);
  
-       if (atomic->pre_disable_primary)
-               intel_pre_disable_primary(&crtc->base);
+               if (old_primary_state->visible &&
+                   (modeset || !primary_state->visible))
+                       intel_pre_disable_primary(&crtc->base);
+       }
  
        if (pipe_config->disable_cxsr) {
                crtc->wm.cxsr_allowed = false;
-               intel_set_memory_cxsr(dev_priv, false);
+               if (old_crtc_state->base.active)
+                       intel_set_memory_cxsr(dev_priv, false);
        }
  
        if (!needs_modeset(&pipe_config->base) && pipe_config->wm_changed)
@@@ -4931,8 -4937,6 +4937,6 @@@ static void ironlake_crtc_enable(struc
        if (intel_crtc->config->has_pch_encoder)
                intel_wait_for_vblank(dev, pipe);
        intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, true);
-       intel_fbc_enable(intel_crtc);
  }
  
  /* IPS only exists on ULT machines and is tied to pipe A. */
@@@ -5045,8 -5049,6 +5049,6 @@@ static void haswell_crtc_enable(struct 
                intel_wait_for_vblank(dev, hsw_workaround_pipe);
                intel_wait_for_vblank(dev, hsw_workaround_pipe);
        }
-       intel_fbc_enable(intel_crtc);
  }
  
  static void ironlake_pfit_disable(struct intel_crtc *crtc, bool force)
@@@ -5127,8 -5129,6 +5129,6 @@@ static void ironlake_crtc_disable(struc
        }
  
        intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, true);
-       intel_fbc_disable_crtc(intel_crtc);
  }
  
  static void haswell_crtc_disable(struct drm_crtc *crtc)
                intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A,
                                                      true);
        }
-       intel_fbc_disable_crtc(intel_crtc);
  }
  
  static void i9xx_pfit_enable(struct intel_crtc *crtc)
@@@ -6291,8 -6289,6 +6289,6 @@@ static void i9xx_crtc_enable(struct drm
  
        for_each_encoder_on_crtc(dev, crtc, encoder)
                encoder->enable(encoder);
-       intel_fbc_enable(intel_crtc);
  }
  
  static void i9xx_pfit_disable(struct intel_crtc *crtc)
@@@ -6355,8 -6351,6 +6351,6 @@@ static void i9xx_crtc_disable(struct dr
  
        if (!IS_GEN2(dev))
                intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false);
-       intel_fbc_disable_crtc(intel_crtc);
  }
  
  static void intel_crtc_disable_noatomic(struct drm_crtc *crtc)
  
        dev_priv->display.crtc_disable(crtc);
        intel_crtc->active = false;
+       intel_fbc_disable(intel_crtc);
        intel_update_watermarks(crtc);
        intel_disable_shared_dpll(intel_crtc);
  
@@@ -9853,8 -9848,13 +9848,13 @@@ static void broadwell_modeset_commit_cd
  static int haswell_crtc_compute_clock(struct intel_crtc *crtc,
                                      struct intel_crtc_state *crtc_state)
  {
-       if (!intel_ddi_pll_select(crtc, crtc_state))
-               return -EINVAL;
+       struct intel_encoder *intel_encoder =
+               intel_ddi_get_crtc_new_encoder(crtc_state);
+       if (intel_encoder->type != INTEL_OUTPUT_DSI) {
+               if (!intel_ddi_pll_select(crtc, crtc_state))
+                       return -EINVAL;
+       }
  
        crtc->lowfreq_avail = false;
  
@@@ -10916,6 -10916,7 +10916,7 @@@ static void intel_unpin_work_fn(struct 
        mutex_unlock(&dev->struct_mutex);
  
        intel_frontbuffer_flip_complete(dev, to_intel_plane(primary)->frontbuffer_bit);
+       intel_fbc_post_update(crtc);
        drm_framebuffer_unreference(work->old_fb);
  
        BUG_ON(atomic_read(&crtc->unpin_work_count) == 0);
@@@ -11631,6 -11632,7 +11632,7 @@@ static int intel_crtc_page_flip(struct 
  
        crtc->primary->fb = fb;
        update_state_fb(crtc->primary);
+       intel_fbc_pre_update(intel_crtc);
  
        work->pending_flip_obj = obj;
  
                          to_intel_plane(primary)->frontbuffer_bit);
        mutex_unlock(&dev->struct_mutex);
  
-       intel_fbc_deactivate(intel_crtc);
        intel_frontbuffer_flip_prepare(dev,
                                       to_intel_plane(primary)->frontbuffer_bit);
  
  cleanup_unpin:
        intel_unpin_fb_obj(fb, crtc->primary->state);
  cleanup_pending:
-       if (request)
+       if (!IS_ERR_OR_NULL(request))
                i915_gem_request_cancel(request);
        atomic_dec(&intel_crtc->unpin_work_count);
        mutex_unlock(&dev->struct_mutex);
@@@ -11837,7 -11838,6 +11838,6 @@@ int intel_plane_atomic_calc_changes(str
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct drm_plane *plane = plane_state->plane;
        struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_plane_state *old_plane_state =
                to_intel_plane_state(plane->state);
        int idx = intel_crtc->base.base.id, ret;
  
        switch (plane->type) {
        case DRM_PLANE_TYPE_PRIMARY:
-               intel_crtc->atomic.pre_disable_primary = turn_off;
                intel_crtc->atomic.post_enable_primary = turn_on;
-               if (turn_off) {
-                       /*
-                        * FIXME: Actually if we will still have any other
-                        * plane enabled on the pipe we could let IPS enabled
-                        * still, but for now lets consider that when we make
-                        * primary invisible by setting DSPCNTR to 0 on
-                        * update_primary_plane function IPS needs to be
-                        * disable.
-                        */
-                       intel_crtc->atomic.disable_ips = true;
-                       intel_crtc->atomic.disable_fbc = true;
-               }
-               /*
-                * FBC does not work on some platforms for rotated
-                * planes, so disable it when rotation is not 0 and
-                * update it when rotation is set back to 0.
-                *
-                * FIXME: This is redundant with the fbc update done in
-                * the primary plane enable function except that that
-                * one is done too late. We eventually need to unify
-                * this.
-                */
-               if (visible &&
-                   INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) &&
-                   dev_priv->fbc.crtc == intel_crtc &&
-                   plane_state->rotation != BIT(DRM_ROTATE_0))
-                       intel_crtc->atomic.disable_fbc = true;
+               intel_crtc->atomic.update_fbc = true;
  
                /*
                 * BDW signals flip done immediately if the plane
                if (turn_on && IS_BROADWELL(dev))
                        intel_crtc->atomic.wait_vblank = true;
  
-               intel_crtc->atomic.update_fbc |= visible || mode_changed;
                break;
        case DRM_PLANE_TYPE_CURSOR:
                break;
@@@ -13350,6 -13318,7 +13318,7 @@@ static void calc_watermark_data(struct 
  static int intel_atomic_check(struct drm_device *dev,
                              struct drm_atomic_state *state)
  {
+       struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
        struct drm_crtc *crtc;
        struct drm_crtc_state *crtc_state;
                        return ret;
  
                if (i915.fastboot &&
-                   intel_pipe_config_compare(state->dev,
+                   intel_pipe_config_compare(dev,
                                        to_intel_crtc_state(crtc->state),
                                        pipe_config, true)) {
                        crtc_state->mode_changed = false;
                if (ret)
                        return ret;
        } else
-               intel_state->cdclk = to_i915(state->dev)->cdclk_freq;
+               intel_state->cdclk = dev_priv->cdclk_freq;
  
-       ret = drm_atomic_helper_check_planes(state->dev, state);
+       ret = drm_atomic_helper_check_planes(dev, state);
        if (ret)
                return ret;
  
+       intel_fbc_choose_crtc(dev_priv, state);
        calc_watermark_data(state);
  
        return 0;
@@@ -13544,12 -13514,13 +13514,13 @@@ static int intel_atomic_commit(struct d
                if (!needs_modeset(crtc->state))
                        continue;
  
-               intel_pre_plane_update(intel_crtc);
+               intel_pre_plane_update(to_intel_crtc_state(crtc_state));
  
                if (crtc_state->active) {
                        intel_crtc_disable_planes(crtc, crtc_state->plane_mask);
                        dev_priv->display.crtc_disable(crtc);
                        intel_crtc->active = false;
+                       intel_fbc_disable(intel_crtc);
                        intel_disable_shared_dpll(intel_crtc);
  
                        /*
                }
  
                if (!modeset)
-                       intel_pre_plane_update(intel_crtc);
+                       intel_pre_plane_update(to_intel_crtc_state(crtc_state));
+               if (crtc->state->active && intel_crtc->atomic.update_fbc)
+                       intel_fbc_enable(intel_crtc);
  
                if (crtc->state->active &&
                    (crtc->state->planes_changed || update_pipe))
@@@ -14684,10 -14658,12 +14658,12 @@@ u32 intel_fb_pitch_limit(struct drm_dev
        u32 gen = INTEL_INFO(dev)->gen;
  
        if (gen >= 9) {
+               int cpp = drm_format_plane_cpp(pixel_format, 0);
                /* "The stride in bytes must not exceed the of the size of 8K
                 *  pixels and 32K bytes."
                 */
-                return min(8192*drm_format_plane_cpp(pixel_format, 0), 32768);
+               return min(8192 * cpp, 32768);
        } else if (gen >= 5 && !IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev)) {
                return 32*1024;
        } else if (gen >= 4) {
@@@ -15933,6 -15909,8 +15909,8 @@@ intel_modeset_setup_hw_state(struct drm
                        modeset_put_power_domains(dev_priv, put_domains);
        }
        intel_display_set_init_power(dev_priv, false);
+       intel_fbc_init_pipe_state(dev_priv);
  }
  
  void intel_display_resume(struct drm_device *dev)
@@@ -16062,7 -16040,7 +16040,7 @@@ void intel_modeset_cleanup(struct drm_d
  
        intel_unregister_dsm_handler();
  
-       intel_fbc_disable(dev_priv);
+       intel_fbc_global_disable(dev_priv);
  
        /* flush any delayed tasks or pending work */
        flush_scheduled_work();
@@@ -16310,3 -16288,24 +16288,3 @@@ intel_display_print_error_state(struct 
                err_printf(m, "  VSYNC: %08x\n", error->transcoder[i].vsync);
        }
  }
 -
 -void intel_modeset_preclose(struct drm_device *dev, struct drm_file *file)
 -{
 -      struct intel_crtc *crtc;
 -
 -      for_each_intel_crtc(dev, crtc) {
 -              struct intel_unpin_work *work;
 -
 -              spin_lock_irq(&dev->event_lock);
 -
 -              work = crtc->unpin_work;
 -
 -              if (work && work->event &&
 -                  work->event->base.file_priv == file) {
 -                      kfree(work->event);
 -                      work->event = NULL;
 -              }
 -
 -              spin_unlock_irq(&dev->event_lock);
 -      }
 -}
index bf6f98134b50e13b80fff10f13e1cddba0d5393d,d0921ba9a65aa2781f92b2fbf22e14baca28aadf..878172a45f397f2a2577b9c273a683b6ab137185
@@@ -492,6 -492,8 +492,8 @@@ struct intel_crtc_state 
  
        bool ips_enabled;
  
+       bool enable_fbc;
        bool double_wide;
  
        bool dp_encoder_is_mst;
@@@ -542,16 -544,15 +544,15 @@@ struct intel_mmio_flip 
   */
  struct intel_crtc_atomic_commit {
        /* Sleepable operations to perform before commit */
-       bool disable_fbc;
-       bool disable_ips;
-       bool pre_disable_primary;
  
        /* Sleepable operations to perform after commit */
        unsigned fb_bits;
        bool wait_vblank;
-       bool update_fbc;
        bool post_enable_primary;
        unsigned update_sprite_watermarks;
+       /* Sleepable operations to perform before and after commit */
+       bool update_fbc;
  };
  
  struct intel_crtc {
        /* Display surface base address adjustement for pageflips. Note that on
         * gen4+ this only adjusts up to a tile, offsets within a tile are
         * handled in the hw itself (with the TILEOFF register). */
-       unsigned long dspaddr_offset;
+       u32 dspaddr_offset;
        int adjusted_x;
        int adjusted_y;
  
@@@ -1172,11 -1173,11 +1173,11 @@@ void assert_fdi_rx_pll(struct drm_i915_
  void assert_pipe(struct drm_i915_private *dev_priv, enum pipe pipe, bool state);
  #define assert_pipe_enabled(d, p) assert_pipe(d, p, true)
  #define assert_pipe_disabled(d, p) assert_pipe(d, p, false)
- unsigned long intel_compute_tile_offset(struct drm_i915_private *dev_priv,
-                                       int *x, int *y,
-                                       uint64_t fb_modifier,
-                                       unsigned int cpp,
-                                       unsigned int pitch);
+ u32 intel_compute_tile_offset(struct drm_i915_private *dev_priv,
+                             int *x, int *y,
+                             uint64_t fb_modifier,
+                             unsigned int cpp,
+                             unsigned int pitch);
  void intel_prepare_reset(struct drm_device *dev);
  void intel_finish_reset(struct drm_device *dev);
  void hsw_enable_pc8(struct drm_i915_private *dev_priv);
@@@ -1212,6 -1213,7 +1213,6 @@@ enum intel_display_power_domai
  intel_display_port_aux_power_domain(struct intel_encoder *intel_encoder);
  void intel_mode_from_pipe_config(struct drm_display_mode *mode,
                                 struct intel_crtc_state *pipe_config);
 -void intel_modeset_preclose(struct drm_device *dev, struct drm_file *file);
  
  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);
@@@ -1327,13 -1329,16 +1328,16 @@@ static inline void intel_fbdev_restore_
  #endif
  
  /* intel_fbc.c */
+ void intel_fbc_choose_crtc(struct drm_i915_private *dev_priv,
+                          struct drm_atomic_state *state);
  bool intel_fbc_is_active(struct drm_i915_private *dev_priv);
- void intel_fbc_deactivate(struct intel_crtc *crtc);
- void intel_fbc_update(struct intel_crtc *crtc);
+ void intel_fbc_pre_update(struct intel_crtc *crtc);
+ void intel_fbc_post_update(struct intel_crtc *crtc);
  void intel_fbc_init(struct drm_i915_private *dev_priv);
+ void intel_fbc_init_pipe_state(struct drm_i915_private *dev_priv);
  void intel_fbc_enable(struct intel_crtc *crtc);
- void intel_fbc_disable(struct drm_i915_private *dev_priv);
- void intel_fbc_disable_crtc(struct intel_crtc *crtc);
+ void intel_fbc_disable(struct intel_crtc *crtc);
+ void intel_fbc_global_disable(struct drm_i915_private *dev_priv);
  void intel_fbc_invalidate(struct drm_i915_private *dev_priv,
                          unsigned int frontbuffer_bits,
                          enum fb_op_origin origin);
@@@ -1559,6 -1564,7 +1563,7 @@@ void skl_wm_get_hw_state(struct drm_dev
  void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv,
                          struct skl_ddb_allocation *ddb /* out */);
  uint32_t ilk_pipe_pixel_rate(const struct intel_crtc_state *pipe_config);
+ int sanitize_rc6_option(const struct drm_device *dev, int enable_rc6);
  
  /* intel_sdvo.c */
  bool intel_sdvo_init(struct drm_device *dev,