]> git.ipfire.org Git - thirdparty/kernel/stable.git/blobdiff - drivers/gpu/drm/i915/intel_display.c
drm/i915: Bump gen7+ fb size limits to 16kx16k
[thirdparty/kernel/stable.git] / drivers / gpu / drm / i915 / intel_display.c
index 45a8c6e3c5cf6613d9934340eae042a748874539..d3b2f51e2dc2997c83c0f6a252a284b851bafbb7 100644 (file)
@@ -575,7 +575,7 @@ int chv_calc_dpll_params(int refclk, struct dpll *clock)
        clock->p = clock->p1 * clock->p2;
        if (WARN_ON(clock->n == 0 || clock->p == 0))
                return 0;
-       clock->vco = DIV_ROUND_CLOSEST_ULL((u64)refclk * clock->m,
+       clock->vco = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(refclk, clock->m),
                                           clock->n << 22);
        clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p);
 
@@ -960,8 +960,8 @@ chv_find_best_dpll(const struct intel_limit *limit,
 
                        clock.p = clock.p1 * clock.p2;
 
-                       m2 = DIV_ROUND_CLOSEST_ULL(((u64)target * clock.p *
-                                       clock.n) << 22, refclk * clock.m1);
+                       m2 = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(target, clock.p * clock.n) << 22,
+                                                  refclk * clock.m1);
 
                        if (m2 > INT_MAX/clock.m1)
                                continue;
@@ -1915,7 +1915,7 @@ intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane)
 
        switch (fb->modifier) {
        case DRM_FORMAT_MOD_LINEAR:
-               return cpp;
+               return intel_tile_size(dev_priv);
        case I915_FORMAT_MOD_X_TILED:
                if (IS_GEN(dev_priv, 2))
                        return 128;
@@ -1958,11 +1958,8 @@ intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane)
 static unsigned int
 intel_tile_height(const struct drm_framebuffer *fb, int color_plane)
 {
-       if (fb->modifier == DRM_FORMAT_MOD_LINEAR)
-               return 1;
-       else
-               return intel_tile_size(to_i915(fb->dev)) /
-                       intel_tile_width_bytes(fb, color_plane);
+       return intel_tile_size(to_i915(fb->dev)) /
+               intel_tile_width_bytes(fb, color_plane);
 }
 
 /* Return the tile dimensions in pixel units */
@@ -1997,6 +1994,17 @@ unsigned int intel_rotation_info_size(const struct intel_rotation_info *rot_info
        return size;
 }
 
+unsigned int intel_remapped_info_size(const struct intel_remapped_info *rem_info)
+{
+       unsigned int size = 0;
+       int i;
+
+       for (i = 0 ; i < ARRAY_SIZE(rem_info->plane); i++)
+               size += rem_info->plane[i].width * rem_info->plane[i].height;
+
+       return size;
+}
+
 static void
 intel_fill_fb_ggtt_view(struct i915_ggtt_view *view,
                        const struct drm_framebuffer *fb,
@@ -2066,7 +2074,9 @@ static bool intel_plane_uses_fence(const struct intel_plane_state *plane_state)
        struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
        struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
 
-       return INTEL_GEN(dev_priv) < 4 || plane->has_fbc;
+       return INTEL_GEN(dev_priv) < 4 ||
+               (plane->has_fbc &&
+                plane_state->view.type == I915_GGTT_VIEW_NORMAL);
 }
 
 struct i915_vma *
@@ -2207,16 +2217,8 @@ void intel_add_fb_offsets(int *x, int *y,
                          int color_plane)
 
 {
-       const struct intel_framebuffer *intel_fb = to_intel_framebuffer(state->base.fb);
-       unsigned int rotation = state->base.rotation;
-
-       if (drm_rotation_90_or_270(rotation)) {
-               *x += intel_fb->rotated[color_plane].x;
-               *y += intel_fb->rotated[color_plane].y;
-       } else {
-               *x += intel_fb->normal[color_plane].x;
-               *y += intel_fb->normal[color_plane].y;
-       }
+       *x += state->color_plane[color_plane].x;
+       *y += state->color_plane[color_plane].y;
 }
 
 static u32 intel_adjust_tile_offset(int *x, int *y,
@@ -2496,6 +2498,134 @@ bool is_ccs_modifier(u64 modifier)
               modifier == I915_FORMAT_MOD_Yf_TILED_CCS;
 }
 
