Merge tag 'drm-intel-fixes-2014-11-19' into drm-intel-next-queued
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / drm / i915 / intel_display.c
index 44060fb020a8832a6b1da4a69248b9b605fb05e0..6060b71d93015fb355cd3e058992af715d6b06e7 100644 (file)
@@ -2931,8 +2931,6 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
                return ret;
        }
 
-       intel_update_pipe_size(intel_crtc);
-
        dev_priv->display.update_primary_plane(crtc, fb, x, y);
 
        if (intel_crtc->active)
@@ -3953,6 +3951,7 @@ static int intel_shared_dpll_start_config(struct drm_i915_private *dev_priv,
 cleanup:
        while (--i >= 0) {
                pll = &dev_priv->shared_dplls[i];
+               kfree(pll->new_config);
                pll->new_config = NULL;
        }
 
@@ -4004,6 +4003,19 @@ static void cpt_verify_modeset(struct drm_device *dev, int pipe)
        }
 }
 
+static void skylake_pfit_enable(struct intel_crtc *crtc)
+{
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int pipe = crtc->pipe;
+
+       if (crtc->config.pch_pfit.enabled) {
+               I915_WRITE(PS_CTL(pipe), PS_ENABLE);
+               I915_WRITE(PS_WIN_POS(pipe), crtc->config.pch_pfit.pos);
+               I915_WRITE(PS_WIN_SZ(pipe), crtc->config.pch_pfit.size);
+       }
+}
+
 static void ironlake_pfit_enable(struct intel_crtc *crtc)
 {
        struct drm_device *dev = crtc->base.dev;
@@ -4387,7 +4399,10 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
 
        intel_ddi_enable_pipe_clock(intel_crtc);
 
-       ironlake_pfit_enable(intel_crtc);
+       if (IS_SKYLAKE(dev))
+               skylake_pfit_enable(intel_crtc);
+       else
+               ironlake_pfit_enable(intel_crtc);
 
        /*
         * On ILK+ LUT must be loaded before the pipe is running but with
@@ -4421,6 +4436,21 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
        intel_crtc_enable_planes(crtc);
 }
 
+static void skylake_pfit_disable(struct intel_crtc *crtc)
+{
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int pipe = crtc->pipe;
+
+       /* To avoid upsetting the power well on haswell only disable the pfit if
+        * it's in use. The hw state code will make sure we get this right. */
+       if (crtc->config.pch_pfit.enabled) {
+               I915_WRITE(PS_CTL(pipe), 0);
+               I915_WRITE(PS_WIN_POS(pipe), 0);
+               I915_WRITE(PS_WIN_SZ(pipe), 0);
+       }
+}
+
 static void ironlake_pfit_disable(struct intel_crtc *crtc)
 {
        struct drm_device *dev = crtc->base.dev;
@@ -4533,7 +4563,10 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
 
        intel_ddi_disable_transcoder_func(dev_priv, cpu_transcoder);
 
-       ironlake_pfit_disable(intel_crtc);
+       if (IS_SKYLAKE(dev))
+               skylake_pfit_disable(intel_crtc);
+       else
+               ironlake_pfit_disable(intel_crtc);
 
        intel_ddi_disable_pipe_clock(intel_crtc);
 
@@ -4683,6 +4716,9 @@ static void modeset_update_crtc_power_domains(struct drm_device *dev)
                        intel_display_power_get(dev_priv, domain);
        }
 
+       if (dev_priv->display.modeset_global_resources)
+               dev_priv->display.modeset_global_resources(dev);
+
        for_each_intel_crtc(dev, crtc) {
                enum intel_display_power_domain domain;
 
@@ -4722,7 +4758,7 @@ static void vlv_update_cdclk(struct drm_device *dev)
         * BSpec erroneously claims we should aim for 4MHz, but
         * in fact 1MHz is the correct frequency.
         */
-       I915_WRITE(GMBUSFREQ_VLV, dev_priv->vlv_cdclk_freq);
+       I915_WRITE(GMBUSFREQ_VLV, DIV_ROUND_UP(dev_priv->vlv_cdclk_freq, 1000));
 }
 
 /* Adjust CDclk dividers to allow high res or save power if possible */
