[RFC] drm/i915: Render decompression support for Gen9 and above

Vandana Kannan
2015-09-04T19:16:35Z

This patch includes enabling render decompression after checking all the
requirements (format, tiling, rotation etc.). Along with this, the WAs
mentioned in BSpec Workaround page have been implemented.

This patch has been implemented on top of Nabendu/Chandra's NV12 patches.

TODO:
1. Disable stereo 3D when render decomp is enabled (bit 7:6)
2. Render decompression must not be used in VTd pass-through mode
3. Program hashing select CHICKEN_MISC1 bit 15
4. For Gen10, add support for RGB 1010102

Signed-off-by: Vandana Kannan <vandana.kannan@intel.com>
---
drivers/gpu/drm/drm_atomic.c | 4 +
drivers/gpu/drm/drm_crtc.c | 16 ++++
drivers/gpu/drm/i915/intel_display.c | 174 +++++++++++++++++++++++++++++++++++
drivers/gpu/drm/i915/intel_drv.h | 7 ++
drivers/gpu/drm/i915/intel_sprite.c | 35 +++++++
include/drm/drm_crtc.h | 11 +++
6 files changed, 247 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 940f80b..d9004e8 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -607,6 +607,8 @@ int drm_atomic_plane_set_property(struct drm_plane *plane,
state->src_h = val;
} else if (property == config->rotation_property) {
state->rotation = val;
+ } else if (property == config->compression_property) {
+ state->compression = val;
} else if (plane->funcs->atomic_set_property) {
return plane->funcs->atomic_set_property(plane, state,
property, val);
@@ -654,6 +656,8 @@ drm_atomic_plane_get_property(struct drm_plane *plane,
*val = state->src_h;
} else if (property == config->rotation_property) {
*val = state->rotation;
+ } else if (property == config->compression_property) {
+ *val = state->compression;
} else if (plane->funcs->atomic_get_property) {
return plane->funcs->atomic_get_property(plane, state, property, val);
} else {
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 474f328..66f817b 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -5778,6 +5778,22 @@ struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev,
}
EXPORT_SYMBOL(drm_mode_create_rotation_property);

+struct drm_property *drm_mode_create_compression_property(
+ struct drm_device *dev,
+ unsigned int comp_caps)
+{
+ static const struct drm_prop_enum_list props[] = {
+ { DRM_COMP_NONE, "Not compression capable" },
+ { DRM_COMP_RENDER, "Only render decompression" },
+ };
+
+ return drm_property_create_bitmask(dev, 0, "render compression",
+ props, ARRAY_SIZE(props),
+ comp_caps);
+}
+EXPORT_SYMBOL(drm_mode_create_compression_property);
+
+
/**
* DOC: Tile group
*
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 59d6736..115736f 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3120,8 +3120,47 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc,

hphase = 0x00010001; /* use trip for both Y and UV */
vphase = 0x00012000; /* use trip for Y and phase 0.5 for UV */
+
+ /*
+ * On SKL-C and BXT-A,
+ * when the plane source pixel format is NV12,
+ * the CHICKEN_PIPESL_* register bit 22 must be
+ * set to 1
+ */
+ if (IS_BROXTON(dev) || (IS_SKYLAKE(dev) &&
+ INTEL_REVID(dev) == SKL_REVID_C0))
+ I915_WRITE(CHICKEN_PIPESL_1(pipe),
+ I915_READ(CHICKEN_PIPESL_1(pipe)) |
+ HSW_FBCQ_DIS);
}
}
+
+ if (plane->state->compression) {
+ /*
+ * FIXME: Check if aux_dist ad aux_stride can be taken as it
+ * is from userspace.
+ */
+ aux_dist = fb->offsets[1];
+ aux_stride = fb->pitches[1];
+ /*
+ * For SKL and BXT,
+ * When the render compression is enabled with plane
+ * width greater than 3840 and horizontal panning,
+ * the stride programmed in the PLANE_STRIDE register
+ * must be multiple of 4.
+ */
+ if (x > 3840 && x_offset != 0)
+ stride = stride - (stride % 4);
+ if (IS_BROXTON(dev) || (IS_SKYLAKE(dev) &&
+ INTEL_REVID(dev) == SKL_REVID_C0))
+ I915_WRITE(CHICKEN_PIPESL_1(pipe),
+ I915_READ(CHICKEN_PIPESL_1(pipe)) &
+ ~HSW_FBCQ_DIS);
+ plane_ctl |= PLANE_CTL_DECOMPRESSION_ENABLE;
+ } else {
+ plane_ctl &= ~PLANE_CTL_DECOMPRESSION_ENABLE;
+ }
+
plane_offset = y_offset << 16 | x_offset;

I915_WRITE(PLANE_CTL(pipe, 0), plane_ctl);
@@ -11760,6 +11799,29 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
plane_state->rotation != BIT(DRM_ROTATE_0))
intel_crtc->atomic.disable_fbc = true;

