diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 56df86ef5a4d..067f8f30c0b8 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6199,6 +6199,10 @@ enum { #define _PLANE_KEYMSK_2_A 0x70298 #define _PLANE_KEYMAX_1_A 0x701a0 #define _PLANE_KEYMAX_2_A 0x702a0 +#define _PLANE_AUX_DIST_1_A 0x701c0 +#define _PLANE_AUX_DIST_2_A 0x702c0 +#define _PLANE_AUX_OFFSET_1_A 0x701c4 +#define _PLANE_AUX_OFFSET_2_A 0x702c4 #define _PLANE_COLOR_CTL_1_A 0x701CC /* GLK+ */ #define _PLANE_COLOR_CTL_2_A 0x702CC /* GLK+ */ #define _PLANE_COLOR_CTL_3_A 0x703CC /* GLK+ */ @@ -6305,6 +6309,24 @@ enum { #define PLANE_NV12_BUF_CFG(pipe, plane) \ _MMIO_PLANE(plane, _PLANE_NV12_BUF_CFG_1(pipe), _PLANE_NV12_BUF_CFG_2(pipe)) +#define _PLANE_AUX_DIST_1_B 0x711c0 +#define _PLANE_AUX_DIST_2_B 0x712c0 +#define _PLANE_AUX_DIST_1(pipe) \ + _PIPE(pipe, _PLANE_AUX_DIST_1_A, _PLANE_AUX_DIST_1_B) +#define _PLANE_AUX_DIST_2(pipe) \ + _PIPE(pipe, _PLANE_AUX_DIST_2_A, _PLANE_AUX_DIST_2_B) +#define PLANE_AUX_DIST(pipe, plane) \ + _MMIO_PLANE(plane, _PLANE_AUX_DIST_1(pipe), _PLANE_AUX_DIST_2(pipe)) + +#define _PLANE_AUX_OFFSET_1_B 0x711c4 +#define _PLANE_AUX_OFFSET_2_B 0x712c4 +#define _PLANE_AUX_OFFSET_1(pipe) \ + _PIPE(pipe, _PLANE_AUX_OFFSET_1_A, _PLANE_AUX_OFFSET_1_B) +#define _PLANE_AUX_OFFSET_2(pipe) \ + _PIPE(pipe, _PLANE_AUX_OFFSET_2_A, _PLANE_AUX_OFFSET_2_B) +#define PLANE_AUX_OFFSET(pipe, plane) \ + _MMIO_PLANE(plane, _PLANE_AUX_OFFSET_1(pipe), _PLANE_AUX_OFFSET_2(pipe)) + #define _PLANE_COLOR_CTL_1_B 0x711CC #define _PLANE_COLOR_CTL_2_B 0x712CC #define _PLANE_COLOR_CTL_3_B 0x713CC @@ -6788,6 +6810,7 @@ enum { # define CHICKEN3_DGMG_DONE_FIX_DISABLE (1 << 2) #define CHICKEN_PAR1_1 _MMIO(0x42080) +#define SKL_RC_HASH_OUTSIDE (1 << 15) #define DPA_MASK_VBLANK_SRD (1 << 15) #define FORCE_ARB_IDLE_PLANES (1 << 14) #define SKL_EDP_PSR_FIX_RDWRAP (1 << 3) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 51035ec1fe62..0e334a2e9d4b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1994,11 +1994,19 @@ intel_tile_width_bytes(const struct drm_framebuffer *fb, int plane) return 128; else return 512; + case I915_FORMAT_MOD_Y_TILED_CCS: + if (plane == 1) + return 128; + /* fall through */ case I915_FORMAT_MOD_Y_TILED: if (IS_GEN2(dev_priv) || HAS_128_BYTE_Y_TILING(dev_priv)) return 128; else return 512; + case I915_FORMAT_MOD_Yf_TILED_CCS: + if (plane == 1) + return 128; + /* fall through */ case I915_FORMAT_MOD_Yf_TILED: switch (cpp) { case 1: @@ -2105,7 +2113,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) { @@ -2115,6 +2123,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; @@ -2422,6 +2432,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; @@ -2486,6 +2497,36 @@ 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 hsub = fb->format->hsub; + int vsub = fb->format->vsub; + int tile_width, tile_height; + int main_x, main_y; + int ccs_x, ccs_y; + + intel_tile_dims(fb, i, &tile_width, &tile_height); + + ccs_x = (x * hsub) % (tile_width * hsub); + ccs_y = (y * vsub) % (tile_height * vsub); + main_x = intel_fb->normal[0].x % (tile_width * hsub); + main_y = intel_fb->normal[0].y % (tile_height * vsub); + + /* + * 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 @@ -2846,6 +2887,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) { @@ -2868,6 +2912,44 @@ 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 hsub = fb->format->hsub; + int vsub = fb->format->vsub; + 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 / hsub; + y = aux_y / vsub; + aux_offset = intel_adjust_tile_offset(&x, &y, plane_state, 1, + aux_offset, aux_offset - alignment); + aux_x = x * hsub + aux_x % hsub; + aux_y = y * vsub + aux_y % vsub; + } + + 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; @@ -2910,7 +2992,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; } @@ -2919,6 +3001,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; @@ -2955,6 +3057,49 @@ 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); + const struct drm_framebuffer *fb = plane_state->base.fb; + int src_x = plane_state->base.src.x1 >> 16; + int src_y = plane_state->base.src.y1 >> 16; + int hsub = fb->format->hsub; + int vsub = fb->format->vsub; + int x = src_x / hsub; + int y = src_y / vsub; + 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 & ~(DRM_MODE_ROTATE_0 | DRM_MODE_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 * hsub + src_x % hsub; + plane_state->aux.y = y * vsub + src_y % vsub; + + return 0; +} + int skl_check_plane_surface(struct intel_plane_state *plane_state) { const struct drm_framebuffer *fb = plane_state->base.fb; @@ -2978,6 +3123,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; @@ -3284,8 +3434,12 @@ static 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); } @@ -3358,6 +3512,7 @@ static void skylake_update_primary_plane(struct intel_plane *plane, u32 plane_ctl = plane_state->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; @@ -3394,6 +3549,10 @@ static void skylake_update_primary_plane(struct intel_plane *plane, I915_WRITE_FW(PLANE_OFFSET(pipe, plane_id), (src_y << 16) | src_x); I915_WRITE_FW(PLANE_STRIDE(pipe, plane_id), stride); I915_WRITE_FW(PLANE_SIZE(pipe, plane_id), (src_h << 16) | src_w); + I915_WRITE_FW(PLANE_AUX_DIST(pipe, plane_id), + (plane_state->aux.offset - surf_addr) | aux_stride); + I915_WRITE_FW(PLANE_AUX_OFFSET(pipe, plane_id), + (plane_state->aux.y << 16) | plane_state->aux.x); if (scaler_id >= 0) { uint32_t ps_ctrl = 0; @@ -8337,10 +8496,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); @@ -13506,10 +13671,12 @@ static int intel_framebuffer_init(struct intel_framebuffer *intel_fb, 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; struct drm_format_name_buf format_name; - u32 pitch_limit, stride_alignment; + u32 pitch_limit; unsigned int tiling, stride; int ret = -EINVAL; + int i; i915_gem_object_lock(obj); obj->framebuffer_references++; @@ -13538,6 +13705,19 @@ static int intel_framebuffer_init(struct intel_framebuffer *intel_fb, /* 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"); + goto err; + } + /* fall through */ case I915_FORMAT_MOD_Y_TILED: case I915_FORMAT_MOD_Yf_TILED: if (INTEL_GEN(dev_priv) < 9) { @@ -13642,25 +13822,46 @@ static int intel_framebuffer_init(struct intel_framebuffer *intel_fb, if (mode_cmd->offsets[0] != 0) goto err; - drm_helper_mode_fill_fb_struct(&dev_priv->drm, - &intel_fb->base, mode_cmd); + drm_helper_mode_fill_fb_struct(&dev_priv->drm, 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); - goto err; + 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); + goto err; + } } intel_fb->obj = obj; - ret = intel_fill_fb_info(dev_priv, &intel_fb->base); + ret = intel_fill_fb_info(dev_priv, fb); if (ret) goto err; - ret = drm_framebuffer_init(obj->base.dev, - &intel_fb->base, - &intel_fb_funcs); + ret = drm_framebuffer_init(&dev_priv->drm, fb, &intel_fb_funcs); if (ret) { DRM_ERROR("framebuffer init failed %d\n", ret); goto err; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 6e393b217450..4a75b673b85f 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); @@ -4077,7 +4091,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; /* @@ -4383,7 +4399,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,cfl */ @@ -4478,6 +4496,13 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv, res_lines = div_round_up_fixed16(selected_result, plane_blocks_per_line); + /* 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 += fixed16_to_u32_round_up(y_tile_minimum); + + /* Display WA #1126: skl,bxt,kbl,glk */ if (level >= 1 && level <= 7) { if (y_tiled) { res_blocks += fixed16_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 048a4cab5589..4bf0d3e4ad91 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -238,6 +238,7 @@ skl_update_plane(struct intel_plane *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); @@ -272,6 +273,10 @@ skl_update_plane(struct intel_plane *plane, I915_WRITE_FW(PLANE_OFFSET(pipe, plane_id), (y << 16) | x); I915_WRITE_FW(PLANE_STRIDE(pipe, plane_id), stride); I915_WRITE_FW(PLANE_SIZE(pipe, plane_id), (src_h << 16) | src_w); + I915_WRITE_FW(PLANE_AUX_DIST(pipe, plane_id), + (plane_state->aux.offset - surf_addr) | aux_stride); + I915_WRITE_FW(PLANE_AUX_OFFSET(pipe, plane_id), + (plane_state->aux.y << 16) | plane_state->aux.x); /* program plane scaler */ if (plane_state->scaler_id >= 0) {