]> rtime.felk.cvut.cz Git - linux-imx.git/blobdiff - drivers/gpu/drm/i915/intel_pm.c
drm/i915: add haswell_update_sprite_wm
[linux-imx.git] / drivers / gpu / drm / i915 / intel_pm.c
index f95b97cf4a0d9421e8a36d2a32fea27493dbad57..9328ed98ce2fddb68deaee7d9b5f860a4196425b 100644 (file)
@@ -242,6 +242,18 @@ static void ironlake_disable_fbc(struct drm_device *dev)
                dpfc_ctl &= ~DPFC_CTL_EN;
                I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl);
 
+               if (IS_IVYBRIDGE(dev))
+                       /* WaFbcDisableDpfcClockGating:ivb */
+                       I915_WRITE(ILK_DSPCLK_GATE_D,
+                                  I915_READ(ILK_DSPCLK_GATE_D) &
+                                  ~ILK_DPFCUNIT_CLOCK_GATE_DISABLE);
+
+               if (IS_HASWELL(dev))
+                       /* WaFbcDisableDpfcClockGating:hsw */
+                       I915_WRITE(HSW_CLKGATE_DISABLE_PART_1,
+                                  I915_READ(HSW_CLKGATE_DISABLE_PART_1) &
+                                  ~HSW_DPFC_GATING_DISABLE);
+
                DRM_DEBUG_KMS("disabled FBC\n");
        }
 }
@@ -253,6 +265,47 @@ static bool ironlake_fbc_enabled(struct drm_device *dev)
        return I915_READ(ILK_DPFC_CONTROL) & DPFC_CTL_EN;
 }
 