+u32 intel_plane_fb_max_stride(struct drm_i915_private *dev_priv,
+                             u32 pixel_format, u64 modifier)
+{
+       struct intel_crtc *crtc;
+       struct intel_plane *plane;
+
+       /*
+        * We assume the primary plane for pipe A has
+        * the highest stride limits of them all.
+        */
+       crtc = intel_get_crtc_for_pipe(dev_priv, PIPE_A);
+       plane = to_intel_plane(crtc->base.primary);
+
+       return plane->max_stride(plane, pixel_format, modifier,
+                                DRM_MODE_ROTATE_0);
+}
+
+static
+u32 intel_fb_max_stride(struct drm_i915_private *dev_priv,
+                       u32 pixel_format, u64 modifier)
+{
+       /*
+        * Arbitrary limit for gen4+ chosen to match the
+        * render engine max stride.
+        *
+        * The new CCS hash mode makes remapping impossible
+        */
+       if (!is_ccs_modifier(modifier)) {
+               if (INTEL_GEN(dev_priv) >= 7)
+                       return 256*1024;
+               else if (INTEL_GEN(dev_priv) >= 4)
+                       return 128*1024;
+       }
+
+       return intel_plane_fb_max_stride(dev_priv, pixel_format, modifier);
+}
+
+static u32
+intel_fb_stride_alignment(const struct drm_framebuffer *fb, int color_plane)
+{
+       struct drm_i915_private *dev_priv = to_i915(fb->dev);
+
+       if (fb->modifier == DRM_FORMAT_MOD_LINEAR) {
+               u32 max_stride = intel_plane_fb_max_stride(dev_priv,
+                                                          fb->format->format,
+                                                          fb->modifier);
+
+               /*
+                * To make remapping with linear generally feasible
+                * we need the stride to be page aligned.
+                */
+               if (fb->pitches[color_plane] > max_stride)
+                       return intel_tile_size(dev_priv);
+               else
+                       return 64;
+       } else {
+               return intel_tile_width_bytes(fb, color_plane);
+       }
+}
+
+bool intel_plane_can_remap(const struct intel_plane_state *plane_state)
+{
+       struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
+       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
+       const struct drm_framebuffer *fb = plane_state->base.fb;
+       int i;
+
+       /* We don't want to deal with remapping with cursors */
+       if (plane->id == PLANE_CURSOR)
+               return false;
+
+       /*
+        * The display engine limits already match/exceed the
+        * render engine limits, so not much point in remapping.
+        * Would also need to deal with the fence POT alignment
+        * and gen2 2KiB GTT tile size.
+        */
+       if (INTEL_GEN(dev_priv) < 4)
+               return false;
+
+       /*
+        * The new CCS hash mode isn't compatible with remapping as
+        * the virtual address of the pages affects the compressed data.
+        */
+       if (is_ccs_modifier(fb->modifier))
+               return false;
+
+       /* Linear needs a page aligned stride for remapping */
+       if (fb->modifier == DRM_FORMAT_MOD_LINEAR) {
+               unsigned int alignment = intel_tile_size(dev_priv) - 1;
+
+               for (i = 0; i < fb->format->num_planes; i++) {
+                       if (fb->pitches[i] & alignment)
+                               return false;
+               }
+       }
+
+       return true;
+}
+
+static bool intel_plane_needs_remap(const struct intel_plane_state *plane_state)
+{
+       struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
+       const struct drm_framebuffer *fb = plane_state->base.fb;
+       unsigned int rotation = plane_state->base.rotation;
+       u32 stride, max_stride;
+
+       /*
+        * No remapping for invisible planes since we don't have
+        * an actual source viewport to remap.
+        */
+       if (!plane_state->base.visible)
+               return false;
+
+       if (!intel_plane_can_remap(plane_state))
+               return false;
+
+       /*
+        * FIXME: aux plane limits on gen9+ are
+        * unclear in Bspec, for now no checking.
+        */
+       stride = intel_fb_pitch(fb, 0, rotation);
+       max_stride = plane->max_stride(plane, fb->format->format,
+                                      fb->modifier, rotation);
+
+       return stride > max_stride;
+}
+
 static int
 intel_fill_fb_info(struct drm_i915_private *dev_priv,
                   struct drm_framebuffer *fb)
@@ -2661,6 +2791,168 @@ intel_fill_fb_info(struct drm_i915_private *dev_priv,
        return 0;
 }
 