+ if (INTEL_INFO(dev)->gen >= 9) {
+ if (plane_state->compression) {
+ ret = skl_check_compression(dev,
+ to_intel_plane(plane),
+ to_intel_plane_state(plane_state),
+ intel_crtc->pipe);
+ if (ret)
+ return ret;
+ }
+ }
+
+ /*
+ * Disable FBC if render decompression has to be enabled.
+ * FIXME: If FBC is disabled here because render decomp
+ * has to be enabled, then in update_primary_plane(), if
+ * render decomp is disabled for some reason, we need to
+ * enable FBC ?
+ */
+ if (IS_SKYLAKE(dev) && dev_priv->fbc.crtc == intel_crtc &&
+ plane_state->compression) {
+ intel_crtc->atomic.disable_fbc = true;
+ }
+
/*
* BDW signals flip done immediately if the plane
* is disabled, even if the plane enable is already
@@ -11778,6 +11840,16 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
intel_crtc->atomic.update_sprite_watermarks |=
1 << i;
}
+ if (INTEL_INFO(dev)->gen >= 9) {
+ if (plane_state->compression) {
+ ret = skl_check_compression(dev,
+ to_intel_plane(plane),
+ to_intel_plane_state(plane_state),
+ intel_crtc->pipe);
+ if (ret)
+ return ret;
+ }
+ }
}
return 0;
}
@@ -13495,6 +13567,88 @@ skl_max_scale(struct intel_crtc *intel_crtc,
return max_scale;
}

+int skl_check_compression(struct drm_device *dev,
+ struct intel_plane *intel_plane,
+ struct intel_plane_state *plane_state,
+ enum pipe pipe)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_rect *src = &plane_state->src;
+ struct drm_framebuffer *fb;
+ int i;
+
+ fb = intel_plane ? plane_state->base.fb : NULL;
+
+ /*
+ * TODO:
+ * 1. Disable stereo 3D when render decomp is enabled (bit 7:6)
+ * 2. Render decompression must not be used in VTd pass-through mode
+ * 3. Program hashing select CHICKEN_MISC1 bit 15
+ */
+
+ /*
+ * On SKL A and SKL B,
+ * Do not enable render decompression when the plane
+ * width is smaller than 32 pixels or greater than
+ * 2048 pixels
+ */
+ if ((IS_SKYLAKE(dev) && INTEL_REVID(dev) < SKL_REVID_C0)
+ && ((src->x1 >> 16) > 2048))
+ plane_state->base.compression = DRM_COMP_NONE;
+
+ if (!plane_state->base.compression)
+ return -EINVAL;
+
+ /*
+ * On SKL:*:C and BXT:*:A, there is a possible hang with NV12 format.
+ * WA: When the plane source pixel format is NV12,
+ * the CHICKEN_PIPESL_* register bit 22 must be set to 1 and the
+ * render decompression must not be enabled on any of the planes in
+ * that pipe.
+ */
+ if (IS_BROXTON(dev) || (IS_SKYLAKE(dev) &&
+ INTEL_REVID(dev) == SKL_REVID_C0)) {
+ struct drm_plane *drm_plane;
+ struct drm_plane_state *state;
+
+ for_each_plane(dev_priv, pipe, i) {
+ drm_plane = drm_plane_from_index(dev, i);
+ if (drm_plane) {
+ state = drm_plane->state;
+ if (state) {
+ if (state->fb &&
+ state->fb->pixel_format
+ == DRM_FORMAT_NV12) {
+ plane_state->base.compression =
+ DRM_COMP_NONE;
+ }
+ }
+ }
+ }
+ }
+
+ if (!plane_state->base.compression)
+ return -EINVAL;
+
+ /*
+ * Conditions to satisfy before enabling render decomp.
+ * SKL+
+ * Pipe A & B, Planes 1 & 2
+ * RGB8888 Tile-Y format
+ * 0/180 rotation
+ */
+ if ((pipe == PIPE_C) ||
+ ((fb->pixel_format != DRM_FORMAT_XRGB8888) &&
+ (fb->pixel_format != DRM_FORMAT_ARGB8888)) ||
+ intel_rotation_90_or_270(plane_state->base.rotation) ||
+ ((fb->modifier[0] == DRM_FORMAT_MOD_NONE) ||
+ (fb->modifier[0] == I915_FORMAT_MOD_X_TILED))) {
+ plane_state->base.compression = DRM_COMP_NONE;
+ return -EINVAL;
+ }
+ return 0;
+}
+
static int
intel_check_primary_plane(struct drm_plane *plane,
struct intel_crtc_state *crtc_state,
@@ -13670,11 +13824,31 @@ static struct drm_plane *intel_primary_plane_create(struct drm_device *dev,
if (INTEL_INFO(dev)->gen >= 4)
intel_create_rotation_property(dev, primary);

+ intel_create_compression_property(dev, primary);
+
drm_plane_helper_add(&primary->base, &intel_plane_helper_funcs);

return &primary->base;
}

+void intel_create_compression_property(struct drm_device *dev,
+ struct intel_plane *plane)
+{
+ /* Render compression is applicable only for plane 1 & 2 */
+ if (INTEL_INFO(dev)->gen >= 9 && (plane->plane <= 1)) {
+ if (!dev->mode_config.compression_property)
+ dev->mode_config.compression_property =
+ drm_mode_create_compression_property(dev,
+ BIT(DRM_COMP_NONE) |
+ BIT(DRM_COMP_RENDER));
+
+ if (dev->mode_config.compression_property)
+ drm_object_attach_property(&plane->base.base,
+ dev->mode_config.compression_property,
+ plane->base.state->compression);
+ }
+}
+
void intel_create_rotation_property(struct drm_device *dev, struct intel_plane *plane)
{
if (!dev->mode_config.rotation_property) {
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 6cd6cb0..bae22eb 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1090,6 +1090,13 @@ intel_rotation_90_or_270(unsigned int rotation)
void intel_create_rotation_property(struct drm_device *dev,
struct intel_plane *plane);

+void intel_create_compression_property(struct drm_device *dev,
+ struct intel_plane *plane);
+int skl_check_compression(struct drm_device *dev,
+ struct intel_plane *intel_plane,
+ struct intel_plane_state *plane_state,
+ enum pipe pipe);
+
/* shared dpll functions */
struct intel_shared_dpll *intel_crtc_to_shared_dpll(struct intel_crtc *crtc);
void assert_shared_dpll(struct drm_i915_private *dev_priv,
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index 2f9f856..c6cf4ad 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -275,8 +275,41 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc,

hphase = 0x00010001; /* use trip for both Y and UV */
vphase = 0x00012000; /* use trip for Y and phase 0.5 for UV */
+
+ if (IS_BROXTON(dev) || (IS_SKYLAKE(dev) &&
+ INTEL_REVID(dev) == SKL_REVID_C0))
+ I915_WRITE(CHICKEN_PIPESL_1(pipe),
+ I915_READ(CHICKEN_PIPESL_1(pipe)) |
+ HSW_FBCQ_DIS);
}
}
+
+ if (drm_plane->state->compression) {
+ /*
+ * FIXME: Check if aux_dist ad aux_stride can be taken as it
+ * is from userspace.
+ */
+ aux_dist = fb->offsets[1];
+ aux_stride = fb->pitches[1];
+ /*
+ * For SKL and BXT,
+ * When the render compression is enabled with plane
+ * width greater than 3840 and horizontal panning,
+ * the stride programmed in the PLANE_STRIDE register
+ * must be multiple of 4.
+ */
+ if (x > 3840 && x_offset != 0)
+ stride = stride - (stride % 4);
+ if (IS_BROXTON(dev) || (IS_SKYLAKE(dev) &&
+ INTEL_REVID(dev) == SKL_REVID_C0))
+ I915_WRITE(CHICKEN_PIPESL_1(pipe),
+ I915_READ(CHICKEN_PIPESL_1(pipe)) &
+ ~HSW_FBCQ_DIS);
+ plane_ctl |= PLANE_CTL_DECOMPRESSION_ENABLE;
+ } else {
+ plane_ctl &= ~PLANE_CTL_DECOMPRESSION_ENABLE;
+ }
+
plane_offset = y_offset << 16 | x_offset;

I915_WRITE(PLANE_OFFSET(pipe, plane), plane_offset);
@@ -1217,6 +1250,8 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane)

intel_create_rotation_property(dev, intel_plane);

+ intel_create_compression_property(dev, intel_plane);
+
drm_plane_helper_add(&intel_plane->base, &intel_plane_helper_funcs);

out:
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 75f49c1..02a9aaa 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -93,6 +93,10 @@ static inline uint64_t I642U64(int64_t val)
#define DRM_REFLECT_X 4
#define DRM_REFLECT_Y 5

+/* render compression property bits */
+#define DRM_COMP_NONE 0
+#define DRM_COMP_RENDER 1
+
enum drm_connector_force {
DRM_FORCE_UNSPECIFIED,
DRM_FORCE_OFF,
@@ -783,6 +787,9 @@ struct drm_plane_state {
/* Plane rotation */
unsigned int rotation;

+ /* Render compression */
+ unsigned int compression;
+
struct drm_atomic_state *state;
};

@@ -1114,6 +1121,7 @@ struct drm_mode_config {
struct drm_property *tile_property;
struct drm_property *plane_type_property;
struct drm_property *rotation_property;
+ struct drm_property *compression_property;
struct drm_property *prop_src_x;
struct drm_property *prop_src_y;
struct drm_property *prop_src_w;
@@ -1507,6 +1515,9 @@ extern int drm_format_vert_chroma_subsampling(uint32_t format);
extern const char *drm_get_format_name(uint32_t format);
extern struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev,
unsigned int supported_rotations);
+extern struct drm_property *drm_mode_create_compression_property(
+ struct drm_device *dev,
+ unsigned int comp_caps);
extern unsigned int drm_rotation_simplify(unsigned int rotation,
unsigned int supported_rotations);

--
1.9.1