+static void gen7_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_framebuffer *fb = crtc->fb;
+       struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
+       struct drm_i915_gem_object *obj = intel_fb->obj;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+       I915_WRITE(IVB_FBC_RT_BASE, obj->gtt_offset | ILK_FBC_RT_VALID);
+
+       I915_WRITE(ILK_DPFC_CONTROL, DPFC_CTL_EN | DPFC_CTL_LIMIT_1X |
+                  IVB_DPFC_CTL_FENCE_EN |
+                  intel_crtc->plane << IVB_DPFC_CTL_PLANE_SHIFT);
+
+       if (IS_IVYBRIDGE(dev)) {
+               /* WaFbcAsynchFlipDisableFbcQueue:ivb */
+               I915_WRITE(ILK_DISPLAY_CHICKEN1, ILK_FBCQ_DIS);
+               /* WaFbcDisableDpfcClockGating:ivb */
+               I915_WRITE(ILK_DSPCLK_GATE_D,
+                          I915_READ(ILK_DSPCLK_GATE_D) |
+                          ILK_DPFCUNIT_CLOCK_GATE_DISABLE);
+       } else {
+               /* WaFbcAsynchFlipDisableFbcQueue:hsw */
+               I915_WRITE(HSW_PIPE_SLICE_CHICKEN_1(intel_crtc->pipe),
+                          HSW_BYPASS_FBC_QUEUE);
+               /* WaFbcDisableDpfcClockGating:hsw */
+               I915_WRITE(HSW_CLKGATE_DISABLE_PART_1,
+                          I915_READ(HSW_CLKGATE_DISABLE_PART_1) |
+                          HSW_DPFC_GATING_DISABLE);
+       }
+
+       I915_WRITE(SNB_DPFC_CTL_SA,
+                  SNB_CPU_FENCE_ENABLE | obj->fence_reg);
+       I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y);
+
+       sandybridge_blit_fbc_update(dev);
+
+       DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane);
+}
+
 bool intel_fbc_enabled(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -439,7 +492,7 @@ void intel_update_fbc(struct drm_device *dev)
        if (enable_fbc < 0) {
                DRM_DEBUG_KMS("fbc set to per-chip default\n");
                enable_fbc = 1;
-               if (INTEL_INFO(dev)->gen <= 6)
+               if (INTEL_INFO(dev)->gen <= 7 && !IS_HASWELL(dev))
                        enable_fbc = 0;
        }
        if (!enable_fbc) {
@@ -460,7 +513,8 @@ void intel_update_fbc(struct drm_device *dev)
                dev_priv->no_fbc_reason = FBC_MODE_TOO_LARGE;
                goto out_disable;
        }
-       if ((IS_I915GM(dev) || IS_I945GM(dev)) && intel_crtc->plane != 0) {
+       if ((IS_I915GM(dev) || IS_I945GM(dev) || IS_HASWELL(dev)) &&
+           intel_crtc->plane != 0) {
                DRM_DEBUG_KMS("plane not 0, disabling compression\n");
                dev_priv->no_fbc_reason = FBC_BAD_PLANE;
                goto out_disable;
@@ -1299,17 +1353,17 @@ static void valleyview_update_wm(struct drm_device *dev)
 
        vlv_update_drain_latency(dev);
 
-       if (g4x_compute_wm0(dev, 0,
+       if (g4x_compute_wm0(dev, PIPE_A,
                            &valleyview_wm_info, latency_ns,
                            &valleyview_cursor_wm_info, latency_ns,
                            &planea_wm, &cursora_wm))
-               enabled |= 1;
+               enabled |= 1 << PIPE_A;
 
-       if (g4x_compute_wm0(dev, 1,
+       if (g4x_compute_wm0(dev, PIPE_B,
                            &valleyview_wm_info, latency_ns,
                            &valleyview_cursor_wm_info, latency_ns,
                            &planeb_wm, &cursorb_wm))
-               enabled |= 2;
+               enabled |= 1 << PIPE_B;
 
        if (single_plane_enabled(enabled) &&
            g4x_compute_srwm(dev, ffs(enabled) - 1,
@@ -1355,17 +1409,17 @@ static void g4x_update_wm(struct drm_device *dev)
        int plane_sr, cursor_sr;
        unsigned int enabled = 0;
 
-       if (g4x_compute_wm0(dev, 0,
+       if (g4x_compute_wm0(dev, PIPE_A,
                            &g4x_wm_info, latency_ns,
                            &g4x_cursor_wm_info, latency_ns,
                            &planea_wm, &cursora_wm))
-               enabled |= 1;
+               enabled |= 1 << PIPE_A;
 
-       if (g4x_compute_wm0(dev, 1,
+       if (g4x_compute_wm0(dev, PIPE_B,
                            &g4x_wm_info, latency_ns,
                            &g4x_cursor_wm_info, latency_ns,
                            &planeb_wm, &cursorb_wm))
-               enabled |= 2;
+               enabled |= 1 << PIPE_B;
 
        if (single_plane_enabled(enabled) &&
            g4x_compute_srwm(dev, ffs(enabled) - 1,
@@ -1631,6 +1685,10 @@ static bool ironlake_check_srwm(struct drm_device *dev, int level,
                I915_WRITE(DISP_ARB_CTL,
                           I915_READ(DISP_ARB_CTL) | DISP_FBC_WM_DIS);
                return false;
+       } else if (INTEL_INFO(dev)->gen >= 6) {
+               /* enable FBC WM (except on ILK, where it must remain off) */
+               I915_WRITE(DISP_ARB_CTL,
+                          I915_READ(DISP_ARB_CTL) & ~DISP_FBC_WM_DIS);
        }
 
        if (display_wm > display->max_wm) {
@@ -1714,7 +1772,7 @@ static void ironlake_update_wm(struct drm_device *dev)
        unsigned int enabled;
 
        enabled = 0;
-       if (g4x_compute_wm0(dev, 0,
+       if (g4x_compute_wm0(dev, PIPE_A,
                            &ironlake_display_wm_info,
                            ILK_LP0_PLANE_LATENCY,
                            &ironlake_cursor_wm_info,
@@ -1725,10 +1783,10 @@ static void ironlake_update_wm(struct drm_device *dev)
                DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
                              " plane %d, " "cursor: %d\n",
                              plane_wm, cursor_wm);
-               enabled |= 1;
+               enabled |= 1 << PIPE_A;
        }
 
-       if (g4x_compute_wm0(dev, 1,
+       if (g4x_compute_wm0(dev, PIPE_B,
                            &ironlake_display_wm_info,
                            ILK_LP0_PLANE_LATENCY,
                            &ironlake_cursor_wm_info,
@@ -1739,7 +1797,7 @@ static void ironlake_update_wm(struct drm_device *dev)
                DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
                              " plane %d, cursor: %d\n",
                              plane_wm, cursor_wm);
-               enabled |= 2;
+               enabled |= 1 << PIPE_B;
        }
 
        /*
@@ -1799,7 +1857,7 @@ static void sandybridge_update_wm(struct drm_device *dev)
        unsigned int enabled;
 
        enabled = 0;
-       if (g4x_compute_wm0(dev, 0,
+       if (g4x_compute_wm0(dev, PIPE_A,
                            &sandybridge_display_wm_info, latency,
                            &sandybridge_cursor_wm_info, latency,
                            &plane_wm, &cursor_wm)) {
@@ -1810,10 +1868,10 @@ static void sandybridge_update_wm(struct drm_device *dev)
                DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
                              " plane %d, " "cursor: %d\n",
                              plane_wm, cursor_wm);
-               enabled |= 1;
+               enabled |= 1 << PIPE_A;
        }
 
-       if (g4x_compute_wm0(dev, 1,
+       if (g4x_compute_wm0(dev, PIPE_B,
                            &sandybridge_display_wm_info, latency,
                            &sandybridge_cursor_wm_info, latency,
                            &plane_wm, &cursor_wm)) {
@@ -1824,7 +1882,7 @@ static void sandybridge_update_wm(struct drm_device *dev)
                DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
                              " plane %d, cursor: %d\n",
                              plane_wm, cursor_wm);
-               enabled |= 2;
+               enabled |= 1 << PIPE_B;
        }
 
        /*
@@ -1902,7 +1960,7 @@ static void ivybridge_update_wm(struct drm_device *dev)
        unsigned int enabled;
 
        enabled = 0;
-       if (g4x_compute_wm0(dev, 0,
+       if (g4x_compute_wm0(dev, PIPE_A,
                            &sandybridge_display_wm_info, latency,
                            &sandybridge_cursor_wm_info, latency,
                            &plane_wm, &cursor_wm)) {
@@ -1913,10 +1971,10 @@ static void ivybridge_update_wm(struct drm_device *dev)
                DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
                              " plane %d, " "cursor: %d\n",
                              plane_wm, cursor_wm);
-               enabled |= 1;
+               enabled |= 1 << PIPE_A;
        }
 
-       if (g4x_compute_wm0(dev, 1,
+       if (g4x_compute_wm0(dev, PIPE_B,
                            &sandybridge_display_wm_info, latency,
                            &sandybridge_cursor_wm_info, latency,
                            &plane_wm, &cursor_wm)) {
@@ -1927,10 +1985,10 @@ static void ivybridge_update_wm(struct drm_device *dev)
                DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
                              " plane %d, cursor: %d\n",
                              plane_wm, cursor_wm);
-               enabled |= 2;
+               enabled |= 1 << PIPE_B;
        }
 
-       if (g4x_compute_wm0(dev, 2,
+       if (g4x_compute_wm0(dev, PIPE_C,
                            &sandybridge_display_wm_info, latency,
                            &sandybridge_cursor_wm_info, latency,
                            &plane_wm, &cursor_wm)) {
@@ -1941,7 +1999,7 @@ static void ivybridge_update_wm(struct drm_device *dev)
                DRM_DEBUG_KMS("FIFO watermarks For pipe C -"
                              " plane %d, cursor: %d\n",
                              plane_wm, cursor_wm);
-               enabled |= 3;
+               enabled |= 1 << PIPE_C;
        }
 
        /*
@@ -2015,30 +2073,69 @@ static void ivybridge_update_wm(struct drm_device *dev)
 }
 
 static void
-haswell_update_linetime_wm(struct drm_device *dev, int pipe,
-                                struct drm_display_mode *mode)
+haswell_update_linetime_wm(struct drm_device *dev, struct drm_crtc *crtc)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 temp;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       enum pipe pipe = intel_crtc->pipe;
+       struct drm_display_mode *mode = &intel_crtc->config.adjusted_mode;
+       u32 linetime, ips_linetime;
 
-       temp = I915_READ(PIPE_WM_LINETIME(pipe));
-       temp &= ~PIPE_WM_LINETIME_MASK;
+       if (!intel_crtc_active(crtc)) {
+               I915_WRITE(PIPE_WM_LINETIME(pipe), 0);
+               return;
+       }
 
        /* The WM are computed with base on how long it takes to fill a single
         * row at the given clock rate, multiplied by 8.
         * */
-       temp |= PIPE_WM_LINETIME_TIME(
-               ((mode->crtc_hdisplay * 1000) / mode->clock) * 8);
+       linetime = DIV_ROUND_CLOSEST(mode->htotal * 1000 * 8, mode->clock);
+       ips_linetime = DIV_ROUND_CLOSEST(mode->htotal * 1000 * 8,
+                                        intel_ddi_get_cdclk_freq(dev_priv));
 
-       /* IPS watermarks are only used by pipe A, and are ignored by
-        * pipes B and C.  They are calculated similarly to the common
-        * linetime values, except that we are using CD clock frequency
-        * in MHz instead of pixel rate for the division.
-        *
-        * This is a placeholder for the IPS watermark calculation code.
-        */
+       I915_WRITE(PIPE_WM_LINETIME(pipe),
+                  PIPE_WM_LINETIME_IPS_LINETIME(ips_linetime) |
+                  PIPE_WM_LINETIME_TIME(linetime));
+}
+
+static void haswell_update_wm(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_crtc *crtc;
+       enum pipe pipe;
+
+       /* Disable the LP WMs before changine the linetime registers. This is
+        * just a temporary code that will be replaced soon. */
+       I915_WRITE(WM3_LP_ILK, 0);
+       I915_WRITE(WM2_LP_ILK, 0);
+       I915_WRITE(WM1_LP_ILK, 0);
 
-       I915_WRITE(PIPE_WM_LINETIME(pipe), temp);
+       for_each_pipe(pipe) {
+               crtc = dev_priv->pipe_to_crtc_mapping[pipe];
+               haswell_update_linetime_wm(dev, crtc);
+       }
+
+       sandybridge_update_wm(dev);
+}
+
+static void haswell_update_sprite_wm(struct drm_device *dev, int pipe,
+                                    uint32_t sprite_width, int pixel_size,
+                                    bool enable)
+{
+       struct drm_plane *plane;
+
+       list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
+               struct intel_plane *intel_plane = to_intel_plane(plane);
+
+               if (intel_plane->pipe == pipe) {
+                       intel_plane->wm.enable = enable;
+                       intel_plane->wm.horiz_pixels = sprite_width + 1;
+                       intel_plane->wm.bytes_per_pixel = pixel_size;
+                       break;
+               }
+       }
+
+       haswell_update_wm(dev);
 }
 
 static bool
@@ -2118,7 +2215,8 @@ sandybridge_compute_sprite_srwm(struct drm_device *dev, int plane,
 }
 
 static void sandybridge_update_sprite_wm(struct drm_device *dev, int pipe,
-                                        uint32_t sprite_width, int pixel_size)
+                                        uint32_t sprite_width, int pixel_size,
+                                        bool enable)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        int latency = SNB_READ_WM0_LATENCY() * 100;     /* In unit 0.1us */
@@ -2126,6 +2224,9 @@ static void sandybridge_update_sprite_wm(struct drm_device *dev, int pipe,
        int sprite_wm, reg;
        int ret;
 
+       if (!enable)
+               return;
+
        switch (pipe) {
        case 0:
                reg = WM0_PIPEA_ILK;
@@ -2236,23 +2337,15 @@ void intel_update_watermarks(struct drm_device *dev)
                dev_priv->display.update_wm(dev);
 }
 
-void intel_update_linetime_watermarks(struct drm_device *dev,
-               int pipe, struct drm_display_mode *mode)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       if (dev_priv->display.update_linetime_wm)
-               dev_priv->display.update_linetime_wm(dev, pipe, mode);
-}
-
 void intel_update_sprite_watermarks(struct drm_device *dev, int pipe,
-                                   uint32_t sprite_width, int pixel_size)
+                                   uint32_t sprite_width, int pixel_size,
+                                   bool enable)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        if (dev_priv->display.update_sprite_wm)
                dev_priv->display.update_sprite_wm(dev, pipe, sprite_width,
-                                                  pixel_size);
+                                                  pixel_size, enable);
 }
 
 static struct drm_i915_gem_object *
@@ -2498,10 +2591,10 @@ void valleyview_set_rps(struct drm_device *dev, u8 val)
        if (val == dev_priv->rps.cur_delay)
                return;
 
-       valleyview_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ, val);
+       vlv_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ, val);
 
        do {
-               valleyview_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS, &pval);
+               pval = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS);
                if (time_after(jiffies, timeout)) {
                        DRM_DEBUG_DRIVER("timed out waiting for Punit\n");
                        break;
@@ -2509,7 +2602,7 @@ void valleyview_set_rps(struct drm_device *dev, u8 val)
                udelay(10);
        } while (pval & 1);
 
-       valleyview_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS, &pval);
+       pval = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS);
        if ((pval >> 8) != val)
                DRM_DEBUG_DRIVER("punit overrode freq: %d requested, but got %d\n",
                          val, pval >> 8);
@@ -2562,6 +2655,11 @@ static void valleyview_disable_rps(struct drm_device *dev)
        spin_unlock_irq(&dev_priv->rps.lock);
 
        I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR));
+
+       if (dev_priv->vlv_pctx) {
+               drm_gem_object_unreference(&dev_priv->vlv_pctx->base);
+               dev_priv->vlv_pctx = NULL;
+       }
 }
 
 int intel_enable_rc6(const struct drm_device *dev)
@@ -2702,7 +2800,7 @@ static void gen6_enable_rps(struct drm_device *dev)
                   (IS_HASWELL(dev) ? GEN7_RP_DOWN_IDLE_AVG : GEN6_RP_DOWN_IDLE_CONT));
 
        ret = sandybridge_pcode_write(dev_priv, GEN6_PCODE_WRITE_MIN_FREQ_TABLE, 0);
-       if (!ret && (IS_GEN6(dev) || IS_IVYBRIDGE(dev))) {
+       if (!ret) {
                pcu_mbox = 0;
                ret = sandybridge_pcode_read(dev_priv, GEN6_READ_OC_PARAMS, &pcu_mbox);
                if (!ret && (pcu_mbox & (1<<31))) { /* OC supported */
@@ -2809,7 +2907,7 @@ int valleyview_rps_max_freq(struct drm_i915_private *dev_priv)
 {
        u32 val, rp0;
 
-       valleyview_nc_read(dev_priv, IOSF_NC_FB_GFX_FREQ_FUSE, &val);
+       val = vlv_nc_read(dev_priv, IOSF_NC_FB_GFX_FREQ_FUSE);
 
        rp0 = (val & FB_GFX_MAX_FREQ_FUSE_MASK) >> FB_GFX_MAX_FREQ_FUSE_SHIFT;
        /* Clamp to max */
@@ -2822,9 +2920,9 @@ static int valleyview_rps_rpe_freq(struct drm_i915_private *dev_priv)
 {
        u32 val, rpe;
 
-       valleyview_nc_read(dev_priv, IOSF_NC_FB_GFX_FMAX_FUSE_LO, &val);
+       val = vlv_nc_read(dev_priv, IOSF_NC_FB_GFX_FMAX_FUSE_LO);
        rpe = (val & FB_FMAX_VMIN_FREQ_LO_MASK) >> FB_FMAX_VMIN_FREQ_LO_SHIFT;
-       valleyview_nc_read(dev_priv, IOSF_NC_FB_GFX_FMAX_FUSE_HI, &val);
+       val = vlv_nc_read(dev_priv, IOSF_NC_FB_GFX_FMAX_FUSE_HI);
        rpe |= (val & FB_FMAX_VMIN_FREQ_HI_MASK) << 5;
 
        return rpe;
@@ -2832,11 +2930,7 @@ static int valleyview_rps_rpe_freq(struct drm_i915_private *dev_priv)
 
 int valleyview_rps_min_freq(struct drm_i915_private *dev_priv)
 {
-       u32 val;
-
-       valleyview_punit_read(dev_priv, PUNIT_REG_GPU_LFM, &val);
-
-       return val & 0xff;
+       return vlv_punit_read(dev_priv, PUNIT_REG_GPU_LFM) & 0xff;
 }
 
 static void vlv_rps_timer_work(struct work_struct *work)
@@ -2856,6 +2950,48 @@ static void vlv_rps_timer_work(struct work_struct *work)
        mutex_unlock(&dev_priv->rps.hw_lock);
 }
 
+static void valleyview_setup_pctx(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_gem_object *pctx;
+       unsigned long pctx_paddr;
+       u32 pcbr;
+       int pctx_size = 24*1024;
+
+       pcbr = I915_READ(VLV_PCBR);
+       if (pcbr) {
+               /* BIOS set it up already, grab the pre-alloc'd space */
+               int pcbr_offset;
+
+               pcbr_offset = (pcbr & (~4095)) - dev_priv->mm.stolen_base;
+               pctx = i915_gem_object_create_stolen_for_preallocated(dev_priv->dev,
+                                                                     pcbr_offset,
+                                                                     -1,
+                                                                     pctx_size);
+               goto out;
+       }
+
+       /*
+        * From the Gunit register HAS:
+        * The Gfx driver is expected to program this register and ensure
+        * proper allocation within Gfx stolen memory.  For example, this
+        * register should be programmed such than the PCBR range does not
+        * overlap with other ranges, such as the frame buffer, protected
+        * memory, or any other relevant ranges.
+        */
+       pctx = i915_gem_object_create_stolen(dev, pctx_size);
+       if (!pctx) {
+               DRM_DEBUG("not enough stolen space for PCTX, disabling\n");
+               return;
+       }
+
+       pctx_paddr = dev_priv->mm.stolen_base + pctx->stolen->start;
+       I915_WRITE(VLV_PCBR, pctx_paddr);
+
+out:
+       dev_priv->vlv_pctx = pctx;
+}
+
 static void valleyview_enable_rps(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -2870,6 +3006,8 @@ static void valleyview_enable_rps(struct drm_device *dev)
                I915_WRITE(GTFIFODBG, gtfifodbg);
        }
 
+       valleyview_setup_pctx(dev);
+
        gen6_gt_force_wake_get(dev_priv);
 
        I915_WRITE(GEN6_RP_UP_THRESHOLD, 59400);
@@ -2901,7 +3039,7 @@ static void valleyview_enable_rps(struct drm_device *dev)
        I915_WRITE(GEN6_RC_CONTROL,
                   GEN7_RC_CTL_TO_MODE);
 
-       valleyview_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS, &val);
+       val = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS);
        switch ((val >> 6) & 3) {
        case 0:
        case 1:
@@ -3836,7 +3974,7 @@ static void cpt_init_clock_gating(struct drm_device *dev)
                val = I915_READ(TRANS_CHICKEN2(pipe));
                val |= TRANS_CHICKEN2_TIMING_OVERRIDE;
                val &= ~TRANS_CHICKEN2_FDI_POLARITY_REVERSED;
-               if (dev_priv->fdi_rx_polarity_inverted)
+               if (dev_priv->vbt.fdi_rx_polarity_inverted)
                        val |= TRANS_CHICKEN2_FDI_POLARITY_REVERSED;
                val &= ~TRANS_CHICKEN2_FRAME_START_DELAY_MASK;
                val &= ~TRANS_CHICKEN2_DISABLE_DEEP_COLOR_COUNTER;
@@ -3986,6 +4124,23 @@ static void lpt_init_clock_gating(struct drm_device *dev)
                I915_WRITE(SOUTH_DSPCLK_GATE_D,
                           I915_READ(SOUTH_DSPCLK_GATE_D) |
                           PCH_LP_PARTITION_LEVEL_DISABLE);
+
+       /* WADPOClockGatingDisable:hsw */
+       I915_WRITE(_TRANSA_CHICKEN1,
+                  I915_READ(_TRANSA_CHICKEN1) |
+                  TRANS_CHICKEN1_DP0UNIT_GC_DISABLE);
+}
+
+static void lpt_suspend_hw(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (dev_priv->pch_id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) {
+               uint32_t val = I915_READ(SOUTH_DSPCLK_GATE_D);
+
+               val &= ~PCH_LP_PARTITION_LEVEL_DISABLE;
+               I915_WRITE(SOUTH_DSPCLK_GATE_D, val);
+       }
 }
 
 static void haswell_init_clock_gating(struct drm_device *dev)
@@ -4038,14 +4193,9 @@ static void haswell_init_clock_gating(struct drm_device *dev)
        /* WaSwitchSolVfFArbitrationPriority:hsw */
        I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | HSW_ECOCHK_ARB_PRIO_SOL);
 
-       /* XXX: This is a workaround for early silicon revisions and should be
-        * removed later.
-        */
-       I915_WRITE(WM_DBG,
-                       I915_READ(WM_DBG) |
-                       WM_DBG_DISALLOW_MULTIPLE_LP |
-                       WM_DBG_DISALLOW_SPRITE |
-                       WM_DBG_DISALLOW_MAXFIFO);
+       /* WaRsPkgCStateDisplayPMReq:hsw */
+       I915_WRITE(CHICKEN_PAR1_1,
+                  I915_READ(CHICKEN_PAR1_1) | FORCE_ARB_IDLE_PLANES);
 
        lpt_init_clock_gating(dev);
 }
@@ -4340,6 +4490,12 @@ void intel_init_clock_gating(struct drm_device *dev)
        dev_priv->display.init_clock_gating(dev);
 }
 
+void intel_suspend_hw(struct drm_device *dev)
+{
+       if (HAS_PCH_LPT(dev))
+               lpt_suspend_hw(dev);
+}
+
 /**
  * We should only use the power well if we explicitly asked the hardware to
  * enable it, so check if it's enabled and also check if we've requested it to
@@ -4436,7 +4592,12 @@ void intel_init_pm(struct drm_device *dev)
        if (I915_HAS_FBC(dev)) {
                if (HAS_PCH_SPLIT(dev)) {
                        dev_priv->display.fbc_enabled = ironlake_fbc_enabled;
-                       dev_priv->display.enable_fbc = ironlake_enable_fbc;
+                       if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev))
+                               dev_priv->display.enable_fbc =
+                                       gen7_enable_fbc;
+                       else
+                               dev_priv->display.enable_fbc =
+                                       ironlake_enable_fbc;
                        dev_priv->display.disable_fbc = ironlake_disable_fbc;
                } else if (IS_GM45(dev)) {
                        dev_priv->display.fbc_enabled = g4x_fbc_enabled;
@@ -4488,10 +4649,10 @@ void intel_init_pm(struct drm_device *dev)
                        }
                        dev_priv->display.init_clock_gating = ivybridge_init_clock_gating;
                } else if (IS_HASWELL(dev)) {
-                       if (SNB_READ_WM0_LATENCY()) {
-                               dev_priv->display.update_wm = sandybridge_update_wm;
-                               dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm;
-                               dev_priv->display.update_linetime_wm = haswell_update_linetime_wm;
+                       if (I915_READ64(MCH_SSKPD)) {
+                               dev_priv->display.update_wm = haswell_update_wm;
+                               dev_priv->display.update_sprite_wm =
+                                       haswell_update_sprite_wm;
                        } else {
                                DRM_DEBUG_KMS("Failed to read display plane latency. "
                                              "Disable CxSR\n");
@@ -4586,6 +4747,7 @@ static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
                            FORCEWAKE_ACK_TIMEOUT_MS))
                DRM_ERROR("Timed out waiting for forcewake to ack request.\n");
 
+       /* WaRsForcewakeWaitTC0:snb */
        __gen6_gt_wait_for_thread_c0(dev_priv);
 }
 
@@ -4617,6 +4779,7 @@ static void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv)
                            FORCEWAKE_ACK_TIMEOUT_MS))
                DRM_ERROR("Timed out waiting for forcewake to ack request.\n");
 
