+ /* fall through */
case I915_FORMAT_MOD_Yf_TILED:
/*
* Bspec seems to suggest that the Yf tile width would
@@ -2156,7 +2164,7 @@ static unsigned int intel_surf_alignment(const
struct drm_framebuffer *fb,
struct drm_i915_private *dev_priv = to_i915(fb->dev);
/* AUX_DIST needs only 4K alignment */
- if (fb->format->format == DRM_FORMAT_NV12 && plane == 1)
+ if (plane == 1)
return 4096;
switch (fb->modifier) {
@@ -2166,6 +2174,8 @@ static unsigned int intel_surf_alignment(const
struct drm_framebuffer *fb,
if (INTEL_GEN(dev_priv) >= 9)
return 256 * 1024;
return 0;
+ case I915_FORMAT_MOD_Y_TILED_CCS:
+ case I915_FORMAT_MOD_Yf_TILED_CCS:
case I915_FORMAT_MOD_Y_TILED:
case I915_FORMAT_MOD_Yf_TILED:
return 1 * 1024 * 1024;
@@ -2472,6 +2482,7 @@ static unsigned int intel_fb_modifier_to_tiling(uint64_t
fb_modifier)
case I915_FORMAT_MOD_X_TILED:
return I915_TILING_X;
case I915_FORMAT_MOD_Y_TILED:
+ case I915_FORMAT_MOD_Y_TILED_CCS:
return I915_TILING_Y;
default:
return I915_TILING_NONE;
@@ -2536,6 +2547,35 @@ intel_fill_fb_info(struct drm_i915_private
*dev_priv,
intel_fb_offset_to_xy(&x, &y, fb, i);
+ if ((fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
+ fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS) && i ==
1) {
+ int main_x, main_y;
+ int ccs_x, ccs_y;
+
+ /*
+ * Each byte of CCS corresponds to a 16x8 area of
the main surface, and
+ * each CCS tile is 64x64 bytes.
+ */
+ ccs_x = (x * 16) % (64 * 16);
+ ccs_y = (y * 8) % (64 * 8);
+ main_x = intel_fb->normal[0].x % (64 * 16);
+ main_y = intel_fb->normal[0].y % (64 * 8);
+
+ /*
+ * CCS doesn't have its own x/y offset register,
so the intra CCS tile
+ * x/y offsets must match between CCS and the main
surface.
+ */
+ if (main_x != ccs_x || main_y != ccs_y) {
+ DRM_DEBUG_KMS("Bad CCS x/y (main %d,%d ccs
%d,%d) full (main %d,%d ccs %d,%d)\n",
+ main_x, main_y,
+ ccs_x, ccs_y,
+ intel_fb->normal[0].x,
+ intel_fb->normal[0].y,
+ x, y);
+ return -EINVAL;
+ }
+ }
+
/*
* The fence (if used) is aligned to the start of the
object
* so having the framebuffer wrap around across the edge
of the
@@ -2873,6 +2913,9 @@ static int skl_max_plane_width(const struct
drm_framebuffer *fb, int plane,
break;
}
break;
+ case I915_FORMAT_MOD_Y_TILED_CCS:
+ case I915_FORMAT_MOD_Yf_TILED_CCS:
+ /* FIXME AUX plane? */
case I915_FORMAT_MOD_Y_TILED:
case I915_FORMAT_MOD_Yf_TILED:
switch (cpp) {
@@ -2895,6 +2938,42 @@ static int skl_max_plane_width(const struct
drm_framebuffer *fb, int plane,
return 2048;
}
+static bool skl_check_main_ccs_coordinates(struct intel_plane_state
*plane_state,
+ int main_x, int main_y, u32
main_offset)
+{
+ const struct drm_framebuffer *fb = plane_state->base.fb;
+ int aux_x = plane_state->aux.x;
+ int aux_y = plane_state->aux.y;
+ u32 aux_offset = plane_state->aux.offset;
+ u32 alignment = intel_surf_alignment(fb, 1);
+
+ while (aux_offset >= main_offset && aux_y <= main_y) {
+ int x, y;
+
+ if (aux_x == main_x && aux_y == main_y)
+ break;
+
+ if (aux_offset == 0)
+ break;
+
+ x = aux_x / 16;
+ y = aux_y / 8;
+ aux_offset = intel_adjust_tile_offset(&x, &y, plane_state,
1,
+ aux_offset,
aux_offset - alignment);
+ aux_x = x * 16 + aux_x % 16;
+ aux_y = y * 8 + aux_y % 8;
+ }
+
+ if (aux_x != main_x || aux_y != main_y)
+ return false;
+
+ plane_state->aux.offset = aux_offset;
+ plane_state->aux.x = aux_x;
+ plane_state->aux.y = aux_y;
+
+ return true;
+}
+
static int skl_check_main_surface(struct intel_plane_state *plane_state)
{
const struct drm_framebuffer *fb = plane_state->base.fb;
@@ -2937,7 +3016,7 @@ static int skl_check_main_surface(struct
intel_plane_state *plane_state)
while ((x + w) * cpp > fb->pitches[0]) {
if (offset == 0) {
- DRM_DEBUG_KMS("Unable to find suitable
display surface offset\n");
+ DRM_DEBUG_KMS("Unable to find suitable
display surface offset due to X-tiling\n");
return -EINVAL;
}
@@ -2946,6 +3025,26 @@ static int skl_check_main_surface(struct
intel_plane_state *plane_state)
}
}
+ /*
+ * CCS AUX surface doesn't have its own x/y offsets, we must make
sure
+ * they match with the main surface x/y offsets.
+ */
+ if (fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
+ fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS) {
+ while (!skl_check_main_ccs_coordinates(plane_state, x, y,
offset)) {
+ if (offset == 0)
+ break;
+
+ offset = intel_adjust_tile_offset(&x, &y,
plane_state, 0,
+ offset, offset -
alignment);
+ }
+
+ if (x != plane_state->aux.x || y != plane_state->aux.y) {
+ DRM_DEBUG_KMS("Unable to find suitable display
surface offset due to CCS\n");
+ return -EINVAL;
+ }
+ }
+
plane_state->main.offset = offset;
plane_state->main.x = x;
plane_state->main.y = y;
@@ -2982,6 +3081,47 @@ static int skl_check_nv12_aux_surface(struct
intel_plane_state *plane_state)
return 0;
}
+static int skl_check_ccs_aux_surface(struct intel_plane_state
*plane_state)
+{
+ struct intel_plane *plane = to_intel_plane(plane_state->
base.plane);
+ struct intel_crtc *crtc = to_intel_crtc(plane_state->base.crtc);
+ int src_x = plane_state->base.src.x1 >> 16;
+ int src_y = plane_state->base.src.y1 >> 16;
+ int x = src_x / 16;
+ int y = src_y / 8;
+ u32 offset;
+
+ switch (plane->id) {
+ case PLANE_PRIMARY:
+ case PLANE_SPRITE0:
+ break;
+ default:
+ DRM_DEBUG_KMS("RC support only on plane 1 and 2\n");
+ return -EINVAL;
+ }
+
+ if (crtc->pipe == PIPE_C) {
+ DRM_DEBUG_KMS("No RC support on pipe C\n");
+ return -EINVAL;
+ }
+
+ if (plane_state->base.rotation &&
+ plane_state->base.rotation & ~(DRM_ROTATE_0 | DRM_ROTATE_180))
{
+ DRM_DEBUG_KMS("RC support only with 0/180 degree rotation
%x\n",
+ plane_state->base.rotation);
+ return -EINVAL;
+ }
+
+ intel_add_fb_offsets(&x, &y, plane_state, 1);
+ offset = intel_compute_tile_offset(&x, &y, plane_state, 1);
+
+ plane_state->aux.offset = offset;
+ plane_state->aux.x = x * 16 + src_x % 16;
+ plane_state->aux.y = y * 8 + src_y % 8;
+
+ return 0;
+}
+
int skl_check_plane_surface(struct intel_plane_state *plane_state)
{
const struct drm_framebuffer *fb = plane_state->base.fb;
@@ -3002,6 +3142,11 @@ int skl_check_plane_surface(struct
intel_plane_state *plane_state)
ret = skl_check_nv12_aux_surface(plane_state);
if (ret)
return ret;
+ } else if (fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
+ fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS) {
+ ret = skl_check_ccs_aux_surface(plane_state);
+ if (ret)
+ return ret;
} else {
plane_state->aux.offset = ~0xfff;
plane_state->aux.x = 0;
@@ -3357,8 +3502,12 @@ u32 skl_plane_ctl_tiling(uint64_t fb_modifier)
return PLANE_CTL_TILED_X;
case I915_FORMAT_MOD_Y_TILED:
return PLANE_CTL_TILED_Y;
+ case I915_FORMAT_MOD_Y_TILED_CCS:
+ return PLANE_CTL_TILED_Y | PLANE_CTL_DECOMPRESSION_ENABLE;
case I915_FORMAT_MOD_Yf_TILED:
return PLANE_CTL_TILED_YF;
+ case I915_FORMAT_MOD_Yf_TILED_CCS:
+ return PLANE_CTL_TILED_YF | PLANE_CTL_DECOMPRESSION_
ENABLE;
default:
MISSING_CASE(fb_modifier);
}
@@ -3401,6 +3550,7 @@ static void skylake_update_primary_plane(struct
drm_plane *plane,
u32 plane_ctl;
unsigned int rotation = plane_state->base.rotation;
u32 stride = skl_plane_stride(fb, 0, rotation);
+ u32 aux_stride = skl_plane_stride(fb, 1, rotation);
u32 surf_addr = plane_state->main.offset;
int scaler_id = plane_state->scaler_id;
int src_x = plane_state->main.x;
@@ -3436,6 +3586,10 @@ static void skylake_update_primary_plane(struct
drm_plane *plane,
I915_WRITE(PLANE_OFFSET(pipe, plane_id), (src_y << 16) | src_x);
I915_WRITE(PLANE_STRIDE(pipe, plane_id), stride);
I915_WRITE(PLANE_SIZE(pipe, plane_id), (src_h << 16) | src_w);
+ I915_WRITE(PLANE_AUX_DIST(pipe, plane_id),
+ (plane_state->aux.offset - surf_addr) | aux_stride);
+ I915_WRITE(PLANE_AUX_OFFSET(pipe, plane_id),
+ (plane_state->aux.y << 16) | plane_state->aux.x);
if (scaler_id >= 0) {
uint32_t ps_ctrl = 0;
@@ -9807,10 +9961,16 @@ skylake_get_initial_plane_config(struct
intel_crtc *crtc,
fb->modifier = I915_FORMAT_MOD_X_TILED;
break;
case PLANE_CTL_TILED_Y:
- fb->modifier = I915_FORMAT_MOD_Y_TILED;
+ if (val & PLANE_CTL_DECOMPRESSION_ENABLE)
+ fb->modifier = I915_FORMAT_MOD_Y_TILED_CCS;
+ else
+ fb->modifier = I915_FORMAT_MOD_Y_TILED;
break;
case PLANE_CTL_TILED_YF:
- fb->modifier = I915_FORMAT_MOD_Yf_TILED;
+ if (val & PLANE_CTL_DECOMPRESSION_ENABLE)
+ fb->modifier = I915_FORMAT_MOD_Yf_TILED_CCS;
+ else
+ fb->modifier = I915_FORMAT_MOD_Yf_TILED;
break;
default:
MISSING_CASE(tiling);
@@ -12014,7 +12174,7 @@ static void skl_do_mmio_flip(struct intel_crtc
*intel_crtc,
u32 ctl, stride = skl_plane_stride(fb, 0, rotation);
ctl = I915_READ(PLANE_CTL(pipe, 0));
- ctl &= ~PLANE_CTL_TILED_MASK;
+ ctl &= ~(PLANE_CTL_TILED_MASK | PLANE_CTL_DECOMPRESSION_ENABLE);
switch (fb->modifier) {
case DRM_FORMAT_MOD_NONE:
break;
@@ -12024,9 +12184,15 @@ static void skl_do_mmio_flip(struct intel_crtc
*intel_crtc,
case I915_FORMAT_MOD_Y_TILED:
ctl |= PLANE_CTL_TILED_Y;
break;
+ case I915_FORMAT_MOD_Y_TILED_CCS:
+ ctl |= PLANE_CTL_TILED_Y | PLANE_CTL_DECOMPRESSION_ENABLE;
+ break;
case I915_FORMAT_MOD_Yf_TILED:
ctl |= PLANE_CTL_TILED_YF;
break;
+ case I915_FORMAT_MOD_Yf_TILED_CCS:
+ ctl |= PLANE_CTL_TILED_YF | PLANE_CTL_DECOMPRESSION_
ENABLE;
+ break;
default:
MISSING_CASE(fb->modifier);
}
@@ -15925,9 +16091,10 @@ static int intel_framebuffer_init(struct
drm_device *dev,
struct drm_i915_gem_object *obj)
{
struct drm_i915_private *dev_priv = to_i915(dev);
+ struct drm_framebuffer *fb = &intel_fb->base;
unsigned int tiling = i915_gem_object_get_tiling(obj);
- int ret;
- u32 pitch_limit, stride_alignment;
+ int ret, i;
+ u32 pitch_limit;
struct drm_format_name_buf format_name;
WARN_ON(!mutex_is_locked(&dev->struct_mutex));
@@ -15953,6 +16120,19 @@ static int intel_framebuffer_init(struct
drm_device *dev,
/* Passed in modifier sanity checking. */
switch (mode_cmd->modifier[0]) {
+ case I915_FORMAT_MOD_Y_TILED_CCS:
+ case I915_FORMAT_MOD_Yf_TILED_CCS:
+ switch (mode_cmd->pixel_format) {
+ case DRM_FORMAT_XBGR8888:
+ case DRM_FORMAT_ABGR8888:
+ case DRM_FORMAT_XRGB8888:
+ case DRM_FORMAT_ARGB8888:
+ break;
+ default:
+ DRM_DEBUG_KMS("RC supported only with RGB8888
formats\n");
+ return -EINVAL;
+ }
+ /* fall through */
case I915_FORMAT_MOD_Y_TILED:
case I915_FORMAT_MOD_Yf_TILED:
if (INTEL_GEN(dev_priv) < 9) {
@@ -16059,22 +16239,46 @@ static int intel_framebuffer_init(struct
drm_device *dev,
if (mode_cmd->offsets[0] != 0)
return -EINVAL;
- drm_helper_mode_fill_fb_struct(dev, &intel_fb->base, mode_cmd);
+ drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd);
- stride_alignment = intel_fb_stride_alignment(&intel_fb->base, 0);
- if (mode_cmd->pitches[0] & (stride_alignment - 1)) {
- DRM_DEBUG_KMS("pitch (%d) must be at least %u byte
aligned\n",
- mode_cmd->pitches[0], stride_alignment);
- return -EINVAL;
+ for (i = 0; i < fb->format->num_planes; i++) {
+ u32 stride_alignment;
+
+ if (mode_cmd->handles[i] != mode_cmd->handles[0]) {
+ DRM_DEBUG_KMS("bad plane %d handle\n", i);
+ return -EINVAL;
+ }
+
+ stride_alignment = intel_fb_stride_alignment(fb, i);
+
+ /*
+ * Display WA #0531: skl,bxt,kbl,glk
+ *
+ * Render decompression and plane width > 3840
+ * combined with horizontal panning requires the
+ * plane stride to be a multiple of 4. We'll just
+ * require the entire fb to accommodate that to avoid
+ * potential runtime errors at plane configuration time.
+ */
+ if (IS_GEN9(dev_priv) && i == 0 && fb->width > 3840 &&
+ (fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
+ fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS))
+ stride_alignment *= 4;
+
+ if (fb->pitches[i] & (stride_alignment - 1)) {
+ DRM_DEBUG_KMS("plane %d pitch (%d) must be at
least %u byte aligned\n",
+ i, fb->pitches[i], stride_alignment);
+ return -EINVAL;
+ }
}
intel_fb->obj = obj;
- ret = intel_fill_fb_info(dev_priv, &intel_fb->base);
+ ret = intel_fill_fb_info(dev_priv, fb);
if (ret)
return ret;
- ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs);
+ ret = drm_framebuffer_init(dev, fb, &intel_fb_funcs);
if (ret) {
DRM_ERROR("framebuffer init failed %d\n", ret);
return ret;
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_
pm.c
index 249623d45be0..25782cd174c0 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -62,6 +62,20 @@ static void gen9_init_clock_gating(struct
drm_i915_private *dev_priv)
I915_WRITE(CHICKEN_PAR1_1,
I915_READ(CHICKEN_PAR1_1) | SKL_EDP_PSR_FIX_RDWRAP);
+ /*
+ * Display WA#0390: skl,bxt,kbl,glk
+ *
+ * Must match Sampler, Pixel Back End, and Media
+ * (0xE194 bit 8, 0x7014 bit 13, 0x4DDC bits 27 and 31).
+ *
+ * Including bits outside the page in the hash would
+ * require 2 (or 4?) MiB alignment of resources. Just
+ * assume the defaul hashing mode which only uses bits
+ * within the page.
+ */
+ I915_WRITE(CHICKEN_PAR1_1,
+ I915_READ(CHICKEN_PAR1_1) & ~SKL_RC_HASH_OUTSIDE);
+
I915_WRITE(GEN8_CONFIG0,
I915_READ(GEN8_CONFIG0) | GEN9_DEFAULT_FIXES);
@@ -3314,7 +3328,9 @@ skl_ddb_min_alloc(const struct drm_plane_state
*pstate,
/* For Non Y-tile return 8-blocks */
if (fb->modifier != I915_FORMAT_MOD_Y_TILED &&
- fb->modifier != I915_FORMAT_MOD_Yf_TILED)
+ fb->modifier != I915_FORMAT_MOD_Yf_TILED &&
+ fb->modifier != I915_FORMAT_MOD_Y_TILED_CCS &&
+ fb->modifier != I915_FORMAT_MOD_Yf_TILED_CCS)
return 8;
src_w = drm_rect_width(&intel_pstate->base.src) >> 16;
@@ -3590,7 +3606,9 @@ static int skl_compute_plane_wm(const struct
drm_i915_private *dev_priv,
}
y_tiled = fb->modifier == I915_FORMAT_MOD_Y_TILED ||
- fb->modifier == I915_FORMAT_MOD_Yf_TILED;
+ fb->modifier == I915_FORMAT_MOD_Yf_TILED ||
+ fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
+ fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS;
x_tiled = fb->modifier == I915_FORMAT_MOD_X_TILED;
/* Display WA #1141: kbl. */
@@ -3675,6 +3693,13 @@ static int skl_compute_plane_wm(const struct
drm_i915_private *dev_priv,
res_lines = DIV_ROUND_UP(selected_result.val,
plane_blocks_per_line.val);
+ /* Display WA #1125: skl,bxt,kbl,glk */
+ if (level == 0 &&
+ (fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
+ fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS))
+ res_blocks += fixed_16_16_to_u32_round_up(y_tile_minimum);
+
+ /* Display WA #1126: skl,bxt,kbl,glk */
if (level >= 1 && level <= 7) {
if (y_tiled) {
res_blocks += fixed_16_16_to_u32_round_up(y_
tile_minimum);
diff --git a/drivers/gpu/drm/i915/intel_sprite.c
b/drivers/gpu/drm/i915/intel_sprite.c
index 7031bc733d97..063a994815d0 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -210,6 +210,7 @@ skl_update_plane(struct drm_plane *drm_plane,
u32 surf_addr = plane_state->main.offset;
unsigned int rotation = plane_state->base.rotation;
u32 stride = skl_plane_stride(fb, 0, rotation);
+ u32 aux_stride = skl_plane_stride(fb, 1, rotation);
int crtc_x = plane_state->base.dst.x1;
int crtc_y = plane_state->base.dst.y1;
uint32_t crtc_w = drm_rect_width(&plane_state->base.dst);
@@ -248,6 +249,10 @@ skl_update_plane(struct drm_plane *drm_plane,
I915_WRITE(PLANE_OFFSET(pipe, plane_id), (y << 16) | x);
I915_WRITE(PLANE_STRIDE(pipe, plane_id), stride);
I915_WRITE(PLANE_SIZE(pipe, plane_id), (src_h << 16) | src_w);
+ I915_WRITE(PLANE_AUX_DIST(pipe, plane_id),
+ (plane_state->aux.offset - surf_addr) | aux_stride);
+ I915_WRITE(PLANE_AUX_OFFSET(pipe, plane_id),
+ (plane_state->aux.y << 16) | plane_state->aux.x);
/* program plane scaler */
if (plane_state->scaler_id >= 0) {
--
2.10.2