drm/i915: Set AGPBUSY# bit in init_clock_gating
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / drm / i915 / intel_pm.c
index 19020e5e914b29a01b9798b415aaa0192bd7e936..71de9eec33812c9fe6d4bf99d63b86ebc89aebb9 100644 (file)
@@ -487,7 +487,7 @@ void intel_update_fbc(struct drm_device *dev)
         *   - new fb is too large to fit in compressed buffer
         *   - going to an unsupported config (interlace, pixel multiply, etc.)
         */
-       list_for_each_entry(tmp_crtc, &dev->mode_config.crtc_list, head) {
+       for_each_crtc(dev, tmp_crtc) {
                if (intel_crtc_active(tmp_crtc) &&
                    to_intel_crtc(tmp_crtc)->primary_enabled) {
                        if (crtc) {
@@ -1010,7 +1010,7 @@ static struct drm_crtc *single_enabled_crtc(struct drm_device *dev)
 {
        struct drm_crtc *crtc, *enabled = NULL;
 
-       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+       for_each_crtc(dev, crtc) {
                if (intel_crtc_active(crtc)) {
                        if (enabled)
                                return NULL;
@@ -1931,6 +1931,16 @@ static void ilk_compute_wm_maximums(const struct drm_device *dev,
        max->fbc = ilk_fbc_wm_reg_max(dev);
 }
 
+static void ilk_compute_wm_reg_maximums(struct drm_device *dev,
+                                       int level,
+                                       struct ilk_wm_maximums *max)
+{
+       max->pri = ilk_plane_wm_reg_max(dev, level, false);
+       max->spr = ilk_plane_wm_reg_max(dev, level, true);
+       max->cur = ilk_cursor_wm_reg_max(dev, level);
+       max->fbc = ilk_fbc_wm_reg_max(dev);
+}
+
 static bool ilk_validate_wm_level(int level,
                                  const struct ilk_wm_maximums *max,
                                  struct intel_wm_level *result)
@@ -2067,7 +2077,7 @@ static void intel_fixup_cur_wm_latency(struct drm_device *dev, uint16_t wm[5])
                wm[3] *= 2;
 }
 
-static int ilk_wm_max_level(const struct drm_device *dev)
+int ilk_wm_max_level(const struct drm_device *dev)
 {
        /* how many WM levels are we expecting */
        if (IS_HASWELL(dev) || IS_BROADWELL(dev))
@@ -2160,7 +2170,7 @@ static void ilk_compute_wm_config(struct drm_device *dev,
        struct intel_crtc *intel_crtc;
 
        /* Compute the currently _active_ config */
-       list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head) {
+       for_each_intel_crtc(dev, intel_crtc) {
                const struct intel_pipe_wm *wm = &intel_crtc->wm.active;
 
                if (!wm->pipe_enabled)
@@ -2188,9 +2198,6 @@ static bool intel_compute_pipe_wm(struct drm_crtc *crtc,
        };
        struct ilk_wm_maximums max;
 
-       /* LP0 watermarks always use 1/2 DDB partitioning */
-       ilk_compute_wm_maximums(dev, 0, &config, INTEL_DDB_PART_1_2, &max);
-
        pipe_wm->pipe_enabled = params->active;
        pipe_wm->sprites_enabled = params->spr.enabled;
        pipe_wm->sprites_scaled = params->spr.scaled;
@@ -2203,15 +2210,37 @@ static bool intel_compute_pipe_wm(struct drm_crtc *crtc,
        if (params->spr.scaled)
                max_level = 0;
 
-       for (level = 0; level <= max_level; level++)
-               ilk_compute_wm_level(dev_priv, level, params,
-                                    &pipe_wm->wm[level]);
+       ilk_compute_wm_level(dev_priv, 0, params, &pipe_wm->wm[0]);
 
        if (IS_HASWELL(dev) || IS_BROADWELL(dev))
                pipe_wm->linetime = hsw_compute_linetime_wm(dev, crtc);
 
+       /* LP0 watermarks always use 1/2 DDB partitioning */
+       ilk_compute_wm_maximums(dev, 0, &config, INTEL_DDB_PART_1_2, &max);
+
        /* At least LP0 must be valid */
-       return ilk_validate_wm_level(0, &max, &pipe_wm->wm[0]);
+       if (!ilk_validate_wm_level(0, &max, &pipe_wm->wm[0]))
+               return false;
+
+       ilk_compute_wm_reg_maximums(dev, 1, &max);
+
+       for (level = 1; level <= max_level; level++) {
+               struct intel_wm_level wm = {};
+
+               ilk_compute_wm_level(dev_priv, level, params, &wm);
+
+               /*
+                * Disable any watermark level that exceeds the
+                * register maximums since such watermarks are
+                * always invalid.
+                */
+               if (!ilk_validate_wm_level(level, &max, &wm))
+                       break;
+
+               pipe_wm->wm[level] = wm;
+       }
+
+       return true;
 }
 
 /*
@@ -2223,23 +2252,28 @@ static void ilk_merge_wm_level(struct drm_device *dev,
 {
        const struct intel_crtc *intel_crtc;
 
-       list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head) {
+       ret_wm->enable = true;
+
+       for_each_intel_crtc(dev, intel_crtc) {
                const struct intel_pipe_wm *active = &intel_crtc->wm.active;
                const struct intel_wm_level *wm = &active->wm[level];
 
                if (!active->pipe_enabled)
                        continue;
 
+               /*
+                * The watermark values may have been used in the past,
+                * so we must maintain them in the registers for some
+                * time even if the level is now disabled.
+                */
                if (!wm->enable)
-                       return;
+                       ret_wm->enable = false;
 
                ret_wm->pri_val = max(ret_wm->pri_val, wm->pri_val);
                ret_wm->spr_val = max(ret_wm->spr_val, wm->spr_val);
                ret_wm->cur_val = max(ret_wm->cur_val, wm->cur_val);
                ret_wm->fbc_val = max(ret_wm->fbc_val, wm->fbc_val);
        }
-
-       ret_wm->enable = true;
 }
 
 /*
@@ -2251,6 +2285,7 @@ static void ilk_wm_merge(struct drm_device *dev,
                         struct intel_pipe_wm *merged)
 {
        int level, max_level = ilk_wm_max_level(dev);
+       int last_enabled_level = max_level;
 
        /* ILK/SNB/IVB: LP1+ watermarks only w/ single pipe */
        if ((INTEL_INFO(dev)->gen <= 6 || IS_IVYBRIDGE(dev)) &&
@@ -2266,15 +2301,19 @@ static void ilk_wm_merge(struct drm_device *dev,
 
                ilk_merge_wm_level(dev, level, wm);
 
-               if (!ilk_validate_wm_level(level, max, wm))
-                       break;
+               if (level > last_enabled_level)
+                       wm->enable = false;
+               else if (!ilk_validate_wm_level(level, max, wm))
+                       /* make sure all following levels get disabled */
+                       last_enabled_level = level - 1;
 
                /*
                 * The spec says it is preferred to disable
                 * FBC WMs instead of disabling a WM level.
                 */
                if (wm->fbc_val > max->fbc) {
-                       merged->fbc_wm_enabled = false;
+                       if (wm->enable)
+                               merged->fbc_wm_enabled = false;
                        wm->fbc_val = 0;
                }
        }
@@ -2329,14 +2368,19 @@ static void ilk_compute_wm_results(struct drm_device *dev,
                level = ilk_wm_lp_to_level(wm_lp, merged);
 
                r = &merged->wm[level];
-               if (!r->enable)
-                       break;
 
-               results->wm_lp[wm_lp - 1] = WM3_LP_EN |
+               /*
+                * Maintain the watermark values even if the level is
+                * disabled. Doing otherwise could cause underruns.
+                */
+               results->wm_lp[wm_lp - 1] =
                        (ilk_wm_lp_latency(dev, level) << WM1_LP_LATENCY_SHIFT) |
                        (r->pri_val << WM1_LP_SR_SHIFT) |
                        r->cur_val;
 
+               if (r->enable)
+                       results->wm_lp[wm_lp - 1] |= WM1_LP_SR_EN;
+
                if (INTEL_INFO(dev)->gen >= 8)
                        results->wm_lp[wm_lp - 1] |=
                                r->fbc_val << WM1_LP_FBC_SHIFT_BDW;
@@ -2344,6 +2388,10 @@ static void ilk_compute_wm_results(struct drm_device *dev,
                        results->wm_lp[wm_lp - 1] |=
                                r->fbc_val << WM1_LP_FBC_SHIFT;
 
+               /*
+                * Always set WM1S_LP_EN when spr_val != 0, even if the
+                * level is disabled. Doing otherwise could cause underruns.
+                */
                if (INTEL_INFO(dev)->gen <= 6 && r->spr_val) {
                        WARN_ON(wm_lp != 1);
                        results->wm_lp_spr[wm_lp - 1] = WM1S_LP_EN | r->spr_val;
@@ -2352,7 +2400,7 @@ static void ilk_compute_wm_results(struct drm_device *dev,
        }
 
        /* LP0 register values */
-       list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head) {
+       for_each_intel_crtc(dev, intel_crtc) {
                enum pipe pipe = intel_crtc->pipe;
                const struct intel_wm_level *r =
                        &intel_crtc->wm.active.wm[0];
@@ -2699,7 +2747,7 @@ void ilk_wm_get_hw_state(struct drm_device *dev)
        struct ilk_wm_values *hw = &dev_priv->wm.hw;
        struct drm_crtc *crtc;
 
-       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
+       for_each_crtc(dev, crtc)
                ilk_pipe_wm_get_hw_state(crtc);
 
        hw->wm_lp[0] = I915_READ(WM1_LP_ILK);
@@ -3066,6 +3114,9 @@ static u32 gen6_rps_pm_mask(struct drm_i915_private *dev_priv, u8 val)
        if (INTEL_INFO(dev_priv->dev)->gen <= 7 && !IS_HASWELL(dev_priv->dev))
                mask |= GEN6_PM_RP_UP_EI_EXPIRED;
 
+       if (IS_GEN8(dev_priv->dev))
+               mask |= GEN8_PMINTR_REDIRECT_TO_NON_DISP;
+
        return ~mask;
 }
 
@@ -3198,6 +3249,26 @@ void valleyview_set_rps(struct drm_device *dev, u8 val)
        trace_intel_gpu_freq_change(vlv_gpu_freq(dev_priv, val));
 }
 
+static void gen8_disable_rps_interrupts(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       I915_WRITE(GEN6_PMINTRMSK, ~GEN8_PMINTR_REDIRECT_TO_NON_DISP);
+       I915_WRITE(GEN8_GT_IER(2), I915_READ(GEN8_GT_IER(2)) &
+                                  ~dev_priv->pm_rps_events);
+       /* Complete PM interrupt masking here doesn't race with the rps work
+        * item again unmasking PM interrupts because that is using a different
+        * register (GEN8_GT_IMR(2)) to mask PM interrupts. The only risk is in
+        * leaving stale bits in GEN8_GT_IIR(2) and GEN8_GT_IMR(2) which
+        * gen8_enable_rps will clean up. */
+
+       spin_lock_irq(&dev_priv->irq_lock);
+       dev_priv->rps.pm_iir = 0;
+       spin_unlock_irq(&dev_priv->irq_lock);
+
+       I915_WRITE(GEN8_GT_IIR(2), dev_priv->pm_rps_events);
+}
+
 static void gen6_disable_rps_interrupts(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -3224,7 +3295,10 @@ static void gen6_disable_rps(struct drm_device *dev)
        I915_WRITE(GEN6_RC_CONTROL, 0);
        I915_WRITE(GEN6_RPNSWREQ, 1 << 31);
 
-       gen6_disable_rps_interrupts(dev);
+       if (IS_BROADWELL(dev))
+               gen8_disable_rps_interrupts(dev);
+       else
+               gen6_disable_rps_interrupts(dev);
 }
 
 static void valleyview_disable_rps(struct drm_device *dev)
@@ -3260,10 +3334,6 @@ static int sanitize_rc6_option(const struct drm_device *dev, int enable_rc6)
        if (INTEL_INFO(dev)->gen == 5 && !IS_IRONLAKE_M(dev))
                return 0;
 
-       /* Disable RC6 on Broadwell for now */
-       if (IS_BROADWELL(dev))
-               return 0;
-
        /* Respect the kernel parameter if it is set */
        if (enable_rc6 >= 0) {
                int mask;
@@ -3276,7 +3346,7 @@ static int sanitize_rc6_option(const struct drm_device *dev, int enable_rc6)
 
                if ((enable_rc6 & mask) != enable_rc6)
                        DRM_INFO("Adjusting RC6 mask to %d (requested %d, valid %d)\n",
-                                enable_rc6, enable_rc6 & mask, mask);
+                                enable_rc6 & mask, enable_rc6, mask);
 
                return enable_rc6 & mask;
        }
@@ -3296,6 +3366,17 @@ int intel_enable_rc6(const struct drm_device *dev)
        return i915.enable_rc6;
 }
 
+static void gen8_enable_rps_interrupts(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       spin_lock_irq(&dev_priv->irq_lock);
+       WARN_ON(dev_priv->rps.pm_iir);
+       bdw_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
+       I915_WRITE(GEN8_GT_IIR(2), dev_priv->pm_rps_events);
+       spin_unlock_irq(&dev_priv->irq_lock);
+}
+
 static void gen6_enable_rps_interrupts(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -3331,7 +3412,7 @@ static void parse_rp_state_cap(struct drm_i915_private *dev_priv, u32 rp_state_c
 static void gen8_enable_rps(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_ring_buffer *ring;
+       struct intel_engine_cs *ring;
        uint32_t rc6_mask = 0, rp_state_cap;
        int unused;
 
@@ -3385,11 +3466,15 @@ static void gen8_enable_rps(struct drm_device *dev)
 
        I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10);
 
+       /* WaDisablePwrmtrEvent:chv (pre-production hw) */
+       I915_WRITE(0xA80C, I915_READ(0xA80C) & 0x00ffffff);
+       I915_WRITE(0xA810, I915_READ(0xA810) & 0xffffff00);
+
        /* 5: Enable RPS */
        I915_WRITE(GEN6_RP_CONTROL,
                   GEN6_RP_MEDIA_TURBO |
                   GEN6_RP_MEDIA_HW_NORMAL_MODE |
-                  GEN6_RP_MEDIA_IS_GFX |
+                  GEN6_RP_MEDIA_IS_GFX | /* WaSetMaskForGfxBusyness:chv (pre-production hw ?) */
                   GEN6_RP_ENABLE |
                   GEN6_RP_UP_BUSY_AVG |
                   GEN6_RP_DOWN_IDLE_AVG);
@@ -3398,7 +3483,7 @@ static void gen8_enable_rps(struct drm_device *dev)
 
        gen6_set_rps(dev, (I915_READ(GEN6_GT_PERF_STATUS) & 0xff00) >> 8);
 
-       gen6_enable_rps_interrupts(dev);
+       gen8_enable_rps_interrupts(dev);
 
        gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
 }
@@ -3406,7 +3491,7 @@ static void gen8_enable_rps(struct drm_device *dev)
 static void gen6_enable_rps(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_ring_buffer *ring;
+       struct intel_engine_cs *ring;
        u32 rp_state_cap;
        u32 gt_perf_status;
        u32 rc6vids, pcu_mbox = 0, rc6_mask = 0;
@@ -3735,7 +3820,7 @@ static void valleyview_cleanup_gt_powersave(struct drm_device *dev)
 static void valleyview_enable_rps(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_ring_buffer *ring;
+       struct intel_engine_cs *ring;
        u32 gtfifodbg, val, rc6_mode = 0;
        int i;
 
@@ -3866,7 +3951,7 @@ static int ironlake_setup_rc6(struct drm_device *dev)
 static void ironlake_enable_rc6(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
+       struct intel_engine_cs *ring = &dev_priv->ring[RCS];
        bool was_interruptible;
        int ret;
 
@@ -4378,7 +4463,7 @@ EXPORT_SYMBOL_GPL(i915_gpu_lower);
 bool i915_gpu_busy(void)
 {
        struct drm_i915_private *dev_priv;
-       struct intel_ring_buffer *ring;
+       struct intel_engine_cs *ring;
        bool ret = false;
        int i;
 
@@ -4560,8 +4645,10 @@ void intel_disable_gt_powersave(struct drm_device *dev)
        if (IS_IRONLAKE_M(dev)) {
                ironlake_disable_drps(dev);
                ironlake_disable_rc6(dev);
-       } else if (IS_GEN6(dev) || IS_GEN7(dev)) {
-               cancel_delayed_work_sync(&dev_priv->rps.delayed_resume_work);
+       } else if (IS_GEN6(dev) || IS_GEN7(dev) || IS_BROADWELL(dev)) {
+               if (cancel_delayed_work_sync(&dev_priv->rps.delayed_resume_work))
+                       intel_runtime_pm_put(dev_priv);
+
                cancel_work_sync(&dev_priv->rps.work);
                mutex_lock(&dev_priv->rps.hw_lock);
                if (IS_VALLEYVIEW(dev))
@@ -4607,7 +4694,7 @@ void intel_enable_gt_powersave(struct drm_device *dev)
                ironlake_enable_rc6(dev);
                intel_init_emon(dev);
                mutex_unlock(&dev->struct_mutex);
-       } else if (IS_GEN6(dev) || IS_GEN7(dev)) {
+       } else if (IS_GEN6(dev) || IS_GEN7(dev) || IS_BROADWELL(dev)) {
                /*
                 * PCU communication is slow and this doesn't need to be
                 * done at any specific time, so do this out of our fast path
@@ -4988,6 +5075,10 @@ static void gen8_init_clock_gating(struct drm_device *dev)
        I915_WRITE(GEN7_HALF_SLICE_CHICKEN1,
                   _MASKED_BIT_ENABLE(GEN7_SINGLE_SUBSCAN_DISPATCH_ENABLE));
 
+       /* WaDisableDopClockGating:bdw May not be needed for production */
+       I915_WRITE(GEN7_ROW_CHICKEN2,
+                  _MASKED_BIT_ENABLE(DOP_CLOCK_GATING_DISABLE));
+
        /* WaSwitchSolVfFArbitrationPriority:bdw */
        I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | HSW_ECOCHK_ARB_PRIO_SOL);
 
@@ -5257,8 +5348,11 @@ static void valleyview_init_clock_gating(struct drm_device *dev)
        I915_WRITE(GEN6_UCGCTL2,
                   GEN6_RCZUNIT_CLOCK_GATE_DISABLE);
 
-       /* WaDisableL3Bank2xClockGate:vlv */
-       I915_WRITE(GEN7_UCGCTL4, GEN7_L3BANK2X_CLOCK_GATE_DISABLE);
+       /* WaDisableL3Bank2xClockGate:vlv
+        * Disabling L3 clock gating- MMIO 940c[25] = 1
+        * Set bit 25, to disable L3_BANK_2x_CLK_GATING */
+       I915_WRITE(GEN7_UCGCTL4,
+                  I915_READ(GEN7_UCGCTL4) | GEN7_L3BANK2X_CLOCK_GATE_DISABLE);
 
        I915_WRITE(MI_ARB_VLV, MI_ARB_DISPLAY_TRICKLE_FEED_DISABLE);
 
@@ -5283,6 +5377,59 @@ static void valleyview_init_clock_gating(struct drm_device *dev)
        I915_WRITE(VLV_GUNIT_CLOCK_GATE, GCFG_DIS);
 }
 
+static void cherryview_init_clock_gating(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       I915_WRITE(DSPCLK_GATE_D, VRHUNIT_CLOCK_GATE_DISABLE);
+
+       I915_WRITE(MI_ARB_VLV, MI_ARB_DISPLAY_TRICKLE_FEED_DISABLE);
+
+       /* WaDisablePartialInstShootdown:chv */
+       I915_WRITE(GEN8_ROW_CHICKEN,
+                  _MASKED_BIT_ENABLE(PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE));
+
+       /* WaDisableThreadStallDopClockGating:chv */
+       I915_WRITE(GEN8_ROW_CHICKEN,
+                  _MASKED_BIT_ENABLE(STALL_DOP_GATING_DISABLE));
+
+       /* WaVSRefCountFullforceMissDisable:chv */
+       /* WaDSRefCountFullforceMissDisable:chv */
+       I915_WRITE(GEN7_FF_THREAD_MODE,
+                  I915_READ(GEN7_FF_THREAD_MODE) &
+                  ~(GEN8_FF_DS_REF_CNT_FFME | GEN7_FF_VS_REF_CNT_FFME));
+
+       /* WaDisableSemaphoreAndSyncFlipWait:chv */
+       I915_WRITE(GEN6_RC_SLEEP_PSMI_CONTROL,
+                  _MASKED_BIT_ENABLE(GEN8_RC_SEMA_IDLE_MSG_DISABLE));
+
+       /* WaDisableCSUnitClockGating:chv */
+       I915_WRITE(GEN6_UCGCTL1, I915_READ(GEN6_UCGCTL1) |
+                  GEN6_CSUNIT_CLOCK_GATE_DISABLE);
+
+       /* WaDisableSDEUnitClockGating:chv */
+       I915_WRITE(GEN8_UCGCTL6, I915_READ(GEN8_UCGCTL6) |
+                  GEN8_SDEUNIT_CLOCK_GATE_DISABLE);
+
+       /* WaDisableSamplerPowerBypass:chv (pre-production hw) */
+       I915_WRITE(HALF_SLICE_CHICKEN3,
+                  _MASKED_BIT_ENABLE(GEN8_SAMPLER_POWER_BYPASS_DIS));
+
+       /* WaDisableGunitClockGating:chv (pre-production hw) */
+       I915_WRITE(VLV_GUNIT_CLOCK_GATE, I915_READ(VLV_GUNIT_CLOCK_GATE) |
+                  GINT_DIS);
+
+       /* WaDisableFfDopClockGating:chv (pre-production hw) */
+       I915_WRITE(GEN6_RC_SLEEP_PSMI_CONTROL,
+                  _MASKED_BIT_ENABLE(GEN8_FF_DOP_CLOCK_GATE_DISABLE));
+
+       /* WaDisableDopClockGating:chv (pre-production hw) */
+       I915_WRITE(GEN7_ROW_CHICKEN2,
+                  _MASKED_BIT_ENABLE(DOP_CLOCK_GATING_DISABLE));
+       I915_WRITE(GEN6_UCGCTL1, I915_READ(GEN6_UCGCTL1) |
+                  GEN6_EU_TCUNIT_CLOCK_GATE_DISABLE);
+}
+
 static void g4x_init_clock_gating(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -5357,6 +5504,9 @@ static void gen3_init_clock_gating(struct drm_device *dev)
 
        /* IIR "flip pending" means done if this bit is set */
        I915_WRITE(ECOSKPD, _MASKED_BIT_DISABLE(ECO_FLIP_DONE));
+
+       /* interrupts should cause a wake up from C3 */
+       I915_WRITE(INSTPM, _MASKED_BIT_DISABLE(INSTPM_AGPBUSY_DIS));
 }
 
 static void i85x_init_clock_gating(struct drm_device *dev)
@@ -5493,33 +5643,6 @@ static void hsw_power_well_post_enable(struct drm_i915_private *dev_priv)
        }
 }
 
-static void reset_vblank_counter(struct drm_device *dev, enum pipe pipe)
-{
-       assert_spin_locked(&dev->vbl_lock);
-
-       dev->vblank[pipe].last = 0;
-}
-
-static void hsw_power_well_post_disable(struct drm_i915_private *dev_priv)
-{
-       struct drm_device *dev = dev_priv->dev;
-       enum pipe pipe;
-       unsigned long irqflags;
-
-       /*
-        * After this, the registers on the pipes that are part of the power
-        * well will become zero, so we have to adjust our counters according to
-        * that.
-        *
-        * FIXME: Should we do this in general in drm_vblank_post_modeset?
-        */
-       spin_lock_irqsave(&dev->vbl_lock, irqflags);
-       for_each_pipe(pipe)
-               if (pipe != PIPE_A)
-                       reset_vblank_counter(dev, pipe);
-       spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
-}
-
 static void hsw_set_power_well(struct drm_i915_private *dev_priv,
                               struct i915_power_well *power_well, bool enable)
 {
@@ -5548,8 +5671,6 @@ static void hsw_set_power_well(struct drm_i915_private *dev_priv,
                        I915_WRITE(HSW_PWR_WELL_DRIVER, 0);
                        POSTING_READ(HSW_PWR_WELL_DRIVER);
                        DRM_DEBUG_KMS("Requesting to disable the power well\n");
-
-                       hsw_power_well_post_disable(dev_priv);
                }
        }
 }
@@ -5590,13 +5711,34 @@ static bool i9xx_always_on_power_well_enabled(struct drm_i915_private *dev_priv,
        return true;
 }
 
-static void vlv_set_power_well(struct drm_i915_private *dev_priv,
-                              struct i915_power_well *power_well, bool enable)
+void __vlv_set_power_well(struct drm_i915_private *dev_priv,
+                         enum punit_power_well power_well_id, bool enable)
 {
-       enum punit_power_well power_well_id = power_well->data;
+       struct drm_device *dev = dev_priv->dev;
        u32 mask;
        u32 state;
        u32 ctrl;
+       enum pipe pipe;
+
+       if (power_well_id == PUNIT_POWER_WELL_DPIO_CMN_BC) {
+               if (enable) {
+                       /*
+                        * Enable the CRI clock source so we can get at the
+                        * display and the reference clock for VGA
+                        * hotplug / manual detection.
+                        */
+                       I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) |
+                                  DPLL_REFA_CLK_ENABLE_VLV |
+                                  DPLL_INTEGRATED_CRI_CLK_VLV);
+                       udelay(1); /* >10ns for cmnreset, >0ns for sidereset */
+               } else {
+                       for_each_pipe(pipe)
+                               assert_pll_disabled(dev_priv, pipe);
+                       /* Assert common reset */
+                       I915_WRITE(DPIO_CTL, I915_READ(DPIO_CTL) &
+                                  ~DPIO_CMNRST);
+               }
+       }
 
        mask = PUNIT_PWRGT_MASK(power_well_id);
        state = enable ? PUNIT_PWRGT_PWR_ON(power_well_id) :
@@ -5624,6 +5766,28 @@ static void vlv_set_power_well(struct drm_i915_private *dev_priv,
 
 out:
        mutex_unlock(&dev_priv->rps.hw_lock);
+
+       /*
+        * From VLV2A0_DP_eDP_DPIO_driver_vbios_notes_10.docx -
+        *  6.  De-assert cmn_reset/side_reset. Same as VLV X0.
+        *   a. GUnit 0x2110 bit[0] set to 1 (def 0)
+        *   b. The other bits such as sfr settings / modesel may all
+        *      be set to 0.
+        *
+        * This should only be done on init and resume from S3 with
+        * both PLLs disabled, or we risk losing DPIO and PLL
+        * synchronization.
+        */
+       if (power_well_id == PUNIT_POWER_WELL_DPIO_CMN_BC && enable)
+               I915_WRITE(DPIO_CTL, I915_READ(DPIO_CTL) | DPIO_CMNRST);
+}
+
+static void vlv_set_power_well(struct drm_i915_private *dev_priv,
+                              struct i915_power_well *power_well, bool enable)
+{
+       enum punit_power_well power_well_id = power_well->data;
+
+       __vlv_set_power_well(dev_priv, power_well_id, enable);
 }
 
 static void vlv_power_well_sync_hw(struct drm_i915_private *dev_priv,
@@ -5692,11 +5856,13 @@ static void vlv_display_power_well_enable(struct drm_i915_private *dev_priv,
        spin_unlock_irq(&dev_priv->irq_lock);
 
        /*
-        * During driver initialization we need to defer enabling hotplug
-        * processing until fbdev is set up.
+        * During driver initialization/resume we can avoid restoring the
+        * part of the HW/SW state that will be inited anyway explicitly.
         */
-       if (dev_priv->enable_hotplug_processing)
-               intel_hpd_init(dev_priv->dev);
+       if (dev_priv->power_domains.initializing)
+               return;
+
+       intel_hpd_init(dev_priv->dev);
 
        i915_redisable_vga_power_on(dev_priv->dev);
 }
@@ -5704,23 +5870,12 @@ static void vlv_display_power_well_enable(struct drm_i915_private *dev_priv,
 static void vlv_display_power_well_disable(struct drm_i915_private *dev_priv,
                                           struct i915_power_well *power_well)
 {
-       struct drm_device *dev = dev_priv->dev;
-       enum pipe pipe;
-
        WARN_ON_ONCE(power_well->data != PUNIT_POWER_WELL_DISP2D);
 
        spin_lock_irq(&dev_priv->irq_lock);
-       for_each_pipe(pipe)
-               __intel_set_cpu_fifo_underrun_reporting(dev, pipe, false);
-
        valleyview_disable_display_irqs(dev_priv);
        spin_unlock_irq(&dev_priv->irq_lock);
 
-       spin_lock_irq(&dev->vbl_lock);
-       for_each_pipe(pipe)
-               reset_vblank_counter(dev, pipe);
-       spin_unlock_irq(&dev->vbl_lock);
-
        vlv_set_power_well(dev_priv, power_well, false);
 }
 
@@ -5967,12 +6122,6 @@ static struct i915_power_well vlv_power_wells[] = {
                .data = PUNIT_POWER_WELL_DISP2D,
                .ops = &vlv_display_power_well_ops,
        },
-       {
-               .name = "dpio-common",
-               .domains = VLV_DPIO_CMN_BC_POWER_DOMAINS,
-               .data = PUNIT_POWER_WELL_DPIO_CMN_BC,
-               .ops = &vlv_dpio_power_well_ops,
-       },
        {
                .name = "dpio-tx-b-01",
                .domains = VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS |
@@ -6009,6 +6158,12 @@ static struct i915_power_well vlv_power_wells[] = {
                .ops = &vlv_dpio_power_well_ops,
                .data = PUNIT_POWER_WELL_DPIO_TX_C_LANES_23,
        },
+       {
+               .name = "dpio-common",
+               .domains = VLV_DPIO_CMN_BC_POWER_DOMAINS,
+               .data = PUNIT_POWER_WELL_DPIO_CMN_BC,
+               .ops = &vlv_dpio_power_well_ops,
+       },
 };
 
 #define set_power_wells(power_domains, __power_wells) ({               \
@@ -6060,9 +6215,13 @@ static void intel_power_domains_resume(struct drm_i915_private *dev_priv)
 
 void intel_power_domains_init_hw(struct drm_i915_private *dev_priv)
 {
+       struct i915_power_domains *power_domains = &dev_priv->power_domains;
+
+       power_domains->initializing = true;
        /* For now, we need the power well to be always enabled. */
        intel_display_set_init_power(dev_priv, true);
        intel_power_domains_resume(dev_priv);
+       power_domains->initializing = false;
 }
 
 void intel_aux_display_runtime_get(struct drm_i915_private *dev_priv)
@@ -6212,6 +6371,10 @@ void intel_init_pm(struct drm_device *dev)
                        dev_priv->display.init_clock_gating = haswell_init_clock_gating;
                else if (INTEL_INFO(dev)->gen == 8)
                        dev_priv->display.init_clock_gating = gen8_init_clock_gating;
+       } else if (IS_CHERRYVIEW(dev)) {
+               dev_priv->display.update_wm = valleyview_update_wm;
+               dev_priv->display.init_clock_gating =
+                       cherryview_init_clock_gating;
        } else if (IS_VALLEYVIEW(dev)) {
                dev_priv->display.update_wm = valleyview_update_wm;
                dev_priv->display.init_clock_gating =