+       /* WaRsForcewakeWaitTC0:ivb,hsw */
        __gen6_gt_wait_for_thread_c0(dev_priv);
 }
 
@@ -4720,6 +4883,7 @@ static void vlv_force_wake_get(struct drm_i915_private *dev_priv)
                            FORCEWAKE_ACK_TIMEOUT_MS))
                DRM_ERROR("Timed out waiting for media to ack forcewake request.\n");
 
+       /* WaRsForcewakeWaitTC0:vlv */
        __gen6_gt_wait_for_thread_c0(dev_priv);
 }
 
@@ -4814,66 +4978,6 @@ int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u8 mbox, u32 val)
        return 0;
 }
 
-static int vlv_punit_rw(struct drm_i915_private *dev_priv, u32 port, u8 opcode,
-                       u8 addr, u32 *val)
-{
-       u32 cmd, devfn, be, bar;
-
-       bar = 0;
-       be = 0xf;
-       devfn = PCI_DEVFN(2, 0);
-
-       cmd = (devfn << IOSF_DEVFN_SHIFT) | (opcode << IOSF_OPCODE_SHIFT) |
-               (port << IOSF_PORT_SHIFT) | (be << IOSF_BYTE_ENABLES_SHIFT) |
-               (bar << IOSF_BAR_SHIFT);
-
-       WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
-
-       if (I915_READ(VLV_IOSF_DOORBELL_REQ) & IOSF_SB_BUSY) {
-               DRM_DEBUG_DRIVER("warning: pcode (%s) mailbox access failed\n",
-                                opcode == PUNIT_OPCODE_REG_READ ?
-                                "read" : "write");
-               return -EAGAIN;
-       }
-
-       I915_WRITE(VLV_IOSF_ADDR, addr);
-       if (opcode == PUNIT_OPCODE_REG_WRITE)
-               I915_WRITE(VLV_IOSF_DATA, *val);
-       I915_WRITE(VLV_IOSF_DOORBELL_REQ, cmd);
-
-       if (wait_for((I915_READ(VLV_IOSF_DOORBELL_REQ) & IOSF_SB_BUSY) == 0,
-                    5)) {
-               DRM_ERROR("timeout waiting for pcode %s (%d) to finish\n",
-                         opcode == PUNIT_OPCODE_REG_READ ? "read" : "write",
-                         addr);
-               return -ETIMEDOUT;
-       }
-
-       if (opcode == PUNIT_OPCODE_REG_READ)
-               *val = I915_READ(VLV_IOSF_DATA);
-       I915_WRITE(VLV_IOSF_DATA, 0);
-
-       return 0;
-}
-
-int valleyview_punit_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val)
-{
-       return vlv_punit_rw(dev_priv, IOSF_PORT_PUNIT, PUNIT_OPCODE_REG_READ,
-                           addr, val);
-}
-
-int valleyview_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val)
-{
-       return vlv_punit_rw(dev_priv, IOSF_PORT_PUNIT, PUNIT_OPCODE_REG_WRITE,
-                           addr, &val);
-}
-
-int valleyview_nc_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val)
-{
-       return vlv_punit_rw(dev_priv, IOSF_PORT_NC, PUNIT_OPCODE_REG_READ,
-                           addr, val);
-}
-
 int vlv_gpu_freq(int ddr_freq, int val)
 {
        int mult, base;