Commit 46d12f91 authored by Dave Airlie's avatar Dave Airlie Committed by Jani Nikula

drm/i915: migrate skl planes code new file (v5)

Rework the plane init calls to do the gen test one level higher.

Rework some of the plane helpers so they can live in new file,
there is still some scope to clean up the plane/fb interactions
later.

v2: drop atomic code back, rename file to Ville suggestions,
add header file.
v3: move scaler bits back
v4: drop wrong new includes (Ville)
v5: integrate the ccs gen12 changes
v6: fix unrelated code movement (Ville)
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
[Jani: fixed up sparse warnings.]
Signed-off-by: default avatarJani Nikula <jani.nikula@intel.com>
Reported-by: default avatarkernel test robot <lkp@intel.com>
Reported-by: default avatarDan Carpenter <dan.carpenter@oracle.com>
Reviewed-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/4e88a5c6b9ab3b93cc2b6c7d78c26ae86f6abbd0.1612536383.git.jani.nikula@intel.com
parent 3c4442aa
......@@ -223,7 +223,8 @@ i915-y += \
display/intel_sprite.o \
display/intel_tc.o \
display/intel_vga.o \
display/i9xx_plane.o
display/i9xx_plane.o \
display/skl_universal_plane.o
i915-$(CONFIG_ACPI) += \
display/intel_acpi.o \
display/intel_opregion.o
......
......@@ -743,10 +743,6 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
int num_formats;
int ret, zpos;
if (INTEL_GEN(dev_priv) >= 9)
return skl_universal_plane_create(dev_priv, pipe,
PLANE_PRIMARY);
plane = intel_plane_alloc();
if (IS_ERR(plane))
return plane;
......
......@@ -35,6 +35,7 @@
#include "intel_dsi.h"
#include "intel_panel.h"
#include "intel_vdsc.h"
#include "skl_universal_plane.h"
static int header_credits_available(struct drm_i915_private *dev_priv,
enum transcoder dsi_trans)
......
......@@ -20,6 +20,7 @@
#include "intel_pipe_crc.h"
#include "intel_sprite.h"
#include "i9xx_plane.h"
#include "skl_universal_plane.h"
static void assert_vblank_disabled(struct drm_crtc *crtc)
{
......@@ -243,6 +244,10 @@ int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe)
crtc->pipe = pipe;
crtc->num_scalers = RUNTIME_INFO(dev_priv)->num_scalers[pipe];
if (INTEL_GEN(dev_priv) >= 9)
primary = skl_universal_plane_create(dev_priv, pipe,
PLANE_PRIMARY);
else
primary = intel_primary_plane_create(dev_priv, pipe);
if (IS_ERR(primary)) {
ret = PTR_ERR(primary);
......@@ -253,6 +258,10 @@ int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe)
for_each_sprite(dev_priv, pipe, sprite) {
struct intel_plane *plane;
if (INTEL_GEN(dev_priv) >= 9)
plane = skl_universal_plane_create(dev_priv, pipe,
PLANE_SPRITE0 + sprite);
else
plane = intel_sprite_plane_create(dev_priv, pipe, sprite);
if (IS_ERR(plane)) {
ret = PTR_ERR(plane);
......
......@@ -54,6 +54,7 @@
#include "intel_tc.h"
#include "intel_vdsc.h"
#include "intel_vrr.h"
#include "skl_universal_plane.h"
static const u8 index_to_dp_signal_levels[] = {
[0] = DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_0,
......
......@@ -94,6 +94,7 @@
#include "intel_tc.h"
#include "intel_vga.h"
#include "i9xx_plane.h"
#include "skl_universal_plane.h"
static void i9xx_crtc_clock_get(struct intel_crtc *crtc,
struct intel_crtc_state *pipe_config);
......@@ -116,7 +117,6 @@ static void vlv_prepare_pll(struct intel_crtc *crtc,
const struct intel_crtc_state *pipe_config);
static void chv_prepare_pll(struct intel_crtc *crtc,
const struct intel_crtc_state *pipe_config);
static void skl_pfit_enable(const struct intel_crtc_state *crtc_state);
static void ilk_pfit_enable(const struct intel_crtc_state *crtc_state);
static void intel_modeset_setup_hw_state(struct drm_device *dev,
struct drm_modeset_acquire_ctx *ctx);
......@@ -1082,32 +1082,6 @@ static unsigned int intel_tile_size(const struct drm_i915_private *dev_priv)
return IS_GEN(dev_priv, 2) ? 2048 : 4096;
}
static bool is_ccs_plane(const struct drm_framebuffer *fb, int plane)
{
if (!is_ccs_modifier(fb->modifier))
return false;
return plane >= fb->format->num_planes / 2;
}
static bool is_gen12_ccs_modifier(u64 modifier)
{
return modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS ||
modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC ||
modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS;
}
static bool is_gen12_ccs_plane(const struct drm_framebuffer *fb, int plane)
{
return is_gen12_ccs_modifier(fb->modifier) && is_ccs_plane(fb, plane);
}
static bool is_gen12_ccs_cc_plane(const struct drm_framebuffer *fb, int plane)
{
return fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC &&
plane == 2;
}
static bool is_aux_plane(const struct drm_framebuffer *fb, int plane)
{
if (is_ccs_modifier(fb->modifier))
......@@ -1116,38 +1090,6 @@ static bool is_aux_plane(const struct drm_framebuffer *fb, int plane)
return plane == 1;
}
static int main_to_ccs_plane(const struct drm_framebuffer *fb, int main_plane)
{
drm_WARN_ON(fb->dev, !is_ccs_modifier(fb->modifier) ||
(main_plane && main_plane >= fb->format->num_planes / 2));
return fb->format->num_planes / 2 + main_plane;
}
static int ccs_to_main_plane(const struct drm_framebuffer *fb, int ccs_plane)
{
drm_WARN_ON(fb->dev, !is_ccs_modifier(fb->modifier) ||
ccs_plane < fb->format->num_planes / 2);
if (is_gen12_ccs_cc_plane(fb, ccs_plane))
return 0;
return ccs_plane - fb->format->num_planes / 2;
}
int intel_main_to_aux_plane(const struct drm_framebuffer *fb, int main_plane)
{
struct drm_i915_private *i915 = to_i915(fb->dev);
if (is_ccs_modifier(fb->modifier))
return main_to_ccs_plane(fb, main_plane);
else if (INTEL_GEN(i915) < 11 &&
intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier))
return 1;
else
return 0;
}
bool
intel_format_info_is_yuv_semiplanar(const struct drm_format_info *info,
u64 modifier)
......@@ -1163,7 +1105,7 @@ static bool is_semiplanar_uv_plane(const struct drm_framebuffer *fb,
color_plane == 1;
}
static unsigned int
unsigned int
intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane)
{
struct drm_i915_private *dev_priv = to_i915(fb->dev);
......@@ -1217,7 +1159,7 @@ intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane)
}
}
static unsigned int
unsigned int
intel_tile_height(const struct drm_framebuffer *fb, int color_plane)
{
if (is_gen12_ccs_plane(fb, color_plane))
......@@ -1322,7 +1264,7 @@ static bool has_async_flips(struct drm_i915_private *i915)
return INTEL_GEN(i915) >= 5;
}
static unsigned int intel_surf_alignment(const struct drm_framebuffer *fb,
unsigned int intel_surf_alignment(const struct drm_framebuffer *fb,
int color_plane)
{
struct drm_i915_private *dev_priv = to_i915(fb->dev);
......@@ -1593,7 +1535,7 @@ static u32 intel_adjust_aligned_offset(int *x, int *y,
* Adjust the tile offset by moving the difference into
* the x/y offsets.
*/
static u32 intel_plane_adjust_aligned_offset(int *x, int *y,
u32 intel_plane_adjust_aligned_offset(int *x, int *y,
const struct intel_plane_state *state,
int color_plane,
u32 old_offset, u32 new_offset)
......@@ -1895,7 +1837,7 @@ bool is_ccs_modifier(u64 modifier)
static int gen12_ccs_aux_stride(struct drm_framebuffer *fb, int ccs_plane)
{
return DIV_ROUND_UP(fb->pitches[ccs_to_main_plane(fb, ccs_plane)],
return DIV_ROUND_UP(fb->pitches[skl_ccs_to_main_plane(fb, ccs_plane)],
512) * 64;
}
......@@ -2053,7 +1995,7 @@ static bool intel_plane_needs_remap(const struct intel_plane_state *plane_state)
return stride > max_stride;
}
static void
void
intel_fb_plane_get_subsampling(int *hsub, int *vsub,
const struct drm_framebuffer *fb,
int color_plane)
......@@ -2078,7 +2020,7 @@ intel_fb_plane_get_subsampling(int *hsub, int *vsub,
return;
}
main_plane = ccs_to_main_plane(fb, color_plane);
main_plane = skl_ccs_to_main_plane(fb, color_plane);
*hsub = drm_format_info_block_width(fb->format, color_plane) /
drm_format_info_block_width(fb->format, main_plane);
......@@ -2118,7 +2060,7 @@ intel_fb_check_ccs_xy(struct drm_framebuffer *fb, int ccs_plane, int x, int y)
ccs_x = (x * hsub) % tile_width;
ccs_y = (y * vsub) % tile_height;
main_plane = ccs_to_main_plane(fb, ccs_plane);
main_plane = skl_ccs_to_main_plane(fb, ccs_plane);
main_x = intel_fb->normal[main_plane].x % tile_width;
main_y = intel_fb->normal[main_plane].y % tile_height;
......@@ -2144,7 +2086,7 @@ static void
intel_fb_plane_dims(int *w, int *h, struct drm_framebuffer *fb, int color_plane)
{
int main_plane = is_ccs_plane(fb, color_plane) ?
ccs_to_main_plane(fb, color_plane) : 0;
skl_ccs_to_main_plane(fb, color_plane) : 0;
int main_hsub, main_vsub;
int hsub, vsub;
......@@ -2531,73 +2473,6 @@ static int i9xx_format_to_fourcc(int format)
}
}
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 struct i915_vma *
initial_plane_vma(struct drm_i915_private *i915,
struct intel_initial_plane_config *plane_config)
......@@ -2902,52 +2777,6 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
&to_intel_frontbuffer(fb)->bits);
}
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)
{
const struct drm_framebuffer *fb = plane_state->hw.fb;
int aux_x = plane_state->color_plane[ccs_plane].x;
int aux_y = plane_state->color_plane[ccs_plane].y;
u32 aux_offset = plane_state->color_plane[ccs_plane].offset;
u32 alignment = intel_surf_alignment(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;
plane_state->color_plane[ccs_plane].offset = aux_offset;
plane_state->color_plane[ccs_plane].x = aux_x;
plane_state->color_plane[ccs_plane].y = aux_y;
return true;
}
unsigned int
intel_plane_fence_y_offset(const struct intel_plane_state *plane_state)
{
......@@ -2959,310 +2788,6 @@ intel_plane_fence_y_offset(const struct intel_plane_state *plane_state)
return y;
}
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;
}
int skl_calc_main_surface_offset(const struct intel_plane_state *plane_state,
int *x, int *y, u32 *offset)
{
struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
const struct drm_framebuffer *fb = plane_state->hw.fb;
const int aux_plane = intel_main_to_aux_plane(fb, 0);
const u32 aux_offset = plane_state->color_plane[aux_plane].offset;
const u32 alignment = intel_surf_alignment(fb, 0);
const 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(&dev_priv->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->color_plane[0].stride) {
if (*offset == 0) {
drm_dbg_kms(&dev_priv->drm,
"Unable to find suitable display surface offset due to X-tiling\n");
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_plane *plane = to_intel_plane(plane_state->uapi.plane);
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
const struct drm_framebuffer *fb = plane_state->hw.fb;
const unsigned int rotation = plane_state->hw.rotation;
int x = plane_state->uapi.src.x1 >> 16;
int y = plane_state->uapi.src.y1 >> 16;
const int w = drm_rect_width(&plane_state->uapi.src) >> 16;
const int h = drm_rect_height(&plane_state->uapi.src) >> 16;
const int min_width = intel_plane_min_width(plane, fb, 0, rotation);
const int max_width = intel_plane_max_width(plane, fb, 0, rotation);
const int max_height = intel_plane_max_height(plane, fb, 0, rotation);
const int aux_plane = intel_main_to_aux_plane(fb, 0);
const u32 alignment = intel_surf_alignment(fb, 0);
u32 offset;
int ret;
if (w > max_width || w < min_width || h > max_height) {
drm_dbg_kms(&dev_priv->drm,
"requested Y/RGB source size %dx%d outside limits (min: %dx1 max: %dx%d)\n",
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.
*/
if (is_ccs_modifier(fb->modifier)) {
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);
}
if (x != plane_state->color_plane[aux_plane].x ||
y != plane_state->color_plane[aux_plane].y) {
drm_dbg_kms(&dev_priv->drm,
"Unable to find suitable display surface offset due to CCS\n");
return -EINVAL;
}
}
drm_WARN_ON(&dev_priv->drm, x > 8191 || y > 8191);
plane_state->color_plane[0].offset = offset;
plane_state->color_plane[0].x = x;
plane_state->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_plane *plane = to_intel_plane(plane_state->uapi.plane);
struct drm_i915_private *i915 = to_i915(plane->base.dev);
const struct drm_framebuffer *fb = plane_state->hw.fb;
unsigned int rotation = plane_state->hw.rotation;
int uv_plane = 1;
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(&i915->drm,
"CbCr source size %dx%d too big (limit %dx%d)\n",
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 (is_ccs_modifier(fb->modifier)) {
int ccs_plane = main_to_ccs_plane(fb, uv_plane);
u32 aux_offset = plane_state->color_plane[ccs_plane].offset;
u32 alignment = intel_surf_alignment(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);
}
if (x != plane_state->color_plane[ccs_plane].x ||
y != plane_state->color_plane[ccs_plane].y) {
drm_dbg_kms(&i915->drm,
"Unable to find suitable display surface offset due to CCS\n");
return -EINVAL;
}
}
drm_WARN_ON(&i915->drm, x > 8191 || y > 8191);
plane_state->color_plane[uv_plane].offset = offset;
plane_state->color_plane[uv_plane].x = x;
plane_state->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 (!is_ccs_plane(fb, ccs_plane) ||
is_gen12_ccs_cc_plane(fb, ccs_plane))
continue;
intel_fb_plane_get_subsampling(&main_hsub, &main_vsub, fb,
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);
plane_state->color_plane[ccs_plane].offset = offset;
plane_state->color_plane[ccs_plane].x = (x * hsub +
src_x % hsub) /
main_hsub;
plane_state->color_plane[ccs_plane].y = (y * vsub +
src_y % vsub) /
main_vsub;
}
return 0;
}
int skl_check_plane_surface(struct intel_plane_state *plane_state)
{
const struct drm_framebuffer *fb = plane_state->hw.fb;
int ret, i;
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 (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;
}
for (i = fb->format->num_planes; i < ARRAY_SIZE(plane_state->color_plane); i++) {
plane_state->color_plane[i].offset = 0;
plane_state->color_plane[i].x = 0;
plane_state->color_plane[i].y = 0;
}
ret = skl_check_main_surface(plane_state);
if (ret)
return ret;
return 0;
}
static void skl_detach_scaler(struct intel_crtc *intel_crtc, int id)
{
struct drm_device *dev = intel_crtc->base.dev;
......@@ -3295,307 +2820,6 @@ static void skl_detach_scalers(const struct intel_crtc_state *crtc_state)
}
}
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);
}
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;
u32 stride = plane_state->color_plane[color_plane].stride;
if (color_plane >= fb->format->num_planes)
return 0;
return stride / skl_plane_stride_mult(fb, color_plane, rotation);
}
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_YUYV;
case DRM_FORMAT_YVYU:
return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_YVYU;
case DRM_FORMAT_UYVY:
return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_UYVY;
case DRM_FORMAT_VYUY:
return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_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_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, thats 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 cnl_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;
}
u32 skl_plane_ctl_crtc(const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
u32 plane_ctl = 0;
if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
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;
}
u32 skl_plane_ctl(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state)
{
struct drm_i915_private *dev_priv =
to_i915(plane_state->uapi.plane->dev);
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 (INTEL_GEN(dev_priv) < 10 && !IS_GEMINILAKE(dev_priv)) {
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 (INTEL_GEN(dev_priv) >= 10)
plane_ctl |= cnl_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;
return plane_ctl;
}
u32 glk_plane_color_ctl_crtc(const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
u32 plane_color_ctl = 0;
if (INTEL_GEN(dev_priv) >= 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;
}
u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state)
{
struct drm_i915_private *dev_priv =
to_i915(plane_state->uapi.plane->dev);
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(dev_priv, 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;
}
return plane_color_ctl;
}
static int
__intel_display_resume(struct drm_device *dev,
struct drm_atomic_state *state,
......@@ -8279,150 +7503,6 @@ static void skl_get_pfit_config(struct intel_crtc_state *crtc_state)
scaler_state->scaler_users &= ~(1 << SKL_CRTC_INDEX);
}
static void
skl_get_initial_plane_config(struct intel_crtc *crtc,
struct intel_initial_plane_config *plane_config)
{
struct intel_crtc_state *crtc_state = to_intel_crtc_state(crtc->base.state);
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = to_i915(dev);
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;
if (!plane->get_hw_state(plane, &pipe))
return;
drm_WARN_ON(dev, pipe != crtc->pipe);
if (crtc_state->bigjoiner) {
drm_dbg_kms(&dev_priv->drm,
"Unsupported bigjoiner configuration for initial FB\n");
return;
}
intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
if (!intel_fb) {
drm_dbg_kms(&dev_priv->drm, "failed to alloc fb\n");
return;
}
fb = &intel_fb->base;
fb->dev = dev;
val = intel_de_read(dev_priv, PLANE_CTL(pipe, plane_id));
if (INTEL_GEN(dev_priv) >= 11)
pixel_format = val & ICL_PLANE_CTL_FORMAT_MASK;
else
pixel_format = val & PLANE_CTL_FORMAT_MASK;
if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) {
alpha = intel_de_read(dev_priv,
PLANE_COLOR_CTL(pipe, plane_id));
alpha &= PLANE_COLOR_ALPHA_MASK;
} else {
alpha = val & PLANE_CTL_ALPHA_MASK;
}
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)
fb->modifier = INTEL_GEN(dev_priv) >= 12 ?
I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS :
I915_FORMAT_MOD_Y_TILED_CCS;
else if (val & PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE)
fb->modifier = I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS;
else
fb->modifier = I915_FORMAT_MOD_Y_TILED;
break;
case PLANE_CTL_TILED_YF:
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;
}
/*
* DRM_MODE_ROTATE_ is counter clockwise to stay compatible with Xrandr
* while i915 HW rotation is clockwise, thats 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 (INTEL_GEN(dev_priv) >= 10 &&
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(dev_priv, PLANE_SURF(pipe, plane_id)) & 0xfffff000;
plane_config->base = base;
offset = intel_de_read(dev_priv, PLANE_OFFSET(pipe, plane_id));
val = intel_de_read(dev_priv, PLANE_SIZE(pipe, plane_id));
fb->height = ((val >> 16) & 0xffff) + 1;
fb->width = ((val >> 0) & 0xffff) + 1;
val = intel_de_read(dev_priv, PLANE_STRIDE(pipe, plane_id));
stride_mult = skl_plane_stride_mult(fb, 0, DRM_MODE_ROTATE_0);
fb->pitches[0] = (val & 0x3ff) * stride_mult;
aligned_height = intel_fb_align_height(fb, 0, fb->height);
plane_config->size = fb->pitches[0] * aligned_height;
drm_dbg_kms(&dev_priv->drm,
"%s/%s with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n",
crtc->base.name, 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);
}
static void ilk_get_pfit_config(struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
......
......@@ -52,6 +52,7 @@ struct intel_crtc_state;
struct intel_digital_port;
struct intel_dp;
struct intel_encoder;
struct intel_initial_plane_config;
struct intel_load_detect_pipe;
struct intel_plane;
struct intel_plane_state;
......@@ -517,7 +518,6 @@ void intel_link_compute_m_n(u16 bpp, int nlanes,
struct intel_link_m_n *m_n,
bool constant_n, bool fec_enable);
bool is_ccs_modifier(u64 modifier);
int intel_main_to_aux_plane(const struct drm_framebuffer *fb, int main_plane);
void lpt_disable_clkout_dp(struct drm_i915_private *dev_priv);
u32 intel_plane_fb_max_stride(struct drm_i915_private *dev_priv,
u32 pixel_format, u64 modifier);
......@@ -629,18 +629,7 @@ u32 skl_scaler_get_filter_select(enum drm_scaling_filter filter, int set);
void skl_scaler_setup_filter(struct drm_i915_private *dev_priv, enum pipe pipe,
int id, int set, enum drm_scaling_filter filter);
void ilk_pfit_disable(const struct intel_crtc_state *old_crtc_state);
u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state);
u32 glk_plane_color_ctl_crtc(const struct intel_crtc_state *crtc_state);
u32 skl_plane_ctl(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state);
u32 skl_plane_ctl_crtc(const struct intel_crtc_state *crtc_state);
u32 skl_plane_stride(const struct intel_plane_state *plane_state,
int plane);
int skl_check_plane_surface(struct intel_plane_state *plane_state);
int skl_calc_main_surface_offset(const struct intel_plane_state *plane_state,
int *x, int *y, u32 *offset);
int skl_format_to_fourcc(int format, bool rgb_order, bool alpha);
int bdw_get_pipemisc_bpp(struct intel_crtc *crtc);
unsigned int intel_plane_fence_y_offset(const struct intel_plane_state *plane_state);
......@@ -663,6 +652,18 @@ struct intel_encoder *
intel_get_crtc_new_encoder(const struct intel_atomic_state *state,
const struct intel_crtc_state *crtc_state);
unsigned int intel_surf_alignment(const struct drm_framebuffer *fb,
int color_plane);
void intel_fb_plane_get_subsampling(int *hsub, int *vsub,
const struct drm_framebuffer *fb,
int color_plane);
u32 intel_plane_adjust_aligned_offset(int *x, int *y,
const struct intel_plane_state *state,
int color_plane,
u32 old_offset, u32 new_offset);
unsigned int intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane);
unsigned int intel_tile_height(const struct drm_framebuffer *fb, int color_plane);
/* modesetting */
void intel_modeset_init_hw(struct drm_i915_private *i915);
int intel_modeset_init_noirq(struct drm_i915_private *i915);
......
......@@ -37,6 +37,7 @@
#include <drm/drm_dp_mst_helper.h>
#include <drm/drm_encoder.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_rect.h>
#include <drm/drm_vblank.h>
......@@ -1945,4 +1946,30 @@ static inline u32 intel_fdi_link_freq(struct drm_i915_private *dev_priv,
return dev_priv->fdi_pll_freq;
}
static inline bool is_ccs_plane(const struct drm_framebuffer *fb, int plane)
{
if (!is_ccs_modifier(fb->modifier))
return false;
return plane >= fb->format->num_planes / 2;
}
static inline bool is_gen12_ccs_modifier(u64 modifier)
{
return modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS ||
modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC ||
modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS;
}
static inline bool is_gen12_ccs_plane(const struct drm_framebuffer *fb, int plane)
{
return is_gen12_ccs_modifier(fb->modifier) && is_ccs_plane(fb, plane);
}
static inline bool is_gen12_ccs_cc_plane(const struct drm_framebuffer *fb, int plane)
{
return fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC &&
plane == 2;
}
#endif /* __INTEL_DISPLAY_TYPES_H__ */
......@@ -32,6 +32,7 @@
#include "intel_hdmi.h"
#include "intel_psr.h"
#include "intel_sprite.h"
#include "skl_universal_plane.h"
/**
* DOC: Panel Self Refresh (PSR/SRD)
......
......@@ -376,212 +376,7 @@ int intel_plane_check_src_coordinates(struct intel_plane_state *plane_state)
return 0;
}
static u8 icl_nv12_y_plane_mask(struct drm_i915_private *i915)
{
if (HAS_D12_PLANE_MINIMIZATION(i915))
return BIT(PLANE_SPRITE2) | BIT(PLANE_SPRITE3);
else
return BIT(PLANE_SPRITE4) | BIT(PLANE_SPRITE5);
}
bool icl_is_nv12_y_plane(struct drm_i915_private *dev_priv,
enum plane_id plane_id)
{
return INTEL_GEN(dev_priv) >= 11 &&
icl_nv12_y_plane_mask(dev_priv) & BIT(plane_id);
}
bool icl_is_hdr_plane(struct drm_i915_private *dev_priv, enum plane_id plane_id)
{
return INTEL_GEN(dev_priv) >= 11 &&
icl_hdr_plane_mask() & BIT(plane_id);
}
static void
skl_plane_ratio(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state,
unsigned int *num, unsigned int *den)
{
struct drm_i915_private *dev_priv = to_i915(plane_state->uapi.plane->dev);
const struct drm_framebuffer *fb = plane_state->hw.fb;
if (fb->format->cpp[0] == 8) {
if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) {
*num = 10;
*den = 8;
} else {
*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)
{
struct drm_i915_private *dev_priv = to_i915(plane_state->uapi.plane->dev);
unsigned int num, den;
unsigned int pixel_rate = intel_plane_pixel_rate(crtc_state, plane_state);
skl_plane_ratio(crtc_state, plane_state, &num, &den);
/* two pixels per clock on glk+ */
if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
den *= 2;
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:
case I915_FORMAT_MOD_Y_TILED_GEN12_MC_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 icl_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
skl_plane_max_stride(struct intel_plane *plane,
u32 pixel_format, u64 modifier,
unsigned int rotation)
{
const struct drm_format_info *info = drm_format_info(pixel_format);
int cpp = info->cpp[0];
/*
* "The stride in bytes must not exceed the
* of the size of 8K pixels and 32K bytes."
*/
if (drm_rotation_90_or_270(rotation))
return min(8192, 32768 / cpp);
else
return min(8192 * cpp, 32768);
}
static void
void
skl_program_scaler(struct intel_plane *plane,
const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state)
......@@ -643,317 +438,6 @@ skl_program_scaler(struct intel_plane *plane,
(crtc_w << 16) | crtc_h);
}
/* 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
icl_program_input_csc(struct intel_plane *plane,
const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state)
{
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
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];
intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 0),
ROFF(csc[0]) | GOFF(csc[1]));
intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 1),
BOFF(csc[2]));
intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 2),
ROFF(csc[3]) | GOFF(csc[4]));
intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 3),
BOFF(csc[5]));
intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 4),
ROFF(csc[6]) | GOFF(csc[7]));
intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 5),
BOFF(csc[8]));
intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 0),
PREOFF_YUV_TO_RGB_HI);
intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 1),
PREOFF_YUV_TO_RGB_ME);
intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 2),
PREOFF_YUV_TO_RGB_LO);
intel_de_write_fw(dev_priv,
PLANE_INPUT_CSC_POSTOFF(pipe, plane_id, 0), 0x0);
intel_de_write_fw(dev_priv,
PLANE_INPUT_CSC_POSTOFF(pipe, plane_id, 1), 0x0);
intel_de_write_fw(dev_priv,
PLANE_INPUT_CSC_POSTOFF(pipe, plane_id, 2), 0x0);
}
static void
skl_plane_async_flip(struct intel_plane *plane,
const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state,
bool async_flip)
{
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
unsigned long irqflags;
enum plane_id plane_id = plane->id;
enum pipe pipe = plane->pipe;
u32 surf_addr = plane_state->color_plane[0].offset;
u32 plane_ctl = plane_state->ctl;
plane_ctl |= skl_plane_ctl_crtc(crtc_state);
if (async_flip)
plane_ctl |= PLANE_CTL_ASYNC_FLIP;
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), plane_ctl);
intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id),
intel_plane_ggtt_offset(plane_state) + surf_addr);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
}
static void
skl_program_plane(struct intel_plane *plane,
const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state,
int color_plane)
{
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
enum plane_id plane_id = plane->id;
enum pipe pipe = plane->pipe;
const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
u32 surf_addr = plane_state->color_plane[color_plane].offset;
u32 stride = skl_plane_stride(plane_state, color_plane);
const struct drm_framebuffer *fb = plane_state->hw.fb;
int aux_plane = intel_main_to_aux_plane(fb, color_plane);
int crtc_x = plane_state->uapi.dst.x1;
int crtc_y = plane_state->uapi.dst.y1;
u32 x = plane_state->color_plane[color_plane].x;
u32 y = plane_state->color_plane[color_plane].y;
u32 src_w = drm_rect_width(&plane_state->uapi.src) >> 16;
u32 src_h = drm_rect_height(&plane_state->uapi.src) >> 16;
u8 alpha = plane_state->hw.alpha >> 8;
u32 plane_color_ctl = 0, aux_dist = 0;
unsigned long irqflags;
u32 keymsk, keymax;
u32 plane_ctl = plane_state->ctl;
plane_ctl |= skl_plane_ctl_crtc(crtc_state);
if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
plane_color_ctl = plane_state->color_ctl |
glk_plane_color_ctl_crtc(crtc_state);
/* Sizes are 0 based */
src_w--;
src_h--;
keymax = (key->max_value & 0xffffff) | PLANE_KEYMAX_ALPHA(alpha);
keymsk = key->channel_mask & 0x7ffffff;
if (alpha < 0xff)
keymsk |= PLANE_KEYMSK_ALPHA_ENABLE;
/* The scaler will handle the output position */
if (plane_state->scaler_id >= 0) {
crtc_x = 0;
crtc_y = 0;
}
if (aux_plane) {
aux_dist = plane_state->color_plane[aux_plane].offset - surf_addr;
if (INTEL_GEN(dev_priv) < 12)
aux_dist |= skl_plane_stride(plane_state, aux_plane);
}
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
intel_de_write_fw(dev_priv, PLANE_STRIDE(pipe, plane_id), stride);
intel_de_write_fw(dev_priv, PLANE_POS(pipe, plane_id),
(crtc_y << 16) | crtc_x);
intel_de_write_fw(dev_priv, PLANE_SIZE(pipe, plane_id),
(src_h << 16) | src_w);
intel_de_write_fw(dev_priv, PLANE_AUX_DIST(pipe, plane_id), aux_dist);
if (icl_is_hdr_plane(dev_priv, plane_id))
intel_de_write_fw(dev_priv, PLANE_CUS_CTL(pipe, plane_id),
plane_state->cus_ctl);
if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
intel_de_write_fw(dev_priv, PLANE_COLOR_CTL(pipe, plane_id),
plane_color_ctl);
if (fb->format->is_yuv && icl_is_hdr_plane(dev_priv, plane_id))
icl_program_input_csc(plane, crtc_state, plane_state);
if (fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC)
intel_uncore_write64_fw(&dev_priv->uncore,
PLANE_CC_VAL(pipe, plane_id), plane_state->ccval);
skl_write_plane_wm(plane, crtc_state);
intel_de_write_fw(dev_priv, PLANE_KEYVAL(pipe, plane_id),
key->min_value);
intel_de_write_fw(dev_priv, PLANE_KEYMSK(pipe, plane_id), keymsk);
intel_de_write_fw(dev_priv, PLANE_KEYMAX(pipe, plane_id), keymax);
intel_de_write_fw(dev_priv, PLANE_OFFSET(pipe, plane_id),
(y << 16) | x);
if (INTEL_GEN(dev_priv) < 11)
intel_de_write_fw(dev_priv, PLANE_AUX_OFFSET(pipe, plane_id),
(plane_state->color_plane[1].y << 16) | plane_state->color_plane[1].x);
if (!drm_atomic_crtc_needs_modeset(&crtc_state->uapi))
intel_psr2_program_plane_sel_fetch(plane, crtc_state, plane_state, color_plane);
/*
* 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.
*/
intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), plane_ctl);
intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id),
intel_plane_ggtt_offset(plane_state) + surf_addr);
if (plane_state->scaler_id >= 0)
skl_program_scaler(plane, crtc_state, plane_state);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
}
static void
skl_update_plane(struct intel_plane *plane,
const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state)
{
int color_plane = 0;
if (plane_state->planar_linked_plane && !plane_state->planar_slave)
/* Program the UV plane on planar master */
color_plane = 1;
skl_program_plane(plane, crtc_state, plane_state, color_plane);
}
static void
skl_disable_plane(struct intel_plane *plane,
const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
enum plane_id plane_id = plane->id;
enum pipe pipe = plane->pipe;
unsigned long irqflags;
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
if (icl_is_hdr_plane(dev_priv, plane_id))
intel_de_write_fw(dev_priv, PLANE_CUS_CTL(pipe, plane_id), 0);
skl_write_plane_wm(plane, crtc_state);
intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), 0);
intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id), 0);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
}
static bool
skl_plane_get_hw_state(struct intel_plane *plane,
enum pipe *pipe)
{
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
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(dev_priv, power_domain);
if (!wakeref)
return false;
ret = intel_de_read(dev_priv, PLANE_CTL(plane->pipe, plane_id)) & PLANE_CTL_ENABLE;
*pipe = plane->pipe;
intel_display_power_put(dev_priv, power_domain, wakeref);
return ret;
}
static void
skl_plane_enable_flip_done(struct intel_plane *plane)
{
struct drm_i915_private *i915 = to_i915(plane->base.dev);
enum pipe pipe = plane->pipe;
spin_lock_irq(&i915->irq_lock);
bdw_enable_pipe_irq(i915, pipe, GEN9_PIPE_PLANE_FLIP_DONE(plane->id));
spin_unlock_irq(&i915->irq_lock);
}
static void
skl_plane_disable_flip_done(struct intel_plane *plane)
{
struct drm_i915_private *i915 = to_i915(plane->base.dev);
enum pipe pipe = plane->pipe;
spin_lock_irq(&i915->irq_lock);
bdw_disable_pipe_irq(i915, pipe, GEN9_PIPE_PLANE_FLIP_DONE(plane->id));
spin_unlock_irq(&i915->irq_lock);
}
static void i9xx_plane_linear_gamma(u16 gamma[8])
{
/* The points are not evenly spaced. */
......@@ -2297,240 +1781,6 @@ vlv_sprite_check(struct intel_crtc_state *crtc_state,
return 0;
}
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_plane *plane = to_intel_plane(plane_state->uapi.plane);
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
const struct drm_framebuffer *fb = plane_state->hw.fb;
unsigned int rotation = plane_state->hw.rotation;
struct drm_format_name_buf format_name;
if (!fb)
return 0;
if (rotation & ~(DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180) &&
is_ccs_modifier(fb->modifier)) {
drm_dbg_kms(&dev_priv->drm,
"RC support only with 0/180 degree rotation (%x)\n",
rotation);
return -EINVAL;
}
if (rotation & DRM_MODE_REFLECT_X &&
fb->modifier == DRM_FORMAT_MOD_LINEAR) {
drm_dbg_kms(&dev_priv->drm,
"horizontal flip is not supported with linear surface formats\n");
return -EINVAL;
}
if (drm_rotation_90_or_270(rotation)) {
if (fb->modifier != I915_FORMAT_MOD_Y_TILED &&
fb->modifier != I915_FORMAT_MOD_Yf_TILED) {
drm_dbg_kms(&dev_priv->drm,
"Y/Yf tiling required for 90/270!\n");
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 (INTEL_GEN(dev_priv) >= 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(&dev_priv->drm,
"Unsupported pixel format %s for 90/270!\n",
drm_get_format_name(fb->format->format,
&format_name));
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 == I915_FORMAT_MOD_Y_TILED ||
fb->modifier == I915_FORMAT_MOD_Yf_TILED ||
fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS ||
fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS ||
fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS ||
fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC)) {
drm_dbg_kms(&dev_priv->drm,
"Y/Yf tiling not supported in IF-ID mode\n");
return -EINVAL;
}
/* Wa_1606054188:tgl,adl-s */
if ((IS_ALDERLAKE_S(dev_priv) || IS_TIGERLAKE(dev_priv)) &&
plane_state->ckey.flags & I915_SET_COLORKEY_SOURCE &&
intel_format_is_p01x(fb->format->format)) {
drm_dbg_kms(&dev_priv->drm,
"Source color keying not supported with P01x formats\n");
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 drm_i915_private *dev_priv =
to_i915(plane_state->uapi.plane->dev);
int crtc_x = plane_state->uapi.dst.x1;
int crtc_w = drm_rect_width(&plane_state->uapi.dst);
int pipe_src_w = crtc_state->pipe_src_w;
/*
* Display WA #1175: cnl,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 ((IS_GEMINILAKE(dev_priv) || IS_CANNONLAKE(dev_priv)) &&
(crtc_x + crtc_w < 4 || crtc_x > pipe_src_w - 4)) {
drm_dbg_kms(&dev_priv->drm,
"requested plane X %s position %d invalid (valid range %d-%d)\n",
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)
{
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_DEBUG_KMS("src width must be multiple of 4 for rotated planar YUV\n");
return -EINVAL;
}
return 0;
}
static int skl_plane_max_scale(struct drm_i915_private *dev_priv,
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 (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv) ||
!intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier))
return 0x30000 - 1;
else
return 0x20000 - 1;
}
static int skl_plane_check(struct intel_crtc_state *crtc_state,
struct intel_plane_state *plane_state)
{
struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
const struct drm_framebuffer *fb = plane_state->hw.fb;
int min_scale = DRM_PLANE_HELPER_NO_SCALING;
int max_scale = DRM_PLANE_HELPER_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 && intel_fb_scalable(fb)) {
min_scale = 1;
max_scale = skl_plane_max_scale(dev_priv, fb);
}
ret = intel_atomic_plane_check_clipping(plane_state, crtc_state,
min_scale, max_scale, true);
if (ret)
return ret;
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;
ret = skl_plane_check_nv12_rotation(plane_state);
if (ret)
return ret;
/* HW only has 8 bits pixel precision, disable plane if invisible */
if (!(plane_state->hw.alpha >> 8))
plane_state->uapi.visible = false;
plane_state->ctl = skl_plane_ctl(crtc_state, plane_state);
if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
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(dev_priv, 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;
}
static bool has_dst_key_in_primary_plane(struct drm_i915_private *dev_priv)
{
return INTEL_GEN(dev_priv) >= 9;
......@@ -2657,169 +1907,41 @@ static const u32 g4x_plane_formats[] = {
DRM_FORMAT_VYUY,
};
static const u64 i9xx_plane_format_modifiers[] = {
I915_FORMAT_MOD_X_TILED,
DRM_FORMAT_MOD_LINEAR,
DRM_FORMAT_MOD_INVALID
};
static const u32 snb_plane_formats[] = {
DRM_FORMAT_XRGB8888,
DRM_FORMAT_XBGR8888,
DRM_FORMAT_XRGB2101010,
DRM_FORMAT_XBGR2101010,
DRM_FORMAT_XRGB16161616F,
DRM_FORMAT_XBGR16161616F,
DRM_FORMAT_YUYV,
DRM_FORMAT_YVYU,
DRM_FORMAT_UYVY,
DRM_FORMAT_VYUY,
};
static const u32 vlv_plane_formats[] = {
DRM_FORMAT_C8,
DRM_FORMAT_RGB565,
DRM_FORMAT_XRGB8888,
DRM_FORMAT_XBGR8888,
DRM_FORMAT_ARGB8888,
DRM_FORMAT_ABGR8888,
DRM_FORMAT_XBGR2101010,
DRM_FORMAT_ABGR2101010,
DRM_FORMAT_YUYV,
DRM_FORMAT_YVYU,
DRM_FORMAT_UYVY,
DRM_FORMAT_VYUY,
};
static const u32 chv_pipe_b_sprite_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,
};
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 u64 i9xx_plane_format_modifiers[] = {
I915_FORMAT_MOD_X_TILED,
DRM_FORMAT_MOD_LINEAR,
DRM_FORMAT_MOD_INVALID
};
static const u32 icl_sdr_y_plane_formats[] = {
DRM_FORMAT_C8,
DRM_FORMAT_RGB565,
static const u32 snb_plane_formats[] = {
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_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,
DRM_FORMAT_XVYU12_16161616,
DRM_FORMAT_XVYU16161616,
};
static const u32 icl_sdr_uv_plane_formats[] = {
static const u32 vlv_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,
DRM_FORMAT_XVYU12_16161616,
DRM_FORMAT_XVYU16161616,
};
static const u32 icl_hdr_plane_formats[] = {
static const u32 chv_pipe_b_sprite_formats[] = {
DRM_FORMAT_C8,
DRM_FORMAT_RGB565,
DRM_FORMAT_XRGB8888,
......@@ -2830,62 +1952,10 @@ static const u32 icl_hdr_plane_formats[] = {
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,
};
static const u64 skl_plane_format_modifiers_noccs[] = {
I915_FORMAT_MOD_Yf_TILED,
I915_FORMAT_MOD_Y_TILED,
I915_FORMAT_MOD_X_TILED,
DRM_FORMAT_MOD_LINEAR,
DRM_FORMAT_MOD_INVALID
};
static const u64 skl_plane_format_modifiers_ccs[] = {
I915_FORMAT_MOD_Yf_TILED_CCS,
I915_FORMAT_MOD_Y_TILED_CCS,
I915_FORMAT_MOD_Yf_TILED,
I915_FORMAT_MOD_Y_TILED,
I915_FORMAT_MOD_X_TILED,
DRM_FORMAT_MOD_LINEAR,
DRM_FORMAT_MOD_INVALID
};
static const u64 gen12_plane_format_modifiers_mc_ccs[] = {
I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS,
I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS,
I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC,
I915_FORMAT_MOD_Y_TILED,
I915_FORMAT_MOD_X_TILED,
DRM_FORMAT_MOD_LINEAR,
DRM_FORMAT_MOD_INVALID
};
static const u64 gen12_plane_format_modifiers_rc_ccs[] = {
I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS,
I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC,
I915_FORMAT_MOD_Y_TILED,
I915_FORMAT_MOD_X_TILED,
DRM_FORMAT_MOD_LINEAR,
DRM_FORMAT_MOD_INVALID
};
static bool g4x_sprite_format_mod_supported(struct drm_plane *_plane,
......@@ -2980,150 +2050,6 @@ static bool vlv_sprite_format_mod_supported(struct drm_plane *_plane,
}
}
static bool skl_plane_format_mod_supported(struct drm_plane *_plane,
u32 format, u64 modifier)
{
struct intel_plane *plane = to_intel_plane(_plane);
switch (modifier) {
case DRM_FORMAT_MOD_LINEAR:
case I915_FORMAT_MOD_X_TILED:
case I915_FORMAT_MOD_Y_TILED:
case I915_FORMAT_MOD_Yf_TILED:
break;
case I915_FORMAT_MOD_Y_TILED_CCS:
case I915_FORMAT_MOD_Yf_TILED_CCS:
if (!plane->has_ccs)
return false;
break;
default:
return false;
}
switch (format) {
case DRM_FORMAT_XRGB8888:
case DRM_FORMAT_XBGR8888:
case DRM_FORMAT_ARGB8888:
case DRM_FORMAT_ABGR8888:
if (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 gen12_plane_supports_mc_ccs(struct drm_i915_private *dev_priv,
enum plane_id plane_id)
{
/* Wa_14010477008:tgl[a0..c0],rkl[all],dg1[all] */
if (IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv) ||
IS_TGL_DISP_STEPPING(dev_priv, STEP_A0, STEP_C0))
return false;
return plane_id < PLANE_SPRITE4;
}
static bool gen12_plane_format_mod_supported(struct drm_plane *_plane,
u32 format, u64 modifier)
{
struct drm_i915_private *dev_priv = to_i915(_plane->dev);
struct intel_plane *plane = to_intel_plane(_plane);
switch (modifier) {
case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
if (!gen12_plane_supports_mc_ccs(dev_priv, plane->id))
return false;
fallthrough;
case DRM_FORMAT_MOD_LINEAR:
case I915_FORMAT_MOD_X_TILED:
case I915_FORMAT_MOD_Y_TILED:
case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC:
break;
default:
return false;
}
switch (format) {
case DRM_FORMAT_XRGB8888:
case DRM_FORMAT_XBGR8888:
case DRM_FORMAT_ARGB8888:
case DRM_FORMAT_ABGR8888:
if (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 (modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS)
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_XVYU2101010:
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 const struct drm_plane_funcs g4x_sprite_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
......@@ -3151,257 +2077,6 @@ static const struct drm_plane_funcs vlv_sprite_funcs = {
.format_mod_supported = vlv_sprite_format_mod_supported,
};
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,
};
static const struct drm_plane_funcs gen12_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 = gen12_plane_format_mod_supported,
};
static bool skl_plane_has_fbc(struct drm_i915_private *dev_priv,
enum pipe pipe, enum plane_id plane_id)
{
if (!HAS_FBC(dev_priv))
return false;
return pipe == PIPE_A && plane_id == PLANE_PRIMARY;
}
static bool skl_plane_has_planar(struct drm_i915_private *dev_priv,
enum pipe pipe, enum plane_id plane_id)
{
/* Display WA #0870: skl, bxt */
if (IS_SKYLAKE(dev_priv) || IS_BROXTON(dev_priv))
return false;
if (IS_GEN(dev_priv, 9) && !IS_GEMINILAKE(dev_priv) && pipe == PIPE_C)
return false;
if (plane_id != PLANE_PRIMARY && plane_id != PLANE_SPRITE0)
return false;
return true;
}
static const u32 *skl_get_plane_formats(struct drm_i915_private *dev_priv,
enum pipe pipe, enum plane_id plane_id,
int *num_formats)
{
if (skl_plane_has_planar(dev_priv, 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 drm_i915_private *dev_priv,
enum pipe pipe, enum plane_id plane_id,
int *num_formats)
{
if (skl_plane_has_planar(dev_priv, 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 drm_i915_private *dev_priv,
enum pipe pipe, enum plane_id plane_id,
int *num_formats)
{
if (icl_is_hdr_plane(dev_priv, plane_id)) {
*num_formats = ARRAY_SIZE(icl_hdr_plane_formats);
return icl_hdr_plane_formats;
} else if (icl_is_nv12_y_plane(dev_priv, 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 const u64 *gen12_get_plane_modifiers(struct drm_i915_private *dev_priv,
enum plane_id plane_id)
{
if (gen12_plane_supports_mc_ccs(dev_priv, plane_id))
return gen12_plane_format_modifiers_mc_ccs;
else
return gen12_plane_format_modifiers_rc_ccs;
}
static bool skl_plane_has_ccs(struct drm_i915_private *dev_priv,
enum pipe pipe, enum plane_id plane_id)
{
if (plane_id == PLANE_CURSOR)
return false;
if (INTEL_GEN(dev_priv) >= 10)
return true;
if (IS_GEMINILAKE(dev_priv))
return pipe != PIPE_C;
return pipe != PIPE_C &&
(plane_id == PLANE_PRIMARY ||
plane_id == PLANE_SPRITE0);
}
struct intel_plane *
skl_universal_plane_create(struct drm_i915_private *dev_priv,
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;
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);
plane->has_fbc = skl_plane_has_fbc(dev_priv, pipe, plane_id);
if (plane->has_fbc) {
struct intel_fbc *fbc = &dev_priv->fbc;
fbc->possible_framebuffer_bits |= plane->frontbuffer_bit;
}
if (INTEL_GEN(dev_priv) >= 11) {
plane->min_width = icl_plane_min_width;
plane->max_width = icl_plane_max_width;
plane->max_height = icl_plane_max_height;
} else if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) {
plane->max_width = glk_plane_max_width;
plane->max_height = skl_plane_max_height;
} else {
plane->max_width = skl_plane_max_width;
plane->max_height = skl_plane_max_height;
}
plane->max_stride = skl_plane_max_stride;
plane->update_plane = skl_update_plane;
plane->disable_plane = skl_disable_plane;
plane->get_hw_state = skl_plane_get_hw_state;
plane->check_plane = skl_plane_check;
plane->min_cdclk = skl_plane_min_cdclk;
if (plane_id == PLANE_PRIMARY) {
plane->need_async_flip_disable_wa = IS_GEN_RANGE(dev_priv, 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 (INTEL_GEN(dev_priv) >= 11)
formats = icl_get_plane_formats(dev_priv, pipe,
plane_id, &num_formats);
else if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
formats = glk_get_plane_formats(dev_priv, pipe,
plane_id, &num_formats);
else
formats = skl_get_plane_formats(dev_priv, pipe,
plane_id, &num_formats);
plane->has_ccs = skl_plane_has_ccs(dev_priv, pipe, plane_id);
if (INTEL_GEN(dev_priv) >= 12) {
modifiers = gen12_get_plane_modifiers(dev_priv, plane_id);
plane_funcs = &gen12_plane_funcs;
} else {
if (plane->has_ccs)
modifiers = skl_plane_format_modifiers_ccs;
else
modifiers = skl_plane_format_modifiers_noccs;
plane_funcs = &skl_plane_funcs;
}
if (plane_id == PLANE_PRIMARY)
plane_type = DRM_PLANE_TYPE_PRIMARY;
else
plane_type = DRM_PLANE_TYPE_OVERLAY;
ret = drm_universal_plane_init(&dev_priv->drm, &plane->base,
0, plane_funcs,
formats, num_formats, modifiers,
plane_type,
"plane %d%c", plane_id + 1,
pipe_name(pipe));
if (ret)
goto fail;
supported_rotations =
DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 |
DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270;
if (INTEL_GEN(dev_priv) >= 10)
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 (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
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 (INTEL_GEN(dev_priv) >= 12)
drm_plane_enable_fb_damage_clips(&plane->base);
if (INTEL_GEN(dev_priv) >= 10)
drm_plane_create_scaling_filter_property(&plane->base,
BIT(DRM_SCALING_FILTER_DEFAULT) |
BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR));
drm_plane_helper_add(&plane->base, &intel_plane_helper_funcs);
return plane;
fail:
intel_plane_free(plane);
return ERR_PTR(ret);
}
struct intel_plane *
intel_sprite_plane_create(struct drm_i915_private *dev_priv,
enum pipe pipe, int sprite)
......@@ -3414,10 +2089,6 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv,
int num_formats;
int ret, zpos;
if (INTEL_GEN(dev_priv) >= 9)
return skl_universal_plane_create(dev_priv, pipe,
PLANE_SPRITE0 + sprite);
plane = intel_plane_alloc();
if (IS_ERR(plane))
return plane;
......
......@@ -38,9 +38,6 @@ void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state);
int intel_plane_check_stride(const struct intel_plane_state *plane_state);
int intel_plane_check_src_coordinates(struct intel_plane_state *plane_state);
int chv_plane_check_rotation(const struct intel_plane_state *plane_state);
struct intel_plane *
skl_universal_plane_create(struct drm_i915_private *dev_priv,
enum pipe pipe, enum plane_id plane_id);
static inline u8 icl_hdr_plane_mask(void)
{
......@@ -59,4 +56,7 @@ int hsw_plane_min_cdclk(const struct intel_crtc_state *crtc_state,
int vlv_plane_min_cdclk(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state);
void skl_program_scaler(struct intel_plane *plane,
const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state);
#endif /* __INTEL_SPRITE_H__ */
// SPDX-License-Identifier: MIT
/*
* Copyright © 2020 Intel Corporation
*/
#include <drm/drm_atomic_helper.h>
#include <drm/drm_damage_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_plane_helper.h>
#include "i915_drv.h"
#include "intel_atomic_plane.h"
#include "intel_display_types.h"
#include "intel_pm.h"
#include "intel_psr.h"
#include "intel_sprite.h"
#include "skl_universal_plane.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,
DRM_FORMAT_XVYU12_16161616,
DRM_FORMAT_XVYU16161616,
};
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,
DRM_FORMAT_XVYU12_16161616,
DRM_FORMAT_XVYU16161616,
};
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,
};
static const u64 skl_plane_format_modifiers_noccs[] = {
I915_FORMAT_MOD_Yf_TILED,
I915_FORMAT_MOD_Y_TILED,
I915_FORMAT_MOD_X_TILED,
DRM_FORMAT_MOD_LINEAR,
DRM_FORMAT_MOD_INVALID
};
static const u64 skl_plane_format_modifiers_ccs[] = {
I915_FORMAT_MOD_Yf_TILED_CCS,
I915_FORMAT_MOD_Y_TILED_CCS,
I915_FORMAT_MOD_Yf_TILED,
I915_FORMAT_MOD_Y_TILED,
I915_FORMAT_MOD_X_TILED,
DRM_FORMAT_MOD_LINEAR,
DRM_FORMAT_MOD_INVALID
};
static const u64 gen12_plane_format_modifiers_mc_ccs[] = {
I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS,
I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS,
I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC,
I915_FORMAT_MOD_Y_TILED,
I915_FORMAT_MOD_X_TILED,
DRM_FORMAT_MOD_LINEAR,
DRM_FORMAT_MOD_INVALID
};
static const u64 gen12_plane_format_modifiers_rc_ccs[] = {
I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS,
I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC,
I915_FORMAT_MOD_Y_TILED,
I915_FORMAT_MOD_X_TILED,
DRM_FORMAT_MOD_LINEAR,
DRM_FORMAT_MOD_INVALID
};
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 drm_i915_private *i915)
{
if (HAS_D12_PLANE_MINIMIZATION(i915))
return BIT(PLANE_SPRITE2) | BIT(PLANE_SPRITE3);
else
return BIT(PLANE_SPRITE4) | BIT(PLANE_SPRITE5);
}
bool icl_is_nv12_y_plane(struct drm_i915_private *dev_priv,
enum plane_id plane_id)
{
return INTEL_GEN(dev_priv) >= 11 &&
icl_nv12_y_plane_mask(dev_priv) & BIT(plane_id);
}
bool icl_is_hdr_plane(struct drm_i915_private *dev_priv, enum plane_id plane_id)
{
return INTEL_GEN(dev_priv) >= 11 &&
icl_hdr_plane_mask() & BIT(plane_id);
}
static void
skl_plane_ratio(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state,
unsigned int *num, unsigned int *den)
{
struct drm_i915_private *dev_priv = to_i915(plane_state->uapi.plane->dev);
const struct drm_framebuffer *fb = plane_state->hw.fb;
if (fb->format->cpp[0] == 8) {
if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) {
*num = 10;
*den = 8;
} else {
*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)
{
struct drm_i915_private *dev_priv = to_i915(plane_state->uapi.plane->dev);
unsigned int num, den;
unsigned int pixel_rate = intel_plane_pixel_rate(crtc_state, plane_state);
skl_plane_ratio(crtc_state, plane_state, &num, &den);
/* two pixels per clock on glk+ */
if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
den *= 2;
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:
case I915_FORMAT_MOD_Y_TILED_GEN12_MC_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 icl_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
skl_plane_max_stride(struct intel_plane *plane,
u32 pixel_format, u64 modifier,
unsigned int rotation)
{
const struct drm_format_info *info = drm_format_info(pixel_format);
int cpp = info->cpp[0];
/*
* "The stride in bytes must not exceed the
* of the size of 8K pixels and 32K bytes."
*/
if (drm_rotation_90_or_270(rotation))
return min(8192, 32768 / cpp);
else
return min(8192 * cpp, 32768);
}
/* 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
icl_program_input_csc(struct intel_plane *plane,
const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state)
{
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
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];
intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 0),
ROFF(csc[0]) | GOFF(csc[1]));
intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 1),
BOFF(csc[2]));
intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 2),
ROFF(csc[3]) | GOFF(csc[4]));
intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 3),
BOFF(csc[5]));
intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 4),
ROFF(csc[6]) | GOFF(csc[7]));
intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 5),
BOFF(csc[8]));
intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 0),
PREOFF_YUV_TO_RGB_HI);
intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 1),
PREOFF_YUV_TO_RGB_ME);
intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 2),
PREOFF_YUV_TO_RGB_LO);
intel_de_write_fw(dev_priv,
PLANE_INPUT_CSC_POSTOFF(pipe, plane_id, 0), 0x0);
intel_de_write_fw(dev_priv,
PLANE_INPUT_CSC_POSTOFF(pipe, plane_id, 1), 0x0);
intel_de_write_fw(dev_priv,
PLANE_INPUT_CSC_POSTOFF(pipe, plane_id, 2), 0x0);
}
static bool is_surface_linear(const struct drm_framebuffer *fb, int color_plane)
{
return fb->modifier == DRM_FORMAT_MOD_LINEAR ||
is_gen12_ccs_plane(fb, color_plane);
}
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;
u32 stride = plane_state->color_plane[color_plane].stride;
if (color_plane >= fb->format->num_planes)
return 0;
return stride / skl_plane_stride_mult(fb, color_plane, rotation);
}
static void
skl_disable_plane(struct intel_plane *plane,
const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
enum plane_id plane_id = plane->id;
enum pipe pipe = plane->pipe;
unsigned long irqflags;
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
if (icl_is_hdr_plane(dev_priv, plane_id))
intel_de_write_fw(dev_priv, PLANE_CUS_CTL(pipe, plane_id), 0);
skl_write_plane_wm(plane, crtc_state);
intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), 0);
intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id), 0);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
}
static bool
skl_plane_get_hw_state(struct intel_plane *plane,
enum pipe *pipe)
{
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
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(dev_priv, power_domain);
if (!wakeref)
return false;
ret = intel_de_read(dev_priv, PLANE_CTL(plane->pipe, plane_id)) & PLANE_CTL_ENABLE;
*pipe = plane->pipe;
intel_display_power_put(dev_priv, 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_YUYV;
case DRM_FORMAT_YVYU:
return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_YVYU;
case DRM_FORMAT_UYVY:
return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_UYVY;
case DRM_FORMAT_VYUY:
return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_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_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, thats 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 cnl_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 skl_plane_ctl_crtc(const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
u32 plane_ctl = 0;
if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
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 drm_i915_private *dev_priv =
to_i915(plane_state->uapi.plane->dev);
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 (INTEL_GEN(dev_priv) < 10 && !IS_GEMINILAKE(dev_priv)) {
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 (INTEL_GEN(dev_priv) >= 10)
plane_ctl |= cnl_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;
return plane_ctl;
}
static u32 glk_plane_color_ctl_crtc(const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
u32 plane_color_ctl = 0;
if (INTEL_GEN(dev_priv) >= 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 drm_i915_private *dev_priv =
to_i915(plane_state->uapi.plane->dev);
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(dev_priv, 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;
}
return plane_color_ctl;
}
static int
main_to_ccs_plane(const struct drm_framebuffer *fb, int main_plane)
{
drm_WARN_ON(fb->dev, !is_ccs_modifier(fb->modifier) ||
(main_plane && main_plane >= fb->format->num_planes / 2));
return fb->format->num_planes / 2 + main_plane;
}
int skl_ccs_to_main_plane(const struct drm_framebuffer *fb, int ccs_plane)
{
drm_WARN_ON(fb->dev, !is_ccs_modifier(fb->modifier) ||
ccs_plane < fb->format->num_planes / 2);
if (is_gen12_ccs_cc_plane(fb, ccs_plane))
return 0;
return ccs_plane - fb->format->num_planes / 2;
}
static int
skl_main_to_aux_plane(const struct drm_framebuffer *fb, int main_plane)
{
struct drm_i915_private *i915 = to_i915(fb->dev);
if (is_ccs_modifier(fb->modifier))
return main_to_ccs_plane(fb, main_plane);
else if (INTEL_GEN(i915) < 11 &&
intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier))
return 1;
else
return 0;
}
static void
skl_program_plane(struct intel_plane *plane,
const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state,
int color_plane)
{
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
enum plane_id plane_id = plane->id;
enum pipe pipe = plane->pipe;
const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
u32 surf_addr = plane_state->color_plane[color_plane].offset;
u32 stride = skl_plane_stride(plane_state, color_plane);
const struct drm_framebuffer *fb = plane_state->hw.fb;
int aux_plane = skl_main_to_aux_plane(fb, color_plane);
int crtc_x = plane_state->uapi.dst.x1;
int crtc_y = plane_state->uapi.dst.y1;
u32 x = plane_state->color_plane[color_plane].x;
u32 y = plane_state->color_plane[color_plane].y;
u32 src_w = drm_rect_width(&plane_state->uapi.src) >> 16;
u32 src_h = drm_rect_height(&plane_state->uapi.src) >> 16;
u8 alpha = plane_state->hw.alpha >> 8;
u32 plane_color_ctl = 0, aux_dist = 0;
unsigned long irqflags;
u32 keymsk, keymax;
u32 plane_ctl = plane_state->ctl;
plane_ctl |= skl_plane_ctl_crtc(crtc_state);
if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
plane_color_ctl = plane_state->color_ctl |
glk_plane_color_ctl_crtc(crtc_state);
/* Sizes are 0 based */
src_w--;
src_h--;
keymax = (key->max_value & 0xffffff) | PLANE_KEYMAX_ALPHA(alpha);
keymsk = key->channel_mask & 0x7ffffff;
if (alpha < 0xff)
keymsk |= PLANE_KEYMSK_ALPHA_ENABLE;
/* The scaler will handle the output position */
if (plane_state->scaler_id >= 0) {
crtc_x = 0;
crtc_y = 0;
}
if (aux_plane) {
aux_dist = plane_state->color_plane[aux_plane].offset - surf_addr;
if (INTEL_GEN(dev_priv) < 12)
aux_dist |= skl_plane_stride(plane_state, aux_plane);
}
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
intel_de_write_fw(dev_priv, PLANE_STRIDE(pipe, plane_id), stride);
intel_de_write_fw(dev_priv, PLANE_POS(pipe, plane_id),
(crtc_y << 16) | crtc_x);
intel_de_write_fw(dev_priv, PLANE_SIZE(pipe, plane_id),
(src_h << 16) | src_w);
intel_de_write_fw(dev_priv, PLANE_AUX_DIST(pipe, plane_id), aux_dist);
if (icl_is_hdr_plane(dev_priv, plane_id))
intel_de_write_fw(dev_priv, PLANE_CUS_CTL(pipe, plane_id),
plane_state->cus_ctl);
if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
intel_de_write_fw(dev_priv, PLANE_COLOR_CTL(pipe, plane_id),
plane_color_ctl);
if (fb->format->is_yuv && icl_is_hdr_plane(dev_priv, plane_id))
icl_program_input_csc(plane, crtc_state, plane_state);
if (fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC)
intel_uncore_write64_fw(&dev_priv->uncore,
PLANE_CC_VAL(pipe, plane_id), plane_state->ccval);
skl_write_plane_wm(plane, crtc_state);
intel_de_write_fw(dev_priv, PLANE_KEYVAL(pipe, plane_id),
key->min_value);
intel_de_write_fw(dev_priv, PLANE_KEYMSK(pipe, plane_id), keymsk);
intel_de_write_fw(dev_priv, PLANE_KEYMAX(pipe, plane_id), keymax);
intel_de_write_fw(dev_priv, PLANE_OFFSET(pipe, plane_id),
(y << 16) | x);
if (INTEL_GEN(dev_priv) < 11)
intel_de_write_fw(dev_priv, PLANE_AUX_OFFSET(pipe, plane_id),
(plane_state->color_plane[1].y << 16) | plane_state->color_plane[1].x);
if (!drm_atomic_crtc_needs_modeset(&crtc_state->uapi))
intel_psr2_program_plane_sel_fetch(plane, crtc_state, plane_state, color_plane);
/*
* 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.
*/
intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), plane_ctl);
intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id),
intel_plane_ggtt_offset(plane_state) + surf_addr);
if (plane_state->scaler_id >= 0)
skl_program_scaler(plane, crtc_state, plane_state);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
}
static void
skl_plane_async_flip(struct intel_plane *plane,
const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state,
bool async_flip)
{
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
unsigned long irqflags;
enum plane_id plane_id = plane->id;
enum pipe pipe = plane->pipe;
u32 surf_addr = plane_state->color_plane[0].offset;
u32 plane_ctl = plane_state->ctl;
plane_ctl |= skl_plane_ctl_crtc(crtc_state);
if (async_flip)
plane_ctl |= PLANE_CTL_ASYNC_FLIP;
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), plane_ctl);
intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id),
intel_plane_ggtt_offset(plane_state) + surf_addr);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
}
static void
skl_update_plane(struct intel_plane *plane,
const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state)
{
int color_plane = 0;
if (plane_state->planar_linked_plane && !plane_state->planar_slave)
/* Program the UV plane on planar master */
color_plane = 1;
skl_program_plane(plane, crtc_state, plane_state, color_plane);
}
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_plane *plane = to_intel_plane(plane_state->uapi.plane);
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
const struct drm_framebuffer *fb = plane_state->hw.fb;
unsigned int rotation = plane_state->hw.rotation;
struct drm_format_name_buf format_name;
if (!fb)
return 0;
if (rotation & ~(DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180) &&
is_ccs_modifier(fb->modifier)) {
drm_dbg_kms(&dev_priv->drm,
"RC support only with 0/180 degree rotation (%x)\n",
rotation);
return -EINVAL;
}
if (rotation & DRM_MODE_REFLECT_X &&
fb->modifier == DRM_FORMAT_MOD_LINEAR) {
drm_dbg_kms(&dev_priv->drm,
"horizontal flip is not supported with linear surface formats\n");
return -EINVAL;
}
if (drm_rotation_90_or_270(rotation)) {
if (fb->modifier != I915_FORMAT_MOD_Y_TILED &&
fb->modifier != I915_FORMAT_MOD_Yf_TILED) {
drm_dbg_kms(&dev_priv->drm,
"Y/Yf tiling required for 90/270!\n");
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 (INTEL_GEN(dev_priv) >= 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(&dev_priv->drm,
"Unsupported pixel format %s for 90/270!\n",
drm_get_format_name(fb->format->format,
&format_name));
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 == I915_FORMAT_MOD_Y_TILED ||
fb->modifier == I915_FORMAT_MOD_Yf_TILED ||
fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS ||
fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS ||
fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS ||
fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC)) {
drm_dbg_kms(&dev_priv->drm,
"Y/Yf tiling not supported in IF-ID mode\n");
return -EINVAL;
}
/* Wa_1606054188:tgl,adl-s */
if ((IS_ALDERLAKE_S(dev_priv) || IS_TIGERLAKE(dev_priv)) &&
plane_state->ckey.flags & I915_SET_COLORKEY_SOURCE &&
intel_format_is_p01x(fb->format->format)) {
drm_dbg_kms(&dev_priv->drm,
"Source color keying not supported with P01x formats\n");
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 drm_i915_private *dev_priv =
to_i915(plane_state->uapi.plane->dev);
int crtc_x = plane_state->uapi.dst.x1;
int crtc_w = drm_rect_width(&plane_state->uapi.dst);
int pipe_src_w = crtc_state->pipe_src_w;
/*
* Display WA #1175: cnl,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 ((IS_GEMINILAKE(dev_priv) || IS_CANNONLAKE(dev_priv)) &&
(crtc_x + crtc_w < 4 || crtc_x > pipe_src_w - 4)) {
drm_dbg_kms(&dev_priv->drm,
"requested plane X %s position %d invalid (valid range %d-%d)\n",
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)
{
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_DEBUG_KMS("src width must be multiple of 4 for rotated planar YUV\n");
return -EINVAL;
}
return 0;
}
static int skl_plane_max_scale(struct drm_i915_private *dev_priv,
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 (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv) ||
!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)
{
const struct drm_framebuffer *fb = plane_state->hw.fb;
int aux_x = plane_state->color_plane[ccs_plane].x;
int aux_y = plane_state->color_plane[ccs_plane].y;
u32 aux_offset = plane_state->color_plane[ccs_plane].offset;
u32 alignment = intel_surf_alignment(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;
plane_state->color_plane[ccs_plane].offset = aux_offset;
plane_state->color_plane[ccs_plane].x = aux_x;
plane_state->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_plane *plane = to_intel_plane(plane_state->uapi.plane);
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
const struct drm_framebuffer *fb = plane_state->hw.fb;
const int aux_plane = skl_main_to_aux_plane(fb, 0);
const u32 aux_offset = plane_state->color_plane[aux_plane].offset;
const u32 alignment = intel_surf_alignment(fb, 0);
const 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(&dev_priv->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->color_plane[0].stride) {
if (*offset == 0) {
drm_dbg_kms(&dev_priv->drm,
"Unable to find suitable display surface offset due to X-tiling\n");
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_plane *plane = to_intel_plane(plane_state->uapi.plane);
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
const struct drm_framebuffer *fb = plane_state->hw.fb;
const unsigned int rotation = plane_state->hw.rotation;
int x = plane_state->uapi.src.x1 >> 16;
int y = plane_state->uapi.src.y1 >> 16;
const int w = drm_rect_width(&plane_state->uapi.src) >> 16;
const int h = drm_rect_height(&plane_state->uapi.src) >> 16;
const int min_width = intel_plane_min_width(plane, fb, 0, rotation);
const int max_width = intel_plane_max_width(plane, fb, 0, rotation);
const int max_height = intel_plane_max_height(plane, fb, 0, rotation);
const int aux_plane = skl_main_to_aux_plane(fb, 0);
const u32 alignment = intel_surf_alignment(fb, 0);
u32 offset;
int ret;
if (w > max_width || w < min_width || h > max_height) {
drm_dbg_kms(&dev_priv->drm,
"requested Y/RGB source size %dx%d outside limits (min: %dx1 max: %dx%d)\n",
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.
*/
if (is_ccs_modifier(fb->modifier)) {
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);
}
if (x != plane_state->color_plane[aux_plane].x ||
y != plane_state->color_plane[aux_plane].y) {
drm_dbg_kms(&dev_priv->drm,
"Unable to find suitable display surface offset due to CCS\n");
return -EINVAL;
}
}
drm_WARN_ON(&dev_priv->drm, x > 8191 || y > 8191);
plane_state->color_plane[0].offset = offset;
plane_state->color_plane[0].x = x;
plane_state->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_plane *plane = to_intel_plane(plane_state->uapi.plane);
struct drm_i915_private *i915 = to_i915(plane->base.dev);
const struct drm_framebuffer *fb = plane_state->hw.fb;
unsigned int rotation = plane_state->hw.rotation;
int uv_plane = 1;
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(&i915->drm,
"CbCr source size %dx%d too big (limit %dx%d)\n",
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 (is_ccs_modifier(fb->modifier)) {
int ccs_plane = main_to_ccs_plane(fb, uv_plane);
u32 aux_offset = plane_state->color_plane[ccs_plane].offset;
u32 alignment = intel_surf_alignment(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);
}
if (x != plane_state->color_plane[ccs_plane].x ||
y != plane_state->color_plane[ccs_plane].y) {
drm_dbg_kms(&i915->drm,
"Unable to find suitable display surface offset due to CCS\n");
return -EINVAL;
}
}
drm_WARN_ON(&i915->drm, x > 8191 || y > 8191);
plane_state->color_plane[uv_plane].offset = offset;
plane_state->color_plane[uv_plane].x = x;
plane_state->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 (!is_ccs_plane(fb, ccs_plane) ||
is_gen12_ccs_cc_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);
plane_state->color_plane[ccs_plane].offset = offset;
plane_state->color_plane[ccs_plane].x = (x * hsub +
src_x % hsub) /
main_hsub;
plane_state->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, i;
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 (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;
}
for (i = fb->format->num_planes; i < ARRAY_SIZE(plane_state->color_plane); i++) {
plane_state->color_plane[i].offset = 0;
plane_state->color_plane[i].x = 0;
plane_state->color_plane[i].y = 0;
}
ret = skl_check_main_surface(plane_state);
if (ret)
return ret;
return 0;
}
static bool intel_fb_scalable(const struct drm_framebuffer *fb)
{
if (!fb)
return false;
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 INTEL_GEN(to_i915(fb->dev)) >= 11;
default:
return true;
}
}
static int skl_plane_check(struct intel_crtc_state *crtc_state,
struct intel_plane_state *plane_state)
{
struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
const struct drm_framebuffer *fb = plane_state->hw.fb;
int min_scale = DRM_PLANE_HELPER_NO_SCALING;
int max_scale = DRM_PLANE_HELPER_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 && intel_fb_scalable(fb)) {
min_scale = 1;
max_scale = skl_plane_max_scale(dev_priv, fb);
}
ret = intel_atomic_plane_check_clipping(plane_state, crtc_state,
min_scale, max_scale, true);
if (ret)
return ret;
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;
ret = skl_plane_check_nv12_rotation(plane_state);
if (ret)
return ret;
/* HW only has 8 bits pixel precision, disable plane if invisible */
if (!(plane_state->hw.alpha >> 8))
plane_state->uapi.visible = false;
plane_state->ctl = skl_plane_ctl(crtc_state, plane_state);
if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
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(dev_priv, 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;
}
static bool skl_plane_has_fbc(struct drm_i915_private *dev_priv,
enum pipe pipe, enum plane_id plane_id)
{
if (!HAS_FBC(dev_priv))
return false;
return pipe == PIPE_A && plane_id == PLANE_PRIMARY;
}
static bool skl_plane_has_planar(struct drm_i915_private *dev_priv,
enum pipe pipe, enum plane_id plane_id)
{
/* Display WA #0870: skl, bxt */
if (IS_SKYLAKE(dev_priv) || IS_BROXTON(dev_priv))
return false;
if (IS_GEN(dev_priv, 9) && !IS_GEMINILAKE(dev_priv) && pipe == PIPE_C)
return false;
if (plane_id != PLANE_PRIMARY && plane_id != PLANE_SPRITE0)
return false;
return true;
}
static const u32 *skl_get_plane_formats(struct drm_i915_private *dev_priv,
enum pipe pipe, enum plane_id plane_id,
int *num_formats)
{
if (skl_plane_has_planar(dev_priv, 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 drm_i915_private *dev_priv,
enum pipe pipe, enum plane_id plane_id,
int *num_formats)
{
if (skl_plane_has_planar(dev_priv, 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 drm_i915_private *dev_priv,
enum pipe pipe, enum plane_id plane_id,
int *num_formats)
{
if (icl_is_hdr_plane(dev_priv, plane_id)) {
*num_formats = ARRAY_SIZE(icl_hdr_plane_formats);
return icl_hdr_plane_formats;
} else if (icl_is_nv12_y_plane(dev_priv, 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_has_ccs(struct drm_i915_private *dev_priv,
enum pipe pipe, enum plane_id plane_id)
{
if (plane_id == PLANE_CURSOR)
return false;
if (INTEL_GEN(dev_priv) >= 10)
return true;
if (IS_GEMINILAKE(dev_priv))
return pipe != PIPE_C;
return pipe != PIPE_C &&
(plane_id == PLANE_PRIMARY ||
plane_id == PLANE_SPRITE0);
}
static bool skl_plane_format_mod_supported(struct drm_plane *_plane,
u32 format, u64 modifier)
{
struct intel_plane *plane = to_intel_plane(_plane);
switch (modifier) {
case DRM_FORMAT_MOD_LINEAR:
case I915_FORMAT_MOD_X_TILED:
case I915_FORMAT_MOD_Y_TILED:
case I915_FORMAT_MOD_Yf_TILED:
break;
case I915_FORMAT_MOD_Y_TILED_CCS:
case I915_FORMAT_MOD_Yf_TILED_CCS:
if (!plane->has_ccs)
return false;
break;
default:
return false;
}
switch (format) {
case DRM_FORMAT_XRGB8888:
case DRM_FORMAT_XBGR8888:
case DRM_FORMAT_ARGB8888:
case DRM_FORMAT_ABGR8888:
if (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 gen12_plane_supports_mc_ccs(struct drm_i915_private *dev_priv,
enum plane_id plane_id)
{
/* Wa_14010477008:tgl[a0..c0],rkl[all],dg1[all] */
if (IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv) ||
IS_TGL_DISP_STEPPING(dev_priv, STEP_A0, STEP_C0))
return false;
return plane_id < PLANE_SPRITE4;
}
static bool gen12_plane_format_mod_supported(struct drm_plane *_plane,
u32 format, u64 modifier)
{
struct drm_i915_private *dev_priv = to_i915(_plane->dev);
struct intel_plane *plane = to_intel_plane(_plane);
switch (modifier) {
case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
if (!gen12_plane_supports_mc_ccs(dev_priv, plane->id))
return false;
fallthrough;
case DRM_FORMAT_MOD_LINEAR:
case I915_FORMAT_MOD_X_TILED:
case I915_FORMAT_MOD_Y_TILED:
case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC:
break;
default:
return false;
}
switch (format) {
case DRM_FORMAT_XRGB8888:
case DRM_FORMAT_XBGR8888:
case DRM_FORMAT_ARGB8888:
case DRM_FORMAT_ABGR8888:
if (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 (modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS)
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_XVYU2101010:
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 const u64 *gen12_get_plane_modifiers(struct drm_i915_private *dev_priv,
enum plane_id plane_id)
{
if (gen12_plane_supports_mc_ccs(dev_priv, plane_id))
return gen12_plane_format_modifiers_mc_ccs;
else
return gen12_plane_format_modifiers_rc_ccs;
}
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,
};
static const struct drm_plane_funcs gen12_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 = gen12_plane_format_mod_supported,
};
static void
skl_plane_enable_flip_done(struct intel_plane *plane)
{
struct drm_i915_private *i915 = to_i915(plane->base.dev);
enum pipe pipe = plane->pipe;
spin_lock_irq(&i915->irq_lock);
bdw_enable_pipe_irq(i915, pipe, GEN9_PIPE_PLANE_FLIP_DONE(plane->id));
spin_unlock_irq(&i915->irq_lock);
}
static void
skl_plane_disable_flip_done(struct intel_plane *plane)
{
struct drm_i915_private *i915 = to_i915(plane->base.dev);
enum pipe pipe = plane->pipe;
spin_lock_irq(&i915->irq_lock);
bdw_disable_pipe_irq(i915, pipe, GEN9_PIPE_PLANE_FLIP_DONE(plane->id));
spin_unlock_irq(&i915->irq_lock);
}
struct intel_plane *
skl_universal_plane_create(struct drm_i915_private *dev_priv,
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;
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);
plane->has_fbc = skl_plane_has_fbc(dev_priv, pipe, plane_id);
if (plane->has_fbc) {
struct intel_fbc *fbc = &dev_priv->fbc;
fbc->possible_framebuffer_bits |= plane->frontbuffer_bit;
}
if (INTEL_GEN(dev_priv) >= 11) {
plane->min_width = icl_plane_min_width;
plane->max_width = icl_plane_max_width;
plane->max_height = icl_plane_max_height;
} else if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) {
plane->max_width = glk_plane_max_width;
plane->max_height = skl_plane_max_height;
} else {
plane->max_width = skl_plane_max_width;
plane->max_height = skl_plane_max_height;
}
plane->max_stride = skl_plane_max_stride;
plane->update_plane = skl_update_plane;
plane->disable_plane = skl_disable_plane;
plane->get_hw_state = skl_plane_get_hw_state;
plane->check_plane = skl_plane_check;
plane->min_cdclk = skl_plane_min_cdclk;
if (plane_id == PLANE_PRIMARY) {
plane->need_async_flip_disable_wa = IS_GEN_RANGE(dev_priv, 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 (INTEL_GEN(dev_priv) >= 11)
formats = icl_get_plane_formats(dev_priv, pipe,
plane_id, &num_formats);
else if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
formats = glk_get_plane_formats(dev_priv, pipe,
plane_id, &num_formats);
else
formats = skl_get_plane_formats(dev_priv, pipe,
plane_id, &num_formats);
plane->has_ccs = skl_plane_has_ccs(dev_priv, pipe, plane_id);
if (INTEL_GEN(dev_priv) >= 12) {
modifiers = gen12_get_plane_modifiers(dev_priv, plane_id);
plane_funcs = &gen12_plane_funcs;
} else {
if (plane->has_ccs)
modifiers = skl_plane_format_modifiers_ccs;
else
modifiers = skl_plane_format_modifiers_noccs;
plane_funcs = &skl_plane_funcs;
}
if (plane_id == PLANE_PRIMARY)
plane_type = DRM_PLANE_TYPE_PRIMARY;
else
plane_type = DRM_PLANE_TYPE_OVERLAY;
ret = drm_universal_plane_init(&dev_priv->drm, &plane->base,
0, plane_funcs,
formats, num_formats, modifiers,
plane_type,
"plane %d%c", plane_id + 1,
pipe_name(pipe));
if (ret)
goto fail;
supported_rotations =
DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 |
DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270;
if (INTEL_GEN(dev_priv) >= 10)
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 (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
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 (INTEL_GEN(dev_priv) >= 12)
drm_plane_enable_fb_damage_clips(&plane->base);
if (INTEL_GEN(dev_priv) >= 10)
drm_plane_create_scaling_filter_property(&plane->base,
BIT(DRM_SCALING_FILTER_DEFAULT) |
BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR));
drm_plane_helper_add(&plane->base, &intel_plane_helper_funcs);
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_crtc_state *crtc_state = to_intel_crtc_state(crtc->base.state);
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = to_i915(dev);
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;
if (!plane->get_hw_state(plane, &pipe))
return;
drm_WARN_ON(dev, pipe != crtc->pipe);
if (crtc_state->bigjoiner) {
drm_dbg_kms(&dev_priv->drm,
"Unsupported bigjoiner configuration for initial FB\n");
return;
}
intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
if (!intel_fb) {
drm_dbg_kms(&dev_priv->drm, "failed to alloc fb\n");
return;
}
fb = &intel_fb->base;
fb->dev = dev;
val = intel_de_read(dev_priv, PLANE_CTL(pipe, plane_id));
if (INTEL_GEN(dev_priv) >= 11)
pixel_format = val & ICL_PLANE_CTL_FORMAT_MASK;
else
pixel_format = val & PLANE_CTL_FORMAT_MASK;
if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) {
alpha = intel_de_read(dev_priv,
PLANE_COLOR_CTL(pipe, plane_id));
alpha &= PLANE_COLOR_ALPHA_MASK;
} else {
alpha = val & PLANE_CTL_ALPHA_MASK;
}
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)
fb->modifier = INTEL_GEN(dev_priv) >= 12 ?
I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS :
I915_FORMAT_MOD_Y_TILED_CCS;
else if (val & PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE)
fb->modifier = I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS;
else
fb->modifier = I915_FORMAT_MOD_Y_TILED;
break;
case PLANE_CTL_TILED_YF:
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;
}
/*
* DRM_MODE_ROTATE_ is counter clockwise to stay compatible with Xrandr
* while i915 HW rotation is clockwise, thats 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 (INTEL_GEN(dev_priv) >= 10 &&
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(dev_priv, PLANE_SURF(pipe, plane_id)) & 0xfffff000;
plane_config->base = base;
offset = intel_de_read(dev_priv, PLANE_OFFSET(pipe, plane_id));
val = intel_de_read(dev_priv, PLANE_SIZE(pipe, plane_id));
fb->height = ((val >> 16) & 0xffff) + 1;
fb->width = ((val >> 0) & 0xffff) + 1;
val = intel_de_read(dev_priv, PLANE_STRIDE(pipe, plane_id));
stride_mult = skl_plane_stride_mult(fb, 0, DRM_MODE_ROTATE_0);
fb->pitches[0] = (val & 0x3ff) * stride_mult;
aligned_height = intel_fb_align_height(fb, 0, fb->height);
plane_config->size = fb->pitches[0] * aligned_height;
drm_dbg_kms(&dev_priv->drm,
"%s/%s with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n",
crtc->base.name, 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);
}
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2020 Intel Corporation
*/
#ifndef _SKL_UNIVERSAL_PLANE_H_
#define _SKL_UNIVERSAL_PLANE_H_
#include <linux/types.h>
struct drm_framebuffer;
struct drm_i915_private;
struct intel_crtc;
struct intel_initial_plane_config;
struct intel_plane_state;
enum pipe;
enum plane_id;
struct intel_plane *
skl_universal_plane_create(struct drm_i915_private *dev_priv,
enum pipe pipe, enum plane_id plane_id);
void skl_get_initial_plane_config(struct intel_crtc *crtc,
struct intel_initial_plane_config *plane_config);
int skl_format_to_fourcc(int format, bool rgb_order, bool alpha);
int skl_ccs_to_main_plane(const struct drm_framebuffer *fb, int ccs_plane);
int skl_calc_main_surface_offset(const struct intel_plane_state *plane_state,
int *x, int *y, u32 *offset);
#endif
......@@ -38,6 +38,7 @@
#include "display/intel_display_types.h"
#include "display/intel_fbc.h"
#include "display/intel_sprite.h"
#include "display/skl_universal_plane.h"
#include "gt/intel_llc.h"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment