drm/i915: Add support for half float framebuffers for gen4+ primary planes
authorVille Syrjälä <ville.syrjala@linux.intel.com>
Tue, 15 Oct 2019 19:30:30 +0000 (22:30 +0300)
committerVille Syrjälä <ville.syrjala@linux.intel.com>
Thu, 24 Oct 2019 18:22:25 +0000 (21:22 +0300)
gen4+ supports fp16 pixel formats on the primary planes. Add the
relevant code.

On ivb fp16 scanout is slightly busted. The output from the plane will
have 1/4 the expected value. For the primary plane we would have to
use the pipe gamma or pipe csc to correct that which would affect all
the other planes as well, hence we simply choose not to expose fp16
on the ivb primary plane. On hsw the primary plane got fixed.

On gmch platforms I observed that the plane width must be below 2k
pixels with fp16 or else we get a corrupted image. This limitation
does not seem to be documented in bspec. I verified the exact limit
using the chv pipe B primary plane since it has windowing capability.
The stride limits are unaffected by fp16.

v2: Rebase on top of icl fp16
    Split thea gen4+ primary plane bits into a separate patch
    Deal with HAS_GMCH()

Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20191015193035.25982-9-ville.syrjala@linux.intel.com
drivers/gpu/drm/i915/display/intel_display.c

index cd79d35de05e6e8327eba9963ecce2612ef1c7e8..6dc3c931edb1eb0d6a124c40a8562b98127d7300 100644 (file)
@@ -88,7 +88,17 @@ static const u32 i8xx_primary_formats[] = {
        DRM_FORMAT_XRGB8888,
 };
 
-/* Primary plane formats for gen >= 4 */
+/* Primary plane formats for ivb (no fp16 due to hw issue) */
+static const u32 ivb_primary_formats[] = {
+       DRM_FORMAT_C8,
+       DRM_FORMAT_RGB565,
+       DRM_FORMAT_XRGB8888,
+       DRM_FORMAT_XBGR8888,
+       DRM_FORMAT_XRGB2101010,
+       DRM_FORMAT_XBGR2101010,
+};
+
+/* Primary plane formats for gen >= 4, except ivb */
 static const u32 i965_primary_formats[] = {
        DRM_FORMAT_C8,
        DRM_FORMAT_RGB565,
@@ -96,6 +106,7 @@ static const u32 i965_primary_formats[] = {
        DRM_FORMAT_XBGR8888,
        DRM_FORMAT_XRGB2101010,
        DRM_FORMAT_XBGR2101010,
+       DRM_FORMAT_XBGR16161616F,
 };
 
 static const u64 i9xx_format_modifiers[] = {
@@ -2971,6 +2982,8 @@ static int i9xx_format_to_fourcc(int format)
                return DRM_FORMAT_XRGB2101010;
        case DISPPLANE_RGBX101010:
                return DRM_FORMAT_XBGR2101010;
+       case DISPPLANE_RGBX161616:
+               return DRM_FORMAT_XBGR16161616F;
        }
 }
 
@@ -3707,6 +3720,9 @@ static u32 i9xx_plane_ctl(const struct intel_crtc_state *crtc_state,
        case DRM_FORMAT_XBGR2101010:
                dspcntr |= DISPPLANE_RGBX101010;
                break;
+       case DRM_FORMAT_XBGR16161616F:
+               dspcntr |= DISPPLANE_RGBX161616;
+               break;
        default:
                MISSING_CASE(fb->format->format);
                return 0;
@@ -3729,7 +3745,8 @@ int i9xx_check_plane_surface(struct intel_plane_state *plane_state)
 {
        struct drm_i915_private *dev_priv =
                to_i915(plane_state->base.plane->dev);
-       int src_x, src_y;
+       const struct drm_framebuffer *fb = plane_state->base.fb;
+       int src_x, src_y, src_w;
        u32 offset;
        int ret;
 
@@ -3740,9 +3757,14 @@ int i9xx_check_plane_surface(struct intel_plane_state *plane_state)
        if (!plane_state->base.visible)
                return 0;
 
+       src_w = drm_rect_width(&plane_state->base.src) >> 16;
        src_x = plane_state->base.src.x1 >> 16;
        src_y = plane_state->base.src.y1 >> 16;
 
+       /* Undocumented hardware limit on i965/g4x/vlv/chv */
+       if (HAS_GMCH(dev_priv) && fb->format->cpp[0] == 8 && src_w > 2048)
+               return -EINVAL;
+
        intel_add_fb_offsets(&src_x, &src_y, plane_state, 0);
 
        if (INTEL_GEN(dev_priv) >= 4)
@@ -15202,6 +15224,7 @@ static bool i965_plane_format_mod_supported(struct drm_plane *_plane,
        case DRM_FORMAT_XBGR8888:
        case DRM_FORMAT_XRGB2101010:
        case DRM_FORMAT_XBGR2101010:
+       case DRM_FORMAT_XBGR16161616F:
                return modifier == DRM_FORMAT_MOD_LINEAR ||
                        modifier == I915_FORMAT_MOD_X_TILED;
        default:
@@ -15422,8 +15445,26 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
        }
 
        if (INTEL_GEN(dev_priv) >= 4) {
-               formats = i965_primary_formats;
-               num_formats = ARRAY_SIZE(i965_primary_formats);
+               /*
+                * WaFP16GammaEnabling:ivb
+                * "Workaround : When using the 64-bit format, the plane
+                *  output on each color channel has one quarter amplitude.
+                *  It can be brought up to full amplitude by using pipe
+                *  gamma correction or pipe color space conversion to
+                *  multiply the plane output by four."
+                *
+                * There is no dedicated plane gamma for the primary plane,
+                * and using the pipe gamma/csc could conflict with other
+                * planes, so we choose not to expose fp16 on IVB primary
+                * planes. HSW primary planes no longer have this problem.
+                */
+               if (IS_IVYBRIDGE(dev_priv)) {
+                       formats = ivb_primary_formats;
+                       num_formats = ARRAY_SIZE(ivb_primary_formats);
+               } else {
+                       formats = i965_primary_formats;
+                       num_formats = ARRAY_SIZE(i965_primary_formats);
+               }
                modifiers = i9xx_format_modifiers;
 
                plane->max_stride = i9xx_plane_max_stride;