@@ -4753,10 +4789,9 @@ static void valleyview_set_cdclk(struct drm_device *dev, int cdclk)
        mutex_unlock(&dev_priv->rps.hw_lock);
 
        if (cdclk == 400000) {
-               u32 divider, vco;
+               u32 divider;
 
-               vco = valleyview_get_vco(dev_priv);
-               divider = DIV_ROUND_CLOSEST(vco << 1, cdclk) - 1;
+               divider = DIV_ROUND_CLOSEST(dev_priv->hpll_freq << 1, cdclk) - 1;
 
                mutex_lock(&dev_priv->dpio_lock);
                /* adjust cdclk divider */
@@ -4835,8 +4870,7 @@ static void cherryview_set_cdclk(struct drm_device *dev, int cdclk)
 static int valleyview_calc_cdclk(struct drm_i915_private *dev_priv,
                                 int max_pixclk)
 {
-       int vco = valleyview_get_vco(dev_priv);
-       int freq_320 = (vco <<  1) % 320000 != 0 ? 333333 : 320000;
+       int freq_320 = (dev_priv->hpll_freq <<  1) % 320000 != 0 ? 333333 : 320000;
 
        /* FIXME: Punit isn't quite ready yet */
        if (IS_CHERRYVIEW(dev_priv->dev))
@@ -4910,8 +4944,6 @@ static void valleyview_modeset_global_resources(struct drm_device *dev)
                else
                        valleyview_set_cdclk(dev, req_cdclk);
        }
-
-       modeset_update_crtc_power_domains(dev);
 }
 
 static void valleyview_crtc_enable(struct drm_crtc *crtc)
@@ -5543,7 +5575,6 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc,
 static int valleyview_get_display_clock_speed(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       int vco = valleyview_get_vco(dev_priv);
        u32 val;
        int divider;
 
@@ -5551,6 +5582,9 @@ static int valleyview_get_display_clock_speed(struct drm_device *dev)
        if (IS_CHERRYVIEW(dev))
                return 400000;
 
+       if (dev_priv->hpll_freq == 0)
+               dev_priv->hpll_freq = valleyview_get_vco(dev_priv);
+
        mutex_lock(&dev_priv->dpio_lock);
        val = vlv_cck_read(dev_priv, CCK_DISPLAY_CLOCK_CONTROL);
        mutex_unlock(&dev_priv->dpio_lock);
@@ -5561,7 +5595,7 @@ static int valleyview_get_display_clock_speed(struct drm_device *dev)
             (divider << DISPLAY_FREQUENCY_STATUS_SHIFT),
             "cdclk change in progress\n");
 
-       return DIV_ROUND_CLOSEST(vco << 1, divider + 1);
+       return DIV_ROUND_CLOSEST(dev_priv->hpll_freq << 1, divider + 1);
 }
 
 static int i945_get_display_clock_speed(struct drm_device *dev)
@@ -5731,24 +5765,24 @@ static void i9xx_update_pll_dividers(struct intel_crtc *crtc,
        u32 fp, fp2 = 0;
 
        if (IS_PINEVIEW(dev)) {
-               fp = pnv_dpll_compute_fp(&crtc->config.dpll);
+               fp = pnv_dpll_compute_fp(&crtc->new_config->dpll);
                if (reduced_clock)
                        fp2 = pnv_dpll_compute_fp(reduced_clock);
        } else {
-               fp = i9xx_dpll_compute_fp(&crtc->config.dpll);
+               fp = i9xx_dpll_compute_fp(&crtc->new_config->dpll);
                if (reduced_clock)
                        fp2 = i9xx_dpll_compute_fp(reduced_clock);
        }
 
-       crtc->config.dpll_hw_state.fp0 = fp;
+       crtc->new_config->dpll_hw_state.fp0 = fp;
 
        crtc->lowfreq_avail = false;
-       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
+       if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS) &&
            reduced_clock && i915.powersave) {
-               crtc->config.dpll_hw_state.fp1 = fp2;
+               crtc->new_config->dpll_hw_state.fp1 = fp2;
                crtc->lowfreq_avail = true;
        } else {
-               crtc->config.dpll_hw_state.fp1 = fp;
+               crtc->new_config->dpll_hw_state.fp1 = fp;
        }
 }
 
@@ -7547,6 +7581,22 @@ static void ironlake_get_fdi_m_n_config(struct intel_crtc *crtc,
                                     &pipe_config->fdi_m_n, NULL);
 }
 
+static void skylake_get_pfit_config(struct intel_crtc *crtc,
+                                   struct intel_crtc_config *pipe_config)
+{
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t tmp;
+
+       tmp = I915_READ(PS_CTL(crtc->pipe));
+
+       if (tmp & PS_ENABLE) {
+               pipe_config->pch_pfit.enabled = true;
+               pipe_config->pch_pfit.pos = I915_READ(PS_WIN_POS(crtc->pipe));
+               pipe_config->pch_pfit.size = I915_READ(PS_WIN_SZ(crtc->pipe));
+       }
+}
+
 static void ironlake_get_pfit_config(struct intel_crtc *crtc,
                                     struct intel_crtc_config *pipe_config)
 {
@@ -7950,16 +8000,6 @@ void hsw_disable_pc8(struct drm_i915_private *dev_priv)
        intel_prepare_ddi(dev);
 }
 
