From b321803dfbe46faeb54e8e758148be40e628225e Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Fri, 27 Feb 2015 11:15:18 +0000 Subject: [PATCH] drm/i915/skl: Allow scanning out Y and Yf fbs MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Skylake is able to scannout those tiling formats. We need to allow them in the ADDFB ioctl and tell the harware about it. v2: Rebased for addfb2 interface. (Tvrtko Ursulin) v3: Rebased for fb modifier changes. (Tvrtko Ursulin) v4: Don't allow Y tiled fbs just yet. (Tvrtko Ursulin) v5: Check for stride alignment and max pitch. (Tvrtko Ursulin) v6: Simplify maximum pitch check. (Ville Syrjälä) v7: Drop the gen9 check since requirements are no different. (Ville Syrjälä) v8: Gen2 has different X tiling stride. (Ville Syrjälä) Signed-off-by: Damien Lespiau Signed-off-by: Tvrtko Ursulin Reviewed-by: Damien Lespiau (v7) Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 121 +++++++++++++++++++-------- drivers/gpu/drm/i915/intel_drv.h | 2 + drivers/gpu/drm/i915/intel_sprite.c | 18 ++-- 3 files changed, 101 insertions(+), 40 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ca6a24064cab..8076bce85160 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2728,6 +2728,40 @@ static void ironlake_update_primary_plane(struct drm_crtc *crtc, POSTING_READ(reg); } +u32 intel_fb_stride_alignment(struct drm_device *dev, uint64_t fb_modifier, + uint32_t pixel_format) +{ + u32 bits_per_pixel = drm_format_plane_cpp(pixel_format, 0) * 8; + + /* + * The stride is either expressed as a multiple of 64 bytes + * chunks for linear buffers or in number of tiles for tiled + * buffers. + */ + switch (fb_modifier) { + case DRM_FORMAT_MOD_NONE: + return 64; + case I915_FORMAT_MOD_X_TILED: + if (INTEL_INFO(dev)->gen == 2) + return 128; + return 512; + case I915_FORMAT_MOD_Y_TILED: + /* No need to check for old gens and Y tiling since this is + * about the display engine and those will be blocked before + * we get here. + */ + return 128; + case I915_FORMAT_MOD_Yf_TILED: + if (bits_per_pixel == 8) + return 64; + else + return 128; + default: + MISSING_CASE(fb_modifier); + return 64; + } +} + static void skylake_update_primary_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb, int x, int y) @@ -2735,10 +2769,9 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc, struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct intel_framebuffer *intel_fb; struct drm_i915_gem_object *obj; int pipe = intel_crtc->pipe; - u32 plane_ctl, stride; + u32 plane_ctl, stride_div; if (!intel_crtc->primary_enabled) { I915_WRITE(PLANE_CTL(pipe, 0), 0); @@ -2773,29 +2806,30 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc, BUG(); } - intel_fb = to_intel_framebuffer(fb); - obj = intel_fb->obj; - - /* - * The stride is either expressed as a multiple of 64 bytes chunks for - * linear buffers or in number of tiles for tiled buffers. - */ switch (fb->modifier[0]) { case DRM_FORMAT_MOD_NONE: - stride = fb->pitches[0] >> 6; break; case I915_FORMAT_MOD_X_TILED: plane_ctl |= PLANE_CTL_TILED_X; - stride = fb->pitches[0] >> 9; + break; + case I915_FORMAT_MOD_Y_TILED: + plane_ctl |= PLANE_CTL_TILED_Y; + break; + case I915_FORMAT_MOD_Yf_TILED: + plane_ctl |= PLANE_CTL_TILED_YF; break; default: - BUG(); + MISSING_CASE(fb->modifier[0]); } plane_ctl |= PLANE_CTL_PLANE_GAMMA_DISABLE; if (crtc->primary->state->rotation == BIT(DRM_ROTATE_180)) plane_ctl |= PLANE_CTL_ROTATE_180; + obj = intel_fb_obj(fb); + stride_div = intel_fb_stride_alignment(dev, fb->modifier[0], + fb->pixel_format); + I915_WRITE(PLANE_CTL(pipe, 0), plane_ctl); DRM_DEBUG_KMS("Writing base %08lX %d,%d,%d,%d pitch=%d\n", @@ -2808,7 +2842,7 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc, I915_WRITE(PLANE_SIZE(pipe, 0), (intel_crtc->config->pipe_src_h - 1) << 16 | (intel_crtc->config->pipe_src_w - 1)); - I915_WRITE(PLANE_STRIDE(pipe, 0), stride); + I915_WRITE(PLANE_STRIDE(pipe, 0), fb->pitches[0] / stride_div); I915_WRITE(PLANE_SURF(pipe, 0), i915_gem_obj_ggtt_offset(obj)); POSTING_READ(PLANE_SURF(pipe, 0)); @@ -12666,14 +12700,43 @@ static const struct drm_framebuffer_funcs intel_fb_funcs = { .create_handle = intel_user_framebuffer_create_handle, }; +static +u32 intel_fb_pitch_limit(struct drm_device *dev, uint64_t fb_modifier, + uint32_t pixel_format) +{ + u32 gen = INTEL_INFO(dev)->gen; + + if (gen >= 9) { + /* "The stride in bytes must not exceed the of the size of 8K + * pixels and 32K bytes." + */ + return min(8192*drm_format_plane_cpp(pixel_format, 0), 32768); + } else if (gen >= 5 && !IS_VALLEYVIEW(dev)) { + return 32*1024; + } else if (gen >= 4) { + if (fb_modifier == I915_FORMAT_MOD_X_TILED) + return 16*1024; + else + return 32*1024; + } else if (gen >= 3) { + if (fb_modifier == I915_FORMAT_MOD_X_TILED) + return 8*1024; + else + return 16*1024; + } else { + /* XXX DSPC is limited to 4k tiled */ + return 8*1024; + } +} + static int intel_framebuffer_init(struct drm_device *dev, struct intel_framebuffer *intel_fb, struct drm_mode_fb_cmd2 *mode_cmd, struct drm_i915_gem_object *obj) { int aligned_height; - int pitch_limit; int ret; + u32 pitch_limit, stride_alignment; WARN_ON(!mutex_is_locked(&dev->struct_mutex)); @@ -12699,31 +12762,19 @@ static int intel_framebuffer_init(struct drm_device *dev, return -EINVAL; } - if (mode_cmd->pitches[0] & 63) { - DRM_DEBUG("pitch (%d) must be at least 64 byte aligned\n", - mode_cmd->pitches[0]); + stride_alignment = intel_fb_stride_alignment(dev, mode_cmd->modifier[0], + mode_cmd->pixel_format); + if (mode_cmd->pitches[0] & (stride_alignment - 1)) { + DRM_DEBUG("pitch (%d) must be at least %u byte aligned\n", + mode_cmd->pitches[0], stride_alignment); return -EINVAL; } - if (INTEL_INFO(dev)->gen >= 5 && !IS_VALLEYVIEW(dev)) { - pitch_limit = 32*1024; - } else if (INTEL_INFO(dev)->gen >= 4) { - if (mode_cmd->modifier[0] == I915_FORMAT_MOD_X_TILED) - pitch_limit = 16*1024; - else - pitch_limit = 32*1024; - } else if (INTEL_INFO(dev)->gen >= 3) { - if (mode_cmd->modifier[0] == I915_FORMAT_MOD_X_TILED) - pitch_limit = 8*1024; - else - pitch_limit = 16*1024; - } else - /* XXX DSPC is limited to 4k tiled */ - pitch_limit = 8*1024; - + pitch_limit = intel_fb_pitch_limit(dev, mode_cmd->modifier[0], + mode_cmd->pixel_format); if (mode_cmd->pitches[0] > pitch_limit) { - DRM_DEBUG("%s pitch (%d) must be at less than %d\n", - mode_cmd->modifier[0] == I915_FORMAT_MOD_X_TILED ? + DRM_DEBUG("%s pitch (%u) must be at less than %d\n", + mode_cmd->modifier[0] != DRM_FORMAT_MOD_NONE ? "tiled" : "linear", mode_cmd->pitches[0], pitch_limit); return -EINVAL; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 1fb15298cfba..76df9d6fc205 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -903,6 +903,8 @@ int intel_fb_align_height(struct drm_device *dev, int height, uint64_t fb_format_modifier); void intel_fb_obj_flush(struct drm_i915_gem_object *obj, bool retire); +u32 intel_fb_stride_alignment(struct drm_device *dev, uint64_t fb_modifier, + uint32_t pixel_format); /* intel_audio.c */ void intel_init_audio(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index f0b06c09da40..bdb64fc14655 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -189,7 +189,7 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc, struct intel_plane *intel_plane = to_intel_plane(drm_plane); const int pipe = intel_plane->pipe; const int plane = intel_plane->plane + 1; - u32 plane_ctl, stride; + u32 plane_ctl, stride_div; int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); plane_ctl = I915_READ(PLANE_CTL(pipe, plane)); @@ -247,15 +247,20 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc, switch (fb->modifier[0]) { case DRM_FORMAT_MOD_NONE: - stride = fb->pitches[0] >> 6; break; case I915_FORMAT_MOD_X_TILED: plane_ctl |= PLANE_CTL_TILED_X; - stride = fb->pitches[0] >> 9; + break; + case I915_FORMAT_MOD_Y_TILED: + plane_ctl |= PLANE_CTL_TILED_Y; + break; + case I915_FORMAT_MOD_Yf_TILED: + plane_ctl |= PLANE_CTL_TILED_YF; break; default: - BUG(); + MISSING_CASE(fb->modifier[0]); } + if (drm_plane->state->rotation == BIT(DRM_ROTATE_180)) plane_ctl |= PLANE_CTL_ROTATE_180; @@ -266,6 +271,9 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc, pixel_size, true, src_w != crtc_w || src_h != crtc_h); + stride_div = intel_fb_stride_alignment(dev, fb->modifier[0], + fb->pixel_format); + /* Sizes are 0 based */ src_w--; src_h--; @@ -273,7 +281,7 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc, crtc_h--; I915_WRITE(PLANE_OFFSET(pipe, plane), (y << 16) | x); - I915_WRITE(PLANE_STRIDE(pipe, plane), stride); + I915_WRITE(PLANE_STRIDE(pipe, plane), fb->pitches[0] / stride_div); I915_WRITE(PLANE_POS(pipe, plane), (crtc_y << 16) | crtc_x); I915_WRITE(PLANE_SIZE(pipe, plane), (crtc_h << 16) | crtc_w); I915_WRITE(PLANE_CTL(pipe, plane), plane_ctl); -- 2.34.1