File Index
Files and directories
Sign in
FILE

skl_universal_plane.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/i915/display/skl_universal_plane.c C
   1// SPDX-License-Identifier: MIT
   2/*
   3 * Copyright © 2020 Intel Corporation
   4 */
   5
   6#include <drm/drm_atomic_helper.h>
   7#include <drm/drm_blend.h>
   8#include <drm/drm_damage_helper.h>
   9#include <drm/drm_fourcc.h>
  10#include <drm/drm_print.h>
  11
  12#include "pxp/intel_pxp.h"
  13#include "intel_bo.h"
  14#include "intel_color.h"
  15#include "intel_color_pipeline.h"
  16#include "intel_de.h"
  17#include "intel_display_irq.h"
  18#include "intel_display_regs.h"
  19#include "intel_display_types.h"
  20#include "intel_display_utils.h"
  21#include "intel_dpt.h"
  22#include "intel_fb.h"
  23#include "intel_fbc.h"
  24#include "intel_frontbuffer.h"
  25#include "intel_panic.h"
  26#include "intel_plane.h"
  27#include "intel_psr.h"
  28#include "intel_psr_regs.h"
  29#include "intel_step.h"
  30#include "skl_scaler.h"
  31#include "skl_universal_plane.h"
  32#include "skl_universal_plane_regs.h"
  33#include "skl_watermark.h"
  34
  35static const u32 skl_plane_formats[] = {
  36	DRM_FORMAT_C8,
  37	DRM_FORMAT_RGB565,
  38	DRM_FORMAT_XRGB8888,
  39	DRM_FORMAT_XBGR8888,
  40	DRM_FORMAT_ARGB8888,
  41	DRM_FORMAT_ABGR8888,
  42	DRM_FORMAT_XRGB2101010,
  43	DRM_FORMAT_XBGR2101010,
  44	DRM_FORMAT_XRGB16161616F,
  45	DRM_FORMAT_XBGR16161616F,
  46	DRM_FORMAT_YUYV,
  47	DRM_FORMAT_YVYU,
  48	DRM_FORMAT_UYVY,
  49	DRM_FORMAT_VYUY,
  50	DRM_FORMAT_XYUV8888,
  51};
  52
  53static const u32 skl_planar_formats[] = {
  54	DRM_FORMAT_C8,
  55	DRM_FORMAT_RGB565,
  56	DRM_FORMAT_XRGB8888,
  57	DRM_FORMAT_XBGR8888,
  58	DRM_FORMAT_ARGB8888,
  59	DRM_FORMAT_ABGR8888,
  60	DRM_FORMAT_XRGB2101010,
  61	DRM_FORMAT_XBGR2101010,
  62	DRM_FORMAT_XRGB16161616F,
  63	DRM_FORMAT_XBGR16161616F,
  64	DRM_FORMAT_YUYV,
  65	DRM_FORMAT_YVYU,
  66	DRM_FORMAT_UYVY,
  67	DRM_FORMAT_VYUY,
  68	DRM_FORMAT_NV12,
  69	DRM_FORMAT_XYUV8888,
  70};
  71
  72static const u32 glk_planar_formats[] = {
  73	DRM_FORMAT_C8,
  74	DRM_FORMAT_RGB565,
  75	DRM_FORMAT_XRGB8888,
  76	DRM_FORMAT_XBGR8888,
  77	DRM_FORMAT_ARGB8888,
  78	DRM_FORMAT_ABGR8888,
  79	DRM_FORMAT_XRGB2101010,
  80	DRM_FORMAT_XBGR2101010,
  81	DRM_FORMAT_XRGB16161616F,
  82	DRM_FORMAT_XBGR16161616F,
  83	DRM_FORMAT_YUYV,
  84	DRM_FORMAT_YVYU,
  85	DRM_FORMAT_UYVY,
  86	DRM_FORMAT_VYUY,
  87	DRM_FORMAT_NV12,
  88	DRM_FORMAT_XYUV8888,
  89	DRM_FORMAT_P010,
  90	DRM_FORMAT_P012,
  91	DRM_FORMAT_P016,
  92};
  93
  94static const u32 icl_sdr_y_plane_formats[] = {
  95	DRM_FORMAT_C8,
  96	DRM_FORMAT_RGB565,
  97	DRM_FORMAT_XRGB8888,
  98	DRM_FORMAT_XBGR8888,
  99	DRM_FORMAT_ARGB8888,
 100	DRM_FORMAT_ABGR8888,
 101	DRM_FORMAT_XRGB2101010,
 102	DRM_FORMAT_XBGR2101010,
 103	DRM_FORMAT_ARGB2101010,
 104	DRM_FORMAT_ABGR2101010,
 105	DRM_FORMAT_YUYV,
 106	DRM_FORMAT_YVYU,
 107	DRM_FORMAT_UYVY,
 108	DRM_FORMAT_VYUY,
 109	DRM_FORMAT_Y210,
 110	DRM_FORMAT_Y212,
 111	DRM_FORMAT_Y216,
 112	DRM_FORMAT_XYUV8888,
 113	DRM_FORMAT_XVYU2101010,
 114};
 115
 116static const u32 icl_sdr_uv_plane_formats[] = {
 117	DRM_FORMAT_C8,
 118	DRM_FORMAT_RGB565,
 119	DRM_FORMAT_XRGB8888,
 120	DRM_FORMAT_XBGR8888,
 121	DRM_FORMAT_ARGB8888,
 122	DRM_FORMAT_ABGR8888,
 123	DRM_FORMAT_XRGB2101010,
 124	DRM_FORMAT_XBGR2101010,
 125	DRM_FORMAT_ARGB2101010,
 126	DRM_FORMAT_ABGR2101010,
 127	DRM_FORMAT_YUYV,
 128	DRM_FORMAT_YVYU,
 129	DRM_FORMAT_UYVY,
 130	DRM_FORMAT_VYUY,
 131	DRM_FORMAT_NV12,
 132	DRM_FORMAT_P010,
 133	DRM_FORMAT_P012,
 134	DRM_FORMAT_P016,
 135	DRM_FORMAT_Y210,
 136	DRM_FORMAT_Y212,
 137	DRM_FORMAT_Y216,
 138	DRM_FORMAT_XYUV8888,
 139	DRM_FORMAT_XVYU2101010,
 140};
 141
 142static const u32 icl_hdr_plane_formats[] = {
 143	DRM_FORMAT_C8,
 144	DRM_FORMAT_RGB565,
 145	DRM_FORMAT_XRGB8888,
 146	DRM_FORMAT_XBGR8888,
 147	DRM_FORMAT_ARGB8888,
 148	DRM_FORMAT_ABGR8888,
 149	DRM_FORMAT_XRGB2101010,
 150	DRM_FORMAT_XBGR2101010,
 151	DRM_FORMAT_ARGB2101010,
 152	DRM_FORMAT_ABGR2101010,
 153	DRM_FORMAT_XRGB16161616F,
 154	DRM_FORMAT_XBGR16161616F,
 155	DRM_FORMAT_ARGB16161616F,
 156	DRM_FORMAT_ABGR16161616F,
 157	DRM_FORMAT_YUYV,
 158	DRM_FORMAT_YVYU,
 159	DRM_FORMAT_UYVY,
 160	DRM_FORMAT_VYUY,
 161	DRM_FORMAT_NV12,
 162	DRM_FORMAT_P010,
 163	DRM_FORMAT_P012,
 164	DRM_FORMAT_P016,
 165	DRM_FORMAT_Y210,
 166	DRM_FORMAT_Y212,
 167	DRM_FORMAT_Y216,
 168	DRM_FORMAT_XYUV8888,
 169	DRM_FORMAT_XVYU2101010,
 170	DRM_FORMAT_XVYU12_16161616,
 171	DRM_FORMAT_XVYU16161616,
 172};
 173
 174int skl_format_to_fourcc(int format, bool rgb_order, bool alpha)
 175{
 176	switch (format) {
 177	case PLANE_CTL_FORMAT_RGB_565:
 178		return DRM_FORMAT_RGB565;
 179	case PLANE_CTL_FORMAT_NV12:
 180		return DRM_FORMAT_NV12;
 181	case PLANE_CTL_FORMAT_XYUV:
 182		return DRM_FORMAT_XYUV8888;
 183	case PLANE_CTL_FORMAT_P010:
 184		return DRM_FORMAT_P010;
 185	case PLANE_CTL_FORMAT_P012:
 186		return DRM_FORMAT_P012;
 187	case PLANE_CTL_FORMAT_P016:
 188		return DRM_FORMAT_P016;
 189	case PLANE_CTL_FORMAT_Y210:
 190		return DRM_FORMAT_Y210;
 191	case PLANE_CTL_FORMAT_Y212:
 192		return DRM_FORMAT_Y212;
 193	case PLANE_CTL_FORMAT_Y216:
 194		return DRM_FORMAT_Y216;
 195	case PLANE_CTL_FORMAT_Y410:
 196		return DRM_FORMAT_XVYU2101010;
 197	case PLANE_CTL_FORMAT_Y412:
 198		return DRM_FORMAT_XVYU12_16161616;
 199	case PLANE_CTL_FORMAT_Y416:
 200		return DRM_FORMAT_XVYU16161616;
 201	default:
 202	case PLANE_CTL_FORMAT_XRGB_8888:
 203		if (rgb_order) {
 204			if (alpha)
 205				return DRM_FORMAT_ABGR8888;
 206			else
 207				return DRM_FORMAT_XBGR8888;
 208		} else {
 209			if (alpha)
 210				return DRM_FORMAT_ARGB8888;
 211			else
 212				return DRM_FORMAT_XRGB8888;
 213		}
 214	case PLANE_CTL_FORMAT_XRGB_2101010:
 215		if (rgb_order) {
 216			if (alpha)
 217				return DRM_FORMAT_ABGR2101010;
 218			else
 219				return DRM_FORMAT_XBGR2101010;
 220		} else {
 221			if (alpha)
 222				return DRM_FORMAT_ARGB2101010;
 223			else
 224				return DRM_FORMAT_XRGB2101010;
 225		}
 226	case PLANE_CTL_FORMAT_XRGB_16161616F:
 227		if (rgb_order) {
 228			if (alpha)
 229				return DRM_FORMAT_ABGR16161616F;
 230			else
 231				return DRM_FORMAT_XBGR16161616F;
 232		} else {
 233			if (alpha)
 234				return DRM_FORMAT_ARGB16161616F;
 235			else
 236				return DRM_FORMAT_XRGB16161616F;
 237		}
 238	}
 239}
 240
 241static u8 icl_nv12_y_plane_mask(struct intel_display *display)
 242{
 243	if (DISPLAY_VER(display) >= 13 || HAS_D12_PLANE_MINIMIZATION(display))
 244		return BIT(PLANE_4) | BIT(PLANE_5);
 245	else
 246		return BIT(PLANE_6) | BIT(PLANE_7);
 247}
 248
 249bool icl_is_nv12_y_plane(struct intel_display *display,
 250			 enum plane_id plane_id)
 251{
 252	return DISPLAY_VER(display) >= 11 &&
 253		icl_nv12_y_plane_mask(display) & BIT(plane_id);
 254}
 255
 256u8 icl_hdr_plane_mask(void)
 257{
 258	return BIT(PLANE_1) | BIT(PLANE_2) | BIT(PLANE_3);
 259}
 260
 261bool icl_is_hdr_plane(struct intel_display *display, enum plane_id plane_id)
 262{
 263	return DISPLAY_VER(display) >= 11 &&
 264		icl_hdr_plane_mask() & BIT(plane_id);
 265}
 266
 267static int icl_plane_min_cdclk(const struct intel_crtc_state *crtc_state,
 268			       const struct intel_plane_state *plane_state)
 269{
 270	unsigned int pixel_rate = intel_plane_pixel_rate(crtc_state, plane_state);
 271
 272	/* two pixels per clock */
 273	return DIV_ROUND_UP(pixel_rate, 2);
 274}
 275
 276static void
 277glk_plane_ratio(const struct intel_plane_state *plane_state,
 278		unsigned int *num, unsigned int *den)
 279{
 280	const struct drm_framebuffer *fb = plane_state->hw.fb;
 281
 282	if (fb->format->cpp[0] == 8) {
 283		*num = 10;
 284		*den = 8;
 285	} else {
 286		*num = 1;
 287		*den = 1;
 288	}
 289}
 290
 291static int glk_plane_min_cdclk(const struct intel_crtc_state *crtc_state,
 292			       const struct intel_plane_state *plane_state)
 293{
 294	unsigned int pixel_rate = intel_plane_pixel_rate(crtc_state, plane_state);
 295	unsigned int num, den;
 296
 297	glk_plane_ratio(plane_state, &num, &den);
 298
 299	/* two pixels per clock */
 300	return DIV_ROUND_UP(pixel_rate * num, 2 * den);
 301}
 302
 303static void
 304skl_plane_ratio(const struct intel_plane_state *plane_state,
 305		unsigned int *num, unsigned int *den)
 306{
 307	const struct drm_framebuffer *fb = plane_state->hw.fb;
 308
 309	if (fb->format->cpp[0] == 8) {
 310		*num = 9;
 311		*den = 8;
 312	} else {
 313		*num = 1;
 314		*den = 1;
 315	}
 316}
 317
 318static int skl_plane_min_cdclk(const struct intel_crtc_state *crtc_state,
 319			       const struct intel_plane_state *plane_state)
 320{
 321	unsigned int pixel_rate = intel_plane_pixel_rate(crtc_state, plane_state);
 322	unsigned int num, den;
 323
 324	skl_plane_ratio(plane_state, &num, &den);
 325
 326	return DIV_ROUND_UP(pixel_rate * num, den);
 327}
 328
 329static int skl_plane_max_width(const struct drm_framebuffer *fb,
 330			       int color_plane,
 331			       unsigned int rotation)
 332{
 333	int cpp = fb->format->cpp[color_plane];
 334
 335	switch (fb->modifier) {
 336	case DRM_FORMAT_MOD_LINEAR:
 337	case I915_FORMAT_MOD_X_TILED:
 338		/*
 339		 * Validated limit is 4k, but has 5k should
 340		 * work apart from the following features:
 341		 * - Ytile (already limited to 4k)
 342		 * - FP16 (already limited to 4k)
 343		 * - render compression (already limited to 4k)
 344		 * - KVMR sprite and cursor (don't care)
 345		 * - horizontal panning (TODO verify this)
 346		 * - pipe and plane scaling (TODO verify this)
 347		 */
 348		if (cpp == 8)
 349			return 4096;
 350		else
 351			return 5120;
 352	case I915_FORMAT_MOD_Y_TILED_CCS:
 353	case I915_FORMAT_MOD_Yf_TILED_CCS:
 354		/* FIXME AUX plane? */
 355	case I915_FORMAT_MOD_Y_TILED:
 356	case I915_FORMAT_MOD_Yf_TILED:
 357		if (cpp == 8)
 358			return 2048;
 359		else
 360			return 4096;
 361	default:
 362		MISSING_CASE(fb->modifier);
 363		return 2048;
 364	}
 365}
 366
 367static int glk_plane_max_width(const struct drm_framebuffer *fb,
 368			       int color_plane,
 369			       unsigned int rotation)
 370{
 371	int cpp = fb->format->cpp[color_plane];
 372
 373	switch (fb->modifier) {
 374	case DRM_FORMAT_MOD_LINEAR:
 375	case I915_FORMAT_MOD_X_TILED:
 376		if (cpp == 8)
 377			return 4096;
 378		else
 379			return 5120;
 380	case I915_FORMAT_MOD_Y_TILED_CCS:
 381	case I915_FORMAT_MOD_Yf_TILED_CCS:
 382		/* FIXME AUX plane? */
 383	case I915_FORMAT_MOD_Y_TILED:
 384	case I915_FORMAT_MOD_Yf_TILED:
 385		if (cpp == 8)
 386			return 2048;
 387		else
 388			return 5120;
 389	default:
 390		MISSING_CASE(fb->modifier);
 391		return 2048;
 392	}
 393}
 394
 395static int adl_plane_min_width(const struct drm_framebuffer *fb,
 396			       int color_plane,
 397			       unsigned int rotation)
 398{
 399	return 16 / fb->format->cpp[color_plane];
 400}
 401
 402static int icl_plane_min_width(const struct drm_framebuffer *fb,
 403			       int color_plane,
 404			       unsigned int rotation)
 405{
 406	/* Wa_14011264657, Wa_14011050563: gen11+ */
 407	return 16 / fb->format->cpp[color_plane] + 2;
 408}
 409
 410static int xe3_plane_max_width(const struct drm_framebuffer *fb,
 411			       int color_plane,
 412			       unsigned int rotation)
 413{
 414	if (intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier))
 415		return 4096;
 416	else
 417		return 6144;
 418}
 419
 420static int icl_hdr_plane_max_width(const struct drm_framebuffer *fb,
 421				   int color_plane,
 422				   unsigned int rotation)
 423{
 424	if (intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier))
 425		return 4096;
 426	else
 427		return 5120;
 428}
 429
 430static int icl_sdr_plane_max_width(const struct drm_framebuffer *fb,
 431				   int color_plane,
 432				   unsigned int rotation)
 433{
 434	return 5120;
 435}
 436
 437static int skl_plane_max_height(const struct drm_framebuffer *fb,
 438				int color_plane,
 439				unsigned int rotation)
 440{
 441	return 4096;
 442}
 443
 444static enum intel_fbc_id skl_fbc_id_for_pipe(enum pipe pipe)
 445{
 446	return pipe - PIPE_A + INTEL_FBC_A;
 447}
 448
 449static bool skl_plane_has_fbc(struct intel_display *display,
 450			      enum intel_fbc_id fbc_id, enum plane_id plane_id)
 451{
 452	if ((DISPLAY_RUNTIME_INFO(display)->fbc_mask & BIT(fbc_id)) == 0)
 453		return false;
 454
 455	if (DISPLAY_VER(display) >= 20)
 456		return icl_is_hdr_plane(display, plane_id);
 457	else
 458		return plane_id == PLANE_1;
 459}
 460
 461static int icl_plane_max_height(const struct drm_framebuffer *fb,
 462				int color_plane,
 463				unsigned int rotation)
 464{
 465	return 4320;
 466}
 467
 468static unsigned int
 469plane_max_stride(struct intel_plane *plane,
 470		 const struct drm_format_info *info,
 471		 u64 modifier, unsigned int rotation,
 472		 unsigned int max_pixels,
 473		 unsigned int max_bytes)
 474{
 475	int cpp = info->cpp[0];
 476
 477	if (drm_rotation_90_or_270(rotation))
 478		return min(max_pixels, max_bytes / cpp);
 479	else
 480		return min(max_pixels * cpp, max_bytes);
 481}
 482
 483static unsigned int
 484adl_plane_max_stride(struct intel_plane *plane,
 485		     const struct drm_format_info *info,
 486		     u64 modifier, unsigned int rotation)
 487{
 488	unsigned int max_pixels = 65536; /* PLANE_OFFSET limit */
 489	unsigned int max_bytes = 128 * 1024;
 490
 491	return plane_max_stride(plane, info,
 492				modifier, rotation,
 493				max_pixels, max_bytes);
 494}
 495
 496static unsigned int
 497skl_plane_max_stride(struct intel_plane *plane,
 498		     const struct drm_format_info *info,
 499		     u64 modifier, unsigned int rotation)
 500{
 501	unsigned int max_pixels = 8192; /* PLANE_OFFSET limit */
 502	unsigned int max_bytes = 32 * 1024;
 503
 504	return plane_max_stride(plane, info,
 505				modifier, rotation,
 506				max_pixels, max_bytes);
 507}
 508
 509static bool tgl_plane_can_async_flip(u64 modifier)
 510{
 511	switch (modifier) {
 512	case DRM_FORMAT_MOD_LINEAR:
 513	case I915_FORMAT_MOD_X_TILED:
 514	case I915_FORMAT_MOD_Y_TILED:
 515	case I915_FORMAT_MOD_4_TILED:
 516	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
 517	case I915_FORMAT_MOD_4_TILED_MTL_RC_CCS:
 518	case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS:
 519	case I915_FORMAT_MOD_4_TILED_BMG_CCS:
 520	case I915_FORMAT_MOD_4_TILED_LNL_CCS:
 521		return true;
 522	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
 523	case I915_FORMAT_MOD_4_TILED_MTL_MC_CCS:
 524	case I915_FORMAT_MOD_4_TILED_DG2_MC_CCS:
 525	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC:
 526	case I915_FORMAT_MOD_4_TILED_MTL_RC_CCS_CC:
 527	case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC:
 528		return false;
 529	default:
 530		return false;
 531	}
 532}
 533
 534static bool icl_plane_can_async_flip(u64 modifier)
 535{
 536	switch (modifier) {
 537	case DRM_FORMAT_MOD_LINEAR:
 538		/*
 539		 * FIXME: Async on Linear buffer is supported on ICL
 540		 * but with additional alignment and fbc restrictions
 541		 * need to be taken care of.
 542		 */
 543		return false;
 544	case I915_FORMAT_MOD_X_TILED:
 545	case I915_FORMAT_MOD_Y_TILED:
 546	case I915_FORMAT_MOD_Yf_TILED:
 547	case I915_FORMAT_MOD_Y_TILED_CCS:
 548	case I915_FORMAT_MOD_Yf_TILED_CCS:
 549		return true;
 550	default:
 551		return false;
 552	}
 553}
 554
 555static bool skl_plane_can_async_flip(u64 modifier)
 556{
 557	switch (modifier) {
 558	case DRM_FORMAT_MOD_LINEAR:
 559		return false;
 560	case I915_FORMAT_MOD_X_TILED:
 561	case I915_FORMAT_MOD_Y_TILED:
 562	case I915_FORMAT_MOD_Yf_TILED:
 563		return true;
 564	case I915_FORMAT_MOD_Y_TILED_CCS:
 565	case I915_FORMAT_MOD_Yf_TILED_CCS:
 566		/*
 567		 * Display WA #0731: skl
 568		 * WaDisableRCWithAsyncFlip: skl
 569		 * "When render decompression is enabled, hardware
 570		 *  internally converts the Async flips to Sync flips."
 571		 *
 572		 * Display WA #1159: glk
 573		 * "Async flip with render compression may result in
 574		 *  intermittent underrun corruption."
 575		 */
 576		return false;
 577	default:
 578		return false;
 579	}
 580}
 581
 582static u32 tgl_plane_min_alignment(struct intel_plane *plane,
 583				   const struct drm_framebuffer *fb,
 584				   int color_plane)
 585{
 586	struct intel_display *display = to_intel_display(plane);
 587	/* PLANE_SURF GGTT -> DPT alignment */
 588	int mult = intel_fb_uses_dpt(fb) ? 512 : 1;
 589
 590	/* AUX_DIST needs only 4K alignment */
 591	if (intel_fb_is_ccs_aux_plane(fb, color_plane))
 592		return mult * 4 * 1024;
 593
 594	/*
 595	 * FIXME ADL sees GGTT/DMAR faults with async
 596	 * flips unless we align to 16k at least.
 597	 * Figure out what's going on here...
 598	 */
 599	if (display->platform.alderlake_p &&
 600	    intel_plane_can_async_flip(plane, fb->format->format, fb->modifier))
 601		return mult * 16 * 1024;
 602
 603	switch (fb->modifier) {
 604	case DRM_FORMAT_MOD_LINEAR:
 605	case I915_FORMAT_MOD_X_TILED:
 606	case I915_FORMAT_MOD_Y_TILED:
 607	case I915_FORMAT_MOD_4_TILED:
 608		return mult * 4 * 1024;
 609	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
 610	case I915_FORMAT_MOD_4_TILED_MTL_RC_CCS:
 611	case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS:
 612	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
 613	case I915_FORMAT_MOD_4_TILED_MTL_MC_CCS:
 614	case I915_FORMAT_MOD_4_TILED_DG2_MC_CCS:
 615	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC:
 616	case I915_FORMAT_MOD_4_TILED_MTL_RC_CCS_CC:
 617	case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC:
 618	case I915_FORMAT_MOD_4_TILED_BMG_CCS:
 619	case I915_FORMAT_MOD_4_TILED_LNL_CCS:
 620		/*
 621		 * Align to at least 4x1 main surface
 622		 * tiles (16K) to match 64B of AUX.
 623		 */
 624		return max(mult * 4 * 1024, 16 * 1024);
 625	default:
 626		MISSING_CASE(fb->modifier);
 627		return 0;
 628	}
 629}
 630
 631static u32 skl_plane_min_alignment(struct intel_plane *plane,
 632				   const struct drm_framebuffer *fb,
 633				   int color_plane)
 634{
 635	/*
 636	 * AUX_DIST needs only 4K alignment,
 637	 * as does ICL UV PLANE_SURF.
 638	 */
 639	if (color_plane != 0)
 640		return 4 * 1024;
 641
 642	/*
 643	 * VT-d needs at least 256k alignment,
 644	 * but that's already covered below.
 645	 */
 646	switch (fb->modifier) {
 647	case DRM_FORMAT_MOD_LINEAR:
 648	case I915_FORMAT_MOD_X_TILED:
 649		return 256 * 1024;
 650	case I915_FORMAT_MOD_Y_TILED_CCS:
 651	case I915_FORMAT_MOD_Yf_TILED_CCS:
 652	case I915_FORMAT_MOD_Y_TILED:
 653	case I915_FORMAT_MOD_Yf_TILED:
 654		return 1 * 1024 * 1024;
 655	default:
 656		MISSING_CASE(fb->modifier);
 657		return 0;
 658	}
 659}
 660
 661/* Preoffset values for YUV to RGB Conversion */
 662#define PREOFF_YUV_TO_RGB_HI		0x1800
 663#define PREOFF_YUV_TO_RGB_ME		0x0000
 664#define PREOFF_YUV_TO_RGB_LO		0x1800
 665
 666#define  ROFF(x)          (((x) & 0xffff) << 16)
 667#define  GOFF(x)          (((x) & 0xffff) << 0)
 668#define  BOFF(x)          (((x) & 0xffff) << 16)
 669
 670/*
 671 * Programs the input color space conversion stage for ICL HDR planes.
 672 * Note that it is assumed that this stage always happens after YUV
 673 * range correction. Thus, the input to this stage is assumed to be
 674 * in full-range YCbCr.
 675 */
 676static void
 677icl_program_input_csc(struct intel_dsb *dsb,
 678		      struct intel_plane *plane,
 679		      const struct intel_plane_state *plane_state)
 680{
 681	struct intel_display *display = to_intel_display(plane);
 682	enum pipe pipe = plane->pipe;
 683	enum plane_id plane_id = plane->id;
 684
 685	static const u16 input_csc_matrix[][9] = {
 686		/*
 687		 * BT.601 full range YCbCr -> full range RGB
 688		 * The matrix required is :
 689		 * [1.000, 0.000, 1.371,
 690		 *  1.000, -0.336, -0.698,
 691		 *  1.000, 1.732, 0.0000]
 692		 */
 693		[DRM_COLOR_YCBCR_BT601] = {
 694			0x7AF8, 0x7800, 0x0,
 695			0x8B28, 0x7800, 0x9AC0,
 696			0x0, 0x7800, 0x7DD8,
 697		},
 698		/*
 699		 * BT.709 full range YCbCr -> full range RGB
 700		 * The matrix required is :
 701		 * [1.000, 0.000, 1.574,
 702		 *  1.000, -0.187, -0.468,
 703		 *  1.000, 1.855, 0.0000]
 704		 */
 705		[DRM_COLOR_YCBCR_BT709] = {
 706			0x7C98, 0x7800, 0x0,
 707			0x9EF8, 0x7800, 0xAC00,
 708			0x0, 0x7800,  0x7ED8,
 709		},
 710		/*
 711		 * BT.2020 full range YCbCr -> full range RGB
 712		 * The matrix required is :
 713		 * [1.000, 0.000, 1.474,
 714		 *  1.000, -0.1645, -0.5713,
 715		 *  1.000, 1.8814, 0.0000]
 716		 */
 717		[DRM_COLOR_YCBCR_BT2020] = {
 718			0x7BC8, 0x7800, 0x0,
 719			0x8928, 0x7800, 0xAA88,
 720			0x0, 0x7800, 0x7F10,
 721		},
 722	};
 723	const u16 *csc = input_csc_matrix[plane_state->hw.color_encoding];
 724
 725	intel_de_write_dsb(display, dsb, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 0),
 726			   ROFF(csc[0]) | GOFF(csc[1]));
 727	intel_de_write_dsb(display, dsb, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 1),
 728			   BOFF(csc[2]));
 729	intel_de_write_dsb(display, dsb, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 2),
 730			   ROFF(csc[3]) | GOFF(csc[4]));
 731	intel_de_write_dsb(display, dsb, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 3),
 732			   BOFF(csc[5]));
 733	intel_de_write_dsb(display, dsb, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 4),
 734			   ROFF(csc[6]) | GOFF(csc[7]));
 735	intel_de_write_dsb(display, dsb, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 5),
 736			   BOFF(csc[8]));
 737
 738	intel_de_write_dsb(display, dsb, PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 0),
 739			   PREOFF_YUV_TO_RGB_HI);
 740	intel_de_write_dsb(display, dsb, PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 1),
 741			   PREOFF_YUV_TO_RGB_ME);
 742	intel_de_write_dsb(display, dsb, PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 2),
 743			   PREOFF_YUV_TO_RGB_LO);
 744	intel_de_write_dsb(display, dsb,
 745			   PLANE_INPUT_CSC_POSTOFF(pipe, plane_id, 0), 0x0);
 746	intel_de_write_dsb(display, dsb,
 747			   PLANE_INPUT_CSC_POSTOFF(pipe, plane_id, 1), 0x0);
 748	intel_de_write_dsb(display, dsb,
 749			   PLANE_INPUT_CSC_POSTOFF(pipe, plane_id, 2), 0x0);
 750}
 751
 752static unsigned int skl_plane_stride_mult(const struct drm_framebuffer *fb,
 753					  int color_plane, unsigned int rotation)
 754{
 755	/*
 756	 * The stride is either expressed as a multiple of 64 bytes chunks for
 757	 * linear buffers or in number of tiles for tiled buffers.
 758	 */
 759	if (is_surface_linear(fb, color_plane))
 760		return 64;
 761	else if (drm_rotation_90_or_270(rotation))
 762		return intel_tile_height(fb, color_plane);
 763	else
 764		return intel_tile_width_bytes(fb, color_plane);
 765}
 766
 767static u32 skl_plane_stride(const struct intel_plane_state *plane_state,
 768			    int color_plane)
 769{
 770	const struct drm_framebuffer *fb = plane_state->hw.fb;
 771	unsigned int rotation = plane_state->hw.rotation;
 772	u32 stride = plane_state->view.color_plane[color_plane].scanout_stride;
 773
 774	if (color_plane >= fb->format->num_planes)
 775		return 0;
 776
 777	return stride / skl_plane_stride_mult(fb, color_plane, rotation);
 778}
 779
 780static u32 skl_plane_ddb_reg_val(const struct skl_ddb_entry *entry)
 781{
 782	if (!entry->end)
 783		return 0;
 784
 785	return PLANE_BUF_END(entry->end - 1) |
 786		PLANE_BUF_START(entry->start);
 787}
 788
 789static u32 xe3_plane_min_ddb_reg_val(const u16 *min_ddb,
 790				     const u16 *interim_ddb)
 791{
 792	u32 val = 0;
 793
 794	if (*min_ddb)
 795		val |= PLANE_MIN_DBUF_BLOCKS(*min_ddb);
 796
 797	if (*interim_ddb)
 798		val |= PLANE_INTERIM_DBUF_BLOCKS(*interim_ddb);
 799
 800	val |= val ? PLANE_AUTO_MIN_DBUF_EN : 0;
 801
 802	return val;
 803}
 804
 805static u32 skl_plane_wm_reg_val(const struct skl_wm_level *level)
 806{
 807	u32 val = 0;
 808
 809	if (level->enable)
 810		val |= PLANE_WM_EN;
 811	if (level->ignore_lines)
 812		val |= PLANE_WM_IGNORE_LINES;
 813	if (level->auto_min_alloc_wm_enable)
 814		val |= PLANE_WM_AUTO_MIN_ALLOC_EN;
 815
 816	val |= REG_FIELD_PREP(PLANE_WM_BLOCKS_MASK, level->blocks);
 817	val |= REG_FIELD_PREP(PLANE_WM_LINES_MASK, level->lines);
 818
 819	return val;
 820}
 821
 822static void skl_write_plane_wm(struct intel_dsb *dsb,
 823			       struct intel_plane *plane,
 824			       const struct intel_crtc_state *crtc_state)
 825{
 826	struct intel_display *display = to_intel_display(plane);
 827	enum plane_id plane_id = plane->id;
 828	enum pipe pipe = plane->pipe;
 829	const struct skl_pipe_wm *pipe_wm = &crtc_state->wm.skl.optimal;
 830	const struct skl_ddb_entry *ddb =
 831		&crtc_state->wm.skl.plane_ddb[plane_id];
 832	const struct skl_ddb_entry *ddb_y =
 833		&crtc_state->wm.skl.plane_ddb_y[plane_id];
 834	const u16 *min_ddb = &crtc_state->wm.skl.plane_min_ddb[plane_id];
 835	const u16 *interim_ddb =
 836		&crtc_state->wm.skl.plane_interim_ddb[plane_id];
 837	int level;
 838
 839	for (level = 0; level < display->wm.num_levels; level++)
 840		intel_de_write_dsb(display, dsb, PLANE_WM(pipe, plane_id, level),
 841				   skl_plane_wm_reg_val(skl_plane_wm_level(pipe_wm, plane_id, level)));
 842
 843	intel_de_write_dsb(display, dsb, PLANE_WM_TRANS(pipe, plane_id),
 844			   skl_plane_wm_reg_val(skl_plane_trans_wm(pipe_wm, plane_id)));
 845
 846	if (HAS_HW_SAGV_WM(display)) {
 847		const struct skl_plane_wm *wm = &pipe_wm->planes[plane_id];
 848
 849		intel_de_write_dsb(display, dsb, PLANE_WM_SAGV(pipe, plane_id),
 850				   skl_plane_wm_reg_val(&wm->sagv.wm0));
 851		intel_de_write_dsb(display, dsb, PLANE_WM_SAGV_TRANS(pipe, plane_id),
 852				   skl_plane_wm_reg_val(&wm->sagv.trans_wm));
 853	}
 854
 855	intel_de_write_dsb(display, dsb, PLANE_BUF_CFG(pipe, plane_id),
 856			   skl_plane_ddb_reg_val(ddb));
 857
 858	if (DISPLAY_VER(display) < 11)
 859		intel_de_write_dsb(display, dsb, PLANE_NV12_BUF_CFG(pipe, plane_id),
 860				   skl_plane_ddb_reg_val(ddb_y));
 861
 862	if (DISPLAY_VER(display) >= 30)
 863		intel_de_write_dsb(display, dsb, PLANE_MIN_BUF_CFG(pipe, plane_id),
 864				   xe3_plane_min_ddb_reg_val(min_ddb, interim_ddb));
 865}
 866
 867static void
 868skl_plane_disable_arm(struct intel_dsb *dsb,
 869		      struct intel_plane *plane,
 870		      const struct intel_crtc_state *crtc_state)
 871{
 872	struct intel_display *display = to_intel_display(plane);
 873	enum plane_id plane_id = plane->id;
 874	enum pipe pipe = plane->pipe;
 875
 876	skl_write_plane_wm(dsb, plane, crtc_state);
 877
 878	intel_de_write_dsb(display, dsb, PLANE_CTL(pipe, plane_id), 0);
 879	intel_de_write_dsb(display, dsb, PLANE_SURF(pipe, plane_id), 0);
 880}
 881
 882static void icl_plane_disable_sel_fetch_arm(struct intel_dsb *dsb,
 883					    struct intel_plane *plane,
 884					    const struct intel_crtc_state *crtc_state)
 885{
 886	struct intel_display *display = to_intel_display(plane);
 887	enum pipe pipe = plane->pipe;
 888
 889	if (!crtc_state->enable_psr2_sel_fetch)
 890		return;
 891
 892	intel_de_write_dsb(display, dsb, SEL_FETCH_PLANE_CTL(pipe, plane->id), 0);
 893}
 894
 895static bool plane_has_normalizer(struct intel_plane *plane)
 896{
 897	struct intel_display *display = to_intel_display(plane);
 898
 899	return HAS_PIXEL_NORMALIZER(display) && icl_is_hdr_plane(display, plane->id);
 900}
 901
 902static u32 pixel_normalizer_value(const struct intel_plane_state *plane_state)
 903{
 904	if (!intel_fbc_need_pixel_normalizer(plane_state))
 905		return 0;
 906
 907	return PLANE_PIXEL_NORMALIZE_ENABLE |
 908	       PLANE_PIXEL_NORMALIZE_NORM_FACTOR(PLANE_PIXEL_NORMALIZE_NORM_FACTOR_1_0);
 909}
 910
 911static void
 912icl_plane_disable_arm(struct intel_dsb *dsb,
 913		      struct intel_plane *plane,
 914		      const struct intel_crtc_state *crtc_state)
 915{
 916	struct intel_display *display = to_intel_display(plane);
 917	enum plane_id plane_id = plane->id;
 918	enum pipe pipe = plane->pipe;
 919
 920	if (icl_is_hdr_plane(display, plane_id))
 921		intel_de_write_dsb(display, dsb, PLANE_CUS_CTL(pipe, plane_id), 0);
 922
 923	skl_write_plane_wm(dsb, plane, crtc_state);
 924
 925	icl_plane_disable_sel_fetch_arm(dsb, plane, crtc_state);
 926
 927	if (plane_has_normalizer(plane))
 928		intel_de_write_dsb(display, dsb,
 929				   PLANE_PIXEL_NORMALIZE(plane->pipe, plane->id), 0);
 930
 931	intel_de_write_dsb(display, dsb, PLANE_CTL(pipe, plane_id), 0);
 932	intel_de_write_dsb(display, dsb, PLANE_SURF(pipe, plane_id), 0);
 933}
 934
 935static bool
 936skl_plane_get_hw_state(struct intel_plane *plane,
 937		       enum pipe *pipe)
 938{
 939	struct intel_display *display = to_intel_display(plane);
 940	enum intel_display_power_domain power_domain;
 941	enum plane_id plane_id = plane->id;
 942	intel_wakeref_t wakeref;
 943	bool ret;
 944
 945	power_domain = POWER_DOMAIN_PIPE(plane->pipe);
 946	wakeref = intel_display_power_get_if_enabled(display, power_domain);
 947	if (!wakeref)
 948		return false;
 949
 950	ret = intel_de_read(display, PLANE_CTL(plane->pipe, plane_id)) & PLANE_CTL_ENABLE;
 951
 952	*pipe = plane->pipe;
 953
 954	intel_display_power_put(display, power_domain, wakeref);
 955
 956	return ret;
 957}
 958
 959static u32 skl_plane_ctl_format(u32 pixel_format)
 960{
 961	switch (pixel_format) {
 962	case DRM_FORMAT_C8:
 963		return PLANE_CTL_FORMAT_INDEXED;
 964	case DRM_FORMAT_RGB565:
 965		return PLANE_CTL_FORMAT_RGB_565;
 966	case DRM_FORMAT_XBGR8888:
 967	case DRM_FORMAT_ABGR8888:
 968		return PLANE_CTL_FORMAT_XRGB_8888 | PLANE_CTL_ORDER_RGBX;
 969	case DRM_FORMAT_XRGB8888:
 970	case DRM_FORMAT_ARGB8888:
 971		return PLANE_CTL_FORMAT_XRGB_8888;
 972	case DRM_FORMAT_XBGR2101010:
 973	case DRM_FORMAT_ABGR2101010:
 974		return PLANE_CTL_FORMAT_XRGB_2101010 | PLANE_CTL_ORDER_RGBX;
 975	case DRM_FORMAT_XRGB2101010:
 976	case DRM_FORMAT_ARGB2101010:
 977		return PLANE_CTL_FORMAT_XRGB_2101010;
 978	case DRM_FORMAT_XBGR16161616F:
 979	case DRM_FORMAT_ABGR16161616F:
 980		return PLANE_CTL_FORMAT_XRGB_16161616F | PLANE_CTL_ORDER_RGBX;
 981	case DRM_FORMAT_XRGB16161616F:
 982	case DRM_FORMAT_ARGB16161616F:
 983		return PLANE_CTL_FORMAT_XRGB_16161616F;
 984	case DRM_FORMAT_XYUV8888:
 985		return PLANE_CTL_FORMAT_XYUV;
 986	case DRM_FORMAT_YUYV:
 987		return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_ORDER_YUYV;
 988	case DRM_FORMAT_YVYU:
 989		return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_ORDER_YVYU;
 990	case DRM_FORMAT_UYVY:
 991		return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_ORDER_UYVY;
 992	case DRM_FORMAT_VYUY:
 993		return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_ORDER_VYUY;
 994	case DRM_FORMAT_NV12:
 995		return PLANE_CTL_FORMAT_NV12;
 996	case DRM_FORMAT_P010:
 997		return PLANE_CTL_FORMAT_P010;
 998	case DRM_FORMAT_P012:
 999		return PLANE_CTL_FORMAT_P012;
1000	case DRM_FORMAT_P016:
1001		return PLANE_CTL_FORMAT_P016;
1002	case DRM_FORMAT_Y210:
1003		return PLANE_CTL_FORMAT_Y210;
1004	case DRM_FORMAT_Y212:
1005		return PLANE_CTL_FORMAT_Y212;
1006	case DRM_FORMAT_Y216:
1007		return PLANE_CTL_FORMAT_Y216;
1008	case DRM_FORMAT_XVYU2101010:
1009		return PLANE_CTL_FORMAT_Y410;
1010	case DRM_FORMAT_XVYU12_16161616:
1011		return PLANE_CTL_FORMAT_Y412;
1012	case DRM_FORMAT_XVYU16161616:
1013		return PLANE_CTL_FORMAT_Y416;
1014	default:
1015		MISSING_CASE(pixel_format);
1016	}
1017
1018	return 0;
1019}
1020
1021static u32 skl_plane_ctl_alpha(const struct intel_plane_state *plane_state)
1022{
1023	if (!plane_state->hw.fb->format->has_alpha)
1024		return PLANE_CTL_ALPHA_DISABLE;
1025
1026	switch (plane_state->hw.pixel_blend_mode) {
1027	case DRM_MODE_BLEND_PIXEL_NONE:
1028		return PLANE_CTL_ALPHA_DISABLE;
1029	case DRM_MODE_BLEND_PREMULTI:
1030		return PLANE_CTL_ALPHA_SW_PREMULTIPLY;
1031	case DRM_MODE_BLEND_COVERAGE:
1032		return PLANE_CTL_ALPHA_HW_PREMULTIPLY;
1033	default:
1034		MISSING_CASE(plane_state->hw.pixel_blend_mode);
1035		return PLANE_CTL_ALPHA_DISABLE;
1036	}
1037}
1038
1039static u32 glk_plane_color_ctl_alpha(const struct intel_plane_state *plane_state)
1040{
1041	if (!plane_state->hw.fb->format->has_alpha)
1042		return PLANE_COLOR_ALPHA_DISABLE;
1043
1044	switch (plane_state->hw.pixel_blend_mode) {
1045	case DRM_MODE_BLEND_PIXEL_NONE:
1046		return PLANE_COLOR_ALPHA_DISABLE;
1047	case DRM_MODE_BLEND_PREMULTI:
1048		return PLANE_COLOR_ALPHA_SW_PREMULTIPLY;
1049	case DRM_MODE_BLEND_COVERAGE:
1050		return PLANE_COLOR_ALPHA_HW_PREMULTIPLY;
1051	default:
1052		MISSING_CASE(plane_state->hw.pixel_blend_mode);
1053		return PLANE_COLOR_ALPHA_DISABLE;
1054	}
1055}
1056
1057static u32 skl_plane_ctl_tiling(u64 fb_modifier)
1058{
1059	switch (fb_modifier) {
1060	case DRM_FORMAT_MOD_LINEAR:
1061		break;
1062	case I915_FORMAT_MOD_X_TILED:
1063		return PLANE_CTL_TILED_X;
1064	case I915_FORMAT_MOD_Y_TILED:
1065		return PLANE_CTL_TILED_Y;
1066	case I915_FORMAT_MOD_4_TILED:
1067		return PLANE_CTL_TILED_4;
1068	case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS:
1069		return PLANE_CTL_TILED_4 |
1070			PLANE_CTL_RENDER_DECOMPRESSION_ENABLE |
1071			PLANE_CTL_CLEAR_COLOR_DISABLE;
1072	case I915_FORMAT_MOD_4_TILED_DG2_MC_CCS:
1073		return PLANE_CTL_TILED_4 |
1074			PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE |
1075			PLANE_CTL_CLEAR_COLOR_DISABLE;
1076	case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC:
1077		return PLANE_CTL_TILED_4 | PLANE_CTL_RENDER_DECOMPRESSION_ENABLE;
1078	case I915_FORMAT_MOD_4_TILED_MTL_RC_CCS:
1079		return PLANE_CTL_TILED_4 |
1080			PLANE_CTL_RENDER_DECOMPRESSION_ENABLE |
1081			PLANE_CTL_CLEAR_COLOR_DISABLE;
1082	case I915_FORMAT_MOD_4_TILED_MTL_RC_CCS_CC:
1083		return PLANE_CTL_TILED_4 | PLANE_CTL_RENDER_DECOMPRESSION_ENABLE;
1084	case I915_FORMAT_MOD_4_TILED_MTL_MC_CCS:
1085		return PLANE_CTL_TILED_4 | PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE;
1086	case I915_FORMAT_MOD_4_TILED_BMG_CCS:
1087	case I915_FORMAT_MOD_4_TILED_LNL_CCS:
1088		return PLANE_CTL_TILED_4 | PLANE_CTL_RENDER_DECOMPRESSION_ENABLE;
1089	case I915_FORMAT_MOD_Y_TILED_CCS:
1090	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC:
1091		return PLANE_CTL_TILED_Y | PLANE_CTL_RENDER_DECOMPRESSION_ENABLE;
1092	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
1093		return PLANE_CTL_TILED_Y |
1094		       PLANE_CTL_RENDER_DECOMPRESSION_ENABLE |
1095		       PLANE_CTL_CLEAR_COLOR_DISABLE;
1096	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
1097		return PLANE_CTL_TILED_Y | PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE;
1098	case I915_FORMAT_MOD_Yf_TILED:
1099		return PLANE_CTL_TILED_YF;
1100	case I915_FORMAT_MOD_Yf_TILED_CCS:
1101		return PLANE_CTL_TILED_YF | PLANE_CTL_RENDER_DECOMPRESSION_ENABLE;
1102	default:
1103		MISSING_CASE(fb_modifier);
1104	}
1105
1106	return 0;
1107}
1108
1109static u32 skl_plane_ctl_rotate(unsigned int rotate)
1110{
1111	switch (rotate) {
1112	case DRM_MODE_ROTATE_0:
1113		break;
1114	/*
1115	 * DRM_MODE_ROTATE_ is counter clockwise to stay compatible with Xrandr
1116	 * while i915 HW rotation is clockwise, that's why this swapping.
1117	 */
1118	case DRM_MODE_ROTATE_90:
1119		return PLANE_CTL_ROTATE_270;
1120	case DRM_MODE_ROTATE_180:
1121		return PLANE_CTL_ROTATE_180;
1122	case DRM_MODE_ROTATE_270:
1123		return PLANE_CTL_ROTATE_90;
1124	default:
1125		MISSING_CASE(rotate);
1126	}
1127
1128	return 0;
1129}
1130
1131static u32 icl_plane_ctl_flip(unsigned int reflect)
1132{
1133	switch (reflect) {
1134	case 0:
1135		break;
1136	case DRM_MODE_REFLECT_X:
1137		return PLANE_CTL_FLIP_HORIZONTAL;
1138	case DRM_MODE_REFLECT_Y:
1139	default:
1140		MISSING_CASE(reflect);
1141	}
1142
1143	return 0;
1144}
1145
1146static u32 adlp_plane_ctl_arb_slots(const struct intel_plane_state *plane_state)
1147{
1148	const struct drm_framebuffer *fb = plane_state->hw.fb;
1149
1150	if (intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier)) {
1151		switch (fb->format->cpp[0]) {
1152		case 2:
1153			return PLANE_CTL_ARB_SLOTS(1);
1154		default:
1155			return PLANE_CTL_ARB_SLOTS(0);
1156		}
1157	} else {
1158		switch (fb->format->cpp[0]) {
1159		case 8:
1160			return PLANE_CTL_ARB_SLOTS(3);
1161		case 4:
1162			return PLANE_CTL_ARB_SLOTS(1);
1163		default:
1164			return PLANE_CTL_ARB_SLOTS(0);
1165		}
1166	}
1167}
1168
1169static u32 skl_plane_ctl_crtc(const struct intel_crtc_state *crtc_state)
1170{
1171	struct intel_display *display = to_intel_display(crtc_state);
1172	u32 plane_ctl = 0;
1173
1174	if (DISPLAY_VER(display) >= 10)
1175		return plane_ctl;
1176
1177	if (crtc_state->gamma_enable)
1178		plane_ctl |= PLANE_CTL_PIPE_GAMMA_ENABLE;
1179
1180	if (crtc_state->csc_enable)
1181		plane_ctl |= PLANE_CTL_PIPE_CSC_ENABLE;
1182
1183	return plane_ctl;
1184}
1185
1186static u32 skl_plane_ctl(const struct intel_plane_state *plane_state)
1187{
1188	struct intel_display *display = to_intel_display(plane_state);
1189	const struct drm_framebuffer *fb = plane_state->hw.fb;
1190	unsigned int rotation = plane_state->hw.rotation;
1191	const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
1192	u32 plane_ctl;
1193
1194	plane_ctl = PLANE_CTL_ENABLE;
1195
1196	if (DISPLAY_VER(display) < 10) {
1197		plane_ctl |= skl_plane_ctl_alpha(plane_state);
1198		plane_ctl |= PLANE_CTL_PLANE_GAMMA_DISABLE;
1199
1200		if (plane_state->hw.color_encoding == DRM_COLOR_YCBCR_BT709)
1201			plane_ctl |= PLANE_CTL_YUV_TO_RGB_CSC_FORMAT_BT709;
1202
1203		if (plane_state->hw.color_range == DRM_COLOR_YCBCR_FULL_RANGE)
1204			plane_ctl |= PLANE_CTL_YUV_RANGE_CORRECTION_DISABLE;
1205	}
1206
1207	plane_ctl |= skl_plane_ctl_format(fb->format->format);
1208	plane_ctl |= skl_plane_ctl_tiling(fb->modifier);
1209	plane_ctl |= skl_plane_ctl_rotate(rotation & DRM_MODE_ROTATE_MASK);
1210
1211	if (DISPLAY_VER(display) >= 11)
1212		plane_ctl |= icl_plane_ctl_flip(rotation &
1213						DRM_MODE_REFLECT_MASK);
1214
1215	if (key->flags & I915_SET_COLORKEY_DESTINATION)
1216		plane_ctl |= PLANE_CTL_KEY_ENABLE_DESTINATION;
1217	else if (key->flags & I915_SET_COLORKEY_SOURCE)
1218		plane_ctl |= PLANE_CTL_KEY_ENABLE_SOURCE;
1219
1220	/* Wa_22012358565:adl-p */
1221	if (DISPLAY_VER(display) == 13)
1222		plane_ctl |= adlp_plane_ctl_arb_slots(plane_state);
1223
1224	return plane_ctl;
1225}
1226
1227static u32 glk_plane_color_ctl_crtc(const struct intel_crtc_state *crtc_state)
1228{
1229	struct intel_display *display = to_intel_display(crtc_state);
1230	u32 plane_color_ctl = 0;
1231
1232	if (DISPLAY_VER(display) >= 11)
1233		return plane_color_ctl;
1234
1235	if (crtc_state->gamma_enable)
1236		plane_color_ctl |= PLANE_COLOR_PIPE_GAMMA_ENABLE;
1237
1238	if (crtc_state->csc_enable)
1239		plane_color_ctl |= PLANE_COLOR_PIPE_CSC_ENABLE;
1240
1241	return plane_color_ctl;
1242}
1243
1244static u32 glk_plane_color_ctl(const struct intel_plane_state *plane_state)
1245{
1246	struct intel_display *display = to_intel_display(plane_state);
1247	const struct drm_framebuffer *fb = plane_state->hw.fb;
1248	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
1249	u32 plane_color_ctl = 0;
1250
1251	plane_color_ctl |= PLANE_COLOR_PLANE_GAMMA_DISABLE;
1252	plane_color_ctl |= glk_plane_color_ctl_alpha(plane_state);
1253
1254	if (fb->format->is_yuv && !icl_is_hdr_plane(display, plane->id)) {
1255		switch (plane_state->hw.color_encoding) {
1256		case DRM_COLOR_YCBCR_BT709:
1257			plane_color_ctl |= PLANE_COLOR_CSC_MODE_YUV709_TO_RGB709;
1258			break;
1259		case DRM_COLOR_YCBCR_BT2020:
1260			plane_color_ctl |=
1261				PLANE_COLOR_CSC_MODE_YUV2020_TO_RGB2020;
1262			break;
1263		default:
1264			plane_color_ctl |=
1265				PLANE_COLOR_CSC_MODE_YUV601_TO_RGB601;
1266		}
1267		if (plane_state->hw.color_range == DRM_COLOR_YCBCR_FULL_RANGE)
1268			plane_color_ctl |= PLANE_COLOR_YUV_RANGE_CORRECTION_DISABLE;
1269	} else if (fb->format->is_yuv) {
1270		plane_color_ctl |= PLANE_COLOR_INPUT_CSC_ENABLE;
1271		if (plane_state->hw.color_range == DRM_COLOR_YCBCR_FULL_RANGE)
1272			plane_color_ctl |= PLANE_COLOR_YUV_RANGE_CORRECTION_DISABLE;
1273	}
1274
1275	if (plane_state->force_black)
1276		plane_color_ctl |= PLANE_COLOR_PLANE_CSC_ENABLE;
1277
1278	if (plane_state->hw.degamma_lut)
1279		plane_color_ctl |= PLANE_COLOR_PRE_CSC_GAMMA_ENABLE;
1280
1281	if (plane_state->hw.ctm)
1282		plane_color_ctl |= PLANE_COLOR_PLANE_CSC_ENABLE;
1283
1284	if (plane_state->hw.gamma_lut) {
1285		plane_color_ctl &= ~PLANE_COLOR_PLANE_GAMMA_DISABLE;
1286		if (drm_color_lut32_size(plane_state->hw.gamma_lut) != 32)
1287			plane_color_ctl |= PLANE_COLOR_POST_CSC_GAMMA_MULTSEG_ENABLE;
1288	}
1289
1290	return plane_color_ctl;
1291}
1292
1293static u32 skl_surf_address(const struct intel_plane_state *plane_state,
1294			    int color_plane)
1295{
1296	struct intel_display *display = to_intel_display(plane_state);
1297	const struct drm_framebuffer *fb = plane_state->hw.fb;
1298	u32 offset = plane_state->view.color_plane[color_plane].offset;
1299
1300	if (intel_fb_uses_dpt(fb)) {
1301		drm_WARN_ON(display->drm, offset & 0x1fffff);
1302		return offset >> 9;
1303	} else {
1304		drm_WARN_ON(display->drm, offset & 0xfff);
1305		return offset;
1306	}
1307}
1308
1309static int icl_plane_color_plane(const struct intel_plane_state *plane_state)
1310{
1311	if (plane_state->planar_linked_plane && !plane_state->is_y_plane)
1312		return 1;
1313	else
1314		return 0;
1315}
1316
1317static u32 skl_plane_surf_offset(const struct intel_plane_state *plane_state)
1318{
1319	int color_plane = icl_plane_color_plane(plane_state);
1320	u32 plane_surf;
1321
1322	plane_surf = skl_surf_address(plane_state, color_plane);
1323
1324	if (plane_state->decrypt)
1325		plane_surf |= PLANE_SURF_DECRYPT;
1326
1327	return plane_surf;
1328}
1329
1330u32 skl_plane_aux_dist(const struct intel_plane_state *plane_state,
1331		       int color_plane)
1332{
1333	struct intel_display *display = to_intel_display(plane_state);
1334	const struct drm_framebuffer *fb = plane_state->hw.fb;
1335	int aux_plane = skl_main_to_aux_plane(fb, color_plane);
1336	u32 aux_dist;
1337
1338	if (!aux_plane)
1339		return 0;
1340
1341	aux_dist = skl_surf_address(plane_state, aux_plane) -
1342		skl_surf_address(plane_state, color_plane);
1343
1344	if (DISPLAY_VER(display) < 12)
1345		aux_dist |= PLANE_AUX_STRIDE(skl_plane_stride(plane_state, aux_plane));
1346
1347	return aux_dist;
1348}
1349
1350static u32 skl_plane_keyval(const struct intel_plane_state *plane_state)
1351{
1352	const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
1353
1354	return key->min_value;
1355}
1356
1357static u32 skl_plane_keymax(const struct intel_plane_state *plane_state)
1358{
1359	const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
1360	u8 alpha = plane_state->hw.alpha >> 8;
1361
1362	return (key->max_value & 0xffffff) | PLANE_KEYMAX_ALPHA(alpha);
1363}
1364
1365static u32 skl_plane_keymsk(const struct intel_plane_state *plane_state)
1366{
1367	const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
1368	u8 alpha = plane_state->hw.alpha >> 8;
1369	u32 keymsk;
1370
1371	keymsk = key->channel_mask & 0x7ffffff;
1372	if (alpha < 0xff)
1373		keymsk |= PLANE_KEYMSK_ALPHA_ENABLE;
1374
1375	return keymsk;
1376}
1377
1378static void icl_plane_csc_load_black(struct intel_dsb *dsb,
1379				     struct intel_plane *plane,
1380				     const struct intel_crtc_state *crtc_state)
1381{
1382	struct intel_display *display = to_intel_display(plane);
1383	enum plane_id plane_id = plane->id;
1384	enum pipe pipe = plane->pipe;
1385
1386	intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane_id, 0), 0);
1387	intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane_id, 1), 0);
1388
1389	intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane_id, 2), 0);
1390	intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane_id, 3), 0);
1391
1392	intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane_id, 4), 0);
1393	intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane_id, 5), 0);
1394
1395	intel_de_write_dsb(display, dsb, PLANE_CSC_PREOFF(pipe, plane_id, 0), 0);
1396	intel_de_write_dsb(display, dsb, PLANE_CSC_PREOFF(pipe, plane_id, 1), 0);
1397	intel_de_write_dsb(display, dsb, PLANE_CSC_PREOFF(pipe, plane_id, 2), 0);
1398
1399	intel_de_write_dsb(display, dsb, PLANE_CSC_POSTOFF(pipe, plane_id, 0), 0);
1400	intel_de_write_dsb(display, dsb, PLANE_CSC_POSTOFF(pipe, plane_id, 1), 0);
1401	intel_de_write_dsb(display, dsb, PLANE_CSC_POSTOFF(pipe, plane_id, 2), 0);
1402}
1403
1404static void
1405skl_plane_update_noarm(struct intel_dsb *dsb,
1406		       struct intel_plane *plane,
1407		       const struct intel_crtc_state *crtc_state,
1408		       const struct intel_plane_state *plane_state)
1409{
1410	struct intel_display *display = to_intel_display(plane);
1411	enum plane_id plane_id = plane->id;
1412	enum pipe pipe = plane->pipe;
1413	u32 stride = skl_plane_stride(plane_state, 0);
1414	int crtc_x = plane_state->uapi.dst.x1;
1415	int crtc_y = plane_state->uapi.dst.y1;
1416	u32 src_w = drm_rect_width(&plane_state->uapi.src) >> 16;
1417	u32 src_h = drm_rect_height(&plane_state->uapi.src) >> 16;
1418
1419	/* The scaler will handle the output position */
1420	if (plane_state->scaler_id >= 0) {
1421		crtc_x = 0;
1422		crtc_y = 0;
1423	}
1424
1425	intel_de_write_dsb(display, dsb, PLANE_STRIDE(pipe, plane_id),
1426			   PLANE_STRIDE_(stride));
1427	intel_de_write_dsb(display, dsb, PLANE_POS(pipe, plane_id),
1428			   PLANE_POS_Y(crtc_y) | PLANE_POS_X(crtc_x));
1429	intel_de_write_dsb(display, dsb, PLANE_SIZE(pipe, plane_id),
1430			   PLANE_HEIGHT(src_h - 1) | PLANE_WIDTH(src_w - 1));
1431
1432	skl_write_plane_wm(dsb, plane, crtc_state);
1433}
1434
1435static void
1436skl_plane_update_arm(struct intel_dsb *dsb,
1437		     struct intel_plane *plane,
1438		     const struct intel_crtc_state *crtc_state,
1439		     const struct intel_plane_state *plane_state)
1440{
1441	struct intel_display *display = to_intel_display(plane);
1442	enum plane_id plane_id = plane->id;
1443	enum pipe pipe = plane->pipe;
1444	u32 x = plane_state->view.color_plane[0].x;
1445	u32 y = plane_state->view.color_plane[0].y;
1446	u32 plane_ctl, plane_color_ctl = 0;
1447
1448	plane_ctl = plane_state->ctl |
1449		skl_plane_ctl_crtc(crtc_state);
1450
1451	/* see intel_plane_atomic_calc_changes() */
1452	if (plane->need_async_flip_toggle_wa &&
1453	    crtc_state->async_flip_planes & BIT(plane->id))
1454		plane_ctl |= PLANE_CTL_ASYNC_FLIP;
1455
1456	if (DISPLAY_VER(display) >= 10)
1457		plane_color_ctl = plane_state->color_ctl |
1458			glk_plane_color_ctl_crtc(crtc_state);
1459
1460	intel_de_write_dsb(display, dsb, PLANE_KEYVAL(pipe, plane_id),
1461			   skl_plane_keyval(plane_state));
1462	intel_de_write_dsb(display, dsb, PLANE_KEYMSK(pipe, plane_id),
1463			   skl_plane_keymsk(plane_state));
1464	intel_de_write_dsb(display, dsb, PLANE_KEYMAX(pipe, plane_id),
1465			   skl_plane_keymax(plane_state));
1466
1467	intel_de_write_dsb(display, dsb, PLANE_OFFSET(pipe, plane_id),
1468			   PLANE_OFFSET_Y(y) | PLANE_OFFSET_X(x));
1469
1470	intel_de_write_dsb(display, dsb, PLANE_AUX_DIST(pipe, plane_id),
1471			   skl_plane_aux_dist(plane_state, 0));
1472
1473	intel_de_write_dsb(display, dsb, PLANE_AUX_OFFSET(pipe, plane_id),
1474			   PLANE_OFFSET_Y(plane_state->view.color_plane[1].y) |
1475			   PLANE_OFFSET_X(plane_state->view.color_plane[1].x));
1476
1477	if (DISPLAY_VER(display) >= 10)
1478		intel_de_write_dsb(display, dsb, PLANE_COLOR_CTL(pipe, plane_id),
1479				   plane_color_ctl);
1480
1481	/*
1482	 * Enable the scaler before the plane so that we don't
1483	 * get a catastrophic underrun even if the two operations
1484	 * end up happening in two different frames.
1485	 *
1486	 * TODO: split into noarm+arm pair
1487	 */
1488	if (plane_state->scaler_id >= 0)
1489		skl_program_plane_scaler(dsb, plane, crtc_state, plane_state);
1490
1491	/*
1492	 * The control register self-arms if the plane was previously
1493	 * disabled. Try to make the plane enable atomic by writing
1494	 * the control register just before the surface register.
1495	 */
1496	intel_de_write_dsb(display, dsb, PLANE_CTL(pipe, plane_id),
1497			   plane_ctl);
1498	intel_de_write_dsb(display, dsb, PLANE_SURF(pipe, plane_id),
1499			   plane_state->surf);
1500}
1501
1502static void icl_plane_update_sel_fetch_noarm(struct intel_dsb *dsb,
1503					     struct intel_plane *plane,
1504					     const struct intel_crtc_state *crtc_state,
1505					     const struct intel_plane_state *plane_state,
1506					     int color_plane)
1507{
1508	struct intel_display *display = to_intel_display(plane);
1509	enum pipe pipe = plane->pipe;
1510	const struct drm_rect *clip;
1511	u32 val;
1512	int x, y;
1513
1514	if (!crtc_state->enable_psr2_sel_fetch)
1515		return;
1516
1517	clip = &plane_state->psr2_sel_fetch_area;
1518
1519	if (crtc_state->enable_psr2_su_region_et)
1520		y = max(0, plane_state->uapi.dst.y1 - crtc_state->psr2_su_area.y1);
1521	else
1522		y = (clip->y1 + plane_state->uapi.dst.y1);
1523	val = y << 16;
1524	val |= plane_state->uapi.dst.x1;
1525	intel_de_write_dsb(display, dsb, SEL_FETCH_PLANE_POS(pipe, plane->id), val);
1526
1527	x = plane_state->view.color_plane[color_plane].x;
1528
1529	/*
1530	 * From Bspec: UV surface Start Y Position = half of Y plane Y
1531	 * start position.
1532	 */
1533	if (!color_plane)
1534		y = plane_state->view.color_plane[color_plane].y + clip->y1;
1535	else
1536		y = plane_state->view.color_plane[color_plane].y + clip->y1 / 2;
1537
1538	val = y << 16 | x;
1539
1540	intel_de_write_dsb(display, dsb, SEL_FETCH_PLANE_OFFSET(pipe, plane->id), val);
1541
1542	/* Sizes are 0 based */
1543	val = (drm_rect_height(clip) - 1) << 16;
1544	val |= (drm_rect_width(&plane_state->uapi.src) >> 16) - 1;
1545	intel_de_write_dsb(display, dsb, SEL_FETCH_PLANE_SIZE(pipe, plane->id), val);
1546}
1547
1548static void
1549icl_plane_update_noarm(struct intel_dsb *dsb,
1550		       struct intel_plane *plane,
1551		       const struct intel_crtc_state *crtc_state,
1552		       const struct intel_plane_state *plane_state)
1553{
1554	struct intel_display *display = to_intel_display(plane);
1555	enum plane_id plane_id = plane->id;
1556	enum pipe pipe = plane->pipe;
1557	int color_plane = icl_plane_color_plane(plane_state);
1558	u32 stride = skl_plane_stride(plane_state, color_plane);
1559	const struct drm_framebuffer *fb = plane_state->hw.fb;
1560	int crtc_x = plane_state->uapi.dst.x1;
1561	int crtc_y = plane_state->uapi.dst.y1;
1562	int x = plane_state->view.color_plane[color_plane].x;
1563	int y = plane_state->view.color_plane[color_plane].y;
1564	int src_w = drm_rect_width(&plane_state->uapi.src) >> 16;
1565	int src_h = drm_rect_height(&plane_state->uapi.src) >> 16;
1566	u32 plane_color_ctl;
1567
1568	plane_color_ctl = plane_state->color_ctl |
1569		glk_plane_color_ctl_crtc(crtc_state);
1570
1571	intel_color_plane_program_pipeline(dsb, plane_state);
1572
1573	/* The scaler will handle the output position */
1574	if (plane_state->scaler_id >= 0) {
1575		crtc_x = 0;
1576		crtc_y = 0;
1577	}
1578
1579	intel_de_write_dsb(display, dsb, PLANE_STRIDE(pipe, plane_id),
1580			   PLANE_STRIDE_(stride));
1581	intel_de_write_dsb(display, dsb, PLANE_POS(pipe, plane_id),
1582			   PLANE_POS_Y(crtc_y) | PLANE_POS_X(crtc_x));
1583	intel_de_write_dsb(display, dsb, PLANE_SIZE(pipe, plane_id),
1584			   PLANE_HEIGHT(src_h - 1) | PLANE_WIDTH(src_w - 1));
1585
1586	intel_de_write_dsb(display, dsb, PLANE_KEYVAL(pipe, plane_id),
1587			   skl_plane_keyval(plane_state));
1588	intel_de_write_dsb(display, dsb, PLANE_KEYMSK(pipe, plane_id),
1589			   skl_plane_keymsk(plane_state));
1590	intel_de_write_dsb(display, dsb, PLANE_KEYMAX(pipe, plane_id),
1591			   skl_plane_keymax(plane_state));
1592
1593	intel_de_write_dsb(display, dsb, PLANE_OFFSET(pipe, plane_id),
1594			   PLANE_OFFSET_Y(y) | PLANE_OFFSET_X(x));
1595
1596	if (intel_fb_is_rc_ccs_cc_modifier(fb->modifier)) {
1597		intel_de_write_dsb(display, dsb, PLANE_CC_VAL(pipe, plane_id, 0),
1598				   lower_32_bits(plane_state->ccval));
1599		intel_de_write_dsb(display, dsb, PLANE_CC_VAL(pipe, plane_id, 1),
1600				   upper_32_bits(plane_state->ccval));
1601	}
1602
1603	/* FLAT CCS doesn't need to program AUX_DIST */
1604	if (HAS_AUX_CCS(display))
1605		intel_de_write_dsb(display, dsb, PLANE_AUX_DIST(pipe, plane_id),
1606				   skl_plane_aux_dist(plane_state, color_plane));
1607
1608	if (icl_is_hdr_plane(display, plane_id))
1609		intel_de_write_dsb(display, dsb, PLANE_CUS_CTL(pipe, plane_id),
1610				   plane_state->cus_ctl);
1611
1612	intel_de_write_dsb(display, dsb, PLANE_COLOR_CTL(pipe, plane_id),
1613			   plane_color_ctl);
1614
1615	if (fb->format->is_yuv && icl_is_hdr_plane(display, plane_id))
1616		icl_program_input_csc(dsb, plane, plane_state);
1617
1618	skl_write_plane_wm(dsb, plane, crtc_state);
1619
1620	/*
1621	 * FIXME: pxp session invalidation can hit any time even at time of commit
1622	 * or after the commit, display content will be garbage.
1623	 */
1624	if (plane_state->force_black)
1625		icl_plane_csc_load_black(dsb, plane, crtc_state);
1626
1627	icl_plane_update_sel_fetch_noarm(dsb, plane, crtc_state, plane_state, color_plane);
1628}
1629
1630static void icl_plane_update_sel_fetch_arm(struct intel_dsb *dsb,
1631					   struct intel_plane *plane,
1632					   const struct intel_crtc_state *crtc_state,
1633					   const struct intel_plane_state *plane_state)
1634{
1635	struct intel_display *display = to_intel_display(plane);
1636	enum pipe pipe = plane->pipe;
1637
1638	if (!crtc_state->enable_psr2_sel_fetch)
1639		return;
1640
1641	if (drm_rect_height(&plane_state->psr2_sel_fetch_area) > 0)
1642		intel_de_write_dsb(display, dsb, SEL_FETCH_PLANE_CTL(pipe, plane->id),
1643				   SEL_FETCH_PLANE_CTL_ENABLE);
1644	else
1645		icl_plane_disable_sel_fetch_arm(dsb, plane, crtc_state);
1646}
1647
1648static void
1649icl_plane_update_arm(struct intel_dsb *dsb,
1650		     struct intel_plane *plane,
1651		     const struct intel_crtc_state *crtc_state,
1652		     const struct intel_plane_state *plane_state)
1653{
1654	struct intel_display *display = to_intel_display(plane);
1655	enum plane_id plane_id = plane->id;
1656	enum pipe pipe = plane->pipe;
1657	u32 plane_ctl;
1658
1659	plane_ctl = plane_state->ctl |
1660		skl_plane_ctl_crtc(crtc_state);
1661
1662	/*
1663	 * Enable the scaler before the plane so that we don't
1664	 * get a catastrophic underrun even if the two operations
1665	 * end up happening in two different frames.
1666	 *
1667	 * TODO: split into noarm+arm pair
1668	 */
1669	if (plane_state->scaler_id >= 0)
1670		skl_program_plane_scaler(dsb, plane, crtc_state, plane_state);
1671
1672	icl_plane_update_sel_fetch_arm(dsb, plane, crtc_state, plane_state);
1673
1674	intel_color_plane_commit_arm(dsb, plane_state);
1675
1676	/*
1677	 * In order to have FBC for fp16 formats pixel normalizer block must be
1678	 * active. For FP16 formats, use normalization factor as 1.0 and enable
1679	 * the block.
1680	 */
1681	if (plane_has_normalizer(plane))
1682		intel_de_write_dsb(display, dsb,
1683				   PLANE_PIXEL_NORMALIZE(plane->pipe, plane->id),
1684				   pixel_normalizer_value(plane_state));
1685
1686	/*
1687	 * The control register self-arms if the plane was previously
1688	 * disabled. Try to make the plane enable atomic by writing
1689	 * the control register just before the surface register.
1690	 */
1691	intel_de_write_dsb(display, dsb, PLANE_CTL(pipe, plane_id),
1692			   plane_ctl);
1693	intel_de_write_dsb(display, dsb, PLANE_SURF(pipe, plane_id),
1694			   plane_state->surf);
1695}
1696
1697static void skl_plane_capture_error(struct intel_crtc *crtc,
1698				    struct intel_plane *plane,
1699				    struct intel_plane_error *error)
1700{
1701	struct intel_display *display = to_intel_display(plane);
1702
1703	error->ctl = intel_de_read(display, PLANE_CTL(crtc->pipe, plane->id));
1704	error->surf = intel_de_read(display, PLANE_SURF(crtc->pipe, plane->id));
1705	error->surflive = intel_de_read(display, PLANE_SURFLIVE(crtc->pipe, plane->id));
1706}
1707
1708static void
1709skl_plane_async_flip(struct intel_dsb *dsb,
1710		     struct intel_plane *plane,
1711		     const struct intel_crtc_state *crtc_state,
1712		     const struct intel_plane_state *plane_state,
1713		     bool async_flip)
1714{
1715	struct intel_display *display = to_intel_display(plane);
1716	enum plane_id plane_id = plane->id;
1717	enum pipe pipe = plane->pipe;
1718	u32 plane_ctl = plane_state->ctl;
1719	u32 plane_surf = plane_state->surf;
1720
1721	plane_ctl |= skl_plane_ctl_crtc(crtc_state);
1722
1723	if (async_flip) {
1724		if (DISPLAY_VER(display) >= 30)
1725			plane_surf |= PLANE_SURF_ASYNC_UPDATE;
1726		else
1727			plane_ctl |= PLANE_CTL_ASYNC_FLIP;
1728	}
1729
1730	intel_de_write_dsb(display, dsb, PLANE_CTL(pipe, plane_id),
1731			   plane_ctl);
1732	intel_de_write_dsb(display, dsb, PLANE_SURF(pipe, plane_id),
1733			   plane_surf);
1734}
1735
1736static bool intel_format_is_p01x(u32 format)
1737{
1738	switch (format) {
1739	case DRM_FORMAT_P010:
1740	case DRM_FORMAT_P012:
1741	case DRM_FORMAT_P016:
1742		return true;
1743	default:
1744		return false;
1745	}
1746}
1747
1748static int skl_plane_check_fb(const struct intel_crtc_state *crtc_state,
1749			      const struct intel_plane_state *plane_state)
1750{
1751	struct intel_display *display = to_intel_display(plane_state);
1752	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
1753	const struct drm_framebuffer *fb = plane_state->hw.fb;
1754	unsigned int rotation = plane_state->hw.rotation;
1755
1756	if (!fb)
1757		return 0;
1758
1759	if (rotation & ~(DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180) &&
1760	    intel_fb_is_ccs_modifier(fb->modifier)) {
1761		drm_dbg_kms(display->drm,
1762			    "[PLANE:%d:%s] RC support only with 0/180 degree rotation (%x)\n",
1763			    plane->base.base.id, plane->base.name, rotation);
1764		return -EINVAL;
1765	}
1766
1767	if (rotation & DRM_MODE_REFLECT_X &&
1768	    fb->modifier == DRM_FORMAT_MOD_LINEAR &&
1769	    DISPLAY_VER(display) < 35) {
1770		drm_dbg_kms(display->drm,
1771			    "[PLANE:%d:%s] horizontal flip is not supported with linear surface formats\n",
1772			    plane->base.base.id, plane->base.name);
1773		return -EINVAL;
1774	}
1775
1776	/*
1777	 * Display20 onward tile4 hflip is not supported
1778	 */
1779	if (rotation & DRM_MODE_REFLECT_X &&
1780	    intel_fb_is_tile4_modifier(fb->modifier) &&
1781	    DISPLAY_VER(display) >= 20) {
1782		drm_dbg_kms(display->drm,
1783			    "[PLANE:%d:%s] horizontal flip is not supported with tile4 surface formats\n",
1784			    plane->base.base.id, plane->base.name);
1785		return -EINVAL;
1786	}
1787
1788	if (drm_rotation_90_or_270(rotation)) {
1789		if (!intel_fb_supports_90_270_rotation(to_intel_framebuffer(fb))) {
1790			drm_dbg_kms(display->drm,
1791				    "[PLANE:%d:%s] Y/Yf tiling required for 90/270!\n",
1792				    plane->base.base.id, plane->base.name);
1793			return -EINVAL;
1794		}
1795
1796		/*
1797		 * 90/270 is not allowed with RGB64 16:16:16:16 and
1798		 * Indexed 8-bit. RGB 16-bit 5:6:5 is allowed gen11 onwards.
1799		 */
1800		switch (fb->format->format) {
1801		case DRM_FORMAT_RGB565:
1802			if (DISPLAY_VER(display) >= 11)
1803				break;
1804			fallthrough;
1805		case DRM_FORMAT_C8:
1806		case DRM_FORMAT_XRGB16161616F:
1807		case DRM_FORMAT_XBGR16161616F:
1808		case DRM_FORMAT_ARGB16161616F:
1809		case DRM_FORMAT_ABGR16161616F:
1810		case DRM_FORMAT_Y210:
1811		case DRM_FORMAT_Y212:
1812		case DRM_FORMAT_Y216:
1813		case DRM_FORMAT_XVYU12_16161616:
1814		case DRM_FORMAT_XVYU16161616:
1815			drm_dbg_kms(display->drm,
1816				    "[PLANE:%d:%s] unsupported pixel format %p4cc for 90/270!\n",
1817				    plane->base.base.id, plane->base.name, &fb->format->format);
1818			return -EINVAL;
1819		default:
1820			break;
1821		}
1822	}
1823
1824	/* Y-tiling is not supported in IF-ID Interlace mode */
1825	if (crtc_state->hw.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE &&
1826	    fb->modifier != DRM_FORMAT_MOD_LINEAR &&
1827	    fb->modifier != I915_FORMAT_MOD_X_TILED) {
1828		drm_dbg_kms(display->drm,
1829			    "[PLANE:%d:%s] Y/Yf tiling not supported in IF-ID mode\n",
1830			    plane->base.base.id, plane->base.name);
1831		return -EINVAL;
1832	}
1833
1834	/* Wa_1606054188:tgl,adl-s */
1835	if ((display->platform.alderlake_s || display->platform.tigerlake) &&
1836	    plane_state->ckey.flags & I915_SET_COLORKEY_SOURCE &&
1837	    intel_format_is_p01x(fb->format->format)) {
1838		drm_dbg_kms(display->drm,
1839			    "[PLANE:%d:%s] source color keying not supported with P01x formats\n",
1840			    plane->base.base.id, plane->base.name);
1841		return -EINVAL;
1842	}
1843
1844	return 0;
1845}
1846
1847static int skl_plane_check_dst_coordinates(const struct intel_crtc_state *crtc_state,
1848					   const struct intel_plane_state *plane_state)
1849{
1850	struct intel_display *display = to_intel_display(plane_state);
1851	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
1852	int crtc_x = plane_state->uapi.dst.x1;
1853	int crtc_w = drm_rect_width(&plane_state->uapi.dst);
1854	int pipe_src_w = drm_rect_width(&crtc_state->pipe_src);
1855
1856	/*
1857	 * Display WA #1175: glk
1858	 * Planes other than the cursor may cause FIFO underflow and display
1859	 * corruption if starting less than 4 pixels from the right edge of
1860	 * the screen.
1861	 * Besides the above WA fix the similar problem, where planes other
1862	 * than the cursor ending less than 4 pixels from the left edge of the
1863	 * screen may cause FIFO underflow and display corruption.
1864	 */
1865	if (DISPLAY_VER(display) == 10 &&
1866	    (crtc_x + crtc_w < 4 || crtc_x > pipe_src_w - 4)) {
1867		drm_dbg_kms(display->drm,
1868			    "[PLANE:%d:%s] requested plane X %s position %d invalid (valid range %d-%d)\n",
1869			    plane->base.base.id, plane->base.name,
1870			    crtc_x + crtc_w < 4 ? "end" : "start",
1871			    crtc_x + crtc_w < 4 ? crtc_x + crtc_w : crtc_x,
1872			    4, pipe_src_w - 4);
1873		return -ERANGE;
1874	}
1875
1876	return 0;
1877}
1878
1879static int skl_plane_check_nv12_rotation(const struct intel_plane_state *plane_state)
1880{
1881	struct intel_display *display = to_intel_display(plane_state);
1882	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
1883	const struct drm_framebuffer *fb = plane_state->hw.fb;
1884	unsigned int rotation = plane_state->hw.rotation;
1885	int src_w = drm_rect_width(&plane_state->uapi.src) >> 16;
1886
1887	/* Display WA #1106 */
1888	if (intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier) &&
1889	    src_w & 3 &&
1890	    (rotation == DRM_MODE_ROTATE_270 ||
1891	     rotation == (DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_90))) {
1892		drm_dbg_kms(display->drm,
1893			    "[PLANE:%d:%s] src width must be multiple of 4 for rotated planar YUV\n",
1894			    plane->base.base.id, plane->base.name);
1895		return -EINVAL;
1896	}
1897
1898	return 0;
1899}
1900
1901static int skl_plane_max_scale(struct intel_display *display,
1902			       const struct drm_framebuffer *fb)
1903{
1904	/*
1905	 * We don't yet know the final source width nor
1906	 * whether we can use the HQ scaler mode. Assume
1907	 * the best case.
1908	 * FIXME need to properly check this later.
1909	 */
1910	if (DISPLAY_VER(display) >= 10 ||
1911	    !intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier))
1912		return 0x30000 - 1;
1913	else
1914		return 0x20000 - 1;
1915}
1916
1917static int intel_plane_min_width(struct intel_plane *plane,
1918				 const struct drm_framebuffer *fb,
1919				 int color_plane,
1920				 unsigned int rotation)
1921{
1922	if (plane->min_width)
1923		return plane->min_width(fb, color_plane, rotation);
1924	else
1925		return 1;
1926}
1927
1928static int intel_plane_min_height(struct intel_plane *plane,
1929				  const struct drm_framebuffer *fb,
1930				  int color_plane,
1931				  unsigned int rotation)
1932{
1933	return 1;
1934}
1935
1936static int intel_plane_max_width(struct intel_plane *plane,
1937				 const struct drm_framebuffer *fb,
1938				 int color_plane,
1939				 unsigned int rotation)
1940{
1941	if (plane->max_width)
1942		return plane->max_width(fb, color_plane, rotation);
1943	else
1944		return INT_MAX;
1945}
1946
1947static int intel_plane_max_height(struct intel_plane *plane,
1948				  const struct drm_framebuffer *fb,
1949				  int color_plane,
1950				  unsigned int rotation)
1951{
1952	if (plane->max_height)
1953		return plane->max_height(fb, color_plane, rotation);
1954	else
1955		return INT_MAX;
1956}
1957
1958static bool
1959skl_check_main_ccs_coordinates(struct intel_plane_state *plane_state,
1960			       int main_x, int main_y, u32 main_offset,
1961			       int ccs_plane)
1962{
1963	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
1964	const struct drm_framebuffer *fb = plane_state->hw.fb;
1965	int aux_x = plane_state->view.color_plane[ccs_plane].x;
1966	int aux_y = plane_state->view.color_plane[ccs_plane].y;
1967	u32 aux_offset = plane_state->view.color_plane[ccs_plane].offset;
1968	unsigned int alignment = plane->min_alignment(plane, fb, ccs_plane);
1969	int hsub;
1970	int vsub;
1971
1972	intel_fb_plane_get_subsampling(&hsub, &vsub, fb, ccs_plane);
1973	while (aux_offset >= main_offset && aux_y <= main_y) {
1974		int x, y;
1975
1976		if (aux_x == main_x && aux_y == main_y)
1977			break;
1978
1979		if (aux_offset == 0)
1980			break;
1981
1982		x = aux_x / hsub;
1983		y = aux_y / vsub;
1984		aux_offset = intel_plane_adjust_aligned_offset(&x, &y,
1985							       plane_state,
1986							       ccs_plane,
1987							       aux_offset,
1988							       aux_offset - alignment);
1989		aux_x = x * hsub + aux_x % hsub;
1990		aux_y = y * vsub + aux_y % vsub;
1991	}
1992
1993	if (aux_x != main_x || aux_y != main_y)
1994		return false;
1995
1996	plane_state->view.color_plane[ccs_plane].offset = aux_offset;
1997	plane_state->view.color_plane[ccs_plane].x = aux_x;
1998	plane_state->view.color_plane[ccs_plane].y = aux_y;
1999
2000	return true;
2001}
2002
2003
2004int skl_calc_main_surface_offset(const struct intel_plane_state *plane_state,
2005				 int *x, int *y, u32 *offset)
2006{
2007	struct intel_display *display = to_intel_display(plane_state);
2008	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
2009	const struct drm_framebuffer *fb = plane_state->hw.fb;
2010	int aux_plane = skl_main_to_aux_plane(fb, 0);
2011	u32 aux_offset = plane_state->view.color_plane[aux_plane].offset;
2012	unsigned int alignment = plane->min_alignment(plane, fb, 0);
2013	int w = drm_rect_width(&plane_state->uapi.src) >> 16;
2014
2015	intel_add_fb_offsets(x, y, plane_state, 0);
2016	*offset = intel_plane_compute_aligned_offset(x, y, plane_state, 0);
2017	if (drm_WARN_ON(display->drm, alignment && !is_power_of_2(alignment)))
2018		return -EINVAL;
2019
2020	/*
2021	 * AUX surface offset is specified as the distance from the
2022	 * main surface offset, and it must be non-negative. Make
2023	 * sure that is what we will get.
2024	 */
2025	if (aux_plane && *offset > aux_offset)
2026		*offset = intel_plane_adjust_aligned_offset(x, y, plane_state, 0,
2027							    *offset,
2028							    aux_offset & ~(alignment - 1));
2029
2030	/*
2031	 * When using an X-tiled surface, the plane blows up
2032	 * if the x offset + width exceed the stride.
2033	 *
2034	 * TODO: linear and Y-tiled seem fine, Yf untested,
2035	 */
2036	if (fb->modifier == I915_FORMAT_MOD_X_TILED) {
2037		int cpp = fb->format->cpp[0];
2038
2039		while ((*x + w) * cpp > plane_state->view.color_plane[0].mapping_stride) {
2040			if (*offset == 0) {
2041				drm_dbg_kms(display->drm,
2042					    "[PLANE:%d:%s] unable to find suitable display surface offset due to X-tiling\n",
2043					    plane->base.base.id, plane->base.name);
2044				return -EINVAL;
2045			}
2046
2047			*offset = intel_plane_adjust_aligned_offset(x, y, plane_state, 0,
2048								    *offset,
2049								    *offset - alignment);
2050		}
2051	}
2052
2053	return 0;
2054}
2055
2056static int skl_check_main_surface(struct intel_plane_state *plane_state)
2057{
2058	struct intel_display *display = to_intel_display(plane_state);
2059	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
2060	const struct drm_framebuffer *fb = plane_state->hw.fb;
2061	unsigned int rotation = plane_state->hw.rotation;
2062	int x = plane_state->uapi.src.x1 >> 16;
2063	int y = plane_state->uapi.src.y1 >> 16;
2064	int w = drm_rect_width(&plane_state->uapi.src) >> 16;
2065	int h = drm_rect_height(&plane_state->uapi.src) >> 16;
2066	int min_width = intel_plane_min_width(plane, fb, 0, rotation);
2067	int min_height = intel_plane_min_height(plane, fb, 0, rotation);
2068	int max_width = intel_plane_max_width(plane, fb, 0, rotation);
2069	int max_height = intel_plane_max_height(plane, fb, 0, rotation);
2070	unsigned int alignment = plane->min_alignment(plane, fb, 0);
2071	int aux_plane = skl_main_to_aux_plane(fb, 0);
2072	u32 offset;
2073	int ret;
2074
2075	if (w > max_width || w < min_width || h > max_height || h < min_height) {
2076		drm_dbg_kms(display->drm,
2077			    "[PLANE:%d:%s] requested Y/RGB source size %dx%d outside limits (min: %dx%d max: %dx%d)\n",
2078			    plane->base.base.id, plane->base.name,
2079			    w, h, min_width, min_height, max_width, max_height);
2080		return -EINVAL;
2081	}
2082
2083	ret = skl_calc_main_surface_offset(plane_state, &x, &y, &offset);
2084	if (ret)
2085		return ret;
2086
2087	/*
2088	 * CCS AUX surface doesn't have its own x/y offsets, we must make sure
2089	 * they match with the main surface x/y offsets. On DG2
2090	 * there's no aux plane on fb so skip this checking.
2091	 */
2092	if (intel_fb_is_ccs_modifier(fb->modifier) && aux_plane) {
2093		while (!skl_check_main_ccs_coordinates(plane_state, x, y,
2094						       offset, aux_plane)) {
2095			if (offset == 0)
2096				break;
2097
2098			offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, 0,
2099								   offset, offset - alignment);
2100		}
2101
2102		if (x != plane_state->view.color_plane[aux_plane].x ||
2103		    y != plane_state->view.color_plane[aux_plane].y) {
2104			drm_dbg_kms(display->drm,
2105				    "[PLANE:%d:%s] unable to find suitable display surface offset due to CCS\n",
2106				    plane->base.base.id, plane->base.name);
2107			return -EINVAL;
2108		}
2109	}
2110
2111	if (DISPLAY_VER(display) >= 13)
2112		drm_WARN_ON(display->drm, x > 65535 || y > 65535);
2113	else
2114		drm_WARN_ON(display->drm, x > 8191 || y > 8191);
2115
2116	plane_state->view.color_plane[0].offset = offset;
2117	plane_state->view.color_plane[0].x = x;
2118	plane_state->view.color_plane[0].y = y;
2119
2120	/*
2121	 * Put the final coordinates back so that the src
2122	 * coordinate checks will see the right values.
2123	 */
2124	drm_rect_translate_to(&plane_state->uapi.src,
2125			      x << 16, y << 16);
2126
2127	return 0;
2128}
2129
2130static int skl_check_nv12_aux_surface(struct intel_plane_state *plane_state)
2131{
2132	struct intel_display *display = to_intel_display(plane_state);
2133	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
2134	const struct drm_framebuffer *fb = plane_state->hw.fb;
2135	unsigned int rotation = plane_state->hw.rotation;
2136	int uv_plane = 1;
2137	int ccs_plane = intel_fb_is_ccs_modifier(fb->modifier) ?
2138			skl_main_to_aux_plane(fb, uv_plane) : 0;
2139	int min_width = intel_plane_min_width(plane, fb, uv_plane, rotation);
2140	int min_height = intel_plane_min_height(plane, fb, uv_plane, rotation);
2141	int max_width = intel_plane_max_width(plane, fb, uv_plane, rotation);
2142	int max_height = intel_plane_max_height(plane, fb, uv_plane, rotation);
2143	int x = plane_state->uapi.src.x1 >> 17;
2144	int y = plane_state->uapi.src.y1 >> 17;
2145	int w = drm_rect_width(&plane_state->uapi.src) >> 17;
2146	int h = drm_rect_height(&plane_state->uapi.src) >> 17;
2147	u32 offset;
2148
2149	/* FIXME not quite sure how/if these apply to the chroma plane */
2150	if (w > max_width || w < min_width || h > max_height || h < min_height) {
2151		drm_dbg_kms(display->drm,
2152			    "[PLANE:%d:%s] requested CbCr source size %dx%d outside limits (min: %dx%d max: %dx%d)\n",
2153			    plane->base.base.id, plane->base.name,
2154			    w, h, min_width, min_height, max_width, max_height);
2155		return -EINVAL;
2156	}
2157
2158	intel_add_fb_offsets(&x, &y, plane_state, uv_plane);
2159	offset = intel_plane_compute_aligned_offset(&x, &y,
2160						    plane_state, uv_plane);
2161
2162	if (ccs_plane) {
2163		u32 aux_offset = plane_state->view.color_plane[ccs_plane].offset;
2164		unsigned int alignment = plane->min_alignment(plane, fb, uv_plane);
2165
2166		if (offset > aux_offset)
2167			offset = intel_plane_adjust_aligned_offset(&x, &y,
2168								   plane_state,
2169								   uv_plane,
2170								   offset,
2171								   aux_offset & ~(alignment - 1));
2172
2173		while (!skl_check_main_ccs_coordinates(plane_state, x, y,
2174						       offset, ccs_plane)) {
2175			if (offset == 0)
2176				break;
2177
2178			offset = intel_plane_adjust_aligned_offset(&x, &y,
2179								   plane_state,
2180								   uv_plane,
2181								   offset, offset - alignment);
2182		}
2183
2184		if (x != plane_state->view.color_plane[ccs_plane].x ||
2185		    y != plane_state->view.color_plane[ccs_plane].y) {
2186			drm_dbg_kms(display->drm,
2187				    "[PLANE:%d:%s] unable to find suitable display surface offset due to CCS\n",
2188				    plane->base.base.id, plane->base.name);
2189			return -EINVAL;
2190		}
2191	}
2192
2193	if (DISPLAY_VER(display) >= 13)
2194		drm_WARN_ON(display->drm, x > 65535 || y > 65535);
2195	else
2196		drm_WARN_ON(display->drm, x > 8191 || y > 8191);
2197
2198	plane_state->view.color_plane[uv_plane].offset = offset;
2199	plane_state->view.color_plane[uv_plane].x = x;
2200	plane_state->view.color_plane[uv_plane].y = y;
2201
2202	return 0;
2203}
2204
2205static int skl_check_ccs_aux_surface(struct intel_plane_state *plane_state)
2206{
2207	const struct drm_framebuffer *fb = plane_state->hw.fb;
2208	int src_x = plane_state->uapi.src.x1 >> 16;
2209	int src_y = plane_state->uapi.src.y1 >> 16;
2210	u32 offset;
2211	int ccs_plane;
2212
2213	for (ccs_plane = 0; ccs_plane < fb->format->num_planes; ccs_plane++) {
2214		int main_hsub, main_vsub;
2215		int hsub, vsub;
2216		int x, y;
2217
2218		if (!intel_fb_is_ccs_aux_plane(fb, ccs_plane))
2219			continue;
2220
2221		intel_fb_plane_get_subsampling(&main_hsub, &main_vsub, fb,
2222					       skl_ccs_to_main_plane(fb, ccs_plane));
2223		intel_fb_plane_get_subsampling(&hsub, &vsub, fb, ccs_plane);
2224
2225		hsub *= main_hsub;
2226		vsub *= main_vsub;
2227		x = src_x / hsub;
2228		y = src_y / vsub;
2229
2230		intel_add_fb_offsets(&x, &y, plane_state, ccs_plane);
2231
2232		offset = intel_plane_compute_aligned_offset(&x, &y,
2233							    plane_state,
2234							    ccs_plane);
2235
2236		plane_state->view.color_plane[ccs_plane].offset = offset;
2237		plane_state->view.color_plane[ccs_plane].x = (x * hsub + src_x % hsub) / main_hsub;
2238		plane_state->view.color_plane[ccs_plane].y = (y * vsub + src_y % vsub) / main_vsub;
2239	}
2240
2241	return 0;
2242}
2243
2244static int skl_check_plane_surface(struct intel_plane_state *plane_state)
2245{
2246	const struct drm_framebuffer *fb = plane_state->hw.fb;
2247	int ret;
2248
2249	ret = intel_plane_compute_gtt(plane_state);
2250	if (ret)
2251		return ret;
2252
2253	if (!plane_state->uapi.visible)
2254		return 0;
2255
2256	/*
2257	 * Handle the AUX surface first since the main surface setup depends on
2258	 * it.
2259	 */
2260	if (intel_fb_is_ccs_modifier(fb->modifier)) {
2261		ret = skl_check_ccs_aux_surface(plane_state);
2262		if (ret)
2263			return ret;
2264	}
2265
2266	if (intel_format_info_is_yuv_semiplanar(fb->format,
2267						fb->modifier)) {
2268		ret = skl_check_nv12_aux_surface(plane_state);
2269		if (ret)
2270			return ret;
2271	}
2272
2273	ret = skl_check_main_surface(plane_state);
2274	if (ret)
2275		return ret;
2276
2277	return 0;
2278}
2279
2280static bool skl_fb_scalable(const struct drm_framebuffer *fb)
2281{
2282	struct intel_display *display;
2283
2284	if (!fb)
2285		return false;
2286
2287	display = to_intel_display(fb->dev);
2288
2289	switch (fb->format->format) {
2290	case DRM_FORMAT_C8:
2291		return false;
2292	case DRM_FORMAT_XRGB16161616F:
2293	case DRM_FORMAT_ARGB16161616F:
2294	case DRM_FORMAT_XBGR16161616F:
2295	case DRM_FORMAT_ABGR16161616F:
2296		return DISPLAY_VER(display) >= 11;
2297	default:
2298		return true;
2299	}
2300}
2301
2302static void check_protection(struct intel_plane_state *plane_state)
2303{
2304	struct intel_display *display = to_intel_display(plane_state);
2305	const struct drm_framebuffer *fb = plane_state->hw.fb;
2306	struct drm_gem_object *obj = intel_fb_bo(fb);
2307
2308	if (DISPLAY_VER(display) < 11)
2309		return;
2310
2311	plane_state->decrypt = intel_pxp_key_check(obj, false) == 0;
2312	plane_state->force_black = intel_bo_is_protected(obj) &&
2313		!plane_state->decrypt;
2314}
2315
2316static void
2317make_damage_viewport_relative(struct intel_plane_state *plane_state)
2318{
2319	const struct drm_framebuffer *fb = plane_state->hw.fb;
2320	const struct drm_rect *src = &plane_state->uapi.src;
2321	unsigned int rotation = plane_state->hw.rotation;
2322	struct drm_rect *damage = &plane_state->damage;
2323
2324	if (!drm_rect_visible(damage))
2325		return;
2326
2327	if (!fb || !plane_state->uapi.visible) {
2328		plane_state->damage = DRM_RECT_INIT(0, 0, 0, 0);
2329		return;
2330	}
2331
2332	if (drm_rotation_90_or_270(rotation)) {
2333		drm_rect_rotate(damage, fb->width, fb->height,
2334				DRM_MODE_ROTATE_270);
2335		drm_rect_translate(damage, -(src->y1 >> 16), -(src->x1 >> 16));
2336	} else {
2337		drm_rect_translate(damage, -(src->x1 >> 16), -(src->y1 >> 16));
2338	}
2339}
2340
2341static void clip_damage(struct intel_plane_state *plane_state)
2342{
2343	struct drm_rect *damage = &plane_state->damage;
2344	struct drm_rect src;
2345
2346	if (!drm_rect_visible(damage))
2347		return;
2348
2349	drm_rect_fp_to_int(&src, &plane_state->uapi.src);
2350	drm_rect_translate(damage, src.x1, src.y1);
2351	drm_rect_intersect(damage, &src);
2352}
2353
2354static int skl_plane_check(struct intel_crtc_state *crtc_state,
2355			   struct intel_plane_state *plane_state)
2356{
2357	struct intel_display *display = to_intel_display(plane_state);
2358	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
2359	const struct drm_framebuffer *fb = plane_state->hw.fb;
2360	int min_scale = DRM_PLANE_NO_SCALING;
2361	int max_scale = DRM_PLANE_NO_SCALING;
2362	int ret;
2363
2364	ret = skl_plane_check_fb(crtc_state, plane_state);
2365	if (ret)
2366		return ret;
2367
2368	/* use scaler when colorkey is not required */
2369	if (!plane_state->ckey.flags && skl_fb_scalable(fb)) {
2370		min_scale = 1;
2371		max_scale = skl_plane_max_scale(display, fb);
2372	}
2373
2374	ret = intel_plane_check_clipping(plane_state, crtc_state,
2375					 min_scale, max_scale, true);
2376	if (ret)
2377		return ret;
2378
2379	make_damage_viewport_relative(plane_state);
2380
2381	ret = skl_check_plane_surface(plane_state);
2382	if (ret)
2383		return ret;
2384
2385	if (!plane_state->uapi.visible)
2386		return 0;
2387
2388	ret = skl_plane_check_dst_coordinates(crtc_state, plane_state);
2389	if (ret)
2390		return ret;
2391
2392	ret = intel_plane_check_src_coordinates(plane_state);
2393	if (ret)
2394		return ret;
2395
2396	clip_damage(plane_state);
2397
2398	ret = skl_plane_check_nv12_rotation(plane_state);
2399	if (ret)
2400		return ret;
2401
2402	check_protection(plane_state);
2403
2404	/* HW only has 8 bits pixel precision, disable plane if invisible */
2405	if (!(plane_state->hw.alpha >> 8)) {
2406		plane_state->uapi.visible = false;
2407		plane_state->damage = DRM_RECT_INIT(0, 0, 0, 0);
2408	}
2409
2410	plane_state->ctl = skl_plane_ctl(plane_state);
2411
2412	if (DISPLAY_VER(display) >= 10)
2413		plane_state->color_ctl = glk_plane_color_ctl(plane_state);
2414
2415	if (intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier) &&
2416	    icl_is_hdr_plane(display, plane->id))
2417		/* Enable and use MPEG-2 chroma siting */
2418		plane_state->cus_ctl = PLANE_CUS_ENABLE |
2419			PLANE_CUS_HPHASE_0 |
2420			PLANE_CUS_VPHASE_SIGN_NEGATIVE | PLANE_CUS_VPHASE_0_25;
2421	else
2422		plane_state->cus_ctl = 0;
2423
2424	return 0;
2425}
2426
2427void icl_link_nv12_planes(struct intel_plane_state *uv_plane_state,
2428			  struct intel_plane_state *y_plane_state)
2429{
2430	struct intel_display *display = to_intel_display(uv_plane_state);
2431	struct intel_plane *uv_plane = to_intel_plane(uv_plane_state->uapi.plane);
2432	struct intel_plane *y_plane = to_intel_plane(y_plane_state->uapi.plane);
2433
2434	drm_WARN_ON(display->drm, icl_is_nv12_y_plane(display, uv_plane->id));
2435	drm_WARN_ON(display->drm, !icl_is_nv12_y_plane(display, y_plane->id));
2436
2437	y_plane_state->ctl |= PLANE_CTL_YUV420_Y_PLANE;
2438
2439	if (icl_is_hdr_plane(display, uv_plane->id)) {
2440		switch (y_plane->id) {
2441		case PLANE_7:
2442			uv_plane_state->cus_ctl |= PLANE_CUS_Y_PLANE_7_ICL;
2443			break;
2444		case PLANE_6:
2445			uv_plane_state->cus_ctl |= PLANE_CUS_Y_PLANE_6_ICL;
2446			break;
2447		case PLANE_5:
2448			uv_plane_state->cus_ctl |= PLANE_CUS_Y_PLANE_5_RKL;
2449			break;
2450		case PLANE_4:
2451			uv_plane_state->cus_ctl |= PLANE_CUS_Y_PLANE_4_RKL;
2452			break;
2453		default:
2454			MISSING_CASE(y_plane->id);
2455		}
2456	}
2457}
2458
2459static struct intel_fbc *skl_plane_fbc(struct intel_display *display,
2460				       enum pipe pipe, enum plane_id plane_id)
2461{
2462	enum intel_fbc_id fbc_id = skl_fbc_id_for_pipe(pipe);
2463
2464	if (skl_plane_has_fbc(display, fbc_id, plane_id))
2465		return display->fbc[fbc_id];
2466	else
2467		return NULL;
2468}
2469
2470static bool skl_plane_has_planar(struct intel_display *display,
2471				 enum pipe pipe, enum plane_id plane_id)
2472{
2473	/* Display WA #0870: skl, bxt */
2474	if (display->platform.skylake || display->platform.broxton)
2475		return false;
2476
2477	if (pipe == PIPE_C)
2478		return false;
2479
2480	return plane_id == PLANE_1 || plane_id == PLANE_2;
2481}
2482
2483static const u32 *skl_get_plane_formats(struct intel_display *display,
2484					enum pipe pipe, enum plane_id plane_id,
2485					int *num_formats)
2486{
2487	if (skl_plane_has_planar(display, pipe, plane_id)) {
2488		*num_formats = ARRAY_SIZE(skl_planar_formats);
2489		return skl_planar_formats;
2490	} else {
2491		*num_formats = ARRAY_SIZE(skl_plane_formats);
2492		return skl_plane_formats;
2493	}
2494}
2495
2496static bool glk_plane_has_planar(struct intel_display *display,
2497				 enum pipe pipe, enum plane_id plane_id)
2498{
2499	return plane_id == PLANE_1 || plane_id == PLANE_2;
2500}
2501
2502static const u32 *glk_get_plane_formats(struct intel_display *display,
2503					enum pipe pipe, enum plane_id plane_id,
2504					int *num_formats)
2505{
2506	if (glk_plane_has_planar(display, pipe, plane_id)) {
2507		*num_formats = ARRAY_SIZE(glk_planar_formats);
2508		return glk_planar_formats;
2509	} else {
2510		*num_formats = ARRAY_SIZE(skl_plane_formats);
2511		return skl_plane_formats;
2512	}
2513}
2514
2515static const u32 *icl_get_plane_formats(struct intel_display *display,
2516					enum pipe pipe, enum plane_id plane_id,
2517					int *num_formats)
2518{
2519	if (icl_is_hdr_plane(display, plane_id)) {
2520		*num_formats = ARRAY_SIZE(icl_hdr_plane_formats);
2521		return icl_hdr_plane_formats;
2522	} else if (icl_is_nv12_y_plane(display, plane_id)) {
2523		*num_formats = ARRAY_SIZE(icl_sdr_y_plane_formats);
2524		return icl_sdr_y_plane_formats;
2525	} else {
2526		*num_formats = ARRAY_SIZE(icl_sdr_uv_plane_formats);
2527		return icl_sdr_uv_plane_formats;
2528	}
2529}
2530
2531static bool skl_plane_format_mod_supported(struct drm_plane *_plane,
2532					   u32 format, u64 modifier)
2533{
2534	struct intel_plane *plane = to_intel_plane(_plane);
2535
2536	if (!intel_fb_plane_supports_modifier(plane, modifier))
2537		return false;
2538
2539	switch (format) {
2540	case DRM_FORMAT_XRGB8888:
2541	case DRM_FORMAT_XBGR8888:
2542	case DRM_FORMAT_ARGB8888:
2543	case DRM_FORMAT_ABGR8888:
2544		if (intel_fb_is_ccs_modifier(modifier))
2545			return true;
2546		fallthrough;
2547	case DRM_FORMAT_RGB565:
2548	case DRM_FORMAT_XRGB2101010:
2549	case DRM_FORMAT_XBGR2101010:
2550	case DRM_FORMAT_ARGB2101010:
2551	case DRM_FORMAT_ABGR2101010:
2552	case DRM_FORMAT_YUYV:
2553	case DRM_FORMAT_YVYU:
2554	case DRM_FORMAT_UYVY:
2555	case DRM_FORMAT_VYUY:
2556	case DRM_FORMAT_NV12:
2557	case DRM_FORMAT_XYUV8888:
2558	case DRM_FORMAT_P010:
2559	case DRM_FORMAT_P012:
2560	case DRM_FORMAT_P016:
2561	case DRM_FORMAT_XVYU2101010:
2562		if (modifier == I915_FORMAT_MOD_Yf_TILED)
2563			return true;
2564		fallthrough;
2565	case DRM_FORMAT_C8:
2566	case DRM_FORMAT_XBGR16161616F:
2567	case DRM_FORMAT_ABGR16161616F:
2568	case DRM_FORMAT_XRGB16161616F:
2569	case DRM_FORMAT_ARGB16161616F:
2570	case DRM_FORMAT_Y210:
2571	case DRM_FORMAT_Y212:
2572	case DRM_FORMAT_Y216:
2573	case DRM_FORMAT_XVYU12_16161616:
2574	case DRM_FORMAT_XVYU16161616:
2575		if (modifier == DRM_FORMAT_MOD_LINEAR ||
2576		    modifier == I915_FORMAT_MOD_X_TILED ||
2577		    modifier == I915_FORMAT_MOD_Y_TILED)
2578			return true;
2579		fallthrough;
2580	default:
2581		return false;
2582	}
2583}
2584
2585static bool icl_plane_format_mod_supported(struct drm_plane *_plane,
2586					   u32 format, u64 modifier)
2587{
2588	struct intel_plane *plane = to_intel_plane(_plane);
2589
2590	if (!intel_fb_plane_supports_modifier(plane, modifier))
2591		return false;
2592
2593	switch (format) {
2594	case DRM_FORMAT_XRGB8888:
2595	case DRM_FORMAT_XBGR8888:
2596	case DRM_FORMAT_ARGB8888:
2597	case DRM_FORMAT_ABGR8888:
2598	case DRM_FORMAT_XRGB2101010:
2599	case DRM_FORMAT_XBGR2101010:
2600	case DRM_FORMAT_ARGB2101010:
2601	case DRM_FORMAT_ABGR2101010:
2602		if (intel_fb_is_ccs_modifier(modifier))
2603			return true;
2604		fallthrough;
2605	case DRM_FORMAT_RGB565:
2606	case DRM_FORMAT_YUYV:
2607	case DRM_FORMAT_YVYU:
2608	case DRM_FORMAT_UYVY:
2609	case DRM_FORMAT_VYUY:
2610	case DRM_FORMAT_NV12:
2611	case DRM_FORMAT_XYUV8888:
2612	case DRM_FORMAT_P010:
2613	case DRM_FORMAT_P012:
2614	case DRM_FORMAT_P016:
2615	case DRM_FORMAT_XVYU2101010:
2616		if (modifier == I915_FORMAT_MOD_Yf_TILED)
2617			return true;
2618		fallthrough;
2619	case DRM_FORMAT_C8:
2620	case DRM_FORMAT_XBGR16161616F:
2621	case DRM_FORMAT_ABGR16161616F:
2622	case DRM_FORMAT_XRGB16161616F:
2623	case DRM_FORMAT_ARGB16161616F:
2624	case DRM_FORMAT_Y210:
2625	case DRM_FORMAT_Y212:
2626	case DRM_FORMAT_Y216:
2627	case DRM_FORMAT_XVYU12_16161616:
2628	case DRM_FORMAT_XVYU16161616:
2629		if (modifier == DRM_FORMAT_MOD_LINEAR ||
2630		    modifier == I915_FORMAT_MOD_X_TILED ||
2631		    modifier == I915_FORMAT_MOD_Y_TILED)
2632			return true;
2633		fallthrough;
2634	default:
2635		return false;
2636	}
2637}
2638
2639static bool tgl_plane_format_mod_supported(struct drm_plane *_plane,
2640					   u32 format, u64 modifier)
2641{
2642	struct intel_plane *plane = to_intel_plane(_plane);
2643
2644	if (!intel_fb_plane_supports_modifier(plane, modifier))
2645		return false;
2646
2647	switch (format) {
2648	case DRM_FORMAT_XRGB8888:
2649	case DRM_FORMAT_XBGR8888:
2650	case DRM_FORMAT_ARGB8888:
2651	case DRM_FORMAT_ABGR8888:
2652	case DRM_FORMAT_XRGB2101010:
2653	case DRM_FORMAT_XBGR2101010:
2654	case DRM_FORMAT_ARGB2101010:
2655	case DRM_FORMAT_ABGR2101010:
2656	case DRM_FORMAT_XBGR16161616F:
2657	case DRM_FORMAT_ABGR16161616F:
2658	case DRM_FORMAT_XRGB16161616F:
2659	case DRM_FORMAT_ARGB16161616F:
2660		if (intel_fb_is_ccs_modifier(modifier))
2661			return true;
2662		fallthrough;
2663	case DRM_FORMAT_YUYV:
2664	case DRM_FORMAT_YVYU:
2665	case DRM_FORMAT_UYVY:
2666	case DRM_FORMAT_VYUY:
2667	case DRM_FORMAT_NV12:
2668	case DRM_FORMAT_XYUV8888:
2669	case DRM_FORMAT_P010:
2670	case DRM_FORMAT_P012:
2671	case DRM_FORMAT_P016:
2672		if (intel_fb_is_mc_ccs_modifier(modifier))
2673			return true;
2674		fallthrough;
2675	case DRM_FORMAT_RGB565:
2676	case DRM_FORMAT_XVYU2101010:
2677	case DRM_FORMAT_C8:
2678	case DRM_FORMAT_Y210:
2679	case DRM_FORMAT_Y212:
2680	case DRM_FORMAT_Y216:
2681	case DRM_FORMAT_XVYU12_16161616:
2682	case DRM_FORMAT_XVYU16161616:
2683		if (!intel_fb_is_ccs_modifier(modifier))
2684			return true;
2685		fallthrough;
2686	default:
2687		return false;
2688	}
2689}
2690
2691static const struct drm_plane_funcs skl_plane_funcs = {
2692	.update_plane = drm_atomic_helper_update_plane,
2693	.disable_plane = drm_atomic_helper_disable_plane,
2694	.destroy = intel_plane_destroy,
2695	.atomic_duplicate_state = intel_plane_duplicate_state,
2696	.atomic_destroy_state = intel_plane_destroy_state,
2697	.format_mod_supported = skl_plane_format_mod_supported,
2698	.format_mod_supported_async = intel_plane_format_mod_supported_async,
2699};
2700
2701static const struct drm_plane_funcs icl_plane_funcs = {
2702	.update_plane = drm_atomic_helper_update_plane,
2703	.disable_plane = drm_atomic_helper_disable_plane,
2704	.destroy = intel_plane_destroy,
2705	.atomic_duplicate_state = intel_plane_duplicate_state,
2706	.atomic_destroy_state = intel_plane_destroy_state,
2707	.format_mod_supported = icl_plane_format_mod_supported,
2708	.format_mod_supported_async = intel_plane_format_mod_supported_async,
2709};
2710
2711static const struct drm_plane_funcs tgl_plane_funcs = {
2712	.update_plane = drm_atomic_helper_update_plane,
2713	.disable_plane = drm_atomic_helper_disable_plane,
2714	.destroy = intel_plane_destroy,
2715	.atomic_duplicate_state = intel_plane_duplicate_state,
2716	.atomic_destroy_state = intel_plane_destroy_state,
2717	.format_mod_supported = tgl_plane_format_mod_supported,
2718	.format_mod_supported_async = intel_plane_format_mod_supported_async,
2719};
2720
2721static void
2722skl_plane_enable_flip_done(struct intel_plane *plane)
2723{
2724	struct intel_display *display = to_intel_display(plane);
2725	enum pipe pipe = plane->pipe;
2726
2727	spin_lock_irq(&display->irq.lock);
2728	bdw_enable_pipe_irq(display, pipe, GEN9_PIPE_PLANE_FLIP_DONE(plane->id));
2729	spin_unlock_irq(&display->irq.lock);
2730}
2731
2732static void
2733skl_plane_disable_flip_done(struct intel_plane *plane)
2734{
2735	struct intel_display *display = to_intel_display(plane);
2736	enum pipe pipe = plane->pipe;
2737
2738	spin_lock_irq(&display->irq.lock);
2739	bdw_disable_pipe_irq(display, pipe, GEN9_PIPE_PLANE_FLIP_DONE(plane->id));
2740	spin_unlock_irq(&display->irq.lock);
2741}
2742
2743static bool skl_plane_has_rc_ccs(struct intel_display *display,
2744				 enum pipe pipe, enum plane_id plane_id)
2745{
2746	if (pipe == PIPE_C)
2747		return false;
2748
2749	return plane_id == PLANE_1 || plane_id == PLANE_2;
2750}
2751
2752static u8 skl_plane_caps(struct intel_display *display,
2753			 enum pipe pipe, enum plane_id plane_id)
2754{
2755	u8 caps = INTEL_PLANE_CAP_TILING_X |
2756		INTEL_PLANE_CAP_TILING_Y |
2757		INTEL_PLANE_CAP_TILING_Yf;
2758
2759	if (skl_plane_has_rc_ccs(display, pipe, plane_id))
2760		caps |= INTEL_PLANE_CAP_CCS_RC;
2761
2762	return caps;
2763}
2764
2765static bool glk_plane_has_rc_ccs(struct intel_display *display,
2766				 enum pipe pipe)
2767{
2768	return pipe != PIPE_C;
2769}
2770
2771static u8 glk_plane_caps(struct intel_display *display,
2772			 enum pipe pipe, enum plane_id plane_id)
2773{
2774	u8 caps = INTEL_PLANE_CAP_TILING_X |
2775		INTEL_PLANE_CAP_TILING_Y |
2776		INTEL_PLANE_CAP_TILING_Yf;
2777
2778	if (glk_plane_has_rc_ccs(display, pipe))
2779		caps |= INTEL_PLANE_CAP_CCS_RC;
2780
2781	return caps;
2782}
2783
2784static u8 icl_plane_caps(struct intel_display *display,
2785			 enum pipe pipe, enum plane_id plane_id)
2786{
2787	return INTEL_PLANE_CAP_TILING_X |
2788		INTEL_PLANE_CAP_TILING_Y |
2789		INTEL_PLANE_CAP_TILING_Yf |
2790		INTEL_PLANE_CAP_CCS_RC;
2791}
2792
2793static bool tgl_plane_has_mc_ccs(struct intel_display *display,
2794				 enum plane_id plane_id)
2795{
2796	/* Wa_14010477008 */
2797	if (display->platform.dg1 || display->platform.rocketlake ||
2798	    (display->platform.tigerlake && IS_DISPLAY_STEP(display, STEP_A0, STEP_D0)))
2799		return false;
2800
2801	return plane_id < PLANE_6;
2802}
2803
2804static u8 tgl_plane_caps(struct intel_display *display,
2805			 enum pipe pipe, enum plane_id plane_id)
2806{
2807	u8 caps = INTEL_PLANE_CAP_TILING_X |
2808		INTEL_PLANE_CAP_CCS_RC |
2809		INTEL_PLANE_CAP_CCS_RC_CC;
2810
2811	if (HAS_4TILE(display))
2812		caps |= INTEL_PLANE_CAP_TILING_4;
2813	else
2814		caps |= INTEL_PLANE_CAP_TILING_Y;
2815
2816	if (tgl_plane_has_mc_ccs(display, plane_id))
2817		caps |= INTEL_PLANE_CAP_CCS_MC;
2818
2819	if (DISPLAY_VER(display) >= 14 && display->platform.dgfx)
2820		caps |= INTEL_PLANE_CAP_NEED64K_PHYS;
2821
2822	return caps;
2823}
2824
2825static void skl_disable_tiling(struct intel_plane *plane)
2826{
2827	struct intel_plane_state *state = to_intel_plane_state(plane->base.state);
2828	struct intel_display *display = to_intel_display(plane);
2829	const struct drm_framebuffer *fb = state->hw.fb;
2830	u32 plane_ctl;
2831
2832	plane_ctl = intel_de_read(display, PLANE_CTL(plane->pipe, plane->id));
2833
2834	if (intel_fb_uses_dpt(fb)) {
2835		/* if DPT is enabled, keep tiling, but disable compression */
2836		plane_ctl &= ~PLANE_CTL_RENDER_DECOMPRESSION_ENABLE;
2837	} else {
2838		/* if DPT is not supported, disable tiling, and update stride */
2839		u32 stride = state->view.color_plane[0].scanout_stride / 64;
2840
2841		plane_ctl &= ~PLANE_CTL_TILED_MASK;
2842		intel_de_write_fw(display, PLANE_STRIDE(plane->pipe, plane->id),
2843				  PLANE_STRIDE_(stride));
2844	}
2845	intel_de_write_fw(display, PLANE_CTL(plane->pipe, plane->id), plane_ctl);
2846
2847	intel_de_write_fw(display, PLANE_SURF(plane->pipe, plane->id),
2848			  state->surf);
2849}
2850
2851struct intel_plane *
2852skl_universal_plane_create(struct intel_display *display,
2853			   enum pipe pipe, enum plane_id plane_id)
2854{
2855	const struct drm_plane_funcs *plane_funcs;
2856	struct intel_plane *plane;
2857	enum drm_plane_type plane_type;
2858	unsigned int supported_rotations;
2859	unsigned int supported_csc;
2860	const u64 *modifiers;
2861	const u32 *formats;
2862	int num_formats;
2863	int ret;
2864	u8 caps;
2865
2866	plane = intel_plane_alloc();
2867	if (IS_ERR(plane))
2868		return plane;
2869
2870	plane->pipe = pipe;
2871	plane->id = plane_id;
2872	plane->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, plane_id);
2873
2874	intel_fbc_add_plane(skl_plane_fbc(display, pipe, plane_id), plane);
2875
2876	if (DISPLAY_VER(display) >= 30) {
2877		plane->min_width = adl_plane_min_width;
2878		plane->max_width = xe3_plane_max_width;
2879		plane->max_height = icl_plane_max_height;
2880		plane->min_cdclk = icl_plane_min_cdclk;
2881	} else if (DISPLAY_VER(display) >= 11) {
2882		if (DISPLAY_VER(display) >= 14 || display->platform.alderlake_p)
2883			plane->min_width = adl_plane_min_width;
2884		else
2885			plane->min_width = icl_plane_min_width;
2886		if (icl_is_hdr_plane(display, plane_id))
2887			plane->max_width = icl_hdr_plane_max_width;
2888		else
2889			plane->max_width = icl_sdr_plane_max_width;
2890		plane->max_height = icl_plane_max_height;
2891		plane->min_cdclk = icl_plane_min_cdclk;
2892	} else if (DISPLAY_VER(display) >= 10) {
2893		plane->max_width = glk_plane_max_width;
2894		plane->max_height = skl_plane_max_height;
2895		plane->min_cdclk = glk_plane_min_cdclk;
2896	} else {
2897		plane->max_width = skl_plane_max_width;
2898		plane->max_height = skl_plane_max_height;
2899		plane->min_cdclk = skl_plane_min_cdclk;
2900	}
2901	plane->disable_tiling = skl_disable_tiling;
2902
2903	plane->surf_offset = skl_plane_surf_offset;
2904
2905	if (DISPLAY_VER(display) >= 13)
2906		plane->max_stride = adl_plane_max_stride;
2907	else
2908		plane->max_stride = skl_plane_max_stride;
2909
2910	if (DISPLAY_VER(display) >= 12)
2911		plane->min_alignment = tgl_plane_min_alignment;
2912	else
2913		plane->min_alignment = skl_plane_min_alignment;
2914
2915	if (intel_scanout_needs_vtd_wa(display))
2916		plane->vtd_guard = DISPLAY_VER(display) >= 10 ? 168 : 136;
2917
2918	if (DISPLAY_VER(display) >= 11) {
2919		plane->update_noarm = icl_plane_update_noarm;
2920		plane->update_arm = icl_plane_update_arm;
2921		plane->disable_arm = icl_plane_disable_arm;
2922	} else {
2923		plane->update_noarm = skl_plane_update_noarm;
2924		plane->update_arm = skl_plane_update_arm;
2925		plane->disable_arm = skl_plane_disable_arm;
2926	}
2927	plane->capture_error = skl_plane_capture_error;
2928	plane->get_hw_state = skl_plane_get_hw_state;
2929	plane->check_plane = skl_plane_check;
2930
2931	if (HAS_ASYNC_FLIPS(display) && plane_id == PLANE_1) {
2932		plane->need_async_flip_toggle_wa = IS_DISPLAY_VER(display, 9, 10);
2933		plane->async_flip = skl_plane_async_flip;
2934		plane->enable_flip_done = skl_plane_enable_flip_done;
2935		plane->disable_flip_done = skl_plane_disable_flip_done;
2936
2937		if (DISPLAY_VER(display) >= 12)
2938			plane->can_async_flip = tgl_plane_can_async_flip;
2939		else if (DISPLAY_VER(display) == 11)
2940			plane->can_async_flip = icl_plane_can_async_flip;
2941		else
2942			plane->can_async_flip = skl_plane_can_async_flip;
2943	}
2944
2945	if (DISPLAY_VER(display) >= 11)
2946		formats = icl_get_plane_formats(display, pipe,
2947						plane_id, &num_formats);
2948	else if (DISPLAY_VER(display) >= 10)
2949		formats = glk_get_plane_formats(display, pipe,
2950						plane_id, &num_formats);
2951	else
2952		formats = skl_get_plane_formats(display, pipe,
2953						plane_id, &num_formats);
2954
2955	if (DISPLAY_VER(display) >= 12)
2956		plane_funcs = &tgl_plane_funcs;
2957	else if (DISPLAY_VER(display) == 11)
2958		plane_funcs = &icl_plane_funcs;
2959	else
2960		plane_funcs = &skl_plane_funcs;
2961
2962	if (plane_id == PLANE_1)
2963		plane_type = DRM_PLANE_TYPE_PRIMARY;
2964	else
2965		plane_type = DRM_PLANE_TYPE_OVERLAY;
2966
2967	if (DISPLAY_VER(display) >= 12)
2968		caps = tgl_plane_caps(display, pipe, plane_id);
2969	else if (DISPLAY_VER(display) == 11)
2970		caps = icl_plane_caps(display, pipe, plane_id);
2971	else if (DISPLAY_VER(display) == 10)
2972		caps = glk_plane_caps(display, pipe, plane_id);
2973	else
2974		caps = skl_plane_caps(display, pipe, plane_id);
2975
2976	/* FIXME: xe has problems with AUX */
2977	if (!IS_ENABLED(I915) && HAS_AUX_CCS(display))
2978		caps &= ~(INTEL_PLANE_CAP_CCS_RC |
2979			  INTEL_PLANE_CAP_CCS_RC_CC |
2980			  INTEL_PLANE_CAP_CCS_MC);
2981
2982	modifiers = intel_fb_plane_get_modifiers(display, caps);
2983
2984	ret = drm_universal_plane_init(display->drm, &plane->base,
2985				       0, plane_funcs,
2986				       formats, num_formats, modifiers,
2987				       plane_type,
2988				       "plane %d%c", plane_id + 1,
2989				       pipe_name(pipe));
2990
2991	kfree(modifiers);
2992
2993	if (ret)
2994		goto fail;
2995
2996	if (DISPLAY_VER(display) >= 13)
2997		supported_rotations = DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180;
2998	else
2999		supported_rotations =
3000			DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 |
3001			DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270;
3002
3003	if (DISPLAY_VER(display) >= 11)
3004		supported_rotations |= DRM_MODE_REFLECT_X;
3005
3006	drm_plane_create_rotation_property(&plane->base,
3007					   DRM_MODE_ROTATE_0,
3008					   supported_rotations);
3009
3010	supported_csc = BIT(DRM_COLOR_YCBCR_BT601) | BIT(DRM_COLOR_YCBCR_BT709);
3011
3012	if (DISPLAY_VER(display) >= 10)
3013		supported_csc |= BIT(DRM_COLOR_YCBCR_BT2020);
3014
3015	drm_plane_create_color_properties(&plane->base,
3016					  supported_csc,
3017					  BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
3018					  BIT(DRM_COLOR_YCBCR_FULL_RANGE),
3019					  DRM_COLOR_YCBCR_BT709,
3020					  DRM_COLOR_YCBCR_LIMITED_RANGE);
3021
3022	if (DISPLAY_VER(display) >= 12)
3023		intel_color_pipeline_plane_init(&plane->base, pipe);
3024
3025	drm_plane_create_alpha_property(&plane->base);
3026	drm_plane_create_blend_mode_property(&plane->base,
3027					     BIT(DRM_MODE_BLEND_PIXEL_NONE) |
3028					     BIT(DRM_MODE_BLEND_PREMULTI) |
3029					     BIT(DRM_MODE_BLEND_COVERAGE));
3030
3031	drm_plane_create_zpos_immutable_property(&plane->base, plane_id);
3032
3033	if (DISPLAY_VER(display) >= 12)
3034		drm_plane_enable_fb_damage_clips(&plane->base);
3035
3036	if (DISPLAY_VER(display) >= 11)
3037		drm_plane_create_scaling_filter_property(&plane->base,
3038						BIT(DRM_SCALING_FILTER_DEFAULT) |
3039						BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR));
3040
3041	intel_plane_helper_add(plane);
3042
3043	return plane;
3044
3045fail:
3046	intel_plane_free(plane);
3047
3048	return ERR_PTR(ret);
3049}
3050
3051void
3052skl_get_initial_plane_config(struct intel_crtc *crtc,
3053			     struct intel_initial_plane_config *plane_config)
3054{
3055	struct intel_display *display = to_intel_display(crtc);
3056	struct intel_crtc_state *crtc_state = to_intel_crtc_state(crtc->base.state);
3057	struct intel_plane *plane = to_intel_plane(crtc->base.primary);
3058	enum plane_id plane_id = plane->id;
3059	enum pipe pipe;
3060	u32 val, base, offset, stride_mult, tiling, alpha;
3061	int fourcc, pixel_format;
3062	unsigned int aligned_height;
3063	struct drm_framebuffer *fb;
3064	struct intel_framebuffer *intel_fb;
3065	static_assert(PLANE_CTL_TILED_YF == PLANE_CTL_TILED_4);
3066
3067	if (!plane->get_hw_state(plane, &pipe))
3068		return;
3069
3070	drm_WARN_ON(display->drm, pipe != crtc->pipe);
3071
3072	if (crtc_state->joiner_pipes) {
3073		drm_dbg_kms(display->drm,
3074			    "[CRTC:%d:%s] Unsupported joiner configuration for initial FB\n",
3075			    crtc->base.base.id, crtc->base.name);
3076		return;
3077	}
3078
3079	intel_fb = intel_framebuffer_alloc();
3080	if (!intel_fb) {
3081		drm_dbg_kms(display->drm, "failed to alloc fb\n");
3082		return;
3083	}
3084
3085	fb = &intel_fb->base;
3086
3087	fb->dev = display->drm;
3088
3089	val = intel_de_read(display, PLANE_CTL(pipe, plane_id));
3090
3091	if (DISPLAY_VER(display) >= 11)
3092		pixel_format = val & PLANE_CTL_FORMAT_MASK_ICL;
3093	else
3094		pixel_format = val & PLANE_CTL_FORMAT_MASK_SKL;
3095
3096	if (DISPLAY_VER(display) >= 10) {
3097		u32 color_ctl;
3098
3099		color_ctl = intel_de_read(display, PLANE_COLOR_CTL(pipe, plane_id));
3100		alpha = REG_FIELD_GET(PLANE_COLOR_ALPHA_MASK, color_ctl);
3101	} else {
3102		alpha = REG_FIELD_GET(PLANE_CTL_ALPHA_MASK, val);
3103	}
3104
3105	fourcc = skl_format_to_fourcc(pixel_format,
3106				      val & PLANE_CTL_ORDER_RGBX, alpha);
3107
3108	tiling = val & PLANE_CTL_TILED_MASK;
3109	switch (tiling) {
3110	case PLANE_CTL_TILED_LINEAR:
3111		fb->modifier = DRM_FORMAT_MOD_LINEAR;
3112		break;
3113	case PLANE_CTL_TILED_X:
3114		fb->modifier = I915_FORMAT_MOD_X_TILED;
3115		break;
3116	case PLANE_CTL_TILED_Y:
3117		if (val & PLANE_CTL_RENDER_DECOMPRESSION_ENABLE)
3118			if (DISPLAY_VER(display) >= 14)
3119				fb->modifier = I915_FORMAT_MOD_4_TILED_MTL_RC_CCS;
3120			else if (DISPLAY_VER(display) >= 12)
3121				fb->modifier = I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS;
3122			else
3123				fb->modifier = I915_FORMAT_MOD_Y_TILED_CCS;
3124		else if (val & PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE)
3125			if (DISPLAY_VER(display) >= 14)
3126				fb->modifier = I915_FORMAT_MOD_4_TILED_MTL_MC_CCS;
3127			else
3128				fb->modifier = I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS;
3129		else
3130			fb->modifier = I915_FORMAT_MOD_Y_TILED;
3131		break;
3132	case PLANE_CTL_TILED_YF: /* aka PLANE_CTL_TILED_4 on XE_LPD+ */
3133		if (HAS_4TILE(display)) {
3134			u32 rc_mask = PLANE_CTL_RENDER_DECOMPRESSION_ENABLE |
3135				      PLANE_CTL_CLEAR_COLOR_DISABLE;
3136
3137			if ((val & rc_mask) == rc_mask)
3138				fb->modifier = I915_FORMAT_MOD_4_TILED_DG2_RC_CCS;
3139			else if (val & PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE)
3140				fb->modifier = I915_FORMAT_MOD_4_TILED_DG2_MC_CCS;
3141			else if (val & PLANE_CTL_RENDER_DECOMPRESSION_ENABLE)
3142				fb->modifier = I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC;
3143			else
3144				fb->modifier = I915_FORMAT_MOD_4_TILED;
3145		} else {
3146			if (val & PLANE_CTL_RENDER_DECOMPRESSION_ENABLE)
3147				fb->modifier = I915_FORMAT_MOD_Yf_TILED_CCS;
3148			else
3149				fb->modifier = I915_FORMAT_MOD_Yf_TILED;
3150		}
3151		break;
3152	default:
3153		MISSING_CASE(tiling);
3154		goto error;
3155	}
3156
3157	fb->format = drm_get_format_info(display->drm, fourcc, fb->modifier);
3158
3159	if (!display->params.enable_dpt &&
3160	    intel_fb_modifier_uses_dpt(display, fb->modifier)) {
3161		drm_dbg_kms(display->drm, "DPT disabled, skipping initial FB\n");
3162		goto error;
3163	}
3164
3165	/*
3166	 * DRM_MODE_ROTATE_ is counter clockwise to stay compatible with Xrandr
3167	 * while i915 HW rotation is clockwise, that's why this swapping.
3168	 */
3169	switch (val & PLANE_CTL_ROTATE_MASK) {
3170	case PLANE_CTL_ROTATE_0:
3171		plane_config->rotation = DRM_MODE_ROTATE_0;
3172		break;
3173	case PLANE_CTL_ROTATE_90:
3174		plane_config->rotation = DRM_MODE_ROTATE_270;
3175		break;
3176	case PLANE_CTL_ROTATE_180:
3177		plane_config->rotation = DRM_MODE_ROTATE_180;
3178		break;
3179	case PLANE_CTL_ROTATE_270:
3180		plane_config->rotation = DRM_MODE_ROTATE_90;
3181		break;
3182	}
3183
3184	if (DISPLAY_VER(display) >= 11 && val & PLANE_CTL_FLIP_HORIZONTAL)
3185		plane_config->rotation |= DRM_MODE_REFLECT_X;
3186
3187	/* 90/270 degree rotation would require extra work */
3188	if (drm_rotation_90_or_270(plane_config->rotation))
3189		goto error;
3190
3191	base = intel_de_read(display, PLANE_SURF(pipe, plane_id)) & PLANE_SURF_ADDR_MASK;
3192	plane_config->base = base;
3193
3194	offset = intel_de_read(display, PLANE_OFFSET(pipe, plane_id));
3195	drm_WARN_ON(display->drm, offset != 0);
3196
3197	val = intel_de_read(display, PLANE_SIZE(pipe, plane_id));
3198	fb->height = REG_FIELD_GET(PLANE_HEIGHT_MASK, val) + 1;
3199	fb->width = REG_FIELD_GET(PLANE_WIDTH_MASK, val) + 1;
3200
3201	val = intel_de_read(display, PLANE_STRIDE(pipe, plane_id));
3202	stride_mult = skl_plane_stride_mult(fb, 0, DRM_MODE_ROTATE_0);
3203
3204	fb->pitches[0] = REG_FIELD_GET(PLANE_STRIDE__MASK, val) * stride_mult;
3205
3206	aligned_height = intel_fb_align_height(fb, 0, fb->height);
3207
3208	plane_config->size = fb->pitches[0] * aligned_height;
3209
3210	drm_dbg_kms(display->drm,
3211		    "[CRTC:%d:%s][PLANE:%d:%s] with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n",
3212		    crtc->base.base.id, crtc->base.name,
3213		    plane->base.base.id, plane->base.name,
3214		    fb->width, fb->height, fb->format->cpp[0] * 8,
3215		    base, fb->pitches[0], plane_config->size);
3216
3217	plane_config->fb = intel_fb;
3218	return;
3219
3220error:
3221	kfree(intel_fb);
3222}
3223
3224bool skl_fixup_initial_plane_config(struct intel_crtc *crtc,
3225				    const struct intel_initial_plane_config *plane_config)
3226{
3227	struct intel_display *display = to_intel_display(crtc);
3228	struct intel_plane *plane = to_intel_plane(crtc->base.primary);
3229	const struct intel_plane_state *plane_state =
3230		to_intel_plane_state(plane->base.state);
3231	enum plane_id plane_id = plane->id;
3232	enum pipe pipe = crtc->pipe;
3233
3234	if (!plane_state->uapi.visible)
3235		return false;
3236
3237	/*
3238	 * We may have moved the surface to a different
3239	 * part of ggtt, make the plane aware of that.
3240	 */
3241	if (plane_config->base == plane_state->surf)
3242		return false;
3243
3244	intel_de_write(display, PLANE_SURF(pipe, plane_id), plane_state->surf);
3245
3246	return true;
3247}
~/ Read-only file preview.