-static void snb_modeset_global_resources(struct drm_device *dev)
-{
-       modeset_update_crtc_power_domains(dev);
-}
-
-static void haswell_modeset_global_resources(struct drm_device *dev)
-{
-       modeset_update_crtc_power_domains(dev);
-}
-
 static int haswell_crtc_compute_clock(struct intel_crtc *crtc)
 {
        if (!intel_ddi_pll_select(crtc))
@@ -7970,6 +8010,28 @@ static int haswell_crtc_compute_clock(struct intel_crtc *crtc)
        return 0;
 }
 
+static void skylake_get_ddi_pll(struct drm_i915_private *dev_priv,
+                               enum port port,
+                               struct intel_crtc_config *pipe_config)
+{
+       u32 temp;
+
+       temp = I915_READ(DPLL_CTRL2) & DPLL_CTRL2_DDI_CLK_SEL_MASK(port);
+       pipe_config->ddi_pll_sel = temp >> (port * 3 + 1);
+
+       switch (pipe_config->ddi_pll_sel) {
+       case SKL_DPLL1:
+               pipe_config->shared_dpll = DPLL_ID_SKL_DPLL1;
+               break;
+       case SKL_DPLL2:
+               pipe_config->shared_dpll = DPLL_ID_SKL_DPLL2;
+               break;
+       case SKL_DPLL3:
+               pipe_config->shared_dpll = DPLL_ID_SKL_DPLL3;
+               break;
+       }
+}
+
 static void haswell_get_ddi_pll(struct drm_i915_private *dev_priv,
                                enum port port,
                                struct intel_crtc_config *pipe_config)