+static void
+intel_plane_remap_gtt(struct intel_plane_state *plane_state)
+{
+       struct drm_i915_private *dev_priv =
+               to_i915(plane_state->base.plane->dev);
+       struct drm_framebuffer *fb = plane_state->base.fb;
+       struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
+       struct intel_rotation_info *info = &plane_state->view.rotated;
+       unsigned int rotation = plane_state->base.rotation;
+       int i, num_planes = fb->format->num_planes;
+       unsigned int tile_size = intel_tile_size(dev_priv);
+       unsigned int src_x, src_y;
+       unsigned int src_w, src_h;
+       u32 gtt_offset = 0;
+
+       memset(&plane_state->view, 0, sizeof(plane_state->view));
+       plane_state->view.type = drm_rotation_90_or_270(rotation) ?
+               I915_GGTT_VIEW_ROTATED : I915_GGTT_VIEW_REMAPPED;
+
+       src_x = plane_state->base.src.x1 >> 16;
+       src_y = plane_state->base.src.y1 >> 16;
+       src_w = drm_rect_width(&plane_state->base.src) >> 16;
+       src_h = drm_rect_height(&plane_state->base.src) >> 16;
+
+       WARN_ON(is_ccs_modifier(fb->modifier));
+
+       /* Make src coordinates relative to the viewport */
+       drm_rect_translate(&plane_state->base.src,
+                          -(src_x << 16), -(src_y << 16));
+
+       /* Rotate src coordinates to match rotated GTT view */
+       if (drm_rotation_90_or_270(rotation))
+               drm_rect_rotate(&plane_state->base.src,
+                               src_w << 16, src_h << 16,
+                               DRM_MODE_ROTATE_270);
+
+       for (i = 0; i < num_planes; i++) {
+               unsigned int hsub = i ? fb->format->hsub : 1;
+               unsigned int vsub = i ? fb->format->vsub : 1;
+               unsigned int cpp = fb->format->cpp[i];
+               unsigned int tile_width, tile_height;
+               unsigned int width, height;
+               unsigned int pitch_tiles;
+               unsigned int x, y;
+               u32 offset;
+
+               intel_tile_dims(fb, i, &tile_width, &tile_height);
+
+               x = src_x / hsub;
+               y = src_y / vsub;
+               width = src_w / hsub;
+               height = src_h / vsub;
+
+               /*
+                * First pixel of the src viewport from the
+                * start of the normal gtt mapping.
+                */
+               x += intel_fb->normal[i].x;
+               y += intel_fb->normal[i].y;
+
+               offset = intel_compute_aligned_offset(dev_priv, &x, &y,
+                                                     fb, i, fb->pitches[i],
+                                                     DRM_MODE_ROTATE_0, tile_size);
+               offset /= tile_size;
+
+               info->plane[i].offset = offset;
+               info->plane[i].stride = DIV_ROUND_UP(fb->pitches[i],
+                                                    tile_width * cpp);
+               info->plane[i].width = DIV_ROUND_UP(x + width, tile_width);
+               info->plane[i].height = DIV_ROUND_UP(y + height, tile_height);
+
+               if (drm_rotation_90_or_270(rotation)) {
+                       struct drm_rect r;
+
+                       /* rotate the x/y offsets to match the GTT view */
+                       r.x1 = x;
+                       r.y1 = y;
+                       r.x2 = x + width;
+                       r.y2 = y + height;
+                       drm_rect_rotate(&r,
+                                       info->plane[i].width * tile_width,
+                                       info->plane[i].height * tile_height,
+                                       DRM_MODE_ROTATE_270);
+                       x = r.x1;
+                       y = r.y1;
+
+                       pitch_tiles = info->plane[i].height;
+                       plane_state->color_plane[i].stride = pitch_tiles * tile_height;
+
+                       /* rotate the tile dimensions to match the GTT view */
+                       swap(tile_width, tile_height);
+               } else {
+                       pitch_tiles = info->plane[i].width;
+                       plane_state->color_plane[i].stride = pitch_tiles * tile_width * cpp;
+               }
+
+               /*
+                * We only keep the x/y offsets, so push all of the
+                * gtt offset into the x/y offsets.
+                */
+               intel_adjust_tile_offset(&x, &y,
+                                        tile_width, tile_height,
+                                        tile_size, pitch_tiles,
+                                        gtt_offset * tile_size, 0);
+
+               gtt_offset += info->plane[i].width * info->plane[i].height;
+
+               plane_state->color_plane[i].offset = 0;
+               plane_state->color_plane[i].x = x;
+               plane_state->color_plane[i].y = y;
+       }
+}
+
+static int
+intel_plane_compute_gtt(struct intel_plane_state *plane_state)
+{
+       const struct intel_framebuffer *fb =
+               to_intel_framebuffer(plane_state->base.fb);
+       unsigned int rotation = plane_state->base.rotation;
+       int i, num_planes;
+
+       if (!fb)
+               return 0;
+
+       num_planes = fb->base.format->num_planes;
+
+       if (intel_plane_needs_remap(plane_state)) {
+               intel_plane_remap_gtt(plane_state);
+
+               /*
+                * Sometimes even remapping can't overcome
+                * the stride limitations :( Can happen with
+                * big plane sizes and suitably misaligned
+                * offsets.
+                */
+               return intel_plane_check_stride(plane_state);
+       }
+
+       intel_fill_fb_ggtt_view(&plane_state->view, &fb->base, rotation);
+
+       for (i = 0; i < num_planes; i++) {
+               plane_state->color_plane[i].stride = intel_fb_pitch(&fb->base, i, rotation);
+               plane_state->color_plane[i].offset = 0;
+
+               if (drm_rotation_90_or_270(rotation)) {
+                       plane_state->color_plane[i].x = fb->rotated[i].x;
+                       plane_state->color_plane[i].y = fb->rotated[i].y;
+               } else {
+                       plane_state->color_plane[i].x = fb->normal[i].x;
+                       plane_state->color_plane[i].y = fb->normal[i].y;
+               }
+       }
+
+       /* Rotate src coordinates to match rotated GTT view */
+       if (drm_rotation_90_or_270(rotation))
+               drm_rect_rotate(&plane_state->base.src,
+                               fb->base.width << 16, fb->base.height << 16,
+                               DRM_MODE_ROTATE_270);
+
+       return intel_plane_check_stride(plane_state);
+}
+
 static int i9xx_format_to_fourcc(int format)
 {
        switch (format) {
@@ -3159,6 +3451,14 @@ static int skl_check_main_surface(struct intel_plane_state *plane_state)
        plane_state->color_plane[0].x = x;
        plane_state->color_plane[0].y = y;
 
+       /*
+        * Put the final coordinates back so that the src
+        * coordinate checks will see the right values.
+        */
+       drm_rect_translate(&plane_state->base.src,
+                          (x << 16) - plane_state->base.src.x1,
+                          (y << 16) - plane_state->base.src.y1);
+
        return 0;
 }
 
@@ -3215,26 +3515,15 @@ static int skl_check_ccs_aux_surface(struct intel_plane_state *plane_state)
 int skl_check_plane_surface(struct intel_plane_state *plane_state)
 {
        const struct drm_framebuffer *fb = plane_state->base.fb;
-       unsigned int rotation = plane_state->base.rotation;
        int ret;
 
-       intel_fill_fb_ggtt_view(&plane_state->view, fb, rotation);
-       plane_state->color_plane[0].stride = intel_fb_pitch(fb, 0, rotation);
-       plane_state->color_plane[1].stride = intel_fb_pitch(fb, 1, rotation);
-
-       ret = intel_plane_check_stride(plane_state);
+       ret = intel_plane_compute_gtt(plane_state);
        if (ret)
                return ret;
 
        if (!plane_state->base.visible)
                return 0;
 
-       /* Rotate src coordinates to match rotated GTT view */
-       if (drm_rotation_90_or_270(rotation))
-               drm_rect_rotate(&plane_state->base.src,
-                               fb->width << 16, fb->height << 16,
-                               DRM_MODE_ROTATE_270);
-
        /*
         * Handle the AUX surface first since
         * the main surface setup depends on it.
@@ -3364,20 +3653,20 @@ int i9xx_check_plane_surface(struct intel_plane_state *plane_state)
 {
        struct drm_i915_private *dev_priv =
                to_i915(plane_state->base.plane->dev);
-       const struct drm_framebuffer *fb = plane_state->base.fb;
-       unsigned int rotation = plane_state->base.rotation;
-       int src_x = plane_state->base.src.x1 >> 16;
-       int src_y = plane_state->base.src.y1 >> 16;
+       int src_x, src_y;
        u32 offset;
        int ret;
 
-       intel_fill_fb_ggtt_view(&plane_state->view, fb, rotation);
-       plane_state->color_plane[0].stride = intel_fb_pitch(fb, 0, rotation);
-
-       ret = intel_plane_check_stride(plane_state);
+       ret = intel_plane_compute_gtt(plane_state);
        if (ret)
                return ret;
 
+       if (!plane_state->base.visible)
+               return 0;
+
+       src_x = plane_state->base.src.x1 >> 16;
+       src_y = plane_state->base.src.y1 >> 16;
+
        intel_add_fb_offsets(&src_x, &src_y, plane_state, 0);
 
        if (INTEL_GEN(dev_priv) >= 4)
@@ -3386,8 +3675,17 @@ int i9xx_check_plane_surface(struct intel_plane_state *plane_state)
        else
                offset = 0;
 
+       /*
+        * Put the final coordinates back so that the src
+        * coordinate checks will see the right values.
+        */
+       drm_rect_translate(&plane_state->base.src,
+                          (src_x << 16) - plane_state->base.src.x1,
+                          (src_y << 16) - plane_state->base.src.y1);
+
        /* HSW/BDW do this automagically in hardware */
        if (!IS_HASWELL(dev_priv) && !IS_BROADWELL(dev_priv)) {
+               unsigned int rotation = plane_state->base.rotation;
                int src_w = drm_rect_width(&plane_state->base.src) >> 16;
                int src_h = drm_rect_height(&plane_state->base.src) >> 16;
 
@@ -3424,6 +3722,10 @@ i9xx_plane_check(struct intel_crtc_state *crtc_state,
        if (ret)
                return ret;
 
+       ret = i9xx_check_plane_surface(plane_state);
+       if (ret)
+               return ret;
+
        if (!plane_state->base.visible)
                return 0;
 
@@ -3431,10 +3733,6 @@ i9xx_plane_check(struct intel_crtc_state *crtc_state,
        if (ret)
                return ret;
 
-       ret = i9xx_check_plane_surface(plane_state);
-       if (ret)
-               return ret;
-
        plane_state->ctl = i9xx_plane_ctl(crtc_state, plane_state);
 
        return 0;
@@ -3573,15 +3871,6 @@ static bool i9xx_plane_get_hw_state(struct intel_plane *plane,
        return ret;
 }
 
-static u32
-intel_fb_stride_alignment(const struct drm_framebuffer *fb, int color_plane)
-{
-       if (fb->modifier == DRM_FORMAT_MOD_LINEAR)
-               return 64;
-       else
-               return intel_tile_width_bytes(fb, color_plane);
-}
-
 static void skl_detach_scaler(struct intel_crtc *intel_crtc, int id)
 {
        struct drm_device *dev = intel_crtc->base.dev;
@@ -6363,7 +6652,7 @@ static u64 get_crtc_power_domains(struct drm_crtc *crtc,
                mask |= BIT_ULL(POWER_DOMAIN_AUDIO);
 
        if (crtc_state->shared_dpll)
-               mask |= BIT_ULL(POWER_DOMAIN_PLLS);
+               mask |= BIT_ULL(POWER_DOMAIN_DISPLAY_CORE);
 
        return mask;
 }
@@ -6946,7 +7235,7 @@ static u32 ilk_pipe_pixel_rate(const struct intel_crtc_state *pipe_config)
                if (WARN_ON(!pfit_w || !pfit_h))
                        return pixel_rate;
 
-               pixel_rate = div_u64((u64)pixel_rate * pipe_w * pipe_h,
+               pixel_rate = div_u64(mul_u32_u32(pixel_rate, pipe_w * pipe_h),
                                     pfit_w * pfit_h);
        }
 
@@ -7066,7 +7355,7 @@ static void compute_m_n(unsigned int m, unsigned int n,
        else
                *ret_n = min_t(unsigned int, roundup_pow_of_two(n), DATA_LINK_N_MAX);
 
-       *ret_m = div_u64((u64)m * *ret_n, n);
+       *ret_m = div_u64(mul_u32_u32(m, *ret_n), n);
        intel_reduce_m_n_ratio(ret_m, ret_n);
 }
 
@@ -7750,9 +8039,14 @@ static void intel_get_pipe_timings(struct intel_crtc *crtc,
        tmp = I915_READ(HTOTAL(cpu_transcoder));
        pipe_config->base.adjusted_mode.crtc_hdisplay = (tmp & 0xffff) + 1;
        pipe_config->base.adjusted_mode.crtc_htotal = ((tmp >> 16) & 0xffff) + 1;
-       tmp = I915_READ(HBLANK(cpu_transcoder));
-       pipe_config->base.adjusted_mode.crtc_hblank_start = (tmp & 0xffff) + 1;
-       pipe_config->base.adjusted_mode.crtc_hblank_end = ((tmp >> 16) & 0xffff) + 1;
+
+       if (!transcoder_is_dsi(cpu_transcoder)) {
+               tmp = I915_READ(HBLANK(cpu_transcoder));
+               pipe_config->base.adjusted_mode.crtc_hblank_start =
+                                                       (tmp & 0xffff) + 1;
+               pipe_config->base.adjusted_mode.crtc_hblank_end =
+                                               ((tmp >> 16) & 0xffff) + 1;
+       }
        tmp = I915_READ(HSYNC(cpu_transcoder));
        pipe_config->base.adjusted_mode.crtc_hsync_start = (tmp & 0xffff) + 1;
        pipe_config->base.adjusted_mode.crtc_hsync_end = ((tmp >> 16) & 0xffff) + 1;
@@ -7760,9 +8054,14 @@ static void intel_get_pipe_timings(struct intel_crtc *crtc,
        tmp = I915_READ(VTOTAL(cpu_transcoder));
        pipe_config->base.adjusted_mode.crtc_vdisplay = (tmp & 0xffff) + 1;
        pipe_config->base.adjusted_mode.crtc_vtotal = ((tmp >> 16) & 0xffff) + 1;
-       tmp = I915_READ(VBLANK(cpu_transcoder));
-       pipe_config->base.adjusted_mode.crtc_vblank_start = (tmp & 0xffff) + 1;
-       pipe_config->base.adjusted_mode.crtc_vblank_end = ((tmp >> 16) & 0xffff) + 1;
+
+       if (!transcoder_is_dsi(cpu_transcoder)) {
+               tmp = I915_READ(VBLANK(cpu_transcoder));
+               pipe_config->base.adjusted_mode.crtc_vblank_start =
+                                                       (tmp & 0xffff) + 1;
+               pipe_config->base.adjusted_mode.crtc_vblank_end =
+                                               ((tmp >> 16) & 0xffff) + 1;
+       }
        tmp = I915_READ(VSYNC(cpu_transcoder));
        pipe_config->base.adjusted_mode.crtc_vsync_start = (tmp & 0xffff) + 1;
        pipe_config->base.adjusted_mode.crtc_vsync_end = ((tmp >> 16) & 0xffff) + 1;
@@ -8725,7 +9024,7 @@ static void lpt_enable_clkout_dp(struct drm_i915_private *dev_priv,
 }
 
 /* Sequence to disable CLKOUT_DP */
-static void lpt_disable_clkout_dp(struct drm_i915_private *dev_priv)
+void lpt_disable_clkout_dp(struct drm_i915_private *dev_priv)
 {
        u32 reg, tmp;
 
@@ -8944,12 +9243,35 @@ static void bdw_set_pipemisc(const struct intel_crtc_state *crtc_state)
                        PIPEMISC_YUV420_MODE_FULL_BLEND;
 
        if (INTEL_GEN(dev_priv) >= 11 &&
-           (crtc_state->active_planes & ~icl_hdr_plane_mask()) == 0)
+           (crtc_state->active_planes & ~(icl_hdr_plane_mask() |
+                                          BIT(PLANE_CURSOR))) == 0)
                val |= PIPEMISC_HDR_MODE_PRECISION;
 
        I915_WRITE(PIPEMISC(crtc->pipe), val);
 }
 
+int bdw_get_pipemisc_bpp(struct intel_crtc *crtc)
+{
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       u32 tmp;
+
+       tmp = I915_READ(PIPEMISC(crtc->pipe));
+
+       switch (tmp & PIPEMISC_DITHER_BPC_MASK) {
+       case PIPEMISC_DITHER_6_BPC:
+               return 18;
+       case PIPEMISC_DITHER_8_BPC:
+               return 24;
+       case PIPEMISC_DITHER_10_BPC:
+               return 30;
+       case PIPEMISC_DITHER_12_BPC:
+               return 36;
+       default:
+               MISSING_CASE(tmp);
+               return 0;
+       }
+}
+
 int ironlake_get_lanes_required(int target_clock, int link_bw, int bpp)
 {
        /*
@@ -9481,226 +9803,6 @@ out:
 
        return ret;
 }
-
-static void assert_can_disable_lcpll(struct drm_i915_private *dev_priv)
-{
-       struct drm_device *dev = &dev_priv->drm;
-       struct intel_crtc *crtc;
-
-       for_each_intel_crtc(dev, crtc)
-               I915_STATE_WARN(crtc->active, "CRTC for pipe %c enabled\n",
-                    pipe_name(crtc->pipe));
-
-       I915_STATE_WARN(I915_READ(HSW_PWR_WELL_CTL2),
-                       "Display power well on\n");
-       I915_STATE_WARN(I915_READ(SPLL_CTL) & SPLL_PLL_ENABLE, "SPLL enabled\n");
-       I915_STATE_WARN(I915_READ(WRPLL_CTL(0)) & WRPLL_PLL_ENABLE, "WRPLL1 enabled\n");
-       I915_STATE_WARN(I915_READ(WRPLL_CTL(1)) & WRPLL_PLL_ENABLE, "WRPLL2 enabled\n");
-       I915_STATE_WARN(I915_READ(PP_STATUS(0)) & PP_ON, "Panel power on\n");
-       I915_STATE_WARN(I915_READ(BLC_PWM_CPU_CTL2) & BLM_PWM_ENABLE,
-            "CPU PWM1 enabled\n");
-       if (IS_HASWELL(dev_priv))
-               I915_STATE_WARN(I915_READ(HSW_BLC_PWM2_CTL) & BLM_PWM_ENABLE,
-                    "CPU PWM2 enabled\n");
-       I915_STATE_WARN(I915_READ(BLC_PWM_PCH_CTL1) & BLM_PCH_PWM_ENABLE,
-            "PCH PWM1 enabled\n");
-       I915_STATE_WARN(I915_READ(UTIL_PIN_CTL) & UTIL_PIN_ENABLE,
-            "Utility pin enabled\n");
-       I915_STATE_WARN(I915_READ(PCH_GTC_CTL) & PCH_GTC_ENABLE, "PCH GTC enabled\n");
-
-       /*
-        * In theory we can still leave IRQs enabled, as long as only the HPD
-        * interrupts remain enabled. We used to check for that, but since it's
-        * gen-specific and since we only disable LCPLL after we fully disable
-        * the interrupts, the check below should be enough.
-        */
-       I915_STATE_WARN(intel_irqs_enabled(dev_priv), "IRQs enabled\n");
-}
-
-static u32 hsw_read_dcomp(struct drm_i915_private *dev_priv)
-{
-       if (IS_HASWELL(dev_priv))
-               return I915_READ(D_COMP_HSW);
-       else
-               return I915_READ(D_COMP_BDW);
-}
-
-static void hsw_write_dcomp(struct drm_i915_private *dev_priv, u32 val)
-{
-       if (IS_HASWELL(dev_priv)) {
-               if (sandybridge_pcode_write(dev_priv, GEN6_PCODE_WRITE_D_COMP,
-                                           val))
-                       DRM_DEBUG_KMS("Failed to write to D_COMP\n");
-       } else {
-               I915_WRITE(D_COMP_BDW, val);
-               POSTING_READ(D_COMP_BDW);
-       }
-}
-
-/*
- * This function implements pieces of two sequences from BSpec:
- * - Sequence for display software to disable LCPLL
- * - Sequence for display software to allow package C8+
- * The steps implemented here are just the steps that actually touch the LCPLL
- * register. Callers should take care of disabling all the display engine
- * functions, doing the mode unset, fixing interrupts, etc.
- */
-static void hsw_disable_lcpll(struct drm_i915_private *dev_priv,
-                             bool switch_to_fclk, bool allow_power_down)
-{
-       u32 val;
-
-       assert_can_disable_lcpll(dev_priv);
-
-       val = I915_READ(LCPLL_CTL);
-
-       if (switch_to_fclk) {
-               val |= LCPLL_CD_SOURCE_FCLK;
-               I915_WRITE(LCPLL_CTL, val);
-
-               if (wait_for_us(I915_READ(LCPLL_CTL) &
-                               LCPLL_CD_SOURCE_FCLK_DONE, 1))
-                       DRM_ERROR("Switching to FCLK failed\n");
-
-               val = I915_READ(LCPLL_CTL);
-       }
-
-       val |= LCPLL_PLL_DISABLE;
-       I915_WRITE(LCPLL_CTL, val);
-       POSTING_READ(LCPLL_CTL);
-
-       if (intel_wait_for_register(&dev_priv->uncore,
-                                   LCPLL_CTL, LCPLL_PLL_LOCK, 0, 1))
-               DRM_ERROR("LCPLL still locked\n");
-
-       val = hsw_read_dcomp(dev_priv);
-       val |= D_COMP_COMP_DISABLE;
-       hsw_write_dcomp(dev_priv, val);
-       ndelay(100);
-
-       if (wait_for((hsw_read_dcomp(dev_priv) & D_COMP_RCOMP_IN_PROGRESS) == 0,
-                    1))
-               DRM_ERROR("D_COMP RCOMP still in progress\n");
-
-       if (allow_power_down) {
-               val = I915_READ(LCPLL_CTL);
-               val |= LCPLL_POWER_DOWN_ALLOW;
-               I915_WRITE(LCPLL_CTL, val);
-               POSTING_READ(LCPLL_CTL);
-       }
-}
-
-/*
- * Fully restores LCPLL, disallowing power down and switching back to LCPLL
- * source.
- */
-static void hsw_restore_lcpll(struct drm_i915_private *dev_priv)
-{
-       u32 val;
-
-       val = I915_READ(LCPLL_CTL);
-
-       if ((val & (LCPLL_PLL_LOCK | LCPLL_PLL_DISABLE | LCPLL_CD_SOURCE_FCLK |
-                   LCPLL_POWER_DOWN_ALLOW)) == LCPLL_PLL_LOCK)
-               return;
-
-       /*
-        * Make sure we're not on PC8 state before disabling PC8, otherwise
-        * we'll hang the machine. To prevent PC8 state, just enable force_wake.
-        */
-       intel_uncore_forcewake_get(&dev_priv->uncore, FORCEWAKE_ALL);
-
-       if (val & LCPLL_POWER_DOWN_ALLOW) {
-               val &= ~LCPLL_POWER_DOWN_ALLOW;
-               I915_WRITE(LCPLL_CTL, val);
-               POSTING_READ(LCPLL_CTL);
-       }
-
-       val = hsw_read_dcomp(dev_priv);
-       val |= D_COMP_COMP_FORCE;
-       val &= ~D_COMP_COMP_DISABLE;
-       hsw_write_dcomp(dev_priv, val);
-
-       val = I915_READ(LCPLL_CTL);
-       val &= ~LCPLL_PLL_DISABLE;
-       I915_WRITE(LCPLL_CTL, val);
-
-       if (intel_wait_for_register(&dev_priv->uncore,
-                                   LCPLL_CTL, LCPLL_PLL_LOCK, LCPLL_PLL_LOCK,
-                                   5))
-               DRM_ERROR("LCPLL not locked yet\n");
-
-       if (val & LCPLL_CD_SOURCE_FCLK) {
-               val = I915_READ(LCPLL_CTL);
-               val &= ~LCPLL_CD_SOURCE_FCLK;
-               I915_WRITE(LCPLL_CTL, val);
-
-               if (wait_for_us((I915_READ(LCPLL_CTL) &
-                                LCPLL_CD_SOURCE_FCLK_DONE) == 0, 1))
-                       DRM_ERROR("Switching back to LCPLL failed\n");
-       }
-
-       intel_uncore_forcewake_put(&dev_priv->uncore, FORCEWAKE_ALL);
-
-       intel_update_cdclk(dev_priv);
-       intel_dump_cdclk_state(&dev_priv->cdclk.hw, "Current CDCLK");
-}
-
-/*
- * Package states C8 and deeper are really deep PC states that can only be
- * reached when all the devices on the system allow it, so even if the graphics
- * device allows PC8+, it doesn't mean the system will actually get to these
- * states. Our driver only allows PC8+ when going into runtime PM.
- *
- * The requirements for PC8+ are that all the outputs are disabled, the power
- * well is disabled and most interrupts are disabled, and these are also
- * requirements for runtime PM. When these conditions are met, we manually do
- * the other conditions: disable the interrupts, clocks and switch LCPLL refclk
- * to Fclk. If we're in PC8+ and we get an non-hotplug interrupt, we can hard
- * hang the machine.
- *
- * When we really reach PC8 or deeper states (not just when we allow it) we lose
- * the state of some registers, so when we come back from PC8+ we need to
- * restore this state. We don't get into PC8+ if we're not in RC6, so we don't
- * need to take care of the registers kept by RC6. Notice that this happens even
- * if we don't put the device in PCI D3 state (which is what currently happens
- * because of the runtime PM support).
- *
- * For more, read "Display Sequences for Package C8" on the hardware
- * documentation.
- */
-void hsw_enable_pc8(struct drm_i915_private *dev_priv)
-{
-       u32 val;
-
-       DRM_DEBUG_KMS("Enabling package C8+\n");
-
-       if (HAS_PCH_LPT_LP(dev_priv)) {
-               val = I915_READ(SOUTH_DSPCLK_GATE_D);
-               val &= ~PCH_LP_PARTITION_LEVEL_DISABLE;
-               I915_WRITE(SOUTH_DSPCLK_GATE_D, val);
-       }
-
-       lpt_disable_clkout_dp(dev_priv);
-       hsw_disable_lcpll(dev_priv, true, true);
-}
-
-void hsw_disable_pc8(struct drm_i915_private *dev_priv)
-{
-       u32 val;
-
-       DRM_DEBUG_KMS("Disabling package C8+\n");
-
-       hsw_restore_lcpll(dev_priv);
-       lpt_init_pch_refclk(dev_priv);
-
-       if (HAS_PCH_LPT_LP(dev_priv)) {
-               val = I915_READ(SOUTH_DSPCLK_GATE_D);
-               val |= PCH_LP_PARTITION_LEVEL_DISABLE;
-               I915_WRITE(SOUTH_DSPCLK_GATE_D, val);
-       }
-}
-
 static int haswell_crtc_compute_clock(struct intel_crtc *crtc,
                                      struct intel_crtc_state *crtc_state)
 {
@@ -9871,6 +9973,7 @@ static bool hsw_get_transcoder_state(struct intel_crtc *crtc,
        for_each_set_bit(panel_transcoder,
                         &panel_transcoder_mask,
                         ARRAY_SIZE(INTEL_INFO(dev_priv)->trans_offsets)) {
+               bool force_thru = false;
                enum pipe trans_pipe;
 
                tmp = I915_READ(TRANS_DDI_FUNC_CTL(panel_transcoder));
@@ -9892,6 +9995,8 @@ static bool hsw_get_transcoder_state(struct intel_crtc *crtc,
                             transcoder_name(panel_transcoder));
                        /* fall through */
                case TRANS_DDI_EDP_INPUT_A_ONOFF:
+                       force_thru = true;
+                       /* fall through */
                case TRANS_DDI_EDP_INPUT_A_ON:
                        trans_pipe = PIPE_A;
                        break;
@@ -9903,8 +10008,10 @@ static bool hsw_get_transcoder_state(struct intel_crtc *crtc,
                        break;
                }
 
-               if (trans_pipe == crtc->pipe)
+               if (trans_pipe == crtc->pipe) {
                        pipe_config->cpu_transcoder = panel_transcoder;
+                       pipe_config->pch_pfit.force_thru = force_thru;
+               }
        }
 
        /*
@@ -10189,19 +10296,17 @@ static bool intel_cursor_size_ok(const struct intel_plane_state *plane_state)
 
 static int intel_cursor_check_surface(struct intel_plane_state *plane_state)
 {
-       const struct drm_framebuffer *fb = plane_state->base.fb;
-       unsigned int rotation = plane_state->base.rotation;
        int src_x, src_y;
        u32 offset;
        int ret;
 
-       intel_fill_fb_ggtt_view(&plane_state->view, fb, rotation);
-       plane_state->color_plane[0].stride = intel_fb_pitch(fb, 0, rotation);
-
-       ret = intel_plane_check_stride(plane_state);
+       ret = intel_plane_compute_gtt(plane_state);
        if (ret)
                return ret;
 
+       if (!plane_state->base.visible)
+               return 0;
+
        src_x = plane_state->base.src_x >> 16;
        src_y = plane_state->base.src_y >> 16;
 
@@ -10238,6 +10343,10 @@ static int intel_check_cursor(struct intel_crtc_state *crtc_state,
        if (ret)
                return ret;
 
+       ret = intel_cursor_check_surface(plane_state);
+       if (ret)
+               return ret;
+
        if (!plane_state->base.visible)
                return 0;
 
@@ -10245,10 +10354,6 @@ static int intel_check_cursor(struct intel_crtc_state *crtc_state,
        if (ret)
                return ret;
 
-       ret = intel_cursor_check_surface(plane_state);
-       if (ret)
-               return ret;
-
        return 0;
 }
 
@@ -11739,10 +11844,11 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc,
                              pipe_config->gmch_pfit.pgm_ratios,
                              pipe_config->gmch_pfit.lvds_border_bits);
        else
-               DRM_DEBUG_KMS("pch pfit: pos: 0x%08x, size: 0x%08x, %s\n",
+               DRM_DEBUG_KMS("pch pfit: pos: 0x%08x, size: 0x%08x, %s, force thru: %s\n",
                              pipe_config->pch_pfit.pos,
                              pipe_config->pch_pfit.size,
-                             enableddisabled(pipe_config->pch_pfit.enabled));
+                             enableddisabled(pipe_config->pch_pfit.enabled),
+                             yesno(pipe_config->pch_pfit.force_thru));
 
        DRM_DEBUG_KMS("ips: %i, double wide: %i\n",
                      pipe_config->ips_enabled, pipe_config->double_wide);
@@ -11864,7 +11970,6 @@ clear_intel_crtc_state(struct intel_crtc_state *crtc_state)
        saved_state->scaler_state = crtc_state->scaler_state;
        saved_state->shared_dpll = crtc_state->shared_dpll;
        saved_state->dpll_hw_state = crtc_state->dpll_hw_state;
-       saved_state->pch_pfit.force_thru = crtc_state->pch_pfit.force_thru;
        saved_state->crc_enabled = crtc_state->crc_enabled;
        if (IS_G4X(dev_priv) ||
            IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
@@ -12377,6 +12482,12 @@ intel_pipe_config_compare(struct drm_i915_private *dev_priv,
                PIPE_CONF_CHECK_X(gmch_pfit.pgm_ratios);
        PIPE_CONF_CHECK_X(gmch_pfit.lvds_border_bits);
 
+       /*
+        * Changing the EDP transcoder input mux
+        * (A_ONOFF vs. A_ON) requires a full modeset.
+        */
+       PIPE_CONF_CHECK_BOOL(pch_pfit.force_thru);
+
        if (!adjust) {
                PIPE_CONF_CHECK_I(pipe_src_w);
                PIPE_CONF_CHECK_I(pipe_src_h);
@@ -15128,31 +15239,13 @@ static const struct drm_framebuffer_funcs intel_fb_funcs = {
        .dirty = intel_user_framebuffer_dirty,
 };
 
-static
-u32 intel_fb_pitch_limit(struct drm_i915_private *dev_priv,
-                        u32 pixel_format, u64 fb_modifier)
-{
-       struct intel_crtc *crtc;
-       struct intel_plane *plane;
-
-       /*
-        * We assume the primary plane for pipe A has
-        * the highest stride limits of them all.
-        */
-       crtc = intel_get_crtc_for_pipe(dev_priv, PIPE_A);
-       plane = to_intel_plane(crtc->base.primary);
-
-       return plane->max_stride(plane, pixel_format, fb_modifier,
-                                DRM_MODE_ROTATE_0);
-}
-
 static int intel_framebuffer_init(struct intel_framebuffer *intel_fb,
                                  struct drm_i915_gem_object *obj,
                                  struct drm_mode_fb_cmd2 *mode_cmd)
 {
        struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
        struct drm_framebuffer *fb = &intel_fb->base;
-       u32 pitch_limit;
+       u32 max_stride;
        unsigned int tiling, stride;
        int ret = -EINVAL;
        int i;
@@ -15204,13 +15297,13 @@ static int intel_framebuffer_init(struct intel_framebuffer *intel_fb,
                goto err;
        }
 
-       pitch_limit = intel_fb_pitch_limit(dev_priv, mode_cmd->pixel_format,
-                                          mode_cmd->modifier[0]);
-       if (mode_cmd->pitches[0] > pitch_limit) {
+       max_stride = intel_fb_max_stride(dev_priv, mode_cmd->pixel_format,
+                                        mode_cmd->modifier[0]);
+       if (mode_cmd->pitches[0] > max_stride) {
                DRM_DEBUG_KMS("%s pitch (%u) must be at most %d\n",
                              mode_cmd->modifier[0] != DRM_FORMAT_MOD_LINEAR ?
                              "tiled" : "linear",
-                             mode_cmd->pitches[0], pitch_limit);
+                             mode_cmd->pitches[0], max_stride);
                goto err;
        }
 
@@ -15734,16 +15827,22 @@ int intel_modeset_init(struct drm_device *dev)
                }
        }
 
-       /* maximum framebuffer dimensions */
-       if (IS_GEN(dev_priv, 2)) {
-               dev->mode_config.max_width = 2048;
-               dev->mode_config.max_height = 2048;
+       /*
+        * Maximum framebuffer dimensions, chosen to match
+        * the maximum render engine surface size on gen4+.
+        */
+       if (INTEL_GEN(dev_priv) >= 7) {
+               dev->mode_config.max_width = 16384;
+               dev->mode_config.max_height = 16384;
+       } else if (INTEL_GEN(dev_priv) >= 4) {
+               dev->mode_config.max_width = 8192;
+               dev->mode_config.max_height = 8192;
        } else if (IS_GEN(dev_priv, 3)) {
                dev->mode_config.max_width = 4096;
                dev->mode_config.max_height = 4096;
        } else {
-               dev->mode_config.max_width = 8192;
-               dev->mode_config.max_height = 8192;
+               dev->mode_config.max_width = 2048;
+               dev->mode_config.max_height = 2048;
        }
 
        if (IS_I845G(dev_priv) || IS_I865G(dev_priv)) {