linux/drivers/gpu/drm/i915/display/skl_universal_plane.c

3212 lines
90 KiB
C
Raw Permalink Normal View History

// SPDX-License-Identifier: MIT
/*
* Copyright © 2020 Intel Corporation
*/
#include <drm/drm_atomic_helper.h>
#include <drm/drm_blend.h>
#include <drm/drm_damage_helper.h>
#include <drm/drm_fourcc.h>
#include "pxp/intel_pxp.h"
#include "i915_drv.h"
#include "intel_bo.h"
#include "intel_de.h"
#include "intel_display_irq.h"
#include "intel_display_regs.h"
#include "intel_display_types.h"
#include "intel_dpt.h"
#include "intel_fb.h"
#include "intel_fbc.h"
#include "intel_frontbuffer.h"
#include "intel_plane.h"
#include "intel_psr.h"
#include "intel_psr_regs.h"
#include "skl_scaler.h"
#include "skl_universal_plane.h"
#include "skl_universal_plane_regs.h"
#include "skl_watermark.h"
static const u32 skl_plane_formats[] = {
DRM_FORMAT_C8,
DRM_FORMAT_RGB565,
DRM_FORMAT_XRGB8888,
DRM_FORMAT_XBGR8888,
DRM_FORMAT_ARGB8888,
DRM_FORMAT_ABGR8888,
DRM_FORMAT_XRGB2101010,
DRM_FORMAT_XBGR2101010,
DRM_FORMAT_XRGB16161616F,
DRM_FORMAT_XBGR16161616F,
DRM_FORMAT_YUYV,
DRM_FORMAT_YVYU,
DRM_FORMAT_UYVY,
DRM_FORMAT_VYUY,
DRM_FORMAT_XYUV8888,
};
static const u32 skl_planar_formats[] = {
DRM_FORMAT_C8,
DRM_FORMAT_RGB565,
DRM_FORMAT_XRGB8888,
DRM_FORMAT_XBGR8888,
DRM_FORMAT_ARGB8888,
DRM_FORMAT_ABGR8888,
DRM_FORMAT_XRGB2101010,
DRM_FORMAT_XBGR2101010,
DRM_FORMAT_XRGB16161616F,
DRM_FORMAT_XBGR16161616F,
DRM_FORMAT_YUYV,
DRM_FORMAT_YVYU,
DRM_FORMAT_UYVY,
DRM_FORMAT_VYUY,
DRM_FORMAT_NV12,
DRM_FORMAT_XYUV8888,
};
static const u32 glk_planar_formats[] = {
DRM_FORMAT_C8,
DRM_FORMAT_RGB565,
DRM_FORMAT_XRGB8888,
DRM_FORMAT_XBGR8888,
DRM_FORMAT_ARGB8888,
DRM_FORMAT_ABGR8888,
DRM_FORMAT_XRGB2101010,
DRM_FORMAT_XBGR2101010,
DRM_FORMAT_XRGB16161616F,
DRM_FORMAT_XBGR16161616F,
DRM_FORMAT_YUYV,
DRM_FORMAT_YVYU,
DRM_FORMAT_UYVY,
DRM_FORMAT_VYUY,
DRM_FORMAT_NV12,
DRM_FORMAT_XYUV8888,
DRM_FORMAT_P010,
DRM_FORMAT_P012,
DRM_FORMAT_P016,
};
static const u32 icl_sdr_y_plane_formats[] = {
DRM_FORMAT_C8,
DRM_FORMAT_RGB565,
DRM_FORMAT_XRGB8888,
DRM_FORMAT_XBGR8888,
DRM_FORMAT_ARGB8888,
DRM_FORMAT_ABGR8888,
DRM_FORMAT_XRGB2101010,
DRM_FORMAT_XBGR2101010,
DRM_FORMAT_ARGB2101010,
DRM_FORMAT_ABGR2101010,
DRM_FORMAT_YUYV,
DRM_FORMAT_YVYU,
DRM_FORMAT_UYVY,
DRM_FORMAT_VYUY,
DRM_FORMAT_Y210,
DRM_FORMAT_Y212,
DRM_FORMAT_Y216,
DRM_FORMAT_XYUV8888,
DRM_FORMAT_XVYU2101010,
};
static const u32 icl_sdr_uv_plane_formats[] = {
DRM_FORMAT_C8,
DRM_FORMAT_RGB565,
DRM_FORMAT_XRGB8888,
DRM_FORMAT_XBGR8888,
DRM_FORMAT_ARGB8888,
DRM_FORMAT_ABGR8888,
DRM_FORMAT_XRGB2101010,
DRM_FORMAT_XBGR2101010,
DRM_FORMAT_ARGB2101010,
DRM_FORMAT_ABGR2101010,
DRM_FORMAT_YUYV,
DRM_FORMAT_YVYU,
DRM_FORMAT_UYVY,
DRM_FORMAT_VYUY,
DRM_FORMAT_NV12,
DRM_FORMAT_P010,
DRM_FORMAT_P012,
DRM_FORMAT_P016,
DRM_FORMAT_Y210,
DRM_FORMAT_Y212,
DRM_FORMAT_Y216,
DRM_FORMAT_XYUV8888,
DRM_FORMAT_XVYU2101010,
};
static const u32 icl_hdr_plane_formats[] = {
DRM_FORMAT_C8,
DRM_FORMAT_RGB565,
DRM_FORMAT_XRGB8888,
DRM_FORMAT_XBGR8888,
DRM_FORMAT_ARGB8888,
DRM_FORMAT_ABGR8888,
DRM_FORMAT_XRGB2101010,
DRM_FORMAT_XBGR2101010,
DRM_FORMAT_ARGB2101010,
DRM_FORMAT_ABGR2101010,
DRM_FORMAT_XRGB16161616F,
DRM_FORMAT_XBGR16161616F,
DRM_FORMAT_ARGB16161616F,
DRM_FORMAT_ABGR16161616F,
DRM_FORMAT_YUYV,
DRM_FORMAT_YVYU,
DRM_FORMAT_UYVY,
DRM_FORMAT_VYUY,
DRM_FORMAT_NV12,
DRM_FORMAT_P010,
DRM_FORMAT_P012,
DRM_FORMAT_P016,
DRM_FORMAT_Y210,
DRM_FORMAT_Y212,
DRM_FORMAT_Y216,
DRM_FORMAT_XYUV8888,
DRM_FORMAT_XVYU2101010,
DRM_FORMAT_XVYU12_16161616,
DRM_FORMAT_XVYU16161616,
};
int skl_format_to_fourcc(int format, bool rgb_order, bool alpha)
{
switch (format) {
case PLANE_CTL_FORMAT_RGB_565:
return DRM_FORMAT_RGB565;
case PLANE_CTL_FORMAT_NV12:
return DRM_FORMAT_NV12;
case PLANE_CTL_FORMAT_XYUV:
return DRM_FORMAT_XYUV8888;
case PLANE_CTL_FORMAT_P010:
return DRM_FORMAT_P010;
case PLANE_CTL_FORMAT_P012:
return DRM_FORMAT_P012;
case PLANE_CTL_FORMAT_P016:
return DRM_FORMAT_P016;
case PLANE_CTL_FORMAT_Y210:
return DRM_FORMAT_Y210;
case PLANE_CTL_FORMAT_Y212:
return DRM_FORMAT_Y212;
case PLANE_CTL_FORMAT_Y216:
return DRM_FORMAT_Y216;
case PLANE_CTL_FORMAT_Y410:
return DRM_FORMAT_XVYU2101010;
case PLANE_CTL_FORMAT_Y412:
return DRM_FORMAT_XVYU12_16161616;
case PLANE_CTL_FORMAT_Y416:
return DRM_FORMAT_XVYU16161616;
default:
case PLANE_CTL_FORMAT_XRGB_8888:
if (rgb_order) {
if (alpha)
return DRM_FORMAT_ABGR8888;
else
return DRM_FORMAT_XBGR8888;
} else {
if (alpha)
return DRM_FORMAT_ARGB8888;
else
return DRM_FORMAT_XRGB8888;
}
case PLANE_CTL_FORMAT_XRGB_2101010:
if (rgb_order) {
if (alpha)
return DRM_FORMAT_ABGR2101010;
else
return DRM_FORMAT_XBGR2101010;
} else {
if (alpha)
return DRM_FORMAT_ARGB2101010;
else
return DRM_FORMAT_XRGB2101010;
}
case PLANE_CTL_FORMAT_XRGB_16161616F:
if (rgb_order) {
if (alpha)
return DRM_FORMAT_ABGR16161616F;
else
return DRM_FORMAT_XBGR16161616F;
} else {
if (alpha)
return DRM_FORMAT_ARGB16161616F;
else
return DRM_FORMAT_XRGB16161616F;
}
}
}
static u8 icl_nv12_y_plane_mask(struct intel_display *display)
{
if (DISPLAY_VER(display) >= 13 || HAS_D12_PLANE_MINIMIZATION(display))
return BIT(PLANE_4) | BIT(PLANE_5);
else
return BIT(PLANE_6) | BIT(PLANE_7);
}
bool icl_is_nv12_y_plane(struct intel_display *display,
enum plane_id plane_id)
{
return DISPLAY_VER(display) >= 11 &&
icl_nv12_y_plane_mask(display) & BIT(plane_id);
}
u8 icl_hdr_plane_mask(void)
{
return BIT(PLANE_1) | BIT(PLANE_2) | BIT(PLANE_3);
}
bool icl_is_hdr_plane(struct intel_display *display, enum plane_id plane_id)
{
return DISPLAY_VER(display) >= 11 &&
icl_hdr_plane_mask() & BIT(plane_id);
}
static int icl_plane_min_cdclk(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state)
{
unsigned int pixel_rate = intel_plane_pixel_rate(crtc_state, plane_state);
/* two pixels per clock */
return DIV_ROUND_UP(pixel_rate, 2);
}
static void
glk_plane_ratio(const struct intel_plane_state *plane_state,
unsigned int *num, unsigned int *den)
{
const struct drm_framebuffer *fb = plane_state->hw.fb;
if (fb->format->cpp[0] == 8) {
*num = 10;
*den = 8;
} else {
*num = 1;
*den = 1;
}
}
static int glk_plane_min_cdclk(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state)
{
unsigned int pixel_rate = intel_plane_pixel_rate(crtc_state, plane_state);
unsigned int num, den;
glk_plane_ratio(plane_state, &num, &den);
/* two pixels per clock */
return DIV_ROUND_UP(pixel_rate * num, 2 * den);
}
static void
skl_plane_ratio(const struct intel_plane_state *plane_state,
unsigned int *num, unsigned int *den)
{
const struct drm_framebuffer *fb = plane_state->hw.fb;
if (fb->format->cpp[0] == 8) {
*num = 9;
*den = 8;
} else {
*num = 1;
*den = 1;
}
}
static int skl_plane_min_cdclk(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state)
{
unsigned int pixel_rate = intel_plane_pixel_rate(crtc_state, plane_state);
unsigned int num, den;
skl_plane_ratio(plane_state, &num, &den);
return DIV_ROUND_UP(pixel_rate * num, den);
}
static int skl_plane_max_width(const struct drm_framebuffer *fb,
int color_plane,
unsigned int rotation)
{
int cpp = fb->format->cpp[color_plane];
switch (fb->modifier) {
case DRM_FORMAT_MOD_LINEAR:
case I915_FORMAT_MOD_X_TILED:
/*
* Validated limit is 4k, but has 5k should
* work apart from the following features:
* - Ytile (already limited to 4k)
* - FP16 (already limited to 4k)
* - render compression (already limited to 4k)
* - KVMR sprite and cursor (don't care)
* - horizontal panning (TODO verify this)
* - pipe and plane scaling (TODO verify this)
*/
if (cpp == 8)
return 4096;
else
return 5120;
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:
if (cpp == 8)
return 2048;
else
return 4096;
default:
MISSING_CASE(fb->modifier);
return 2048;
}
}
static int glk_plane_max_width(const struct drm_framebuffer *fb,
int color_plane,
unsigned int rotation)
{
int cpp = fb->format->cpp[color_plane];
switch (fb->modifier) {
case DRM_FORMAT_MOD_LINEAR:
case I915_FORMAT_MOD_X_TILED:
if (cpp == 8)
return 4096;
else
return 5120;
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:
if (cpp == 8)
return 2048;
else
return 5120;
default:
MISSING_CASE(fb->modifier);
return 2048;
}
}
static int icl_plane_min_width(const struct drm_framebuffer *fb,
int color_plane,
unsigned int rotation)
{
/* Wa_14011264657, Wa_14011050563: gen11+ */
switch (fb->format->format) {
case DRM_FORMAT_C8:
return 18;
case DRM_FORMAT_RGB565:
return 10;
case DRM_FORMAT_XRGB8888:
case DRM_FORMAT_XBGR8888:
case DRM_FORMAT_ARGB8888:
case DRM_FORMAT_ABGR8888:
case DRM_FORMAT_XRGB2101010:
case DRM_FORMAT_XBGR2101010:
case DRM_FORMAT_ARGB2101010:
case DRM_FORMAT_ABGR2101010:
case DRM_FORMAT_XVYU2101010:
case DRM_FORMAT_Y212:
case DRM_FORMAT_Y216:
return 6;
case DRM_FORMAT_NV12:
return 20;
case DRM_FORMAT_P010:
case DRM_FORMAT_P012:
case DRM_FORMAT_P016:
return 12;
case DRM_FORMAT_XRGB16161616F:
case DRM_FORMAT_XBGR16161616F:
case DRM_FORMAT_ARGB16161616F:
case DRM_FORMAT_ABGR16161616F:
case DRM_FORMAT_XVYU12_16161616:
case DRM_FORMAT_XVYU16161616:
return 4;
default:
return 1;
}
}
static int xe3_plane_max_width(const struct drm_framebuffer *fb,
int color_plane,
unsigned int rotation)
{
if (intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier))
return 4096;
else
return 6144;
}
static int icl_hdr_plane_max_width(const struct drm_framebuffer *fb,
int color_plane,
unsigned int rotation)
{
if (intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier))
return 4096;
else
return 5120;
}
static int icl_sdr_plane_max_width(const struct drm_framebuffer *fb,
int color_plane,
unsigned int rotation)
{
return 5120;
}
static int skl_plane_max_height(const struct drm_framebuffer *fb,
int color_plane,
unsigned int rotation)
{
return 4096;
}
static int icl_plane_max_height(const struct drm_framebuffer *fb,
int color_plane,
unsigned int rotation)
{
return 4320;
}
static unsigned int
plane_max_stride(struct intel_plane *plane,
u32 pixel_format, u64 modifier,
unsigned int rotation,
unsigned int max_pixels,
unsigned int max_bytes)
{
const struct drm_format_info *info = drm_format_info(pixel_format);
int cpp = info->cpp[0];
if (drm_rotation_90_or_270(rotation))
return min(max_pixels, max_bytes / cpp);
else
return min(max_pixels * cpp, max_bytes);
}
static unsigned int
adl_plane_max_stride(struct intel_plane *plane,
u32 pixel_format, u64 modifier,
unsigned int rotation)
{
unsigned int max_pixels = 65536; /* PLANE_OFFSET limit */
unsigned int max_bytes = 128 * 1024;
return plane_max_stride(plane, pixel_format,
modifier, rotation,
max_pixels, max_bytes);
}
static unsigned int
skl_plane_max_stride(struct intel_plane *plane,
u32 pixel_format, u64 modifier,
unsigned int rotation)
{
unsigned int max_pixels = 8192; /* PLANE_OFFSET limit */
unsigned int max_bytes = 32 * 1024;
return plane_max_stride(plane, pixel_format,
modifier, rotation,
max_pixels, max_bytes);
}
static bool tgl_plane_can_async_flip(u64 modifier)
{
switch (modifier) {
case DRM_FORMAT_MOD_LINEAR:
case I915_FORMAT_MOD_X_TILED:
case I915_FORMAT_MOD_Y_TILED:
case I915_FORMAT_MOD_4_TILED:
case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
case I915_FORMAT_MOD_4_TILED_MTL_RC_CCS:
case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS:
case I915_FORMAT_MOD_4_TILED_BMG_CCS:
case I915_FORMAT_MOD_4_TILED_LNL_CCS:
return true;
case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
case I915_FORMAT_MOD_4_TILED_MTL_MC_CCS:
case I915_FORMAT_MOD_4_TILED_DG2_MC_CCS:
case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC:
case I915_FORMAT_MOD_4_TILED_MTL_RC_CCS_CC:
case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC:
return false;
default:
return false;
}
}
static bool icl_plane_can_async_flip(u64 modifier)
{
switch (modifier) {
case DRM_FORMAT_MOD_LINEAR:
/*
* FIXME: Async on Linear buffer is supported on ICL
* but with additional alignment and fbc restrictions
* need to be taken care of.
*/
return false;
case I915_FORMAT_MOD_X_TILED:
case I915_FORMAT_MOD_Y_TILED:
case I915_FORMAT_MOD_Yf_TILED:
case I915_FORMAT_MOD_Y_TILED_CCS:
case I915_FORMAT_MOD_Yf_TILED_CCS:
return true;
default:
return false;
}
}
static bool skl_plane_can_async_flip(u64 modifier)
{
switch (modifier) {
case DRM_FORMAT_MOD_LINEAR:
return false;
case I915_FORMAT_MOD_X_TILED:
case I915_FORMAT_MOD_Y_TILED:
case I915_FORMAT_MOD_Yf_TILED:
return true;
case I915_FORMAT_MOD_Y_TILED_CCS:
case I915_FORMAT_MOD_Yf_TILED_CCS:
/*
* Display WA #0731: skl
* WaDisableRCWithAsyncFlip: skl
* "When render decompression is enabled, hardware
* internally converts the Async flips to Sync flips."
*
* Display WA #1159: glk
* "Async flip with render compression may result in
* intermittent underrun corruption."
*/
return false;
default:
return false;
}
}
static u32 tgl_plane_min_alignment(struct intel_plane *plane,
const struct drm_framebuffer *fb,
int color_plane)
{
struct intel_display *display = to_intel_display(plane);
/* PLANE_SURF GGTT -> DPT alignment */
int mult = intel_fb_uses_dpt(fb) ? 512 : 1;
/* AUX_DIST needs only 4K alignment */
if (intel_fb_is_ccs_aux_plane(fb, color_plane))
return mult * 4 * 1024;
/*
* FIXME ADL sees GGTT/DMAR faults with async
* flips unless we align to 16k at least.
* Figure out what's going on here...
*/
if (display->platform.alderlake_p &&
intel_plane_can_async_flip(plane, fb->format->format, fb->modifier))
return mult * 16 * 1024;
switch (fb->modifier) {
case DRM_FORMAT_MOD_LINEAR:
case I915_FORMAT_MOD_X_TILED:
case I915_FORMAT_MOD_Y_TILED:
case I915_FORMAT_MOD_4_TILED:
return mult * 4 * 1024;
case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
case I915_FORMAT_MOD_4_TILED_MTL_RC_CCS:
case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS:
case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
case I915_FORMAT_MOD_4_TILED_MTL_MC_CCS:
case I915_FORMAT_MOD_4_TILED_DG2_MC_CCS:
case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC:
case I915_FORMAT_MOD_4_TILED_MTL_RC_CCS_CC:
case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC:
case I915_FORMAT_MOD_4_TILED_BMG_CCS:
case I915_FORMAT_MOD_4_TILED_LNL_CCS:
/*
* Align to at least 4x1 main surface
* tiles (16K) to match 64B of AUX.
*/
return max(mult * 4 * 1024, 16 * 1024);
default:
MISSING_CASE(fb->modifier);
return 0;
}
}
static u32 skl_plane_min_alignment(struct intel_plane *plane,
const struct drm_framebuffer *fb,
int color_plane)
{
/*
* AUX_DIST needs only 4K alignment,
* as does ICL UV PLANE_SURF.
*/
if (color_plane != 0)
return 4 * 1024;
/*
* VT-d needs at least 256k alignment,
* but that's already covered below.
*/
switch (fb->modifier) {
case DRM_FORMAT_MOD_LINEAR:
case I915_FORMAT_MOD_X_TILED:
return 256 * 1024;
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;
default:
MISSING_CASE(fb->modifier);
return 0;
}
}
/* Preoffset values for YUV to RGB Conversion */
#define PREOFF_YUV_TO_RGB_HI 0x1800
#define PREOFF_YUV_TO_RGB_ME 0x0000
#define PREOFF_YUV_TO_RGB_LO 0x1800
#define ROFF(x) (((x) & 0xffff) << 16)
#define GOFF(x) (((x) & 0xffff) << 0)
#define BOFF(x) (((x) & 0xffff) << 16)
/*
* Programs the input color space conversion stage for ICL HDR planes.
* Note that it is assumed that this stage always happens after YUV
* range correction. Thus, the input to this stage is assumed to be
* in full-range YCbCr.
*/
static void
2024-09-30 20:04:13 +03:00
icl_program_input_csc(struct intel_dsb *dsb,
struct intel_plane *plane,
const struct intel_plane_state *plane_state)
{
struct intel_display *display = to_intel_display(plane);
enum pipe pipe = plane->pipe;
enum plane_id plane_id = plane->id;
static const u16 input_csc_matrix[][9] = {
/*
* BT.601 full range YCbCr -> full range RGB
* The matrix required is :
* [1.000, 0.000, 1.371,
* 1.000, -0.336, -0.698,
* 1.000, 1.732, 0.0000]
*/
[DRM_COLOR_YCBCR_BT601] = {
0x7AF8, 0x7800, 0x0,
0x8B28, 0x7800, 0x9AC0,
0x0, 0x7800, 0x7DD8,
},
/*
* BT.709 full range YCbCr -> full range RGB
* The matrix required is :
* [1.000, 0.000, 1.574,
* 1.000, -0.187, -0.468,
* 1.000, 1.855, 0.0000]
*/
[DRM_COLOR_YCBCR_BT709] = {
0x7C98, 0x7800, 0x0,
0x9EF8, 0x7800, 0xAC00,
0x0, 0x7800, 0x7ED8,
},
/*
* BT.2020 full range YCbCr -> full range RGB
* The matrix required is :
* [1.000, 0.000, 1.474,
* 1.000, -0.1645, -0.5713,
* 1.000, 1.8814, 0.0000]
*/
[DRM_COLOR_YCBCR_BT2020] = {
0x7BC8, 0x7800, 0x0,
0x8928, 0x7800, 0xAA88,
0x0, 0x7800, 0x7F10,
},
};
const u16 *csc = input_csc_matrix[plane_state->hw.color_encoding];
2024-09-30 20:04:13 +03:00
intel_de_write_dsb(display, dsb, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 0),
ROFF(csc[0]) | GOFF(csc[1]));
intel_de_write_dsb(display, dsb, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 1),
BOFF(csc[2]));
intel_de_write_dsb(display, dsb, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 2),
ROFF(csc[3]) | GOFF(csc[4]));
intel_de_write_dsb(display, dsb, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 3),
BOFF(csc[5]));
intel_de_write_dsb(display, dsb, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 4),
ROFF(csc[6]) | GOFF(csc[7]));
intel_de_write_dsb(display, dsb, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 5),
BOFF(csc[8]));
intel_de_write_dsb(display, dsb, PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 0),
PREOFF_YUV_TO_RGB_HI);
intel_de_write_dsb(display, dsb, PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 1),
PREOFF_YUV_TO_RGB_ME);
intel_de_write_dsb(display, dsb, PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 2),
PREOFF_YUV_TO_RGB_LO);
intel_de_write_dsb(display, dsb,
PLANE_INPUT_CSC_POSTOFF(pipe, plane_id, 0), 0x0);
intel_de_write_dsb(display, dsb,
PLANE_INPUT_CSC_POSTOFF(pipe, plane_id, 1), 0x0);
intel_de_write_dsb(display, dsb,
PLANE_INPUT_CSC_POSTOFF(pipe, plane_id, 2), 0x0);
}
static unsigned int skl_plane_stride_mult(const struct drm_framebuffer *fb,
int color_plane, unsigned int rotation)
{
/*
* The stride is either expressed as a multiple of 64 bytes chunks for
* linear buffers or in number of tiles for tiled buffers.
*/
if (is_surface_linear(fb, color_plane))
return 64;
else if (drm_rotation_90_or_270(rotation))
return intel_tile_height(fb, color_plane);
else
return intel_tile_width_bytes(fb, color_plane);
}
static u32 skl_plane_stride(const struct intel_plane_state *plane_state,
int color_plane)
{
const struct drm_framebuffer *fb = plane_state->hw.fb;
unsigned int rotation = plane_state->hw.rotation;
drm/i915/adlp/fb: Remove restriction on CCS AUX plane strides As opposed to other GEN12 platforms ADLP provides a way to program the stride of CCS surfaces independently of the main surface stride (within the corresponding limit of the preceding and succeeding power-of-two values of the main surface stride). Using this HW feature we can remove the POT stride restriction on CCS surfaces, making the ADLP CCS FB uAPI (FB modifiers) identical to that of TGL. The HW makes the CCS stride flexible programming possible by deriving the stride from the value programmed to the PLANE_STRIDE register. After that the HW rounds up this value to the next power-of-two value and uses this for walking the pages of the main surface mapped to GTT/DPT. To align with the above scheme, introduce a scanout_stride view parameter which will be programmed to the PLANE_STRIDE register and use the mapping_stride view param to store the POT aligned value of the same. By requiring userspace to pass in FBs with a CCS stride that aligns with the main surface stride (matching the requirement of all GEN12 platforms), the scanout_stride will be the userspace main surface stride and the mapping_stride will be the POT rounded value of the same. Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Cc: Juha-Pekka Heikkila <juhapekka.heikkila@gmail.com> Cc: Nanley G Chery <nanley.g.chery@intel.com> Cc: Sameer Lattannavar <sameer.lattannavar@intel.com> Signed-off-by: Imre Deak <imre.deak@intel.com> Reviewed-by: Juha-Pekka Heikkila <juhapekka.heikkila@gmail.com> Link: https://patchwork.freedesktop.org/patch/msgid/20211026225105.2783797-8-imre.deak@intel.com
2021-10-27 01:51:05 +03:00
u32 stride = plane_state->view.color_plane[color_plane].scanout_stride;
if (color_plane >= fb->format->num_planes)
return 0;
return stride / skl_plane_stride_mult(fb, color_plane, rotation);
}
static u32 skl_plane_ddb_reg_val(const struct skl_ddb_entry *entry)
{
if (!entry->end)
return 0;
return PLANE_BUF_END(entry->end - 1) |
PLANE_BUF_START(entry->start);
}
static u32 xe3_plane_min_ddb_reg_val(const u16 *min_ddb,
const u16 *interim_ddb)
{
u32 val = 0;
if (*min_ddb)
val |= PLANE_MIN_DBUF_BLOCKS(*min_ddb);
if (*interim_ddb)
val |= PLANE_INTERIM_DBUF_BLOCKS(*interim_ddb);
val |= val ? PLANE_AUTO_MIN_DBUF_EN : 0;
return val;
}
static u32 skl_plane_wm_reg_val(const struct skl_wm_level *level)
{
u32 val = 0;
if (level->enable)
val |= PLANE_WM_EN;
if (level->ignore_lines)
val |= PLANE_WM_IGNORE_LINES;
if (level->auto_min_alloc_wm_enable)
val |= PLANE_WM_AUTO_MIN_ALLOC_EN;
val |= REG_FIELD_PREP(PLANE_WM_BLOCKS_MASK, level->blocks);
val |= REG_FIELD_PREP(PLANE_WM_LINES_MASK, level->lines);
return val;
}
2024-09-30 20:04:13 +03:00
static void skl_write_plane_wm(struct intel_dsb *dsb,
struct intel_plane *plane,
const struct intel_crtc_state *crtc_state)
{
struct intel_display *display = to_intel_display(plane);
enum plane_id plane_id = plane->id;
enum pipe pipe = plane->pipe;
const struct skl_pipe_wm *pipe_wm = &crtc_state->wm.skl.optimal;
const struct skl_ddb_entry *ddb =
&crtc_state->wm.skl.plane_ddb[plane_id];
const struct skl_ddb_entry *ddb_y =
&crtc_state->wm.skl.plane_ddb_y[plane_id];
const u16 *min_ddb = &crtc_state->wm.skl.plane_min_ddb[plane_id];
const u16 *interim_ddb =
&crtc_state->wm.skl.plane_interim_ddb[plane_id];
int level;
for (level = 0; level < display->wm.num_levels; level++)
2024-09-30 20:04:13 +03:00
intel_de_write_dsb(display, dsb, PLANE_WM(pipe, plane_id, level),
skl_plane_wm_reg_val(skl_plane_wm_level(pipe_wm, plane_id, level)));
2024-09-30 20:04:13 +03:00
intel_de_write_dsb(display, dsb, PLANE_WM_TRANS(pipe, plane_id),
skl_plane_wm_reg_val(skl_plane_trans_wm(pipe_wm, plane_id)));
if (HAS_HW_SAGV_WM(display)) {
const struct skl_plane_wm *wm = &pipe_wm->planes[plane_id];
2024-09-30 20:04:13 +03:00
intel_de_write_dsb(display, dsb, PLANE_WM_SAGV(pipe, plane_id),
skl_plane_wm_reg_val(&wm->sagv.wm0));
intel_de_write_dsb(display, dsb, PLANE_WM_SAGV_TRANS(pipe, plane_id),
skl_plane_wm_reg_val(&wm->sagv.trans_wm));
}
2024-09-30 20:04:13 +03:00
intel_de_write_dsb(display, dsb, PLANE_BUF_CFG(pipe, plane_id),
skl_plane_ddb_reg_val(ddb));
if (DISPLAY_VER(display) < 11)
2024-09-30 20:04:13 +03:00
intel_de_write_dsb(display, dsb, PLANE_NV12_BUF_CFG(pipe, plane_id),
skl_plane_ddb_reg_val(ddb_y));
if (DISPLAY_VER(display) >= 30)
intel_de_write_dsb(display, dsb, PLANE_MIN_BUF_CFG(pipe, plane_id),
xe3_plane_min_ddb_reg_val(min_ddb, interim_ddb));
}
static void
2024-09-30 20:04:13 +03:00
skl_plane_disable_arm(struct intel_dsb *dsb,
struct intel_plane *plane,
drm/i915: Split update_plane() into update_noarm() + update_arm() The amount of plane registers we have to write has been steadily increasing, putting more pressure on the vblank evasion mechanism and forcing us to increase its time budget. Let's try to take some of the pressure off by splitting plane updates into two parts: 1) write all non-self arming plane registers, ie. the registers where the write actually does nothing until a separate arming register is also written which will cause the hardware to latch the new register values at the next start of vblank 2) write all self arming plane registers, ie. registers which always just latch at the next start of vblank, and registers which also arm other registers to do so Here we just provide the mechanism, but don't actually implement the split on any platform yet. so everything stays now in the _arm() hooks. Subsequently we can move a whole bunch of stuff into the _noarm() part, especially in more modern platforms where the number of registers we have to write is also the greatest. On older platforms this is less beneficial probably, but no real reason to deviate from a common behaviour. And let's sprinkle some TODOs around the areas that will need adapting. Cc: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20211018115030.3547-5-ville.syrjala@linux.intel.com Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com>
2021-10-18 14:50:25 +03:00
const struct intel_crtc_state *crtc_state)
{
struct intel_display *display = to_intel_display(plane);
enum plane_id plane_id = plane->id;
enum pipe pipe = plane->pipe;
2024-09-30 20:04:13 +03:00
skl_write_plane_wm(dsb, plane, crtc_state);
2024-09-30 20:04:13 +03:00
intel_de_write_dsb(display, dsb, PLANE_CTL(pipe, plane_id), 0);
intel_de_write_dsb(display, dsb, PLANE_SURF(pipe, plane_id), 0);
}
2024-09-30 20:04:13 +03:00
static void icl_plane_disable_sel_fetch_arm(struct intel_dsb *dsb,
struct intel_plane *plane,
const struct intel_crtc_state *crtc_state)
{
struct intel_display *display = to_intel_display(plane);
enum pipe pipe = plane->pipe;
if (!crtc_state->enable_psr2_sel_fetch)
return;
2024-09-30 20:04:13 +03:00
intel_de_write_dsb(display, dsb, SEL_FETCH_PLANE_CTL(pipe, plane->id), 0);
}
static void
2024-09-30 20:04:13 +03:00
icl_plane_disable_arm(struct intel_dsb *dsb,
struct intel_plane *plane,
const struct intel_crtc_state *crtc_state)
{
struct intel_display *display = to_intel_display(plane);
enum plane_id plane_id = plane->id;
enum pipe pipe = plane->pipe;
if (icl_is_hdr_plane(display, plane_id))
2024-09-30 20:04:13 +03:00
intel_de_write_dsb(display, dsb, PLANE_CUS_CTL(pipe, plane_id), 0);
2024-09-30 20:04:13 +03:00
skl_write_plane_wm(dsb, plane, crtc_state);
2024-09-30 20:04:13 +03:00
icl_plane_disable_sel_fetch_arm(dsb, plane, crtc_state);
intel_de_write_dsb(display, dsb, PLANE_CTL(pipe, plane_id), 0);
intel_de_write_dsb(display, dsb, PLANE_SURF(pipe, plane_id), 0);
}
static bool
skl_plane_get_hw_state(struct intel_plane *plane,
enum pipe *pipe)
{
struct intel_display *display = to_intel_display(plane);
enum intel_display_power_domain power_domain;
enum plane_id plane_id = plane->id;
intel_wakeref_t wakeref;
bool ret;
power_domain = POWER_DOMAIN_PIPE(plane->pipe);
wakeref = intel_display_power_get_if_enabled(display, power_domain);
if (!wakeref)
return false;
ret = intel_de_read(display, PLANE_CTL(plane->pipe, plane_id)) & PLANE_CTL_ENABLE;
*pipe = plane->pipe;
intel_display_power_put(display, power_domain, wakeref);
return ret;
}
static u32 skl_plane_ctl_format(u32 pixel_format)
{
switch (pixel_format) {
case DRM_FORMAT_C8:
return PLANE_CTL_FORMAT_INDEXED;
case DRM_FORMAT_RGB565:
return PLANE_CTL_FORMAT_RGB_565;
case DRM_FORMAT_XBGR8888:
case DRM_FORMAT_ABGR8888:
return PLANE_CTL_FORMAT_XRGB_8888 | PLANE_CTL_ORDER_RGBX;
case DRM_FORMAT_XRGB8888:
case DRM_FORMAT_ARGB8888:
return PLANE_CTL_FORMAT_XRGB_8888;
case DRM_FORMAT_XBGR2101010:
case DRM_FORMAT_ABGR2101010:
return PLANE_CTL_FORMAT_XRGB_2101010 | PLANE_CTL_ORDER_RGBX;
case DRM_FORMAT_XRGB2101010:
case DRM_FORMAT_ARGB2101010:
return PLANE_CTL_FORMAT_XRGB_2101010;
case DRM_FORMAT_XBGR16161616F:
case DRM_FORMAT_ABGR16161616F:
return PLANE_CTL_FORMAT_XRGB_16161616F | PLANE_CTL_ORDER_RGBX;
case DRM_FORMAT_XRGB16161616F:
case DRM_FORMAT_ARGB16161616F:
return PLANE_CTL_FORMAT_XRGB_16161616F;
case DRM_FORMAT_XYUV8888:
return PLANE_CTL_FORMAT_XYUV;
case DRM_FORMAT_YUYV:
return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_ORDER_YUYV;
case DRM_FORMAT_YVYU:
return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_ORDER_YVYU;
case DRM_FORMAT_UYVY:
return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_ORDER_UYVY;
case DRM_FORMAT_VYUY:
return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_ORDER_VYUY;
case DRM_FORMAT_NV12:
return PLANE_CTL_FORMAT_NV12;
case DRM_FORMAT_P010:
return PLANE_CTL_FORMAT_P010;
case DRM_FORMAT_P012:
return PLANE_CTL_FORMAT_P012;
case DRM_FORMAT_P016:
return PLANE_CTL_FORMAT_P016;
case DRM_FORMAT_Y210:
return PLANE_CTL_FORMAT_Y210;
case DRM_FORMAT_Y212:
return PLANE_CTL_FORMAT_Y212;
case DRM_FORMAT_Y216:
return PLANE_CTL_FORMAT_Y216;
case DRM_FORMAT_XVYU2101010:
return PLANE_CTL_FORMAT_Y410;
case DRM_FORMAT_XVYU12_16161616:
return PLANE_CTL_FORMAT_Y412;
case DRM_FORMAT_XVYU16161616:
return PLANE_CTL_FORMAT_Y416;
default:
MISSING_CASE(pixel_format);
}
return 0;
}
static u32 skl_plane_ctl_alpha(const struct intel_plane_state *plane_state)
{
if (!plane_state->hw.fb->format->has_alpha)
return PLANE_CTL_ALPHA_DISABLE;
switch (plane_state->hw.pixel_blend_mode) {
case DRM_MODE_BLEND_PIXEL_NONE:
return PLANE_CTL_ALPHA_DISABLE;
case DRM_MODE_BLEND_PREMULTI:
return PLANE_CTL_ALPHA_SW_PREMULTIPLY;
case DRM_MODE_BLEND_COVERAGE:
return PLANE_CTL_ALPHA_HW_PREMULTIPLY;
default:
MISSING_CASE(plane_state->hw.pixel_blend_mode);
return PLANE_CTL_ALPHA_DISABLE;
}
}
static u32 glk_plane_color_ctl_alpha(const struct intel_plane_state *plane_state)
{
if (!plane_state->hw.fb->format->has_alpha)
return PLANE_COLOR_ALPHA_DISABLE;
switch (plane_state->hw.pixel_blend_mode) {
case DRM_MODE_BLEND_PIXEL_NONE:
return PLANE_COLOR_ALPHA_DISABLE;
case DRM_MODE_BLEND_PREMULTI:
return PLANE_COLOR_ALPHA_SW_PREMULTIPLY;
case DRM_MODE_BLEND_COVERAGE:
return PLANE_COLOR_ALPHA_HW_PREMULTIPLY;
default:
MISSING_CASE(plane_state->hw.pixel_blend_mode);
return PLANE_COLOR_ALPHA_DISABLE;
}
}
static u32 skl_plane_ctl_tiling(u64 fb_modifier)
{
switch (fb_modifier) {
case DRM_FORMAT_MOD_LINEAR:
break;
case I915_FORMAT_MOD_X_TILED:
return PLANE_CTL_TILED_X;
case I915_FORMAT_MOD_Y_TILED:
return PLANE_CTL_TILED_Y;
case I915_FORMAT_MOD_4_TILED:
return PLANE_CTL_TILED_4;
case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS:
return PLANE_CTL_TILED_4 |
PLANE_CTL_RENDER_DECOMPRESSION_ENABLE |
PLANE_CTL_CLEAR_COLOR_DISABLE;
case I915_FORMAT_MOD_4_TILED_DG2_MC_CCS:
return PLANE_CTL_TILED_4 |
PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE |
PLANE_CTL_CLEAR_COLOR_DISABLE;
case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC:
return PLANE_CTL_TILED_4 | PLANE_CTL_RENDER_DECOMPRESSION_ENABLE;
case I915_FORMAT_MOD_4_TILED_MTL_RC_CCS:
return PLANE_CTL_TILED_4 |
PLANE_CTL_RENDER_DECOMPRESSION_ENABLE |
PLANE_CTL_CLEAR_COLOR_DISABLE;
case I915_FORMAT_MOD_4_TILED_MTL_RC_CCS_CC:
return PLANE_CTL_TILED_4 | PLANE_CTL_RENDER_DECOMPRESSION_ENABLE;
case I915_FORMAT_MOD_4_TILED_MTL_MC_CCS:
return PLANE_CTL_TILED_4 | PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE;
case I915_FORMAT_MOD_4_TILED_BMG_CCS:
case I915_FORMAT_MOD_4_TILED_LNL_CCS:
return PLANE_CTL_TILED_4 | PLANE_CTL_RENDER_DECOMPRESSION_ENABLE;
case I915_FORMAT_MOD_Y_TILED_CCS:
case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC:
return PLANE_CTL_TILED_Y | PLANE_CTL_RENDER_DECOMPRESSION_ENABLE;
case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
return PLANE_CTL_TILED_Y |
PLANE_CTL_RENDER_DECOMPRESSION_ENABLE |
PLANE_CTL_CLEAR_COLOR_DISABLE;
case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
return PLANE_CTL_TILED_Y | PLANE_CTL_MEDIA_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_RENDER_DECOMPRESSION_ENABLE;
default:
MISSING_CASE(fb_modifier);
}
return 0;
}
static u32 skl_plane_ctl_rotate(unsigned int rotate)
{
switch (rotate) {
case DRM_MODE_ROTATE_0:
break;
/*
* DRM_MODE_ROTATE_ is counter clockwise to stay compatible with Xrandr
* while i915 HW rotation is clockwise, that's why this swapping.
*/
case DRM_MODE_ROTATE_90:
return PLANE_CTL_ROTATE_270;
case DRM_MODE_ROTATE_180:
return PLANE_CTL_ROTATE_180;
case DRM_MODE_ROTATE_270:
return PLANE_CTL_ROTATE_90;
default:
MISSING_CASE(rotate);
}
return 0;
}
static u32 icl_plane_ctl_flip(unsigned int reflect)
{
switch (reflect) {
case 0:
break;
case DRM_MODE_REFLECT_X:
return PLANE_CTL_FLIP_HORIZONTAL;
case DRM_MODE_REFLECT_Y:
default:
MISSING_CASE(reflect);
}
return 0;
}
static u32 adlp_plane_ctl_arb_slots(const struct intel_plane_state *plane_state)
{
const struct drm_framebuffer *fb = plane_state->hw.fb;
if (intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier)) {
switch (fb->format->cpp[0]) {
case 2:
return PLANE_CTL_ARB_SLOTS(1);
default:
return PLANE_CTL_ARB_SLOTS(0);
}
} else {
switch (fb->format->cpp[0]) {
case 8:
return PLANE_CTL_ARB_SLOTS(3);
case 4:
return PLANE_CTL_ARB_SLOTS(1);
default:
return PLANE_CTL_ARB_SLOTS(0);
}
}
}
static u32 skl_plane_ctl_crtc(const struct intel_crtc_state *crtc_state)
{
struct intel_display *display = to_intel_display(crtc_state);
u32 plane_ctl = 0;
if (DISPLAY_VER(display) >= 10)
return plane_ctl;
if (crtc_state->gamma_enable)
plane_ctl |= PLANE_CTL_PIPE_GAMMA_ENABLE;
if (crtc_state->csc_enable)
plane_ctl |= PLANE_CTL_PIPE_CSC_ENABLE;
return plane_ctl;
}
static u32 skl_plane_ctl(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state)
{
struct intel_display *display = to_intel_display(plane_state);
const struct drm_framebuffer *fb = plane_state->hw.fb;
unsigned int rotation = plane_state->hw.rotation;
const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
u32 plane_ctl;
plane_ctl = PLANE_CTL_ENABLE;
if (DISPLAY_VER(display) < 10) {
plane_ctl |= skl_plane_ctl_alpha(plane_state);
plane_ctl |= PLANE_CTL_PLANE_GAMMA_DISABLE;
if (plane_state->hw.color_encoding == DRM_COLOR_YCBCR_BT709)
plane_ctl |= PLANE_CTL_YUV_TO_RGB_CSC_FORMAT_BT709;
if (plane_state->hw.color_range == DRM_COLOR_YCBCR_FULL_RANGE)
plane_ctl |= PLANE_CTL_YUV_RANGE_CORRECTION_DISABLE;
}
plane_ctl |= skl_plane_ctl_format(fb->format->format);
plane_ctl |= skl_plane_ctl_tiling(fb->modifier);
plane_ctl |= skl_plane_ctl_rotate(rotation & DRM_MODE_ROTATE_MASK);
if (DISPLAY_VER(display) >= 11)
plane_ctl |= icl_plane_ctl_flip(rotation &
DRM_MODE_REFLECT_MASK);
if (key->flags & I915_SET_COLORKEY_DESTINATION)
plane_ctl |= PLANE_CTL_KEY_ENABLE_DESTINATION;
else if (key->flags & I915_SET_COLORKEY_SOURCE)
plane_ctl |= PLANE_CTL_KEY_ENABLE_SOURCE;
/* Wa_22012358565:adl-p */
if (DISPLAY_VER(display) == 13)
plane_ctl |= adlp_plane_ctl_arb_slots(plane_state);
return plane_ctl;
}
static u32 glk_plane_color_ctl_crtc(const struct intel_crtc_state *crtc_state)
{
struct intel_display *display = to_intel_display(crtc_state);
u32 plane_color_ctl = 0;
if (DISPLAY_VER(display) >= 11)
return plane_color_ctl;
if (crtc_state->gamma_enable)
plane_color_ctl |= PLANE_COLOR_PIPE_GAMMA_ENABLE;
if (crtc_state->csc_enable)
plane_color_ctl |= PLANE_COLOR_PIPE_CSC_ENABLE;
return plane_color_ctl;
}
static u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state)
{
struct intel_display *display = to_intel_display(plane_state);
const struct drm_framebuffer *fb = plane_state->hw.fb;
struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
u32 plane_color_ctl = 0;
plane_color_ctl |= PLANE_COLOR_PLANE_GAMMA_DISABLE;
plane_color_ctl |= glk_plane_color_ctl_alpha(plane_state);
if (fb->format->is_yuv && !icl_is_hdr_plane(display, plane->id)) {
switch (plane_state->hw.color_encoding) {
case DRM_COLOR_YCBCR_BT709:
plane_color_ctl |= PLANE_COLOR_CSC_MODE_YUV709_TO_RGB709;
break;
case DRM_COLOR_YCBCR_BT2020:
plane_color_ctl |=
PLANE_COLOR_CSC_MODE_YUV2020_TO_RGB2020;
break;
default:
plane_color_ctl |=
PLANE_COLOR_CSC_MODE_YUV601_TO_RGB601;
}
if (plane_state->hw.color_range == DRM_COLOR_YCBCR_FULL_RANGE)
plane_color_ctl |= PLANE_COLOR_YUV_RANGE_CORRECTION_DISABLE;
} else if (fb->format->is_yuv) {
plane_color_ctl |= PLANE_COLOR_INPUT_CSC_ENABLE;
if (plane_state->hw.color_range == DRM_COLOR_YCBCR_FULL_RANGE)
plane_color_ctl |= PLANE_COLOR_YUV_RANGE_CORRECTION_DISABLE;
}
if (plane_state->force_black)
plane_color_ctl |= PLANE_COLOR_PLANE_CSC_ENABLE;
return plane_color_ctl;
}
static u32 skl_surf_address(const struct intel_plane_state *plane_state,
int color_plane)
{
struct intel_display *display = to_intel_display(plane_state);
const struct drm_framebuffer *fb = plane_state->hw.fb;
u32 offset = plane_state->view.color_plane[color_plane].offset;
if (intel_fb_uses_dpt(fb)) {
/*
* The DPT object contains only one vma, so the VMA's offset
* within the DPT is always 0.
*/
drm_WARN_ON(display->drm, plane_state->dpt_vma &&
intel_dpt_offset(plane_state->dpt_vma));
drm_WARN_ON(display->drm, offset & 0x1fffff);
return offset >> 9;
} else {
drm_WARN_ON(display->drm, offset & 0xfff);
return offset;
}
}
static u32 skl_plane_surf(const struct intel_plane_state *plane_state,
int color_plane)
{
u32 plane_surf;
plane_surf = intel_plane_ggtt_offset(plane_state) +
skl_surf_address(plane_state, color_plane);
if (plane_state->decrypt)
plane_surf |= PLANE_SURF_DECRYPT;
return plane_surf;
}
u32 skl_plane_aux_dist(const struct intel_plane_state *plane_state,
int color_plane)
{
struct intel_display *display = to_intel_display(plane_state);
const struct drm_framebuffer *fb = plane_state->hw.fb;
int aux_plane = skl_main_to_aux_plane(fb, color_plane);
u32 aux_dist;
if (!aux_plane)
return 0;
aux_dist = skl_surf_address(plane_state, aux_plane) -
skl_surf_address(plane_state, color_plane);
if (DISPLAY_VER(display) < 12)
aux_dist |= PLANE_AUX_STRIDE(skl_plane_stride(plane_state, aux_plane));
return aux_dist;
}
static u32 skl_plane_keyval(const struct intel_plane_state *plane_state)
{
const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
return key->min_value;
}
static u32 skl_plane_keymax(const struct intel_plane_state *plane_state)
{
const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
u8 alpha = plane_state->hw.alpha >> 8;
return (key->max_value & 0xffffff) | PLANE_KEYMAX_ALPHA(alpha);
}
static u32 skl_plane_keymsk(const struct intel_plane_state *plane_state)
{
const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
u8 alpha = plane_state->hw.alpha >> 8;
u32 keymsk;
keymsk = key->channel_mask & 0x7ffffff;
if (alpha < 0xff)
keymsk |= PLANE_KEYMSK_ALPHA_ENABLE;
return keymsk;
}
2024-09-30 20:04:13 +03:00
static void icl_plane_csc_load_black(struct intel_dsb *dsb,
struct intel_plane *plane,
const struct intel_crtc_state *crtc_state)
{
struct intel_display *display = to_intel_display(plane);
enum plane_id plane_id = plane->id;
enum pipe pipe = plane->pipe;
2024-09-30 20:04:13 +03:00
intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane_id, 0), 0);
intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane_id, 1), 0);
2024-09-30 20:04:13 +03:00
intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane_id, 2), 0);
intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane_id, 3), 0);
2024-09-30 20:04:13 +03:00
intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane_id, 4), 0);
intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane_id, 5), 0);
2024-09-30 20:04:13 +03:00
intel_de_write_dsb(display, dsb, PLANE_CSC_PREOFF(pipe, plane_id, 0), 0);
intel_de_write_dsb(display, dsb, PLANE_CSC_PREOFF(pipe, plane_id, 1), 0);
intel_de_write_dsb(display, dsb, PLANE_CSC_PREOFF(pipe, plane_id, 2), 0);
2024-09-30 20:04:13 +03:00
intel_de_write_dsb(display, dsb, PLANE_CSC_POSTOFF(pipe, plane_id, 0), 0);
intel_de_write_dsb(display, dsb, PLANE_CSC_POSTOFF(pipe, plane_id, 1), 0);
intel_de_write_dsb(display, dsb, PLANE_CSC_POSTOFF(pipe, plane_id, 2), 0);
}
static int icl_plane_color_plane(const struct intel_plane_state *plane_state)
{
if (plane_state->planar_linked_plane && !plane_state->is_y_plane)
return 1;
else
return 0;
}
static void
2024-09-30 20:04:13 +03:00
skl_plane_update_noarm(struct intel_dsb *dsb,
struct intel_plane *plane,
const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state)
{
struct intel_display *display = to_intel_display(plane);
enum plane_id plane_id = plane->id;
enum pipe pipe = plane->pipe;
u32 stride = skl_plane_stride(plane_state, 0);
int crtc_x = plane_state->uapi.dst.x1;
int crtc_y = plane_state->uapi.dst.y1;
u32 src_w = drm_rect_width(&plane_state->uapi.src) >> 16;
u32 src_h = drm_rect_height(&plane_state->uapi.src) >> 16;
/* The scaler will handle the output position */
if (plane_state->scaler_id >= 0) {
crtc_x = 0;
crtc_y = 0;
}
2024-09-30 20:04:13 +03:00
intel_de_write_dsb(display, dsb, PLANE_STRIDE(pipe, plane_id),
PLANE_STRIDE_(stride));
intel_de_write_dsb(display, dsb, PLANE_POS(pipe, plane_id),
PLANE_POS_Y(crtc_y) | PLANE_POS_X(crtc_x));
intel_de_write_dsb(display, dsb, PLANE_SIZE(pipe, plane_id),
PLANE_HEIGHT(src_h - 1) | PLANE_WIDTH(src_w - 1));
2024-09-30 20:04:13 +03:00
skl_write_plane_wm(dsb, plane, crtc_state);
}
static void
2024-09-30 20:04:13 +03:00
skl_plane_update_arm(struct intel_dsb *dsb,
struct intel_plane *plane,
const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state)
{
struct intel_display *display = to_intel_display(plane);
enum plane_id plane_id = plane->id;
enum pipe pipe = plane->pipe;
u32 x = plane_state->view.color_plane[0].x;
u32 y = plane_state->view.color_plane[0].y;
u32 plane_ctl, plane_color_ctl = 0;
plane_ctl = plane_state->ctl |
skl_plane_ctl_crtc(crtc_state);
/* see intel_plane_atomic_calc_changes() */
if (plane->need_async_flip_toggle_wa &&
crtc_state->async_flip_planes & BIT(plane->id))
plane_ctl |= PLANE_CTL_ASYNC_FLIP;
if (DISPLAY_VER(display) >= 10)
plane_color_ctl = plane_state->color_ctl |
glk_plane_color_ctl_crtc(crtc_state);
2024-09-30 20:04:13 +03:00
intel_de_write_dsb(display, dsb, PLANE_KEYVAL(pipe, plane_id),
skl_plane_keyval(plane_state));
intel_de_write_dsb(display, dsb, PLANE_KEYMSK(pipe, plane_id),
skl_plane_keymsk(plane_state));
intel_de_write_dsb(display, dsb, PLANE_KEYMAX(pipe, plane_id),
skl_plane_keymax(plane_state));
2024-09-30 20:04:13 +03:00
intel_de_write_dsb(display, dsb, PLANE_OFFSET(pipe, plane_id),
PLANE_OFFSET_Y(y) | PLANE_OFFSET_X(x));
2024-09-30 20:04:13 +03:00
intel_de_write_dsb(display, dsb, PLANE_AUX_DIST(pipe, plane_id),
skl_plane_aux_dist(plane_state, 0));
2024-09-30 20:04:13 +03:00
intel_de_write_dsb(display, dsb, PLANE_AUX_OFFSET(pipe, plane_id),
PLANE_OFFSET_Y(plane_state->view.color_plane[1].y) |
PLANE_OFFSET_X(plane_state->view.color_plane[1].x));
if (DISPLAY_VER(display) >= 10)
2024-09-30 20:04:13 +03:00
intel_de_write_dsb(display, dsb, PLANE_COLOR_CTL(pipe, plane_id),
plane_color_ctl);
/*
* Enable the scaler before the plane so that we don't
* get a catastrophic underrun even if the two operations
* end up happening in two different frames.
*
* TODO: split into noarm+arm pair
*/
if (plane_state->scaler_id >= 0)
skl_program_plane_scaler(dsb, plane, crtc_state, plane_state);
/*
* The control register self-arms if the plane was previously
* disabled. Try to make the plane enable atomic by writing
* the control register just before the surface register.
*/
2024-09-30 20:04:13 +03:00
intel_de_write_dsb(display, dsb, PLANE_CTL(pipe, plane_id),
plane_ctl);
intel_de_write_dsb(display, dsb, PLANE_SURF(pipe, plane_id),
skl_plane_surf(plane_state, 0));
}
2024-09-30 20:04:13 +03:00
static void icl_plane_update_sel_fetch_noarm(struct intel_dsb *dsb,
struct intel_plane *plane,
const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state,
int color_plane)
{
struct intel_display *display = to_intel_display(plane);
enum pipe pipe = plane->pipe;
const struct drm_rect *clip;
u32 val;
int x, y;
if (!crtc_state->enable_psr2_sel_fetch)
return;
clip = &plane_state->psr2_sel_fetch_area;
if (crtc_state->enable_psr2_su_region_et)
y = max(0, plane_state->uapi.dst.y1 - crtc_state->psr2_su_area.y1);
else
y = (clip->y1 + plane_state->uapi.dst.y1);
val = y << 16;
val |= plane_state->uapi.dst.x1;
2024-09-30 20:04:13 +03:00
intel_de_write_dsb(display, dsb, SEL_FETCH_PLANE_POS(pipe, plane->id), val);
x = plane_state->view.color_plane[color_plane].x;
/*
* From Bspec: UV surface Start Y Position = half of Y plane Y
* start position.
*/
if (!color_plane)
y = plane_state->view.color_plane[color_plane].y + clip->y1;
else
y = plane_state->view.color_plane[color_plane].y + clip->y1 / 2;
val = y << 16 | x;
2024-09-30 20:04:13 +03:00
intel_de_write_dsb(display, dsb, SEL_FETCH_PLANE_OFFSET(pipe, plane->id), val);
/* Sizes are 0 based */
val = (drm_rect_height(clip) - 1) << 16;
val |= (drm_rect_width(&plane_state->uapi.src) >> 16) - 1;
2024-09-30 20:04:13 +03:00
intel_de_write_dsb(display, dsb, SEL_FETCH_PLANE_SIZE(pipe, plane->id), val);
}
static void
2024-09-30 20:04:13 +03:00
icl_plane_update_noarm(struct intel_dsb *dsb,
struct intel_plane *plane,
const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state)
{
struct intel_display *display = to_intel_display(plane);
enum plane_id plane_id = plane->id;
enum pipe pipe = plane->pipe;
int color_plane = icl_plane_color_plane(plane_state);
u32 stride = skl_plane_stride(plane_state, color_plane);
const struct drm_framebuffer *fb = plane_state->hw.fb;
int crtc_x = plane_state->uapi.dst.x1;
int crtc_y = plane_state->uapi.dst.y1;
int x = plane_state->view.color_plane[color_plane].x;
int y = plane_state->view.color_plane[color_plane].y;
int src_w = drm_rect_width(&plane_state->uapi.src) >> 16;
int src_h = drm_rect_height(&plane_state->uapi.src) >> 16;
u32 plane_color_ctl;
plane_color_ctl = plane_state->color_ctl |
glk_plane_color_ctl_crtc(crtc_state);
/* The scaler will handle the output position */
if (plane_state->scaler_id >= 0) {
crtc_x = 0;
crtc_y = 0;
}
2024-09-30 20:04:13 +03:00
intel_de_write_dsb(display, dsb, PLANE_STRIDE(pipe, plane_id),
PLANE_STRIDE_(stride));
intel_de_write_dsb(display, dsb, PLANE_POS(pipe, plane_id),
PLANE_POS_Y(crtc_y) | PLANE_POS_X(crtc_x));
intel_de_write_dsb(display, dsb, PLANE_SIZE(pipe, plane_id),
PLANE_HEIGHT(src_h - 1) | PLANE_WIDTH(src_w - 1));
2024-09-30 20:04:13 +03:00
intel_de_write_dsb(display, dsb, PLANE_KEYVAL(pipe, plane_id),
skl_plane_keyval(plane_state));
intel_de_write_dsb(display, dsb, PLANE_KEYMSK(pipe, plane_id),
skl_plane_keymsk(plane_state));
intel_de_write_dsb(display, dsb, PLANE_KEYMAX(pipe, plane_id),
skl_plane_keymax(plane_state));
2024-09-30 20:04:13 +03:00
intel_de_write_dsb(display, dsb, PLANE_OFFSET(pipe, plane_id),
PLANE_OFFSET_Y(y) | PLANE_OFFSET_X(x));
if (intel_fb_is_rc_ccs_cc_modifier(fb->modifier)) {
2024-09-30 20:04:13 +03:00
intel_de_write_dsb(display, dsb, PLANE_CC_VAL(pipe, plane_id, 0),
lower_32_bits(plane_state->ccval));
intel_de_write_dsb(display, dsb, PLANE_CC_VAL(pipe, plane_id, 1),
upper_32_bits(plane_state->ccval));
}
/* FLAT CCS doesn't need to program AUX_DIST */
if (!HAS_FLAT_CCS(to_i915(display->drm)) && DISPLAY_VER(display) < 20)
2024-09-30 20:04:13 +03:00
intel_de_write_dsb(display, dsb, PLANE_AUX_DIST(pipe, plane_id),
skl_plane_aux_dist(plane_state, color_plane));
if (icl_is_hdr_plane(display, plane_id))
2024-09-30 20:04:13 +03:00
intel_de_write_dsb(display, dsb, PLANE_CUS_CTL(pipe, plane_id),
plane_state->cus_ctl);
2024-09-30 20:04:13 +03:00
intel_de_write_dsb(display, dsb, PLANE_COLOR_CTL(pipe, plane_id),
plane_color_ctl);
if (fb->format->is_yuv && icl_is_hdr_plane(display, plane_id))
2024-09-30 20:04:13 +03:00
icl_program_input_csc(dsb, plane, plane_state);
2024-09-30 20:04:13 +03:00
skl_write_plane_wm(dsb, plane, crtc_state);
/*
* FIXME: pxp session invalidation can hit any time even at time of commit
* or after the commit, display content will be garbage.
*/
if (plane_state->force_black)
2024-09-30 20:04:13 +03:00
icl_plane_csc_load_black(dsb, plane, crtc_state);
2024-09-30 20:04:13 +03:00
icl_plane_update_sel_fetch_noarm(dsb, plane, crtc_state, plane_state, color_plane);
}
2024-09-30 20:04:13 +03:00
static void icl_plane_update_sel_fetch_arm(struct intel_dsb *dsb,
struct intel_plane *plane,
const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state)
{
struct intel_display *display = to_intel_display(plane);
enum pipe pipe = plane->pipe;
if (!crtc_state->enable_psr2_sel_fetch)
return;
if (drm_rect_height(&plane_state->psr2_sel_fetch_area) > 0)
2024-09-30 20:04:13 +03:00
intel_de_write_dsb(display, dsb, SEL_FETCH_PLANE_CTL(pipe, plane->id),
SEL_FETCH_PLANE_CTL_ENABLE);
else
2024-09-30 20:04:13 +03:00
icl_plane_disable_sel_fetch_arm(dsb, plane, crtc_state);
drm/i915: Split skl+ plane update into noarm+arm pair Chop skl_program_plane() into two halves. Fist half becomes the _noarm() variant, second part the _arm() variant. Fortunately I have already previously grouped the register writes into roughtly the correct order, so the split looks surprisingly clean. A few notable oddities I did not realize were self arming are AUX_DIST and COLOR_CTL. i915_update_info doesn't look too terrible on my cfl running kms_atomic_transition --r plane-all-transition --extended: w/o patch w/ patch Updates: 2178 Updates: 2018 | | 1us | 1us | | | 4us | 4us |***** |********* |********** 16us |********** 16us |******* |*** | 66us | 66us | | | 262us | 262us | | | 1ms | 1ms | | | 4ms | 4ms | | | 17ms | 17ms | | | Min update: 8332ns Min update: 6164ns Max update: 48758ns Max update: 31808ns Average update: 19959ns Average update: 13159ns Overruns > 100us: 0 Overruns > 100us: 0 And with lockdep enabled: w/o patch w/ patch Updates: 2177 Updates: 2172 | | 1us | 1us | | | 4us | 4us | |******* |********* 16us |********** 16us |********** |******* |* 66us | 66us | | | 262us | 262us | | | 1ms | 1ms | | | 4ms | 4ms | | | 17ms | 17ms | | | Min update: 12645ns Min update: 9980ns Max update: 50153ns Max update: 33533ns Average update: 25337ns Average update: 18245ns Overruns > 250us: 0 Overruns > 250us: 0 TODO: On icl+ everything seems to be armed by PLANE_SURF, so we can optimize this even further on modern platforms. But I think there's a bit of refactoring to be done first to figure out the best way to go about it (eg. just reusing the current skl+ functions, or doing a lower level split). TODO: Split scaler programming as well, but IIRC the scaler has some oddball double buffering behaviour on some platforms, so needs proper reverse engineering Cc: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20211018115030.3547-6-ville.syrjala@linux.intel.com Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com>
2021-10-18 14:50:26 +03:00
}
static void
2024-09-30 20:04:13 +03:00
icl_plane_update_arm(struct intel_dsb *dsb,
struct intel_plane *plane,
const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state)
drm/i915: Split skl+ plane update into noarm+arm pair Chop skl_program_plane() into two halves. Fist half becomes the _noarm() variant, second part the _arm() variant. Fortunately I have already previously grouped the register writes into roughtly the correct order, so the split looks surprisingly clean. A few notable oddities I did not realize were self arming are AUX_DIST and COLOR_CTL. i915_update_info doesn't look too terrible on my cfl running kms_atomic_transition --r plane-all-transition --extended: w/o patch w/ patch Updates: 2178 Updates: 2018 | | 1us | 1us | | | 4us | 4us |***** |********* |********** 16us |********** 16us |******* |*** | 66us | 66us | | | 262us | 262us | | | 1ms | 1ms | | | 4ms | 4ms | | | 17ms | 17ms | | | Min update: 8332ns Min update: 6164ns Max update: 48758ns Max update: 31808ns Average update: 19959ns Average update: 13159ns Overruns > 100us: 0 Overruns > 100us: 0 And with lockdep enabled: w/o patch w/ patch Updates: 2177 Updates: 2172 | | 1us | 1us | | | 4us | 4us | |******* |********* 16us |********** 16us |********** |******* |* 66us | 66us | | | 262us | 262us | | | 1ms | 1ms | | | 4ms | 4ms | | | 17ms | 17ms | | | Min update: 12645ns Min update: 9980ns Max update: 50153ns Max update: 33533ns Average update: 25337ns Average update: 18245ns Overruns > 250us: 0 Overruns > 250us: 0 TODO: On icl+ everything seems to be armed by PLANE_SURF, so we can optimize this even further on modern platforms. But I think there's a bit of refactoring to be done first to figure out the best way to go about it (eg. just reusing the current skl+ functions, or doing a lower level split). TODO: Split scaler programming as well, but IIRC the scaler has some oddball double buffering behaviour on some platforms, so needs proper reverse engineering Cc: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20211018115030.3547-6-ville.syrjala@linux.intel.com Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com>
2021-10-18 14:50:26 +03:00
{
struct intel_display *display = to_intel_display(plane);
drm/i915: Split skl+ plane update into noarm+arm pair Chop skl_program_plane() into two halves. Fist half becomes the _noarm() variant, second part the _arm() variant. Fortunately I have already previously grouped the register writes into roughtly the correct order, so the split looks surprisingly clean. A few notable oddities I did not realize were self arming are AUX_DIST and COLOR_CTL. i915_update_info doesn't look too terrible on my cfl running kms_atomic_transition --r plane-all-transition --extended: w/o patch w/ patch Updates: 2178 Updates: 2018 | | 1us | 1us | | | 4us | 4us |***** |********* |********** 16us |********** 16us |******* |*** | 66us | 66us | | | 262us | 262us | | | 1ms | 1ms | | | 4ms | 4ms | | | 17ms | 17ms | | | Min update: 8332ns Min update: 6164ns Max update: 48758ns Max update: 31808ns Average update: 19959ns Average update: 13159ns Overruns > 100us: 0 Overruns > 100us: 0 And with lockdep enabled: w/o patch w/ patch Updates: 2177 Updates: 2172 | | 1us | 1us | | | 4us | 4us | |******* |********* 16us |********** 16us |********** |******* |* 66us | 66us | | | 262us | 262us | | | 1ms | 1ms | | | 4ms | 4ms | | | 17ms | 17ms | | | Min update: 12645ns Min update: 9980ns Max update: 50153ns Max update: 33533ns Average update: 25337ns Average update: 18245ns Overruns > 250us: 0 Overruns > 250us: 0 TODO: On icl+ everything seems to be armed by PLANE_SURF, so we can optimize this even further on modern platforms. But I think there's a bit of refactoring to be done first to figure out the best way to go about it (eg. just reusing the current skl+ functions, or doing a lower level split). TODO: Split scaler programming as well, but IIRC the scaler has some oddball double buffering behaviour on some platforms, so needs proper reverse engineering Cc: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20211018115030.3547-6-ville.syrjala@linux.intel.com Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com>
2021-10-18 14:50:26 +03:00
enum plane_id plane_id = plane->id;
enum pipe pipe = plane->pipe;
int color_plane = icl_plane_color_plane(plane_state);
u32 plane_ctl;
drm/i915: Split skl+ plane update into noarm+arm pair Chop skl_program_plane() into two halves. Fist half becomes the _noarm() variant, second part the _arm() variant. Fortunately I have already previously grouped the register writes into roughtly the correct order, so the split looks surprisingly clean. A few notable oddities I did not realize were self arming are AUX_DIST and COLOR_CTL. i915_update_info doesn't look too terrible on my cfl running kms_atomic_transition --r plane-all-transition --extended: w/o patch w/ patch Updates: 2178 Updates: 2018 | | 1us | 1us | | | 4us | 4us |***** |********* |********** 16us |********** 16us |******* |*** | 66us | 66us | | | 262us | 262us | | | 1ms | 1ms | | | 4ms | 4ms | | | 17ms | 17ms | | | Min update: 8332ns Min update: 6164ns Max update: 48758ns Max update: 31808ns Average update: 19959ns Average update: 13159ns Overruns > 100us: 0 Overruns > 100us: 0 And with lockdep enabled: w/o patch w/ patch Updates: 2177 Updates: 2172 | | 1us | 1us | | | 4us | 4us | |******* |********* 16us |********** 16us |********** |******* |* 66us | 66us | | | 262us | 262us | | | 1ms | 1ms | | | 4ms | 4ms | | | 17ms | 17ms | | | Min update: 12645ns Min update: 9980ns Max update: 50153ns Max update: 33533ns Average update: 25337ns Average update: 18245ns Overruns > 250us: 0 Overruns > 250us: 0 TODO: On icl+ everything seems to be armed by PLANE_SURF, so we can optimize this even further on modern platforms. But I think there's a bit of refactoring to be done first to figure out the best way to go about it (eg. just reusing the current skl+ functions, or doing a lower level split). TODO: Split scaler programming as well, but IIRC the scaler has some oddball double buffering behaviour on some platforms, so needs proper reverse engineering Cc: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20211018115030.3547-6-ville.syrjala@linux.intel.com Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com>
2021-10-18 14:50:26 +03:00
plane_ctl = plane_state->ctl |
skl_plane_ctl_crtc(crtc_state);
drm/i915: Split skl+ plane update into noarm+arm pair Chop skl_program_plane() into two halves. Fist half becomes the _noarm() variant, second part the _arm() variant. Fortunately I have already previously grouped the register writes into roughtly the correct order, so the split looks surprisingly clean. A few notable oddities I did not realize were self arming are AUX_DIST and COLOR_CTL. i915_update_info doesn't look too terrible on my cfl running kms_atomic_transition --r plane-all-transition --extended: w/o patch w/ patch Updates: 2178 Updates: 2018 | | 1us | 1us | | | 4us | 4us |***** |********* |********** 16us |********** 16us |******* |*** | 66us | 66us | | | 262us | 262us | | | 1ms | 1ms | | | 4ms | 4ms | | | 17ms | 17ms | | | Min update: 8332ns Min update: 6164ns Max update: 48758ns Max update: 31808ns Average update: 19959ns Average update: 13159ns Overruns > 100us: 0 Overruns > 100us: 0 And with lockdep enabled: w/o patch w/ patch Updates: 2177 Updates: 2172 | | 1us | 1us | | | 4us | 4us | |******* |********* 16us |********** 16us |********** |******* |* 66us | 66us | | | 262us | 262us | | | 1ms | 1ms | | | 4ms | 4ms | | | 17ms | 17ms | | | Min update: 12645ns Min update: 9980ns Max update: 50153ns Max update: 33533ns Average update: 25337ns Average update: 18245ns Overruns > 250us: 0 Overruns > 250us: 0 TODO: On icl+ everything seems to be armed by PLANE_SURF, so we can optimize this even further on modern platforms. But I think there's a bit of refactoring to be done first to figure out the best way to go about it (eg. just reusing the current skl+ functions, or doing a lower level split). TODO: Split scaler programming as well, but IIRC the scaler has some oddball double buffering behaviour on some platforms, so needs proper reverse engineering Cc: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20211018115030.3547-6-ville.syrjala@linux.intel.com Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com>
2021-10-18 14:50:26 +03:00
/*
* Enable the scaler before the plane so that we don't
* get a catastrophic underrun even if the two operations
* end up happening in two different frames.
drm/i915: Split skl+ plane update into noarm+arm pair Chop skl_program_plane() into two halves. Fist half becomes the _noarm() variant, second part the _arm() variant. Fortunately I have already previously grouped the register writes into roughtly the correct order, so the split looks surprisingly clean. A few notable oddities I did not realize were self arming are AUX_DIST and COLOR_CTL. i915_update_info doesn't look too terrible on my cfl running kms_atomic_transition --r plane-all-transition --extended: w/o patch w/ patch Updates: 2178 Updates: 2018 | | 1us | 1us | | | 4us | 4us |***** |********* |********** 16us |********** 16us |******* |*** | 66us | 66us | | | 262us | 262us | | | 1ms | 1ms | | | 4ms | 4ms | | | 17ms | 17ms | | | Min update: 8332ns Min update: 6164ns Max update: 48758ns Max update: 31808ns Average update: 19959ns Average update: 13159ns Overruns > 100us: 0 Overruns > 100us: 0 And with lockdep enabled: w/o patch w/ patch Updates: 2177 Updates: 2172 | | 1us | 1us | | | 4us | 4us | |******* |********* 16us |********** 16us |********** |******* |* 66us | 66us | | | 262us | 262us | | | 1ms | 1ms | | | 4ms | 4ms | | | 17ms | 17ms | | | Min update: 12645ns Min update: 9980ns Max update: 50153ns Max update: 33533ns Average update: 25337ns Average update: 18245ns Overruns > 250us: 0 Overruns > 250us: 0 TODO: On icl+ everything seems to be armed by PLANE_SURF, so we can optimize this even further on modern platforms. But I think there's a bit of refactoring to be done first to figure out the best way to go about it (eg. just reusing the current skl+ functions, or doing a lower level split). TODO: Split scaler programming as well, but IIRC the scaler has some oddball double buffering behaviour on some platforms, so needs proper reverse engineering Cc: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20211018115030.3547-6-ville.syrjala@linux.intel.com Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com>
2021-10-18 14:50:26 +03:00
*
* TODO: split into noarm+arm pair
*/
if (plane_state->scaler_id >= 0)
skl_program_plane_scaler(dsb, plane, crtc_state, plane_state);
2024-09-30 20:04:13 +03:00
icl_plane_update_sel_fetch_arm(dsb, plane, crtc_state, plane_state);
/*
* The control register self-arms if the plane was previously
* disabled. Try to make the plane enable atomic by writing
* the control register just before the surface register.
*/
2024-09-30 20:04:13 +03:00
intel_de_write_dsb(display, dsb, PLANE_CTL(pipe, plane_id),
plane_ctl);
intel_de_write_dsb(display, dsb, PLANE_SURF(pipe, plane_id),
skl_plane_surf(plane_state, color_plane));
}
static void skl_plane_capture_error(struct intel_crtc *crtc,
struct intel_plane *plane,
struct intel_plane_error *error)
{
struct intel_display *display = to_intel_display(plane);
error->ctl = intel_de_read(display, PLANE_CTL(crtc->pipe, plane->id));
error->surf = intel_de_read(display, PLANE_SURF(crtc->pipe, plane->id));
error->surflive = intel_de_read(display, PLANE_SURFLIVE(crtc->pipe, plane->id));
}
static void
2024-09-30 20:04:13 +03:00
skl_plane_async_flip(struct intel_dsb *dsb,
struct intel_plane *plane,
const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state,
bool async_flip)
{
struct intel_display *display = to_intel_display(plane);
enum plane_id plane_id = plane->id;
enum pipe pipe = plane->pipe;
u32 plane_ctl = plane_state->ctl, plane_surf;
plane_ctl |= skl_plane_ctl_crtc(crtc_state);
plane_surf = skl_plane_surf(plane_state, 0);
if (async_flip) {
if (DISPLAY_VER(display) >= 30)
plane_surf |= PLANE_SURF_ASYNC_UPDATE;
else
plane_ctl |= PLANE_CTL_ASYNC_FLIP;
}
2024-09-30 20:04:13 +03:00
intel_de_write_dsb(display, dsb, PLANE_CTL(pipe, plane_id),
plane_ctl);
intel_de_write_dsb(display, dsb, PLANE_SURF(pipe, plane_id),
plane_surf);
}
static bool intel_format_is_p01x(u32 format)
{
switch (format) {
case DRM_FORMAT_P010:
case DRM_FORMAT_P012:
case DRM_FORMAT_P016:
return true;
default:
return false;
}
}
static int skl_plane_check_fb(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state)
{
struct intel_display *display = to_intel_display(plane_state);
struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
const struct drm_framebuffer *fb = plane_state->hw.fb;
unsigned int rotation = plane_state->hw.rotation;
if (!fb)
return 0;
if (rotation & ~(DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180) &&
intel_fb_is_ccs_modifier(fb->modifier)) {
drm_dbg_kms(display->drm,
"[PLANE:%d:%s] RC support only with 0/180 degree rotation (%x)\n",
plane->base.base.id, plane->base.name, rotation);
return -EINVAL;
}
if (rotation & DRM_MODE_REFLECT_X &&
fb->modifier == DRM_FORMAT_MOD_LINEAR) {
drm_dbg_kms(display->drm,
"[PLANE:%d:%s] horizontal flip is not supported with linear surface formats\n",
plane->base.base.id, plane->base.name);
return -EINVAL;
}
/*
* Display20 onward tile4 hflip is not supported
*/
if (rotation & DRM_MODE_REFLECT_X &&
intel_fb_is_tile4_modifier(fb->modifier) &&
DISPLAY_VER(display) >= 20) {
drm_dbg_kms(display->drm,
"[PLANE:%d:%s] horizontal flip is not supported with tile4 surface formats\n",
plane->base.base.id, plane->base.name);
return -EINVAL;
}
if (drm_rotation_90_or_270(rotation)) {
if (!intel_fb_supports_90_270_rotation(to_intel_framebuffer(fb))) {
drm_dbg_kms(display->drm,
"[PLANE:%d:%s] Y/Yf tiling required for 90/270!\n",
plane->base.base.id, plane->base.name);
return -EINVAL;
}
/*
* 90/270 is not allowed with RGB64 16:16:16:16 and
* Indexed 8-bit. RGB 16-bit 5:6:5 is allowed gen11 onwards.
*/
switch (fb->format->format) {
case DRM_FORMAT_RGB565:
if (DISPLAY_VER(display) >= 11)
break;
fallthrough;
case DRM_FORMAT_C8:
case DRM_FORMAT_XRGB16161616F:
case DRM_FORMAT_XBGR16161616F:
case DRM_FORMAT_ARGB16161616F:
case DRM_FORMAT_ABGR16161616F:
case DRM_FORMAT_Y210:
case DRM_FORMAT_Y212:
case DRM_FORMAT_Y216:
case DRM_FORMAT_XVYU12_16161616:
case DRM_FORMAT_XVYU16161616:
drm_dbg_kms(display->drm,
"[PLANE:%d:%s] unsupported pixel format %p4cc for 90/270!\n",
plane->base.base.id, plane->base.name, &fb->format->format);
return -EINVAL;
default:
break;
}
}
/* Y-tiling is not supported in IF-ID Interlace mode */
if (crtc_state->hw.enable &&
crtc_state->hw.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE &&
fb->modifier != DRM_FORMAT_MOD_LINEAR &&
fb->modifier != I915_FORMAT_MOD_X_TILED) {
drm_dbg_kms(display->drm,
"[PLANE:%d:%s] Y/Yf tiling not supported in IF-ID mode\n",
plane->base.base.id, plane->base.name);
return -EINVAL;
}
/* Wa_1606054188:tgl,adl-s */
if ((display->platform.alderlake_s || display->platform.tigerlake) &&
plane_state->ckey.flags & I915_SET_COLORKEY_SOURCE &&
intel_format_is_p01x(fb->format->format)) {
drm_dbg_kms(display->drm,
"[PLANE:%d:%s] source color keying not supported with P01x formats\n",
plane->base.base.id, plane->base.name);
return -EINVAL;
}
return 0;
}
static int skl_plane_check_dst_coordinates(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state)
{
struct intel_display *display = to_intel_display(plane_state);
struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
int crtc_x = plane_state->uapi.dst.x1;
int crtc_w = drm_rect_width(&plane_state->uapi.dst);
int pipe_src_w = drm_rect_width(&crtc_state->pipe_src);
/*
* Display WA #1175: glk
* Planes other than the cursor may cause FIFO underflow and display
* corruption if starting less than 4 pixels from the right edge of
* the screen.
* Besides the above WA fix the similar problem, where planes other
* than the cursor ending less than 4 pixels from the left edge of the
* screen may cause FIFO underflow and display corruption.
*/
if (DISPLAY_VER(display) == 10 &&
(crtc_x + crtc_w < 4 || crtc_x > pipe_src_w - 4)) {
drm_dbg_kms(display->drm,
"[PLANE:%d:%s] requested plane X %s position %d invalid (valid range %d-%d)\n",
plane->base.base.id, plane->base.name,
crtc_x + crtc_w < 4 ? "end" : "start",
crtc_x + crtc_w < 4 ? crtc_x + crtc_w : crtc_x,
4, pipe_src_w - 4);
return -ERANGE;
}
return 0;
}
static int skl_plane_check_nv12_rotation(const struct intel_plane_state *plane_state)
{
struct intel_display *display = to_intel_display(plane_state);
struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
const struct drm_framebuffer *fb = plane_state->hw.fb;
unsigned int rotation = plane_state->hw.rotation;
int src_w = drm_rect_width(&plane_state->uapi.src) >> 16;
/* Display WA #1106 */
if (intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier) &&
src_w & 3 &&
(rotation == DRM_MODE_ROTATE_270 ||
rotation == (DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_90))) {
drm_dbg_kms(display->drm,
"[PLANE:%d:%s] src width must be multiple of 4 for rotated planar YUV\n",
plane->base.base.id, plane->base.name);
return -EINVAL;
}
return 0;
}
static int skl_plane_max_scale(struct intel_display *display,
const struct drm_framebuffer *fb)
{
/*
* We don't yet know the final source width nor
* whether we can use the HQ scaler mode. Assume
* the best case.
* FIXME need to properly check this later.
*/
if (DISPLAY_VER(display) >= 10 ||
!intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier))
return 0x30000 - 1;
else
return 0x20000 - 1;
}
static int intel_plane_min_width(struct intel_plane *plane,
const struct drm_framebuffer *fb,
int color_plane,
unsigned int rotation)
{
if (plane->min_width)
return plane->min_width(fb, color_plane, rotation);
else
return 1;
}
static int intel_plane_max_width(struct intel_plane *plane,
const struct drm_framebuffer *fb,
int color_plane,
unsigned int rotation)
{
if (plane->max_width)
return plane->max_width(fb, color_plane, rotation);
else
return INT_MAX;
}
static int intel_plane_max_height(struct intel_plane *plane,
const struct drm_framebuffer *fb,
int color_plane,
unsigned int rotation)
{
if (plane->max_height)
return plane->max_height(fb, color_plane, rotation);
else
return INT_MAX;
}
static bool
skl_check_main_ccs_coordinates(struct intel_plane_state *plane_state,
int main_x, int main_y, u32 main_offset,
int ccs_plane)
{
struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
const struct drm_framebuffer *fb = plane_state->hw.fb;
drm/i915: Unify the FB and plane state view information into one struct To allow the simplification of FB/plane view computation in the follow-up patches, unify the corresponding state in the intel_framebuffer and intel_plane_state structs into a new intel_fb_view struct. This adds some overhead to intel_framebuffer as the rotated view will have now space for 4 color planes instead of the required 2 and it'll also contain the unused offset for each color_plane info. Imo this is an acceptable trade-off to get a simplified way of the remap computation. Use the new intel_fb_view struct for the FB normal view as well, so (in the follow-up patches) we can remove the special casing for normal view calculation wrt. the calculation of remapped/rotated views. This also adds an overhead to the intel_framebuffer struct, as the gtt remap info and per-color plane offset/pitch is not required for the normal view, but imo this is an acceptable trade-off as above. The per-color plane pitch filed will be used by a follow-up patch, so we can retrieve the pitch for each view in the same way. No functional changes in this patch. v2: - Make the patch have _no functional change_. (fix skl_check_nv12_aux_surface() and skl_check_main_surface()). - s/i915_color_plane_view::pitch/stride/ (Ville) Suggested-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Imre Deak <imre.deak@intel.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20210325214808.2071517-17-imre.deak@intel.com
2021-03-28 00:09:10 +02:00
int aux_x = plane_state->view.color_plane[ccs_plane].x;
int aux_y = plane_state->view.color_plane[ccs_plane].y;
u32 aux_offset = plane_state->view.color_plane[ccs_plane].offset;
unsigned int alignment = plane->min_alignment(plane, fb, ccs_plane);
int hsub;
int vsub;
intel_fb_plane_get_subsampling(&hsub, &vsub, fb, ccs_plane);
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_plane_adjust_aligned_offset(&x, &y,
plane_state,
ccs_plane,
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;
drm/i915: Unify the FB and plane state view information into one struct To allow the simplification of FB/plane view computation in the follow-up patches, unify the corresponding state in the intel_framebuffer and intel_plane_state structs into a new intel_fb_view struct. This adds some overhead to intel_framebuffer as the rotated view will have now space for 4 color planes instead of the required 2 and it'll also contain the unused offset for each color_plane info. Imo this is an acceptable trade-off to get a simplified way of the remap computation. Use the new intel_fb_view struct for the FB normal view as well, so (in the follow-up patches) we can remove the special casing for normal view calculation wrt. the calculation of remapped/rotated views. This also adds an overhead to the intel_framebuffer struct, as the gtt remap info and per-color plane offset/pitch is not required for the normal view, but imo this is an acceptable trade-off as above. The per-color plane pitch filed will be used by a follow-up patch, so we can retrieve the pitch for each view in the same way. No functional changes in this patch. v2: - Make the patch have _no functional change_. (fix skl_check_nv12_aux_surface() and skl_check_main_surface()). - s/i915_color_plane_view::pitch/stride/ (Ville) Suggested-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Imre Deak <imre.deak@intel.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20210325214808.2071517-17-imre.deak@intel.com
2021-03-28 00:09:10 +02:00
plane_state->view.color_plane[ccs_plane].offset = aux_offset;
plane_state->view.color_plane[ccs_plane].x = aux_x;
plane_state->view.color_plane[ccs_plane].y = aux_y;
return true;
}
int skl_calc_main_surface_offset(const struct intel_plane_state *plane_state,
int *x, int *y, u32 *offset)
{
struct intel_display *display = to_intel_display(plane_state);
struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
const struct drm_framebuffer *fb = plane_state->hw.fb;
int aux_plane = skl_main_to_aux_plane(fb, 0);
u32 aux_offset = plane_state->view.color_plane[aux_plane].offset;
unsigned int alignment = plane->min_alignment(plane, fb, 0);
int w = drm_rect_width(&plane_state->uapi.src) >> 16;
intel_add_fb_offsets(x, y, plane_state, 0);
*offset = intel_plane_compute_aligned_offset(x, y, plane_state, 0);
if (drm_WARN_ON(display->drm, alignment && !is_power_of_2(alignment)))
return -EINVAL;
/*
* AUX surface offset is specified as the distance from the
* main surface offset, and it must be non-negative. Make
* sure that is what we will get.
*/
if (aux_plane && *offset > aux_offset)
*offset = intel_plane_adjust_aligned_offset(x, y, plane_state, 0,
*offset,
aux_offset & ~(alignment - 1));
/*
* When using an X-tiled surface, the plane blows up
* if the x offset + width exceed the stride.
*
* TODO: linear and Y-tiled seem fine, Yf untested,
*/
if (fb->modifier == I915_FORMAT_MOD_X_TILED) {
int cpp = fb->format->cpp[0];
while ((*x + w) * cpp > plane_state->view.color_plane[0].mapping_stride) {
if (*offset == 0) {
drm_dbg_kms(display->drm,
"[PLANE:%d:%s] unable to find suitable display surface offset due to X-tiling\n",
plane->base.base.id, plane->base.name);
return -EINVAL;
}
*offset = intel_plane_adjust_aligned_offset(x, y, plane_state, 0,
*offset,
*offset - alignment);
}
}
return 0;
}
static int skl_check_main_surface(struct intel_plane_state *plane_state)
{
struct intel_display *display = to_intel_display(plane_state);
struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
const struct drm_framebuffer *fb = plane_state->hw.fb;
unsigned int rotation = plane_state->hw.rotation;
int x = plane_state->uapi.src.x1 >> 16;
int y = plane_state->uapi.src.y1 >> 16;
int w = drm_rect_width(&plane_state->uapi.src) >> 16;
int h = drm_rect_height(&plane_state->uapi.src) >> 16;
int min_width = intel_plane_min_width(plane, fb, 0, rotation);
int max_width = intel_plane_max_width(plane, fb, 0, rotation);
int max_height = intel_plane_max_height(plane, fb, 0, rotation);
unsigned int alignment = plane->min_alignment(plane, fb, 0);
int aux_plane = skl_main_to_aux_plane(fb, 0);
u32 offset;
int ret;
if (w > max_width || w < min_width || h > max_height || h < 1) {
drm_dbg_kms(display->drm,
"[PLANE:%d:%s] requested Y/RGB source size %dx%d outside limits (min: %dx1 max: %dx%d)\n",
plane->base.base.id, plane->base.name,
w, h, min_width, max_width, max_height);
return -EINVAL;
}
ret = skl_calc_main_surface_offset(plane_state, &x, &y, &offset);
if (ret)
return ret;
/*
* CCS AUX surface doesn't have its own x/y offsets, we must make sure
* they match with the main surface x/y offsets. On DG2
* there's no aux plane on fb so skip this checking.
*/
if (intel_fb_is_ccs_modifier(fb->modifier) && aux_plane) {
while (!skl_check_main_ccs_coordinates(plane_state, x, y,
offset, aux_plane)) {
if (offset == 0)
break;
offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, 0,
offset, offset - alignment);
}
drm/i915: Unify the FB and plane state view information into one struct To allow the simplification of FB/plane view computation in the follow-up patches, unify the corresponding state in the intel_framebuffer and intel_plane_state structs into a new intel_fb_view struct. This adds some overhead to intel_framebuffer as the rotated view will have now space for 4 color planes instead of the required 2 and it'll also contain the unused offset for each color_plane info. Imo this is an acceptable trade-off to get a simplified way of the remap computation. Use the new intel_fb_view struct for the FB normal view as well, so (in the follow-up patches) we can remove the special casing for normal view calculation wrt. the calculation of remapped/rotated views. This also adds an overhead to the intel_framebuffer struct, as the gtt remap info and per-color plane offset/pitch is not required for the normal view, but imo this is an acceptable trade-off as above. The per-color plane pitch filed will be used by a follow-up patch, so we can retrieve the pitch for each view in the same way. No functional changes in this patch. v2: - Make the patch have _no functional change_. (fix skl_check_nv12_aux_surface() and skl_check_main_surface()). - s/i915_color_plane_view::pitch/stride/ (Ville) Suggested-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Imre Deak <imre.deak@intel.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20210325214808.2071517-17-imre.deak@intel.com
2021-03-28 00:09:10 +02:00
if (x != plane_state->view.color_plane[aux_plane].x ||
y != plane_state->view.color_plane[aux_plane].y) {
drm_dbg_kms(display->drm,
"[PLANE:%d:%s] unable to find suitable display surface offset due to CCS\n",
plane->base.base.id, plane->base.name);
return -EINVAL;
}
}
if (DISPLAY_VER(display) >= 13)
drm_WARN_ON(display->drm, x > 65535 || y > 65535);
else
drm_WARN_ON(display->drm, x > 8191 || y > 8191);
drm/i915: Unify the FB and plane state view information into one struct To allow the simplification of FB/plane view computation in the follow-up patches, unify the corresponding state in the intel_framebuffer and intel_plane_state structs into a new intel_fb_view struct. This adds some overhead to intel_framebuffer as the rotated view will have now space for 4 color planes instead of the required 2 and it'll also contain the unused offset for each color_plane info. Imo this is an acceptable trade-off to get a simplified way of the remap computation. Use the new intel_fb_view struct for the FB normal view as well, so (in the follow-up patches) we can remove the special casing for normal view calculation wrt. the calculation of remapped/rotated views. This also adds an overhead to the intel_framebuffer struct, as the gtt remap info and per-color plane offset/pitch is not required for the normal view, but imo this is an acceptable trade-off as above. The per-color plane pitch filed will be used by a follow-up patch, so we can retrieve the pitch for each view in the same way. No functional changes in this patch. v2: - Make the patch have _no functional change_. (fix skl_check_nv12_aux_surface() and skl_check_main_surface()). - s/i915_color_plane_view::pitch/stride/ (Ville) Suggested-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Imre Deak <imre.deak@intel.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20210325214808.2071517-17-imre.deak@intel.com
2021-03-28 00:09:10 +02:00
plane_state->view.color_plane[0].offset = offset;
plane_state->view.color_plane[0].x = x;
plane_state->view.color_plane[0].y = y;
/*
* Put the final coordinates back so that the src
* coordinate checks will see the right values.
*/
drm_rect_translate_to(&plane_state->uapi.src,
x << 16, y << 16);
return 0;
}
static int skl_check_nv12_aux_surface(struct intel_plane_state *plane_state)
{
struct intel_display *display = to_intel_display(plane_state);
struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
const struct drm_framebuffer *fb = plane_state->hw.fb;
unsigned int rotation = plane_state->hw.rotation;
int uv_plane = 1;
int ccs_plane = intel_fb_is_ccs_modifier(fb->modifier) ?
skl_main_to_aux_plane(fb, uv_plane) : 0;
int max_width = intel_plane_max_width(plane, fb, uv_plane, rotation);
int max_height = intel_plane_max_height(plane, fb, uv_plane, rotation);
int x = plane_state->uapi.src.x1 >> 17;
int y = plane_state->uapi.src.y1 >> 17;
int w = drm_rect_width(&plane_state->uapi.src) >> 17;
int h = drm_rect_height(&plane_state->uapi.src) >> 17;
u32 offset;
/* FIXME not quite sure how/if these apply to the chroma plane */
if (w > max_width || h > max_height) {
drm_dbg_kms(display->drm,
"[PLANE:%d:%s] CbCr source size %dx%d too big (limit %dx%d)\n",
plane->base.base.id, plane->base.name,
w, h, max_width, max_height);
return -EINVAL;
}
intel_add_fb_offsets(&x, &y, plane_state, uv_plane);
offset = intel_plane_compute_aligned_offset(&x, &y,
plane_state, uv_plane);
if (ccs_plane) {
drm/i915: Unify the FB and plane state view information into one struct To allow the simplification of FB/plane view computation in the follow-up patches, unify the corresponding state in the intel_framebuffer and intel_plane_state structs into a new intel_fb_view struct. This adds some overhead to intel_framebuffer as the rotated view will have now space for 4 color planes instead of the required 2 and it'll also contain the unused offset for each color_plane info. Imo this is an acceptable trade-off to get a simplified way of the remap computation. Use the new intel_fb_view struct for the FB normal view as well, so (in the follow-up patches) we can remove the special casing for normal view calculation wrt. the calculation of remapped/rotated views. This also adds an overhead to the intel_framebuffer struct, as the gtt remap info and per-color plane offset/pitch is not required for the normal view, but imo this is an acceptable trade-off as above. The per-color plane pitch filed will be used by a follow-up patch, so we can retrieve the pitch for each view in the same way. No functional changes in this patch. v2: - Make the patch have _no functional change_. (fix skl_check_nv12_aux_surface() and skl_check_main_surface()). - s/i915_color_plane_view::pitch/stride/ (Ville) Suggested-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Imre Deak <imre.deak@intel.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20210325214808.2071517-17-imre.deak@intel.com
2021-03-28 00:09:10 +02:00
u32 aux_offset = plane_state->view.color_plane[ccs_plane].offset;
unsigned int alignment = plane->min_alignment(plane, fb, uv_plane);
if (offset > aux_offset)
offset = intel_plane_adjust_aligned_offset(&x, &y,
plane_state,
uv_plane,
offset,
aux_offset & ~(alignment - 1));
while (!skl_check_main_ccs_coordinates(plane_state, x, y,
offset, ccs_plane)) {
if (offset == 0)
break;
offset = intel_plane_adjust_aligned_offset(&x, &y,
plane_state,
uv_plane,
offset, offset - alignment);
}
drm/i915: Unify the FB and plane state view information into one struct To allow the simplification of FB/plane view computation in the follow-up patches, unify the corresponding state in the intel_framebuffer and intel_plane_state structs into a new intel_fb_view struct. This adds some overhead to intel_framebuffer as the rotated view will have now space for 4 color planes instead of the required 2 and it'll also contain the unused offset for each color_plane info. Imo this is an acceptable trade-off to get a simplified way of the remap computation. Use the new intel_fb_view struct for the FB normal view as well, so (in the follow-up patches) we can remove the special casing for normal view calculation wrt. the calculation of remapped/rotated views. This also adds an overhead to the intel_framebuffer struct, as the gtt remap info and per-color plane offset/pitch is not required for the normal view, but imo this is an acceptable trade-off as above. The per-color plane pitch filed will be used by a follow-up patch, so we can retrieve the pitch for each view in the same way. No functional changes in this patch. v2: - Make the patch have _no functional change_. (fix skl_check_nv12_aux_surface() and skl_check_main_surface()). - s/i915_color_plane_view::pitch/stride/ (Ville) Suggested-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Imre Deak <imre.deak@intel.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20210325214808.2071517-17-imre.deak@intel.com
2021-03-28 00:09:10 +02:00
if (x != plane_state->view.color_plane[ccs_plane].x ||
y != plane_state->view.color_plane[ccs_plane].y) {
drm_dbg_kms(display->drm,
"[PLANE:%d:%s] unable to find suitable display surface offset due to CCS\n",
plane->base.base.id, plane->base.name);
return -EINVAL;
}
}
if (DISPLAY_VER(display) >= 13)
drm_WARN_ON(display->drm, x > 65535 || y > 65535);
else
drm_WARN_ON(display->drm, x > 8191 || y > 8191);
drm/i915: Unify the FB and plane state view information into one struct To allow the simplification of FB/plane view computation in the follow-up patches, unify the corresponding state in the intel_framebuffer and intel_plane_state structs into a new intel_fb_view struct. This adds some overhead to intel_framebuffer as the rotated view will have now space for 4 color planes instead of the required 2 and it'll also contain the unused offset for each color_plane info. Imo this is an acceptable trade-off to get a simplified way of the remap computation. Use the new intel_fb_view struct for the FB normal view as well, so (in the follow-up patches) we can remove the special casing for normal view calculation wrt. the calculation of remapped/rotated views. This also adds an overhead to the intel_framebuffer struct, as the gtt remap info and per-color plane offset/pitch is not required for the normal view, but imo this is an acceptable trade-off as above. The per-color plane pitch filed will be used by a follow-up patch, so we can retrieve the pitch for each view in the same way. No functional changes in this patch. v2: - Make the patch have _no functional change_. (fix skl_check_nv12_aux_surface() and skl_check_main_surface()). - s/i915_color_plane_view::pitch/stride/ (Ville) Suggested-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Imre Deak <imre.deak@intel.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20210325214808.2071517-17-imre.deak@intel.com
2021-03-28 00:09:10 +02:00
plane_state->view.color_plane[uv_plane].offset = offset;
plane_state->view.color_plane[uv_plane].x = x;
plane_state->view.color_plane[uv_plane].y = y;
return 0;
}
static int skl_check_ccs_aux_surface(struct intel_plane_state *plane_state)
{
const struct drm_framebuffer *fb = plane_state->hw.fb;
int src_x = plane_state->uapi.src.x1 >> 16;
int src_y = plane_state->uapi.src.y1 >> 16;
u32 offset;
int ccs_plane;
for (ccs_plane = 0; ccs_plane < fb->format->num_planes; ccs_plane++) {
int main_hsub, main_vsub;
int hsub, vsub;
int x, y;
if (!intel_fb_is_ccs_aux_plane(fb, ccs_plane))
continue;
intel_fb_plane_get_subsampling(&main_hsub, &main_vsub, fb,
skl_ccs_to_main_plane(fb, ccs_plane));
intel_fb_plane_get_subsampling(&hsub, &vsub, fb, ccs_plane);
hsub *= main_hsub;
vsub *= main_vsub;
x = src_x / hsub;
y = src_y / vsub;
intel_add_fb_offsets(&x, &y, plane_state, ccs_plane);
offset = intel_plane_compute_aligned_offset(&x, &y,
plane_state,
ccs_plane);
drm/i915: Unify the FB and plane state view information into one struct To allow the simplification of FB/plane view computation in the follow-up patches, unify the corresponding state in the intel_framebuffer and intel_plane_state structs into a new intel_fb_view struct. This adds some overhead to intel_framebuffer as the rotated view will have now space for 4 color planes instead of the required 2 and it'll also contain the unused offset for each color_plane info. Imo this is an acceptable trade-off to get a simplified way of the remap computation. Use the new intel_fb_view struct for the FB normal view as well, so (in the follow-up patches) we can remove the special casing for normal view calculation wrt. the calculation of remapped/rotated views. This also adds an overhead to the intel_framebuffer struct, as the gtt remap info and per-color plane offset/pitch is not required for the normal view, but imo this is an acceptable trade-off as above. The per-color plane pitch filed will be used by a follow-up patch, so we can retrieve the pitch for each view in the same way. No functional changes in this patch. v2: - Make the patch have _no functional change_. (fix skl_check_nv12_aux_surface() and skl_check_main_surface()). - s/i915_color_plane_view::pitch/stride/ (Ville) Suggested-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Imre Deak <imre.deak@intel.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20210325214808.2071517-17-imre.deak@intel.com
2021-03-28 00:09:10 +02:00
plane_state->view.color_plane[ccs_plane].offset = offset;
plane_state->view.color_plane[ccs_plane].x = (x * hsub + src_x % hsub) / main_hsub;
plane_state->view.color_plane[ccs_plane].y = (y * vsub + src_y % vsub) / main_vsub;
}
return 0;
}
static int skl_check_plane_surface(struct intel_plane_state *plane_state)
{
const struct drm_framebuffer *fb = plane_state->hw.fb;
int ret;
ret = intel_plane_compute_gtt(plane_state);
if (ret)
return ret;
if (!plane_state->uapi.visible)
return 0;
/*
* Handle the AUX surface first since the main surface setup depends on
* it.
*/
if (intel_fb_is_ccs_modifier(fb->modifier)) {
ret = skl_check_ccs_aux_surface(plane_state);
if (ret)
return ret;
}
if (intel_format_info_is_yuv_semiplanar(fb->format,
fb->modifier)) {
ret = skl_check_nv12_aux_surface(plane_state);
if (ret)
return ret;
}
ret = skl_check_main_surface(plane_state);
if (ret)
return ret;
return 0;
}
static bool skl_fb_scalable(const struct drm_framebuffer *fb)
{
struct intel_display *display;
if (!fb)
return false;
display = to_intel_display(fb->dev);
switch (fb->format->format) {
case DRM_FORMAT_C8:
return false;
case DRM_FORMAT_XRGB16161616F:
case DRM_FORMAT_ARGB16161616F:
case DRM_FORMAT_XBGR16161616F:
case DRM_FORMAT_ABGR16161616F:
return DISPLAY_VER(display) >= 11;
default:
return true;
}
}
static void check_protection(struct intel_plane_state *plane_state)
{
struct intel_display *display = to_intel_display(plane_state);
const struct drm_framebuffer *fb = plane_state->hw.fb;
struct drm_gem_object *obj = intel_fb_bo(fb);
if (DISPLAY_VER(display) < 11)
return;
plane_state->decrypt = intel_pxp_key_check(obj, false) == 0;
plane_state->force_black = intel_bo_is_protected(obj) &&
!plane_state->decrypt;
}
static void
make_damage_viewport_relative(struct intel_plane_state *plane_state)
{
const struct drm_framebuffer *fb = plane_state->hw.fb;
const struct drm_rect *src = &plane_state->uapi.src;
unsigned int rotation = plane_state->hw.rotation;
struct drm_rect *damage = &plane_state->damage;
if (!drm_rect_visible(damage))
return;
if (!fb || !plane_state->uapi.visible) {
plane_state->damage = DRM_RECT_INIT(0, 0, 0, 0);
return;
}
if (drm_rotation_90_or_270(rotation)) {
drm_rect_rotate(damage, fb->width, fb->height,
DRM_MODE_ROTATE_270);
drm_rect_translate(damage, -(src->y1 >> 16), -(src->x1 >> 16));
} else {
drm_rect_translate(damage, -(src->x1 >> 16), -(src->y1 >> 16));
}
}
static void clip_damage(struct intel_plane_state *plane_state)
{
struct drm_rect *damage = &plane_state->damage;
struct drm_rect src;
if (!drm_rect_visible(damage))
return;
drm_rect_fp_to_int(&src, &plane_state->uapi.src);
drm_rect_translate(damage, src.x1, src.y1);
drm_rect_intersect(damage, &src);
}
static int skl_plane_check(struct intel_crtc_state *crtc_state,
struct intel_plane_state *plane_state)
{
struct intel_display *display = to_intel_display(plane_state);
struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
const struct drm_framebuffer *fb = plane_state->hw.fb;
int min_scale = DRM_PLANE_NO_SCALING;
int max_scale = DRM_PLANE_NO_SCALING;
int ret;
ret = skl_plane_check_fb(crtc_state, plane_state);
if (ret)
return ret;
/* use scaler when colorkey is not required */
if (!plane_state->ckey.flags && skl_fb_scalable(fb)) {
min_scale = 1;
max_scale = skl_plane_max_scale(display, fb);
}
ret = intel_plane_check_clipping(plane_state, crtc_state,
min_scale, max_scale, true);
if (ret)
return ret;
make_damage_viewport_relative(plane_state);
ret = skl_check_plane_surface(plane_state);
if (ret)
return ret;
if (!plane_state->uapi.visible)
return 0;
ret = skl_plane_check_dst_coordinates(crtc_state, plane_state);
if (ret)
return ret;
ret = intel_plane_check_src_coordinates(plane_state);
if (ret)
return ret;
clip_damage(plane_state);
ret = skl_plane_check_nv12_rotation(plane_state);
if (ret)
return ret;
check_protection(plane_state);
/* HW only has 8 bits pixel precision, disable plane if invisible */
if (!(plane_state->hw.alpha >> 8)) {
plane_state->uapi.visible = false;
plane_state->damage = DRM_RECT_INIT(0, 0, 0, 0);
}
plane_state->ctl = skl_plane_ctl(crtc_state, plane_state);
if (DISPLAY_VER(display) >= 10)
plane_state->color_ctl = glk_plane_color_ctl(crtc_state,
plane_state);
if (intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier) &&
icl_is_hdr_plane(display, plane->id))
/* Enable and use MPEG-2 chroma siting */
plane_state->cus_ctl = PLANE_CUS_ENABLE |
PLANE_CUS_HPHASE_0 |
PLANE_CUS_VPHASE_SIGN_NEGATIVE | PLANE_CUS_VPHASE_0_25;
else
plane_state->cus_ctl = 0;
return 0;
}
void icl_link_nv12_planes(struct intel_plane_state *uv_plane_state,
struct intel_plane_state *y_plane_state)
{
struct intel_display *display = to_intel_display(uv_plane_state);
struct intel_plane *uv_plane = to_intel_plane(uv_plane_state->uapi.plane);
struct intel_plane *y_plane = to_intel_plane(y_plane_state->uapi.plane);
drm_WARN_ON(display->drm, icl_is_nv12_y_plane(display, uv_plane->id));
drm_WARN_ON(display->drm, !icl_is_nv12_y_plane(display, y_plane->id));
y_plane_state->ctl |= PLANE_CTL_YUV420_Y_PLANE;
if (icl_is_hdr_plane(display, uv_plane->id)) {
switch (y_plane->id) {
case PLANE_7:
uv_plane_state->cus_ctl |= PLANE_CUS_Y_PLANE_7_ICL;
break;
case PLANE_6:
uv_plane_state->cus_ctl |= PLANE_CUS_Y_PLANE_6_ICL;
break;
case PLANE_5:
uv_plane_state->cus_ctl |= PLANE_CUS_Y_PLANE_5_RKL;
break;
case PLANE_4:
uv_plane_state->cus_ctl |= PLANE_CUS_Y_PLANE_4_RKL;
break;
default:
MISSING_CASE(y_plane->id);
}
}
}
static enum intel_fbc_id skl_fbc_id_for_pipe(enum pipe pipe)
{
return pipe - PIPE_A + INTEL_FBC_A;
}
static bool skl_plane_has_fbc(struct intel_display *display,
enum intel_fbc_id fbc_id, enum plane_id plane_id)
{
if ((DISPLAY_RUNTIME_INFO(display)->fbc_mask & BIT(fbc_id)) == 0)
return false;
if (DISPLAY_VER(display) >= 20)
return icl_is_hdr_plane(display, plane_id);
else
return plane_id == PLANE_1;
}
static struct intel_fbc *skl_plane_fbc(struct intel_display *display,
enum pipe pipe, enum plane_id plane_id)
{
enum intel_fbc_id fbc_id = skl_fbc_id_for_pipe(pipe);
if (skl_plane_has_fbc(display, fbc_id, plane_id))
return display->fbc[fbc_id];
else
return NULL;
}
static bool skl_plane_has_planar(struct intel_display *display,
enum pipe pipe, enum plane_id plane_id)
{
/* Display WA #0870: skl, bxt */
if (display->platform.skylake || display->platform.broxton)
return false;
if (DISPLAY_VER(display) == 9 && pipe == PIPE_C)
return false;
if (plane_id != PLANE_1 && plane_id != PLANE_2)
return false;
return true;
}
static const u32 *skl_get_plane_formats(struct intel_display *display,
enum pipe pipe, enum plane_id plane_id,
int *num_formats)
{
if (skl_plane_has_planar(display, pipe, plane_id)) {
*num_formats = ARRAY_SIZE(skl_planar_formats);
return skl_planar_formats;
} else {
*num_formats = ARRAY_SIZE(skl_plane_formats);
return skl_plane_formats;
}
}
static const u32 *glk_get_plane_formats(struct intel_display *display,
enum pipe pipe, enum plane_id plane_id,
int *num_formats)
{
if (skl_plane_has_planar(display, pipe, plane_id)) {
*num_formats = ARRAY_SIZE(glk_planar_formats);
return glk_planar_formats;
} else {
*num_formats = ARRAY_SIZE(skl_plane_formats);
return skl_plane_formats;
}
}
static const u32 *icl_get_plane_formats(struct intel_display *display,
enum pipe pipe, enum plane_id plane_id,
int *num_formats)
{
if (icl_is_hdr_plane(display, plane_id)) {
*num_formats = ARRAY_SIZE(icl_hdr_plane_formats);
return icl_hdr_plane_formats;
} else if (icl_is_nv12_y_plane(display, plane_id)) {
*num_formats = ARRAY_SIZE(icl_sdr_y_plane_formats);
return icl_sdr_y_plane_formats;
} else {
*num_formats = ARRAY_SIZE(icl_sdr_uv_plane_formats);
return icl_sdr_uv_plane_formats;
}
}
static bool skl_plane_format_mod_supported(struct drm_plane *_plane,
u32 format, u64 modifier)
{
struct intel_plane *plane = to_intel_plane(_plane);
drm/i915: Add a table with a descriptor for all i915 modifiers Add a table describing all the framebuffer modifiers used by i915 at one place. This has the benefit of deduplicating the listing of supported modifiers for each platform and checking the support of these modifiers on a given plane. This also simplifies in a similar way getting some attribute for a modifier, for instance checking if the modifier is a CCS modifier type. While at it drop the cursor plane filtering from skl_plane_has_rc_ccs(), as the cursor plane is registered with DRM core elsewhere. v1: Unchanged. v2: - Keep the plane caps calculation in the plane code and pass an enum with these caps to intel_fb_get_modifiers(). (Ville) - Get the modifiers calling intel_fb_get_modifiers() in i9xx_plane.c as well. v3: - s/.id/.modifier/ (Ville) - Keep modifier_desc vs. plane_cap filter conditions consistent. (Ville) - Drop redundant cursor plane check from skl_plane_has_rc_ccs(). (Ville) - Use from, until display version fields in modifier_desc instead of a mask. (Jani) - Unexport struct intel_modifier_desc, separate its decl and init. (Jani) - Remove enum pipe, plane_id forward decls from intel_fb.h, which are not needed after v2. v4: - Reuse IS_DISPLAY_VER() instead of open-coding it. (Jani) - Preserve the current modifier order exposed to user space. (Ville) v5: Use }, { on one line to seperate the descriptor array elements. (Jani) Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Cc: Juha-Pekka Heikkila <juhapekka.heikkila@gmail.com> Cc: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Imre Deak <imre.deak@intel.com> Reviewed-by: Juha-Pekka Heikkila <juhapekka.heikkila@gmail.com> (v3) Link: https://patchwork.freedesktop.org/patch/msgid/20211020195138.1841242-2-imre.deak@intel.com
2021-10-20 22:51:28 +03:00
if (!intel_fb_plane_supports_modifier(plane, modifier))
return false;
switch (format) {
case DRM_FORMAT_XRGB8888:
case DRM_FORMAT_XBGR8888:
case DRM_FORMAT_ARGB8888:
case DRM_FORMAT_ABGR8888:
if (intel_fb_is_ccs_modifier(modifier))
return true;
fallthrough;
case DRM_FORMAT_RGB565:
case DRM_FORMAT_XRGB2101010:
case DRM_FORMAT_XBGR2101010:
case DRM_FORMAT_ARGB2101010:
case DRM_FORMAT_ABGR2101010:
case DRM_FORMAT_YUYV:
case DRM_FORMAT_YVYU:
case DRM_FORMAT_UYVY:
case DRM_FORMAT_VYUY:
case DRM_FORMAT_NV12:
case DRM_FORMAT_XYUV8888:
case DRM_FORMAT_P010:
case DRM_FORMAT_P012:
case DRM_FORMAT_P016:
case DRM_FORMAT_XVYU2101010:
if (modifier == I915_FORMAT_MOD_Yf_TILED)
return true;
fallthrough;
case DRM_FORMAT_C8:
case DRM_FORMAT_XBGR16161616F:
case DRM_FORMAT_ABGR16161616F:
case DRM_FORMAT_XRGB16161616F:
case DRM_FORMAT_ARGB16161616F:
case DRM_FORMAT_Y210:
case DRM_FORMAT_Y212:
case DRM_FORMAT_Y216:
case DRM_FORMAT_XVYU12_16161616:
case DRM_FORMAT_XVYU16161616:
if (modifier == DRM_FORMAT_MOD_LINEAR ||
modifier == I915_FORMAT_MOD_X_TILED ||
modifier == I915_FORMAT_MOD_Y_TILED)
return true;
fallthrough;
default:
return false;
}
}
static bool icl_plane_format_mod_supported(struct drm_plane *_plane,
u32 format, u64 modifier)
{
struct intel_plane *plane = to_intel_plane(_plane);
if (!intel_fb_plane_supports_modifier(plane, modifier))
return false;
switch (format) {
case DRM_FORMAT_XRGB8888:
case DRM_FORMAT_XBGR8888:
case DRM_FORMAT_ARGB8888:
case DRM_FORMAT_ABGR8888:
case DRM_FORMAT_XRGB2101010:
case DRM_FORMAT_XBGR2101010:
case DRM_FORMAT_ARGB2101010:
case DRM_FORMAT_ABGR2101010:
if (intel_fb_is_ccs_modifier(modifier))
return true;
fallthrough;
case DRM_FORMAT_RGB565:
case DRM_FORMAT_YUYV:
case DRM_FORMAT_YVYU:
case DRM_FORMAT_UYVY:
case DRM_FORMAT_VYUY:
case DRM_FORMAT_NV12:
case DRM_FORMAT_XYUV8888:
case DRM_FORMAT_P010:
case DRM_FORMAT_P012:
case DRM_FORMAT_P016:
case DRM_FORMAT_XVYU2101010:
if (modifier == I915_FORMAT_MOD_Yf_TILED)
return true;
fallthrough;
case DRM_FORMAT_C8:
case DRM_FORMAT_XBGR16161616F:
case DRM_FORMAT_ABGR16161616F:
case DRM_FORMAT_XRGB16161616F:
case DRM_FORMAT_ARGB16161616F:
case DRM_FORMAT_Y210:
case DRM_FORMAT_Y212:
case DRM_FORMAT_Y216:
case DRM_FORMAT_XVYU12_16161616:
case DRM_FORMAT_XVYU16161616:
if (modifier == DRM_FORMAT_MOD_LINEAR ||
modifier == I915_FORMAT_MOD_X_TILED ||
modifier == I915_FORMAT_MOD_Y_TILED)
return true;
fallthrough;
default:
return false;
}
}
static bool tgl_plane_format_mod_supported(struct drm_plane *_plane,
u32 format, u64 modifier)
{
struct intel_plane *plane = to_intel_plane(_plane);
drm/i915: Add a table with a descriptor for all i915 modifiers Add a table describing all the framebuffer modifiers used by i915 at one place. This has the benefit of deduplicating the listing of supported modifiers for each platform and checking the support of these modifiers on a given plane. This also simplifies in a similar way getting some attribute for a modifier, for instance checking if the modifier is a CCS modifier type. While at it drop the cursor plane filtering from skl_plane_has_rc_ccs(), as the cursor plane is registered with DRM core elsewhere. v1: Unchanged. v2: - Keep the plane caps calculation in the plane code and pass an enum with these caps to intel_fb_get_modifiers(). (Ville) - Get the modifiers calling intel_fb_get_modifiers() in i9xx_plane.c as well. v3: - s/.id/.modifier/ (Ville) - Keep modifier_desc vs. plane_cap filter conditions consistent. (Ville) - Drop redundant cursor plane check from skl_plane_has_rc_ccs(). (Ville) - Use from, until display version fields in modifier_desc instead of a mask. (Jani) - Unexport struct intel_modifier_desc, separate its decl and init. (Jani) - Remove enum pipe, plane_id forward decls from intel_fb.h, which are not needed after v2. v4: - Reuse IS_DISPLAY_VER() instead of open-coding it. (Jani) - Preserve the current modifier order exposed to user space. (Ville) v5: Use }, { on one line to seperate the descriptor array elements. (Jani) Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Cc: Juha-Pekka Heikkila <juhapekka.heikkila@gmail.com> Cc: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Imre Deak <imre.deak@intel.com> Reviewed-by: Juha-Pekka Heikkila <juhapekka.heikkila@gmail.com> (v3) Link: https://patchwork.freedesktop.org/patch/msgid/20211020195138.1841242-2-imre.deak@intel.com
2021-10-20 22:51:28 +03:00
if (!intel_fb_plane_supports_modifier(plane, modifier))
return false;
switch (format) {
case DRM_FORMAT_XRGB8888:
case DRM_FORMAT_XBGR8888:
case DRM_FORMAT_ARGB8888:
case DRM_FORMAT_ABGR8888:
case DRM_FORMAT_XRGB2101010:
case DRM_FORMAT_XBGR2101010:
case DRM_FORMAT_ARGB2101010:
case DRM_FORMAT_ABGR2101010:
case DRM_FORMAT_XBGR16161616F:
case DRM_FORMAT_ABGR16161616F:
case DRM_FORMAT_XRGB16161616F:
case DRM_FORMAT_ARGB16161616F:
if (intel_fb_is_ccs_modifier(modifier))
return true;
fallthrough;
case DRM_FORMAT_YUYV:
case DRM_FORMAT_YVYU:
case DRM_FORMAT_UYVY:
case DRM_FORMAT_VYUY:
case DRM_FORMAT_NV12:
case DRM_FORMAT_XYUV8888:
case DRM_FORMAT_P010:
case DRM_FORMAT_P012:
case DRM_FORMAT_P016:
if (intel_fb_is_mc_ccs_modifier(modifier))
return true;
fallthrough;
case DRM_FORMAT_RGB565:
case DRM_FORMAT_XVYU2101010:
case DRM_FORMAT_C8:
case DRM_FORMAT_Y210:
case DRM_FORMAT_Y212:
case DRM_FORMAT_Y216:
case DRM_FORMAT_XVYU12_16161616:
case DRM_FORMAT_XVYU16161616:
if (!intel_fb_is_ccs_modifier(modifier))
return true;
fallthrough;
default:
return false;
}
}
static const struct drm_plane_funcs skl_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
.destroy = intel_plane_destroy,
.atomic_duplicate_state = intel_plane_duplicate_state,
.atomic_destroy_state = intel_plane_destroy_state,
.format_mod_supported = skl_plane_format_mod_supported,
.format_mod_supported_async = intel_plane_format_mod_supported_async,
};
static const struct drm_plane_funcs icl_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
.destroy = intel_plane_destroy,
.atomic_duplicate_state = intel_plane_duplicate_state,
.atomic_destroy_state = intel_plane_destroy_state,
.format_mod_supported = icl_plane_format_mod_supported,
.format_mod_supported_async = intel_plane_format_mod_supported_async,
};
static const struct drm_plane_funcs tgl_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
.destroy = intel_plane_destroy,
.atomic_duplicate_state = intel_plane_duplicate_state,
.atomic_destroy_state = intel_plane_destroy_state,
.format_mod_supported = tgl_plane_format_mod_supported,
.format_mod_supported_async = intel_plane_format_mod_supported_async,
};
static void
skl_plane_enable_flip_done(struct intel_plane *plane)
{
struct intel_display *display = to_intel_display(plane);
enum pipe pipe = plane->pipe;
spin_lock_irq(&display->irq.lock);
bdw_enable_pipe_irq(display, pipe, GEN9_PIPE_PLANE_FLIP_DONE(plane->id));
spin_unlock_irq(&display->irq.lock);
}
static void
skl_plane_disable_flip_done(struct intel_plane *plane)
{
struct intel_display *display = to_intel_display(plane);
enum pipe pipe = plane->pipe;
spin_lock_irq(&display->irq.lock);
bdw_disable_pipe_irq(display, pipe, GEN9_PIPE_PLANE_FLIP_DONE(plane->id));
spin_unlock_irq(&display->irq.lock);
}
static bool skl_plane_has_rc_ccs(struct intel_display *display,
drm/i915: Add a table with a descriptor for all i915 modifiers Add a table describing all the framebuffer modifiers used by i915 at one place. This has the benefit of deduplicating the listing of supported modifiers for each platform and checking the support of these modifiers on a given plane. This also simplifies in a similar way getting some attribute for a modifier, for instance checking if the modifier is a CCS modifier type. While at it drop the cursor plane filtering from skl_plane_has_rc_ccs(), as the cursor plane is registered with DRM core elsewhere. v1: Unchanged. v2: - Keep the plane caps calculation in the plane code and pass an enum with these caps to intel_fb_get_modifiers(). (Ville) - Get the modifiers calling intel_fb_get_modifiers() in i9xx_plane.c as well. v3: - s/.id/.modifier/ (Ville) - Keep modifier_desc vs. plane_cap filter conditions consistent. (Ville) - Drop redundant cursor plane check from skl_plane_has_rc_ccs(). (Ville) - Use from, until display version fields in modifier_desc instead of a mask. (Jani) - Unexport struct intel_modifier_desc, separate its decl and init. (Jani) - Remove enum pipe, plane_id forward decls from intel_fb.h, which are not needed after v2. v4: - Reuse IS_DISPLAY_VER() instead of open-coding it. (Jani) - Preserve the current modifier order exposed to user space. (Ville) v5: Use }, { on one line to seperate the descriptor array elements. (Jani) Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Cc: Juha-Pekka Heikkila <juhapekka.heikkila@gmail.com> Cc: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Imre Deak <imre.deak@intel.com> Reviewed-by: Juha-Pekka Heikkila <juhapekka.heikkila@gmail.com> (v3) Link: https://patchwork.freedesktop.org/patch/msgid/20211020195138.1841242-2-imre.deak@intel.com
2021-10-20 22:51:28 +03:00
enum pipe pipe, enum plane_id plane_id)
{
return pipe != PIPE_C &&
(plane_id == PLANE_1 || plane_id == PLANE_2);
drm/i915: Add a table with a descriptor for all i915 modifiers Add a table describing all the framebuffer modifiers used by i915 at one place. This has the benefit of deduplicating the listing of supported modifiers for each platform and checking the support of these modifiers on a given plane. This also simplifies in a similar way getting some attribute for a modifier, for instance checking if the modifier is a CCS modifier type. While at it drop the cursor plane filtering from skl_plane_has_rc_ccs(), as the cursor plane is registered with DRM core elsewhere. v1: Unchanged. v2: - Keep the plane caps calculation in the plane code and pass an enum with these caps to intel_fb_get_modifiers(). (Ville) - Get the modifiers calling intel_fb_get_modifiers() in i9xx_plane.c as well. v3: - s/.id/.modifier/ (Ville) - Keep modifier_desc vs. plane_cap filter conditions consistent. (Ville) - Drop redundant cursor plane check from skl_plane_has_rc_ccs(). (Ville) - Use from, until display version fields in modifier_desc instead of a mask. (Jani) - Unexport struct intel_modifier_desc, separate its decl and init. (Jani) - Remove enum pipe, plane_id forward decls from intel_fb.h, which are not needed after v2. v4: - Reuse IS_DISPLAY_VER() instead of open-coding it. (Jani) - Preserve the current modifier order exposed to user space. (Ville) v5: Use }, { on one line to seperate the descriptor array elements. (Jani) Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Cc: Juha-Pekka Heikkila <juhapekka.heikkila@gmail.com> Cc: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Imre Deak <imre.deak@intel.com> Reviewed-by: Juha-Pekka Heikkila <juhapekka.heikkila@gmail.com> (v3) Link: https://patchwork.freedesktop.org/patch/msgid/20211020195138.1841242-2-imre.deak@intel.com
2021-10-20 22:51:28 +03:00
}
static u8 skl_plane_caps(struct intel_display *display,
enum pipe pipe, enum plane_id plane_id)
{
u8 caps = INTEL_PLANE_CAP_TILING_X |
INTEL_PLANE_CAP_TILING_Y |
INTEL_PLANE_CAP_TILING_Yf;
if (skl_plane_has_rc_ccs(display, pipe, plane_id))
caps |= INTEL_PLANE_CAP_CCS_RC;
return caps;
}
static bool glk_plane_has_rc_ccs(struct intel_display *display,
enum pipe pipe)
{
return pipe != PIPE_C;
}
static u8 glk_plane_caps(struct intel_display *display,
enum pipe pipe, enum plane_id plane_id)
{
u8 caps = INTEL_PLANE_CAP_TILING_X |
INTEL_PLANE_CAP_TILING_Y |
INTEL_PLANE_CAP_TILING_Yf;
if (glk_plane_has_rc_ccs(display, pipe))
caps |= INTEL_PLANE_CAP_CCS_RC;
return caps;
}
static u8 icl_plane_caps(struct intel_display *display,
enum pipe pipe, enum plane_id plane_id)
{
return INTEL_PLANE_CAP_TILING_X |
INTEL_PLANE_CAP_TILING_Y |
INTEL_PLANE_CAP_TILING_Yf |
INTEL_PLANE_CAP_CCS_RC;
}
static bool tgl_plane_has_mc_ccs(struct intel_display *display,
enum plane_id plane_id)
drm/i915: Add a table with a descriptor for all i915 modifiers Add a table describing all the framebuffer modifiers used by i915 at one place. This has the benefit of deduplicating the listing of supported modifiers for each platform and checking the support of these modifiers on a given plane. This also simplifies in a similar way getting some attribute for a modifier, for instance checking if the modifier is a CCS modifier type. While at it drop the cursor plane filtering from skl_plane_has_rc_ccs(), as the cursor plane is registered with DRM core elsewhere. v1: Unchanged. v2: - Keep the plane caps calculation in the plane code and pass an enum with these caps to intel_fb_get_modifiers(). (Ville) - Get the modifiers calling intel_fb_get_modifiers() in i9xx_plane.c as well. v3: - s/.id/.modifier/ (Ville) - Keep modifier_desc vs. plane_cap filter conditions consistent. (Ville) - Drop redundant cursor plane check from skl_plane_has_rc_ccs(). (Ville) - Use from, until display version fields in modifier_desc instead of a mask. (Jani) - Unexport struct intel_modifier_desc, separate its decl and init. (Jani) - Remove enum pipe, plane_id forward decls from intel_fb.h, which are not needed after v2. v4: - Reuse IS_DISPLAY_VER() instead of open-coding it. (Jani) - Preserve the current modifier order exposed to user space. (Ville) v5: Use }, { on one line to seperate the descriptor array elements. (Jani) Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Cc: Juha-Pekka Heikkila <juhapekka.heikkila@gmail.com> Cc: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Imre Deak <imre.deak@intel.com> Reviewed-by: Juha-Pekka Heikkila <juhapekka.heikkila@gmail.com> (v3) Link: https://patchwork.freedesktop.org/patch/msgid/20211020195138.1841242-2-imre.deak@intel.com
2021-10-20 22:51:28 +03:00
{
/* Wa_14010477008 */
if (display->platform.dg1 || display->platform.rocketlake ||
(display->platform.tigerlake && IS_DISPLAY_STEP(display, STEP_A0, STEP_D0)))
drm/i915: Add a table with a descriptor for all i915 modifiers Add a table describing all the framebuffer modifiers used by i915 at one place. This has the benefit of deduplicating the listing of supported modifiers for each platform and checking the support of these modifiers on a given plane. This also simplifies in a similar way getting some attribute for a modifier, for instance checking if the modifier is a CCS modifier type. While at it drop the cursor plane filtering from skl_plane_has_rc_ccs(), as the cursor plane is registered with DRM core elsewhere. v1: Unchanged. v2: - Keep the plane caps calculation in the plane code and pass an enum with these caps to intel_fb_get_modifiers(). (Ville) - Get the modifiers calling intel_fb_get_modifiers() in i9xx_plane.c as well. v3: - s/.id/.modifier/ (Ville) - Keep modifier_desc vs. plane_cap filter conditions consistent. (Ville) - Drop redundant cursor plane check from skl_plane_has_rc_ccs(). (Ville) - Use from, until display version fields in modifier_desc instead of a mask. (Jani) - Unexport struct intel_modifier_desc, separate its decl and init. (Jani) - Remove enum pipe, plane_id forward decls from intel_fb.h, which are not needed after v2. v4: - Reuse IS_DISPLAY_VER() instead of open-coding it. (Jani) - Preserve the current modifier order exposed to user space. (Ville) v5: Use }, { on one line to seperate the descriptor array elements. (Jani) Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Cc: Juha-Pekka Heikkila <juhapekka.heikkila@gmail.com> Cc: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Imre Deak <imre.deak@intel.com> Reviewed-by: Juha-Pekka Heikkila <juhapekka.heikkila@gmail.com> (v3) Link: https://patchwork.freedesktop.org/patch/msgid/20211020195138.1841242-2-imre.deak@intel.com
2021-10-20 22:51:28 +03:00
return false;
return plane_id < PLANE_6;
drm/i915: Add a table with a descriptor for all i915 modifiers Add a table describing all the framebuffer modifiers used by i915 at one place. This has the benefit of deduplicating the listing of supported modifiers for each platform and checking the support of these modifiers on a given plane. This also simplifies in a similar way getting some attribute for a modifier, for instance checking if the modifier is a CCS modifier type. While at it drop the cursor plane filtering from skl_plane_has_rc_ccs(), as the cursor plane is registered with DRM core elsewhere. v1: Unchanged. v2: - Keep the plane caps calculation in the plane code and pass an enum with these caps to intel_fb_get_modifiers(). (Ville) - Get the modifiers calling intel_fb_get_modifiers() in i9xx_plane.c as well. v3: - s/.id/.modifier/ (Ville) - Keep modifier_desc vs. plane_cap filter conditions consistent. (Ville) - Drop redundant cursor plane check from skl_plane_has_rc_ccs(). (Ville) - Use from, until display version fields in modifier_desc instead of a mask. (Jani) - Unexport struct intel_modifier_desc, separate its decl and init. (Jani) - Remove enum pipe, plane_id forward decls from intel_fb.h, which are not needed after v2. v4: - Reuse IS_DISPLAY_VER() instead of open-coding it. (Jani) - Preserve the current modifier order exposed to user space. (Ville) v5: Use }, { on one line to seperate the descriptor array elements. (Jani) Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Cc: Juha-Pekka Heikkila <juhapekka.heikkila@gmail.com> Cc: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Imre Deak <imre.deak@intel.com> Reviewed-by: Juha-Pekka Heikkila <juhapekka.heikkila@gmail.com> (v3) Link: https://patchwork.freedesktop.org/patch/msgid/20211020195138.1841242-2-imre.deak@intel.com
2021-10-20 22:51:28 +03:00
}
static u8 tgl_plane_caps(struct intel_display *display,
enum pipe pipe, enum plane_id plane_id)
{
u8 caps = INTEL_PLANE_CAP_TILING_X |
INTEL_PLANE_CAP_CCS_RC |
INTEL_PLANE_CAP_CCS_RC_CC;
if (HAS_4TILE(display))
caps |= INTEL_PLANE_CAP_TILING_4;
else
caps |= INTEL_PLANE_CAP_TILING_Y;
if (tgl_plane_has_mc_ccs(display, plane_id))
caps |= INTEL_PLANE_CAP_CCS_MC;
if (DISPLAY_VER(display) >= 14 && display->platform.dgfx)
caps |= INTEL_PLANE_CAP_NEED64K_PHYS;
return caps;
}
static void skl_disable_tiling(struct intel_plane *plane)
{
struct intel_plane_state *state = to_intel_plane_state(plane->base.state);
struct intel_display *display = to_intel_display(plane);
const struct drm_framebuffer *fb = state->hw.fb;
u32 plane_ctl;
plane_ctl = intel_de_read(display, PLANE_CTL(plane->pipe, plane->id));
if (intel_fb_uses_dpt(fb)) {
/* if DPT is enabled, keep tiling, but disable compression */
plane_ctl &= ~PLANE_CTL_RENDER_DECOMPRESSION_ENABLE;
} else {
/* if DPT is not supported, disable tiling, and update stride */
u32 stride = state->view.color_plane[0].scanout_stride / 64;
plane_ctl &= ~PLANE_CTL_TILED_MASK;
intel_de_write_fw(display, PLANE_STRIDE(plane->pipe, plane->id),
PLANE_STRIDE_(stride));
}
intel_de_write_fw(display, PLANE_CTL(plane->pipe, plane->id), plane_ctl);
intel_de_write_fw(display, PLANE_SURF(plane->pipe, plane->id),
skl_plane_surf(state, 0));
}
struct intel_plane *
skl_universal_plane_create(struct intel_display *display,
enum pipe pipe, enum plane_id plane_id)
{
const struct drm_plane_funcs *plane_funcs;
struct intel_plane *plane;
enum drm_plane_type plane_type;
unsigned int supported_rotations;
unsigned int supported_csc;
const u64 *modifiers;
const u32 *formats;
int num_formats;
int ret;
u8 caps;
plane = intel_plane_alloc();
if (IS_ERR(plane))
return plane;
plane->pipe = pipe;
plane->id = plane_id;
plane->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, plane_id);
intel_fbc_add_plane(skl_plane_fbc(display, pipe, plane_id), plane);
if (DISPLAY_VER(display) >= 30) {
plane->max_width = xe3_plane_max_width;
plane->max_height = icl_plane_max_height;
plane->min_cdclk = icl_plane_min_cdclk;
} else if (DISPLAY_VER(display) >= 11) {
plane->min_width = icl_plane_min_width;
if (icl_is_hdr_plane(display, plane_id))
plane->max_width = icl_hdr_plane_max_width;
else
plane->max_width = icl_sdr_plane_max_width;
plane->max_height = icl_plane_max_height;
plane->min_cdclk = icl_plane_min_cdclk;
} else if (DISPLAY_VER(display) >= 10) {
plane->max_width = glk_plane_max_width;
plane->max_height = skl_plane_max_height;
plane->min_cdclk = glk_plane_min_cdclk;
} else {
plane->max_width = skl_plane_max_width;
plane->max_height = skl_plane_max_height;
plane->min_cdclk = skl_plane_min_cdclk;
}
plane->disable_tiling = skl_disable_tiling;
if (DISPLAY_VER(display) >= 13)
plane->max_stride = adl_plane_max_stride;
else
plane->max_stride = skl_plane_max_stride;
if (DISPLAY_VER(display) >= 12)
plane->min_alignment = tgl_plane_min_alignment;
else
plane->min_alignment = skl_plane_min_alignment;
if (intel_scanout_needs_vtd_wa(display))
plane->vtd_guard = DISPLAY_VER(display) >= 10 ? 168 : 136;
if (DISPLAY_VER(display) >= 11) {
plane->update_noarm = icl_plane_update_noarm;
plane->update_arm = icl_plane_update_arm;
plane->disable_arm = icl_plane_disable_arm;
} else {
plane->update_noarm = skl_plane_update_noarm;
plane->update_arm = skl_plane_update_arm;
plane->disable_arm = skl_plane_disable_arm;
}
plane->capture_error = skl_plane_capture_error;
plane->get_hw_state = skl_plane_get_hw_state;
plane->check_plane = skl_plane_check;
if (HAS_ASYNC_FLIPS(display) && plane_id == PLANE_1) {
plane->need_async_flip_toggle_wa = IS_DISPLAY_VER(display, 9, 10);
plane->async_flip = skl_plane_async_flip;
plane->enable_flip_done = skl_plane_enable_flip_done;
plane->disable_flip_done = skl_plane_disable_flip_done;
if (DISPLAY_VER(display) >= 12)
plane->can_async_flip = tgl_plane_can_async_flip;
else if (DISPLAY_VER(display) == 11)
plane->can_async_flip = icl_plane_can_async_flip;
else
plane->can_async_flip = skl_plane_can_async_flip;
}
if (DISPLAY_VER(display) >= 11)
formats = icl_get_plane_formats(display, pipe,
plane_id, &num_formats);
else if (DISPLAY_VER(display) >= 10)
formats = glk_get_plane_formats(display, pipe,
plane_id, &num_formats);
else
formats = skl_get_plane_formats(display, pipe,
plane_id, &num_formats);
if (DISPLAY_VER(display) >= 12)
plane_funcs = &tgl_plane_funcs;
else if (DISPLAY_VER(display) == 11)
plane_funcs = &icl_plane_funcs;
drm/i915: Add a table with a descriptor for all i915 modifiers Add a table describing all the framebuffer modifiers used by i915 at one place. This has the benefit of deduplicating the listing of supported modifiers for each platform and checking the support of these modifiers on a given plane. This also simplifies in a similar way getting some attribute for a modifier, for instance checking if the modifier is a CCS modifier type. While at it drop the cursor plane filtering from skl_plane_has_rc_ccs(), as the cursor plane is registered with DRM core elsewhere. v1: Unchanged. v2: - Keep the plane caps calculation in the plane code and pass an enum with these caps to intel_fb_get_modifiers(). (Ville) - Get the modifiers calling intel_fb_get_modifiers() in i9xx_plane.c as well. v3: - s/.id/.modifier/ (Ville) - Keep modifier_desc vs. plane_cap filter conditions consistent. (Ville) - Drop redundant cursor plane check from skl_plane_has_rc_ccs(). (Ville) - Use from, until display version fields in modifier_desc instead of a mask. (Jani) - Unexport struct intel_modifier_desc, separate its decl and init. (Jani) - Remove enum pipe, plane_id forward decls from intel_fb.h, which are not needed after v2. v4: - Reuse IS_DISPLAY_VER() instead of open-coding it. (Jani) - Preserve the current modifier order exposed to user space. (Ville) v5: Use }, { on one line to seperate the descriptor array elements. (Jani) Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Cc: Juha-Pekka Heikkila <juhapekka.heikkila@gmail.com> Cc: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Imre Deak <imre.deak@intel.com> Reviewed-by: Juha-Pekka Heikkila <juhapekka.heikkila@gmail.com> (v3) Link: https://patchwork.freedesktop.org/patch/msgid/20211020195138.1841242-2-imre.deak@intel.com
2021-10-20 22:51:28 +03:00
else
plane_funcs = &skl_plane_funcs;
if (plane_id == PLANE_1)
plane_type = DRM_PLANE_TYPE_PRIMARY;
else
plane_type = DRM_PLANE_TYPE_OVERLAY;
if (DISPLAY_VER(display) >= 12)
caps = tgl_plane_caps(display, pipe, plane_id);
else if (DISPLAY_VER(display) == 11)
caps = icl_plane_caps(display, pipe, plane_id);
else if (DISPLAY_VER(display) == 10)
caps = glk_plane_caps(display, pipe, plane_id);
else
caps = skl_plane_caps(display, pipe, plane_id);
/* FIXME: xe has problems with AUX */
if (!IS_ENABLED(I915) && !HAS_FLAT_CCS(to_i915(display->drm)))
caps &= ~(INTEL_PLANE_CAP_CCS_RC |
INTEL_PLANE_CAP_CCS_RC_CC |
INTEL_PLANE_CAP_CCS_MC);
modifiers = intel_fb_plane_get_modifiers(display, caps);
drm/i915: Add a table with a descriptor for all i915 modifiers Add a table describing all the framebuffer modifiers used by i915 at one place. This has the benefit of deduplicating the listing of supported modifiers for each platform and checking the support of these modifiers on a given plane. This also simplifies in a similar way getting some attribute for a modifier, for instance checking if the modifier is a CCS modifier type. While at it drop the cursor plane filtering from skl_plane_has_rc_ccs(), as the cursor plane is registered with DRM core elsewhere. v1: Unchanged. v2: - Keep the plane caps calculation in the plane code and pass an enum with these caps to intel_fb_get_modifiers(). (Ville) - Get the modifiers calling intel_fb_get_modifiers() in i9xx_plane.c as well. v3: - s/.id/.modifier/ (Ville) - Keep modifier_desc vs. plane_cap filter conditions consistent. (Ville) - Drop redundant cursor plane check from skl_plane_has_rc_ccs(). (Ville) - Use from, until display version fields in modifier_desc instead of a mask. (Jani) - Unexport struct intel_modifier_desc, separate its decl and init. (Jani) - Remove enum pipe, plane_id forward decls from intel_fb.h, which are not needed after v2. v4: - Reuse IS_DISPLAY_VER() instead of open-coding it. (Jani) - Preserve the current modifier order exposed to user space. (Ville) v5: Use }, { on one line to seperate the descriptor array elements. (Jani) Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Cc: Juha-Pekka Heikkila <juhapekka.heikkila@gmail.com> Cc: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Imre Deak <imre.deak@intel.com> Reviewed-by: Juha-Pekka Heikkila <juhapekka.heikkila@gmail.com> (v3) Link: https://patchwork.freedesktop.org/patch/msgid/20211020195138.1841242-2-imre.deak@intel.com
2021-10-20 22:51:28 +03:00
ret = drm_universal_plane_init(display->drm, &plane->base,
0, plane_funcs,
formats, num_formats, modifiers,
plane_type,
"plane %d%c", plane_id + 1,
pipe_name(pipe));
drm/i915: Add a table with a descriptor for all i915 modifiers Add a table describing all the framebuffer modifiers used by i915 at one place. This has the benefit of deduplicating the listing of supported modifiers for each platform and checking the support of these modifiers on a given plane. This also simplifies in a similar way getting some attribute for a modifier, for instance checking if the modifier is a CCS modifier type. While at it drop the cursor plane filtering from skl_plane_has_rc_ccs(), as the cursor plane is registered with DRM core elsewhere. v1: Unchanged. v2: - Keep the plane caps calculation in the plane code and pass an enum with these caps to intel_fb_get_modifiers(). (Ville) - Get the modifiers calling intel_fb_get_modifiers() in i9xx_plane.c as well. v3: - s/.id/.modifier/ (Ville) - Keep modifier_desc vs. plane_cap filter conditions consistent. (Ville) - Drop redundant cursor plane check from skl_plane_has_rc_ccs(). (Ville) - Use from, until display version fields in modifier_desc instead of a mask. (Jani) - Unexport struct intel_modifier_desc, separate its decl and init. (Jani) - Remove enum pipe, plane_id forward decls from intel_fb.h, which are not needed after v2. v4: - Reuse IS_DISPLAY_VER() instead of open-coding it. (Jani) - Preserve the current modifier order exposed to user space. (Ville) v5: Use }, { on one line to seperate the descriptor array elements. (Jani) Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Cc: Juha-Pekka Heikkila <juhapekka.heikkila@gmail.com> Cc: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Imre Deak <imre.deak@intel.com> Reviewed-by: Juha-Pekka Heikkila <juhapekka.heikkila@gmail.com> (v3) Link: https://patchwork.freedesktop.org/patch/msgid/20211020195138.1841242-2-imre.deak@intel.com
2021-10-20 22:51:28 +03:00
kfree(modifiers);
if (ret)
goto fail;
if (DISPLAY_VER(display) >= 13)
supported_rotations = DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180;
else
supported_rotations =
DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 |
DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270;
if (DISPLAY_VER(display) >= 11)
supported_rotations |= DRM_MODE_REFLECT_X;
drm_plane_create_rotation_property(&plane->base,
DRM_MODE_ROTATE_0,
supported_rotations);
supported_csc = BIT(DRM_COLOR_YCBCR_BT601) | BIT(DRM_COLOR_YCBCR_BT709);
if (DISPLAY_VER(display) >= 10)
supported_csc |= BIT(DRM_COLOR_YCBCR_BT2020);
drm_plane_create_color_properties(&plane->base,
supported_csc,
BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
BIT(DRM_COLOR_YCBCR_FULL_RANGE),
DRM_COLOR_YCBCR_BT709,
DRM_COLOR_YCBCR_LIMITED_RANGE);
drm_plane_create_alpha_property(&plane->base);
drm_plane_create_blend_mode_property(&plane->base,
BIT(DRM_MODE_BLEND_PIXEL_NONE) |
BIT(DRM_MODE_BLEND_PREMULTI) |
BIT(DRM_MODE_BLEND_COVERAGE));
drm_plane_create_zpos_immutable_property(&plane->base, plane_id);
if (DISPLAY_VER(display) >= 12)
drm_plane_enable_fb_damage_clips(&plane->base);
if (DISPLAY_VER(display) >= 11)
drm_plane_create_scaling_filter_property(&plane->base,
BIT(DRM_SCALING_FILTER_DEFAULT) |
BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR));
intel_plane_helper_add(plane);
return plane;
fail:
intel_plane_free(plane);
return ERR_PTR(ret);
}
void
skl_get_initial_plane_config(struct intel_crtc *crtc,
struct intel_initial_plane_config *plane_config)
{
struct intel_display *display = to_intel_display(crtc);
struct intel_crtc_state *crtc_state = to_intel_crtc_state(crtc->base.state);
struct intel_plane *plane = to_intel_plane(crtc->base.primary);
enum plane_id plane_id = plane->id;
enum pipe pipe;
u32 val, base, offset, stride_mult, tiling, alpha;
int fourcc, pixel_format;
unsigned int aligned_height;
struct drm_framebuffer *fb;
struct intel_framebuffer *intel_fb;
static_assert(PLANE_CTL_TILED_YF == PLANE_CTL_TILED_4);
if (!plane->get_hw_state(plane, &pipe))
return;
drm_WARN_ON(display->drm, pipe != crtc->pipe);
if (crtc_state->joiner_pipes) {
drm_dbg_kms(display->drm,
"[CRTC:%d:%s] Unsupported joiner configuration for initial FB\n",
crtc->base.base.id, crtc->base.name);
return;
}
intel_fb = intel_bo_alloc_framebuffer();
if (!intel_fb) {
drm_dbg_kms(display->drm, "failed to alloc fb\n");
return;
}
fb = &intel_fb->base;
fb->dev = display->drm;
val = intel_de_read(display, PLANE_CTL(pipe, plane_id));
if (DISPLAY_VER(display) >= 11)
pixel_format = val & PLANE_CTL_FORMAT_MASK_ICL;
else
pixel_format = val & PLANE_CTL_FORMAT_MASK_SKL;
if (DISPLAY_VER(display) >= 10) {
u32 color_ctl;
color_ctl = intel_de_read(display, PLANE_COLOR_CTL(pipe, plane_id));
alpha = REG_FIELD_GET(PLANE_COLOR_ALPHA_MASK, color_ctl);
} else {
alpha = REG_FIELD_GET(PLANE_CTL_ALPHA_MASK, val);
}
fourcc = skl_format_to_fourcc(pixel_format,
val & PLANE_CTL_ORDER_RGBX, alpha);
fb->format = drm_format_info(fourcc);
tiling = val & PLANE_CTL_TILED_MASK;
switch (tiling) {
case PLANE_CTL_TILED_LINEAR:
fb->modifier = DRM_FORMAT_MOD_LINEAR;
break;
case PLANE_CTL_TILED_X:
plane_config->tiling = I915_TILING_X;
fb->modifier = I915_FORMAT_MOD_X_TILED;
break;
case PLANE_CTL_TILED_Y:
plane_config->tiling = I915_TILING_Y;
if (val & PLANE_CTL_RENDER_DECOMPRESSION_ENABLE)
if (DISPLAY_VER(display) >= 14)
fb->modifier = I915_FORMAT_MOD_4_TILED_MTL_RC_CCS;
else if (DISPLAY_VER(display) >= 12)
fb->modifier = I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS;
else
fb->modifier = I915_FORMAT_MOD_Y_TILED_CCS;
else if (val & PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE)
if (DISPLAY_VER(display) >= 14)
fb->modifier = I915_FORMAT_MOD_4_TILED_MTL_MC_CCS;
else
fb->modifier = I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS;
else
fb->modifier = I915_FORMAT_MOD_Y_TILED;
break;
case PLANE_CTL_TILED_YF: /* aka PLANE_CTL_TILED_4 on XE_LPD+ */
if (HAS_4TILE(display)) {
u32 rc_mask = PLANE_CTL_RENDER_DECOMPRESSION_ENABLE |
PLANE_CTL_CLEAR_COLOR_DISABLE;
if ((val & rc_mask) == rc_mask)
fb->modifier = I915_FORMAT_MOD_4_TILED_DG2_RC_CCS;
else if (val & PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE)
fb->modifier = I915_FORMAT_MOD_4_TILED_DG2_MC_CCS;
else if (val & PLANE_CTL_RENDER_DECOMPRESSION_ENABLE)
fb->modifier = I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC;
else
fb->modifier = I915_FORMAT_MOD_4_TILED;
} else {
if (val & PLANE_CTL_RENDER_DECOMPRESSION_ENABLE)
fb->modifier = I915_FORMAT_MOD_Yf_TILED_CCS;
else
fb->modifier = I915_FORMAT_MOD_Yf_TILED;
}
break;
default:
MISSING_CASE(tiling);
goto error;
}
if (!display->params.enable_dpt &&
intel_fb_modifier_uses_dpt(display, fb->modifier)) {
drm_dbg_kms(display->drm, "DPT disabled, skipping initial FB\n");
goto error;
}
/*
* DRM_MODE_ROTATE_ is counter clockwise to stay compatible with Xrandr
* while i915 HW rotation is clockwise, that's why this swapping.
*/
switch (val & PLANE_CTL_ROTATE_MASK) {
case PLANE_CTL_ROTATE_0:
plane_config->rotation = DRM_MODE_ROTATE_0;
break;
case PLANE_CTL_ROTATE_90:
plane_config->rotation = DRM_MODE_ROTATE_270;
break;
case PLANE_CTL_ROTATE_180:
plane_config->rotation = DRM_MODE_ROTATE_180;
break;
case PLANE_CTL_ROTATE_270:
plane_config->rotation = DRM_MODE_ROTATE_90;
break;
}
if (DISPLAY_VER(display) >= 11 && val & PLANE_CTL_FLIP_HORIZONTAL)
plane_config->rotation |= DRM_MODE_REFLECT_X;
/* 90/270 degree rotation would require extra work */
if (drm_rotation_90_or_270(plane_config->rotation))
goto error;
base = intel_de_read(display, PLANE_SURF(pipe, plane_id)) & PLANE_SURF_ADDR_MASK;
plane_config->base = base;
offset = intel_de_read(display, PLANE_OFFSET(pipe, plane_id));
drm_WARN_ON(display->drm, offset != 0);
val = intel_de_read(display, PLANE_SIZE(pipe, plane_id));
fb->height = REG_FIELD_GET(PLANE_HEIGHT_MASK, val) + 1;
fb->width = REG_FIELD_GET(PLANE_WIDTH_MASK, val) + 1;
val = intel_de_read(display, PLANE_STRIDE(pipe, plane_id));
stride_mult = skl_plane_stride_mult(fb, 0, DRM_MODE_ROTATE_0);
fb->pitches[0] = REG_FIELD_GET(PLANE_STRIDE__MASK, val) * stride_mult;
aligned_height = intel_fb_align_height(fb, 0, fb->height);
plane_config->size = fb->pitches[0] * aligned_height;
drm_dbg_kms(display->drm,
"[CRTC:%d:%s][PLANE:%d:%s] with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n",
crtc->base.base.id, crtc->base.name,
plane->base.base.id, plane->base.name,
fb->width, fb->height, fb->format->cpp[0] * 8,
base, fb->pitches[0], plane_config->size);
plane_config->fb = intel_fb;
return;
error:
kfree(intel_fb);
}
drm/i915: Try to relocate the BIOS fb to the start of ggtt On MTL the GOP (for whatever reason) likes to bind its framebuffer high up in the ggtt address space. This can conflict with whatever ggtt_reserve_guc_top() is trying to do, and the result is that ggtt_reserve_guc_top() fails and then we proceed to explode when trying to tear down the driver. Thus far I haven't analyzed what causes the actual fireworks, but it's not super important as even if it didn't explode we'd still fail the driver load and the user would be left with an unusable GPU. To remedy this (without having to figure out exactly what ggtt_reserve_guc_top() is trying to achieve) we can attempt to relocate the BIOS framebuffer to a lower ggtt address. We can do this at this early point in driver init because nothing else is supposed to be clobbering the ggtt yet. So we simply change where in the ggtt we pin the vma, the original PTEs will be left as is, and the new PTEs will get written with the same dma addresses. The plane will keep on scanning out from the original PTEs until we are done with the whole process, and at that point we rewrite the plane's surface address register to point at the new ggtt address. Since we don't need a specific ggtt address for the plane (apart from needing it to land in the mappable region for normal stolen objects) we'll just try to pin it without a fixed offset first. It should end up at the lowest available address (which really should be 0 at this point in the driver init). If that fails we'll fall back to just pinning it exactly to the origianal address. To make sure we don't accidentlally pin it partially over the original ggtt range (as that would corrupt the original PTEs) we reserve the original range temporarily during this process. v2: Try to pin explicitly to ggtt offset 0 as otherwise DG2 puts it even higher (atm we have no PIN_LOW flag to force it low) v3: "fix" xe Reviewed-by: Andrzej Hajda <andrzej.hajda@intel.com> Tested-by: Paz Zcharya <pazz@chromium.org> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20240202224340.30647-16-ville.syrjala@linux.intel.com Acked-by: Lucas De Marchi <lucas.demarchi@intel.com>
2024-02-03 00:43:39 +02:00
bool skl_fixup_initial_plane_config(struct intel_crtc *crtc,
const struct intel_initial_plane_config *plane_config)
{
struct intel_display *display = to_intel_display(crtc);
drm/i915: Try to relocate the BIOS fb to the start of ggtt On MTL the GOP (for whatever reason) likes to bind its framebuffer high up in the ggtt address space. This can conflict with whatever ggtt_reserve_guc_top() is trying to do, and the result is that ggtt_reserve_guc_top() fails and then we proceed to explode when trying to tear down the driver. Thus far I haven't analyzed what causes the actual fireworks, but it's not super important as even if it didn't explode we'd still fail the driver load and the user would be left with an unusable GPU. To remedy this (without having to figure out exactly what ggtt_reserve_guc_top() is trying to achieve) we can attempt to relocate the BIOS framebuffer to a lower ggtt address. We can do this at this early point in driver init because nothing else is supposed to be clobbering the ggtt yet. So we simply change where in the ggtt we pin the vma, the original PTEs will be left as is, and the new PTEs will get written with the same dma addresses. The plane will keep on scanning out from the original PTEs until we are done with the whole process, and at that point we rewrite the plane's surface address register to point at the new ggtt address. Since we don't need a specific ggtt address for the plane (apart from needing it to land in the mappable region for normal stolen objects) we'll just try to pin it without a fixed offset first. It should end up at the lowest available address (which really should be 0 at this point in the driver init). If that fails we'll fall back to just pinning it exactly to the origianal address. To make sure we don't accidentlally pin it partially over the original ggtt range (as that would corrupt the original PTEs) we reserve the original range temporarily during this process. v2: Try to pin explicitly to ggtt offset 0 as otherwise DG2 puts it even higher (atm we have no PIN_LOW flag to force it low) v3: "fix" xe Reviewed-by: Andrzej Hajda <andrzej.hajda@intel.com> Tested-by: Paz Zcharya <pazz@chromium.org> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20240202224340.30647-16-ville.syrjala@linux.intel.com Acked-by: Lucas De Marchi <lucas.demarchi@intel.com>
2024-02-03 00:43:39 +02:00
struct intel_plane *plane = to_intel_plane(crtc->base.primary);
const struct intel_plane_state *plane_state =
to_intel_plane_state(plane->base.state);
enum plane_id plane_id = plane->id;
enum pipe pipe = crtc->pipe;
u32 base;
if (!plane_state->uapi.visible)
return false;
base = intel_plane_ggtt_offset(plane_state);
/*
* We may have moved the surface to a different
* part of ggtt, make the plane aware of that.
*/
if (plane_config->base == base)
return false;
intel_de_write(display, PLANE_SURF(pipe, plane_id), base);
drm/i915: Try to relocate the BIOS fb to the start of ggtt On MTL the GOP (for whatever reason) likes to bind its framebuffer high up in the ggtt address space. This can conflict with whatever ggtt_reserve_guc_top() is trying to do, and the result is that ggtt_reserve_guc_top() fails and then we proceed to explode when trying to tear down the driver. Thus far I haven't analyzed what causes the actual fireworks, but it's not super important as even if it didn't explode we'd still fail the driver load and the user would be left with an unusable GPU. To remedy this (without having to figure out exactly what ggtt_reserve_guc_top() is trying to achieve) we can attempt to relocate the BIOS framebuffer to a lower ggtt address. We can do this at this early point in driver init because nothing else is supposed to be clobbering the ggtt yet. So we simply change where in the ggtt we pin the vma, the original PTEs will be left as is, and the new PTEs will get written with the same dma addresses. The plane will keep on scanning out from the original PTEs until we are done with the whole process, and at that point we rewrite the plane's surface address register to point at the new ggtt address. Since we don't need a specific ggtt address for the plane (apart from needing it to land in the mappable region for normal stolen objects) we'll just try to pin it without a fixed offset first. It should end up at the lowest available address (which really should be 0 at this point in the driver init). If that fails we'll fall back to just pinning it exactly to the origianal address. To make sure we don't accidentlally pin it partially over the original ggtt range (as that would corrupt the original PTEs) we reserve the original range temporarily during this process. v2: Try to pin explicitly to ggtt offset 0 as otherwise DG2 puts it even higher (atm we have no PIN_LOW flag to force it low) v3: "fix" xe Reviewed-by: Andrzej Hajda <andrzej.hajda@intel.com> Tested-by: Paz Zcharya <pazz@chromium.org> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20240202224340.30647-16-ville.syrjala@linux.intel.com Acked-by: Lucas De Marchi <lucas.demarchi@intel.com>
2024-02-03 00:43:39 +02:00
return true;
}