@@ -7999,7 +8061,10 @@ static void haswell_get_ddi_port_state(struct intel_crtc *crtc,
 
        port = (tmp & TRANS_DDI_PORT_MASK) >> TRANS_DDI_PORT_SHIFT;
 
-       haswell_get_ddi_pll(dev_priv, port, pipe_config);
+       if (IS_SKYLAKE(dev))
+               skylake_get_ddi_pll(dev_priv, port, pipe_config);
+       else
+               haswell_get_ddi_pll(dev_priv, port, pipe_config);
 
        if (pipe_config->shared_dpll >= 0) {
                pll = &dev_priv->shared_dplls[pipe_config->shared_dpll];
@@ -8075,8 +8140,12 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
        intel_get_pipe_timings(crtc, pipe_config);
 
        pfit_domain = POWER_DOMAIN_PIPE_PANEL_FITTER(crtc->pipe);
-       if (intel_display_power_is_enabled(dev_priv, pfit_domain))
-               ironlake_get_pfit_config(crtc, pipe_config);
+       if (intel_display_power_is_enabled(dev_priv, pfit_domain)) {
+               if (IS_SKYLAKE(dev))
+                       skylake_get_pfit_config(crtc, pipe_config);
+               else
+                       ironlake_get_pfit_config(crtc, pipe_config);
+       }
 
        if (IS_HASWELL(dev))
                pipe_config->ips_enabled = hsw_crtc_supports_ips(crtc) &&
@@ -8429,7 +8498,7 @@ __intel_framebuffer_create(struct drm_device *dev,
 
        intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
        if (!intel_fb) {
-               drm_gem_object_unreference_unlocked(&obj->base);
+               drm_gem_object_unreference(&obj->base);
                return ERR_PTR(-ENOMEM);
        }
 
@@ -8439,7 +8508,7 @@ __intel_framebuffer_create(struct drm_device *dev,
 
        return &intel_fb->base;
 err:
-       drm_gem_object_unreference_unlocked(&obj->base);
+       drm_gem_object_unreference(&obj->base);
        kfree(intel_fb);
 
        return ERR_PTR(ret);
@@ -9401,11 +9470,15 @@ static void intel_do_mmio_flip(struct intel_crtc *intel_crtc)
        struct intel_framebuffer *intel_fb =
                to_intel_framebuffer(intel_crtc->base.primary->fb);
        struct drm_i915_gem_object *obj = intel_fb->obj;
+       bool atomic_update;
+       u32 start_vbl_count;
        u32 dspcntr;
        u32 reg;
 
        intel_mark_page_flip_active(intel_crtc);
 
+       atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
+
        reg = DSPCNTR(intel_crtc->plane);
        dspcntr = I915_READ(reg);
 
@@ -9419,95 +9492,106 @@ static void intel_do_mmio_flip(struct intel_crtc *intel_crtc)
        I915_WRITE(DSPSURF(intel_crtc->plane),
                   intel_crtc->unpin_work->gtt_offset);
        POSTING_READ(DSPSURF(intel_crtc->plane));
+
+       if (atomic_update)
+               intel_pipe_update_end(intel_crtc, start_vbl_count);
 }
 
-static int intel_postpone_flip(struct drm_i915_gem_object *obj)
+static void intel_mmio_flip_work_func(struct work_struct *work)
 {
+       struct intel_crtc *intel_crtc =
+               container_of(work, struct intel_crtc, mmio_flip.work);
        struct intel_engine_cs *ring;
-       int ret;
-
-       lockdep_assert_held(&obj->base.dev->struct_mutex);
-
-       if (!obj->last_write_seqno)
-               return 0;
-
-       ring = obj->ring;
+       uint32_t seqno;
 
-       if (i915_seqno_passed(ring->get_seqno(ring, true),
-                             obj->last_write_seqno))
-               return 0;
+       seqno = intel_crtc->mmio_flip.seqno;
+       ring = intel_crtc->mmio_flip.ring;
 
-       ret = i915_gem_check_olr(ring, obj->last_write_seqno);
-       if (ret)
-               return ret;
+       if (seqno)
+               WARN_ON(__i915_wait_seqno(ring, seqno,
+                                         intel_crtc->reset_counter,
+                                         false, NULL, NULL) != 0);
 
-       if (WARN_ON(!ring->irq_get(ring)))
-               return 0;
-
-       return 1;
+       intel_do_mmio_flip(intel_crtc);
 }
 
-void intel_notify_mmio_flip(struct intel_engine_cs *ring)
+static int intel_queue_mmio_flip(struct drm_device *dev,
+                                struct drm_crtc *crtc,
+                                struct drm_framebuffer *fb,
+                                struct drm_i915_gem_object *obj,
+                                struct intel_engine_cs *ring,
+                                uint32_t flags)
 {
-       struct drm_i915_private *dev_priv = to_i915(ring->dev);
-       struct intel_crtc *intel_crtc;
-       unsigned long irq_flags;
-       u32 seqno;
-
-       seqno = ring->get_seqno(ring, false);
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
-       spin_lock_irqsave(&dev_priv->mmio_flip_lock, irq_flags);
-       for_each_intel_crtc(ring->dev, intel_crtc) {
-               struct intel_mmio_flip *mmio_flip;
+       intel_crtc->mmio_flip.seqno = obj->last_write_seqno;
+       intel_crtc->mmio_flip.ring = obj->ring;
 
-               mmio_flip = &intel_crtc->mmio_flip;
-               if (mmio_flip->seqno == 0)
-                       continue;
+       schedule_work(&intel_crtc->mmio_flip.work);
 
-               if (ring->id != mmio_flip->ring_id)
-                       continue;
-
-               if (i915_seqno_passed(seqno, mmio_flip->seqno)) {
-                       intel_do_mmio_flip(intel_crtc);
-                       mmio_flip->seqno = 0;
-                       ring->irq_put(ring);
-               }
-       }
-       spin_unlock_irqrestore(&dev_priv->mmio_flip_lock, irq_flags);
+       return 0;
 }
 
-static int intel_queue_mmio_flip(struct drm_device *dev,
+static int intel_gen9_queue_flip(struct drm_device *dev,
                                 struct drm_crtc *crtc,
                                 struct drm_framebuffer *fb,
                                 struct drm_i915_gem_object *obj,
                                 struct intel_engine_cs *ring,
                                 uint32_t flags)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       uint32_t plane = 0, stride;
        int ret;
 
-       if (WARN_ON(intel_crtc->mmio_flip.seqno))
-               return -EBUSY;
+       switch(intel_crtc->pipe) {
+       case PIPE_A:
+               plane = MI_DISPLAY_FLIP_SKL_PLANE_1_A;
+               break;
+       case PIPE_B:
+               plane = MI_DISPLAY_FLIP_SKL_PLANE_1_B;
+               break;
+       case PIPE_C:
+               plane = MI_DISPLAY_FLIP_SKL_PLANE_1_C;
+               break;
+       default:
+               WARN_ONCE(1, "unknown plane in flip command\n");
+               return -ENODEV;
+       }
 
-       ret = intel_postpone_flip(obj);
-       if (ret < 0)
-               return ret;
-       if (ret == 0) {
-               intel_do_mmio_flip(intel_crtc);
-               return 0;
+       switch (obj->tiling_mode) {
+       case I915_TILING_NONE:
+               stride = fb->pitches[0] >> 6;
+               break;
+       case I915_TILING_X:
+               stride = fb->pitches[0] >> 9;
+               break;
+       default:
+               WARN_ONCE(1, "unknown tiling in flip command\n");
+               return -ENODEV;
        }
 
-       spin_lock_irq(&dev_priv->mmio_flip_lock);
-       intel_crtc->mmio_flip.seqno = obj->last_write_seqno;
-       intel_crtc->mmio_flip.ring_id = obj->ring->id;
-       spin_unlock_irq(&dev_priv->mmio_flip_lock);
+       ret = intel_ring_begin(ring, 10);
+       if (ret)
+               return ret;
+
+       intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
+       intel_ring_emit(ring, DERRMR);
+       intel_ring_emit(ring, ~(DERRMR_PIPEA_PRI_FLIP_DONE |
+                               DERRMR_PIPEB_PRI_FLIP_DONE |
+                               DERRMR_PIPEC_PRI_FLIP_DONE));
+       intel_ring_emit(ring, MI_STORE_REGISTER_MEM_GEN8(1) |
+                             MI_SRM_LRM_GLOBAL_GTT);
+       intel_ring_emit(ring, DERRMR);
+       intel_ring_emit(ring, ring->scratch.gtt_offset + 256);
+       intel_ring_emit(ring, 0);
+
+       intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 | plane);
+       intel_ring_emit(ring, stride << 6 | obj->tiling_mode);
+       intel_ring_emit(ring, intel_crtc->unpin_work->gtt_offset);
+
+       intel_mark_page_flip_active(intel_crtc);
+       __intel_ring_advance(ring);
 
-       /*
-        * Double check to catch cases where irq fired before
-        * mmio flip data was ready
-        */
-       intel_notify_mmio_flip(obj->ring);
        return 0;
 }
 
@@ -10418,6 +10502,7 @@ intel_pipe_config_compare(struct drm_device *dev,
        if ((INTEL_INFO(dev)->gen < 8 && !IS_HASWELL(dev)) ||
            IS_VALLEYVIEW(dev))
                PIPE_CONF_CHECK_I(limited_color_range);
+       PIPE_CONF_CHECK_I(has_infoframe);
 
        PIPE_CONF_CHECK_I(has_audio);
 
@@ -10474,6 +10559,9 @@ intel_pipe_config_compare(struct drm_device *dev,
        PIPE_CONF_CHECK_X(dpll_hw_state.fp0);
        PIPE_CONF_CHECK_X(dpll_hw_state.fp1);
        PIPE_CONF_CHECK_X(dpll_hw_state.wrpll);
+       PIPE_CONF_CHECK_X(dpll_hw_state.ctrl1);
+       PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr1);
+       PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr2);
 
        if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5)
                PIPE_CONF_CHECK_I(pipe_bpp);
@@ -10491,6 +10579,56 @@ intel_pipe_config_compare(struct drm_device *dev,
        return true;
 }
 
+static void check_wm_state(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct skl_ddb_allocation hw_ddb, *sw_ddb;
+       struct intel_crtc *intel_crtc;
+       int plane;
+
+       if (INTEL_INFO(dev)->gen < 9)
+               return;
+
+       skl_ddb_get_hw_state(dev_priv, &hw_ddb);
+       sw_ddb = &dev_priv->wm.skl_hw.ddb;
+
+       for_each_intel_crtc(dev, intel_crtc) {
+               struct skl_ddb_entry *hw_entry, *sw_entry;
+               const enum pipe pipe = intel_crtc->pipe;
+
+               if (!intel_crtc->active)
+                       continue;
+
+               /* planes */
+               for_each_plane(pipe, plane) {
+                       hw_entry = &hw_ddb.plane[pipe][plane];
+                       sw_entry = &sw_ddb->plane[pipe][plane];
+
+                       if (skl_ddb_entry_equal(hw_entry, sw_entry))
+                               continue;
+
+                       DRM_ERROR("mismatch in DDB state pipe %c plane %d "
+                                 "(expected (%u,%u), found (%u,%u))\n",
+                                 pipe_name(pipe), plane + 1,
+                                 sw_entry->start, sw_entry->end,
+                                 hw_entry->start, hw_entry->end);
+               }
+
+               /* cursor */
+               hw_entry = &hw_ddb.cursor[pipe];
+               sw_entry = &sw_ddb->cursor[pipe];
+
+               if (skl_ddb_entry_equal(hw_entry, sw_entry))
+                       continue;
+
+               DRM_ERROR("mismatch in DDB state pipe %c cursor "
+                         "(expected (%u,%u), found (%u,%u))\n",
+                         pipe_name(pipe),
+                         sw_entry->start, sw_entry->end,
+                         hw_entry->start, hw_entry->end);
+       }
+}
+
 static void
 check_connector_state(struct drm_device *dev)
 {
@@ -10690,6 +10828,7 @@ check_shared_dpll_state(struct drm_device *dev)
 void
 intel_modeset_check_state(struct drm_device *dev)
 {
+       check_wm_state(dev);
        check_connector_state(dev);
        check_encoder_state(dev);
        check_crtc_state(dev);
@@ -10746,45 +10885,60 @@ static void update_scanline_offset(struct intel_crtc *crtc)
                crtc->scanline_offset = 1;
 }
 
+static struct intel_crtc_config *
+intel_modeset_compute_config(struct drm_crtc *crtc,
+                            struct drm_display_mode *mode,
+                            struct drm_framebuffer *fb,
+                            unsigned *modeset_pipes,
+                            unsigned *prepare_pipes,
+                            unsigned *disable_pipes)
+{
+       struct intel_crtc_config *pipe_config = NULL;
+
+       intel_modeset_affected_pipes(crtc, modeset_pipes,
+                                    prepare_pipes, disable_pipes);
+
+       if ((*modeset_pipes) == 0)
+               goto out;
+
+       /*
+        * Note this needs changes when we start tracking multiple modes
+        * and crtcs.  At that point we'll need to compute the whole config
+        * (i.e. one pipe_config for each crtc) rather than just the one
+        * for this crtc.
+        */
+       pipe_config = intel_modeset_pipe_config(crtc, fb, mode);
+       if (IS_ERR(pipe_config)) {
+               goto out;
+       }
+       intel_dump_pipe_config(to_intel_crtc(crtc), pipe_config,
+                              "[modeset]");
+       to_intel_crtc(crtc)->new_config = pipe_config;
+
+out:
+       return pipe_config;
+}
+
 static int __intel_set_mode(struct drm_crtc *crtc,
                            struct drm_display_mode *mode,
-                           int x, int y, struct drm_framebuffer *fb)
+                           int x, int y, struct drm_framebuffer *fb,
+                           struct intel_crtc_config *pipe_config,
+                           unsigned modeset_pipes,
+                           unsigned prepare_pipes,
+                           unsigned disable_pipes)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_display_mode *saved_mode;
-       struct intel_crtc_config *pipe_config = NULL;
        struct intel_crtc *intel_crtc;
-       unsigned disable_pipes, prepare_pipes, modeset_pipes;
        int ret = 0;
 
        saved_mode = kmalloc(sizeof(*saved_mode), GFP_KERNEL);
        if (!saved_mode)
                return -ENOMEM;
 
-       intel_modeset_affected_pipes(crtc, &modeset_pipes,
-                                    &prepare_pipes, &disable_pipes);
-
        *saved_mode = crtc->mode;
 
-       /* Hack: Because we don't (yet) support global modeset on multiple
-        * crtcs, we don't keep track of the new mode for more than one crtc.
-        * Hence simply check whether any bit is set in modeset_pipes in all the
-        * pieces of code that are not yet converted to deal with mutliple crtcs
-        * changing their mode at the same time. */
-       if (modeset_pipes) {
-               pipe_config = intel_modeset_pipe_config(crtc, fb, mode);
-               if (IS_ERR(pipe_config)) {
-                       ret = PTR_ERR(pipe_config);
-                       pipe_config = NULL;
-
-                       goto out;
-               }
-               intel_dump_pipe_config(to_intel_crtc(crtc), pipe_config,
-                                      "[modeset]");
-               to_intel_crtc(crtc)->new_config = pipe_config;
-       }
-
        /*
         * See if the config requires any additional preparation, e.g.
         * to adjust global state with pipes off.  We need to do this
@@ -10825,6 +10979,10 @@ static int __intel_set_mode(struct drm_crtc *crtc,
 
        /* crtc->mode is already used by the ->mode_set callbacks, hence we need
         * to set it here already despite that we pass it down the callchain.
+        *
+        * Note we'll need to fix this up when we start tracking multiple
+        * pipes; here we assume a single modeset_pipe and only track the
+        * single crtc and mode.
         */
        if (modeset_pipes) {
                crtc->mode = *mode;
@@ -10846,8 +11004,7 @@ static int __intel_set_mode(struct drm_crtc *crtc,
         * update the the output configuration. */
        intel_modeset_update_state(dev, prepare_pipes);
 
-       if (dev_priv->display.modeset_global_resources)
-               dev_priv->display.modeset_global_resources(dev);
+       modeset_update_crtc_power_domains(dev);
 
        /* Set up the DPLL and any encoders state that needs to adjust or depend
         * on the DPLL.
@@ -10887,19 +11044,23 @@ done:
        if (ret && crtc->enabled)
                crtc->mode = *saved_mode;
 
-out:
        kfree(pipe_config);
        kfree(saved_mode);
        return ret;
 }
 
-static int intel_set_mode(struct drm_crtc *crtc,
-                         struct drm_display_mode *mode,
-                         int x, int y, struct drm_framebuffer *fb)
+static int intel_set_mode_pipes(struct drm_crtc *crtc,
+                               struct drm_display_mode *mode,
+                               int x, int y, struct drm_framebuffer *fb,
+                               struct intel_crtc_config *pipe_config,
+                               unsigned modeset_pipes,
+                               unsigned prepare_pipes,
+                               unsigned disable_pipes)
 {
        int ret;
 
-       ret = __intel_set_mode(crtc, mode, x, y, fb);
+       ret = __intel_set_mode(crtc, mode, x, y, fb, pipe_config, modeset_pipes,
+                              prepare_pipes, disable_pipes);
 
        if (ret == 0)
                intel_modeset_check_state(crtc->dev);
@@ -10907,6 +11068,26 @@ static int intel_set_mode(struct drm_crtc *crtc,
        return ret;
 }
 
+static int intel_set_mode(struct drm_crtc *crtc,
+                         struct drm_display_mode *mode,
+                         int x, int y, struct drm_framebuffer *fb)
+{
+       struct intel_crtc_config *pipe_config;
+       unsigned modeset_pipes, prepare_pipes, disable_pipes;
+
+       pipe_config = intel_modeset_compute_config(crtc, mode, fb,
+                                                  &modeset_pipes,
+                                                  &prepare_pipes,
+                                                  &disable_pipes);
+
+       if (IS_ERR(pipe_config))
+               return PTR_ERR(pipe_config);
+
+       return intel_set_mode_pipes(crtc, mode, x, y, fb, pipe_config,
+                                   modeset_pipes, prepare_pipes,
+                                   disable_pipes);
+}
+
 void intel_crtc_restore_mode(struct drm_crtc *crtc)
 {
        intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, crtc->primary->fb);
@@ -11235,6 +11416,8 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
        struct drm_device *dev;
        struct drm_mode_set save_set;
        struct intel_set_config *config;
+       struct intel_crtc_config *pipe_config;
+       unsigned modeset_pipes, prepare_pipes, disable_pipes;
        int ret;
 
        BUG_ON(!set);
@@ -11280,9 +11463,36 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
        if (ret)
                goto fail;
 
+       pipe_config = intel_modeset_compute_config(set->crtc, set->mode,
+                                                  set->fb,
+                                                  &modeset_pipes,
+                                                  &prepare_pipes,
+                                                  &disable_pipes);
+       if (IS_ERR(pipe_config)) {
+               ret = PTR_ERR(pipe_config);
+               goto fail;
+       } else if (pipe_config) {
+               if (to_intel_crtc(set->crtc)->new_config->has_audio !=
+                   to_intel_crtc(set->crtc)->config.has_audio)
+                       config->mode_changed = true;
+
+               /* Force mode sets for any infoframe stuff */
+               if (to_intel_crtc(set->crtc)->new_config->has_infoframe ||
+                   to_intel_crtc(set->crtc)->config.has_infoframe)
+                       config->mode_changed = true;
+       }
+
+       /* set_mode will free it in the mode_changed case */
+       if (!config->mode_changed)
+               kfree(pipe_config);
+
+       intel_update_pipe_size(to_intel_crtc(set->crtc));
+
        if (config->mode_changed) {
-               ret = intel_set_mode(set->crtc, set->mode,
-                                    set->x, set->y, set->fb);
+               ret = intel_set_mode_pipes(set->crtc, set->mode,
+                                          set->x, set->y, set->fb, pipe_config,
+                                          modeset_pipes, prepare_pipes,
+                                          disable_pipes);
        } else if (config->fb_changed) {
                struct intel_crtc *intel_crtc = to_intel_crtc(set->crtc);
 
@@ -11555,8 +11765,8 @@ intel_commit_primary_plane(struct drm_plane *plane,
        struct drm_rect *src = &state->src;
 
        crtc->primary->fb = fb;
-       crtc->x = src->x1;
-       crtc->y = src->y1;
+       crtc->x = src->x1 >> 16;
+       crtc->y = src->y1 >> 16;
 
        intel_plane->crtc_x = state->orig_dst.x1;
        intel_plane->crtc_y = state->orig_dst.y1;
@@ -11983,6 +12193,8 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
        dev_priv->plane_to_crtc_mapping[intel_crtc->plane] = &intel_crtc->base;
        dev_priv->pipe_to_crtc_mapping[intel_crtc->pipe] = &intel_crtc->base;
 
+       INIT_WORK(&intel_crtc->mmio_flip.work, intel_mmio_flip_work_func);
+
        drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs);
 
        WARN_ON(drm_crtc_index(&intel_crtc->base) != intel_crtc->pipe);
@@ -12003,7 +12215,7 @@ enum pipe intel_get_pipe_from_connector(struct intel_connector *connector)
 
        WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
 
-       if (!encoder)
+       if (!encoder || WARN_ON(!encoder->crtc))
                return INVALID_PIPE;
 
        return to_intel_crtc(encoder->crtc)->pipe;
@@ -12238,7 +12450,7 @@ static void intel_setup_outputs(struct drm_device *dev)
        if (SUPPORTS_TV(dev))
                intel_tv_init(dev);
 
-       intel_edp_psr_init(dev);
+       intel_psr_init(dev);
 
        for_each_intel_encoder(dev, encoder) {
                encoder->base.possible_crtcs = encoder->crtc_mask;
@@ -12516,8 +12728,6 @@ static void intel_init_display(struct drm_device *dev)
                dev_priv->display.fdi_link_train = ironlake_fdi_link_train;
        } else if (IS_GEN6(dev)) {
                dev_priv->display.fdi_link_train = gen6_fdi_link_train;
-               dev_priv->display.modeset_global_resources =
-                       snb_modeset_global_resources;
        } else if (IS_IVYBRIDGE(dev)) {
                /* FIXME: detect B0+ stepping and use auto training */
                dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train;
@@ -12525,14 +12735,9 @@ static void intel_init_display(struct drm_device *dev)
                        ivb_modeset_global_resources;
        } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
                dev_priv->display.fdi_link_train = hsw_fdi_link_train;
-               dev_priv->display.modeset_global_resources =
-                       haswell_modeset_global_resources;
        } else if (IS_VALLEYVIEW(dev)) {
                dev_priv->display.modeset_global_resources =
                        valleyview_modeset_global_resources;
-       } else if (INTEL_INFO(dev)->gen >= 9) {
-               dev_priv->display.modeset_global_resources =
-                       haswell_modeset_global_resources;
        }
 
        /* Default just returns -ENODEV to indicate unsupported */
@@ -12559,6 +12764,9 @@ static void intel_init_display(struct drm_device *dev)
        case 8: /* FIXME(BDW): Check that the gen8 RCS flip works. */
                dev_priv->display.queue_flip = intel_gen7_queue_flip;
                break;
+       case 9:
+               dev_priv->display.queue_flip = intel_gen9_queue_flip;
+               break;
        }
 
        intel_panel_init_backlight_funcs(dev);
@@ -12697,6 +12905,9 @@ static struct intel_quirk intel_quirks[] = {
        /* Acer C720 Chromebook (Core i3 4005U) */
        { 0x0a16, 0x1025, 0x0a11, quirk_backlight_present },
 
+       /* Apple Macbook 2,1 (Core 2 T7400) */
+       { 0x27a2, 0x8086, 0x7270, quirk_backlight_present },
+
        /* Toshiba CB35 Chromebook (Celeron 2955U) */
        { 0x0a06, 0x1179, 0x0a88, quirk_backlight_present },
 
@@ -13244,7 +13455,9 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
                pll->on = false;
        }
 
-       if (HAS_PCH_SPLIT(dev))
+       if (IS_GEN9(dev))
+               skl_wm_get_hw_state(dev);
+       else if (HAS_PCH_SPLIT(dev))
                ilk_wm_get_hw_state(dev);
 
        if (force_restore) {
@@ -13258,8 +13471,8 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
                        struct drm_crtc *crtc =
                                dev_priv->pipe_to_crtc_mapping[pipe];
 
-                       __intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y,
-                                        crtc->primary->fb);
+                       intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y,
+                                      crtc->primary->fb);
                }
        } else {
                intel_modeset_update_staged_output_state(dev);
@@ -13270,6 +13483,7 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
 
 void intel_modeset_gem_init(struct drm_device *dev)
 {
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_crtc *c;
        struct drm_i915_gem_object *obj;
 
@@ -13277,6 +13491,16 @@ void intel_modeset_gem_init(struct drm_device *dev)
        intel_init_gt_powersave(dev);
        mutex_unlock(&dev->struct_mutex);
 
+       /*
+        * There may be no VBT; and if the BIOS enabled SSC we can
+        * just keep using it to avoid unnecessary flicker.  Whereas if the
+        * BIOS isn't using it, don't assume it will work even if the VBT
+        * indicates as much.
+        */
+       if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev))
+               dev_priv->vbt.lvds_use_ssc = !!(I915_READ(PCH_DREF_CONTROL) &
+                                               DREF_SSC1_ENABLE);
+
        intel_modeset_init_hw(dev);
 
        intel_setup_overlay(dev);
@@ -13302,6 +13526,8 @@ void intel_modeset_gem_init(struct drm_device *dev)
                }
        }
        mutex_unlock(&dev->struct_mutex);
+
+       intel_backlight_register(dev);
 }
 
 void intel_connector_unregister(struct intel_connector *intel_connector)
@@ -13317,9 +13543,13 @@ void intel_modeset_cleanup(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_connector *connector;
 
+       intel_disable_gt_powersave(dev);
+
+       intel_backlight_unregister(dev);
+
        /*
         * Interrupts and polling as the first thing to avoid creating havoc.
-        * Too much stuff here (turning of rps, connectors, ...) would
+        * Too much stuff here (turning of connectors, ...) would
         * experience fancy races otherwise.
         */
        intel_irq_uninstall(dev_priv);
@@ -13336,8 +13566,6 @@ void intel_modeset_cleanup(struct drm_device *dev)
 
        intel_disable_fbc(dev);
 
-       intel_disable_gt_powersave(dev);
-
        ironlake_teardown_rc6(dev);
 
        mutex_unlock(&dev->struct_mutex);