File Index
Files and directories
Sign in
FILE

dpu_plane.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c C
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) 2014-2018 The Linux Foundation. All rights reserved.
   4 * Copyright (C) 2013 Red Hat
   5 * Author: Rob Clark <robdclark@gmail.com>
   6 */
   7
   8#define pr_fmt(fmt)	"[drm:%s:%d] " fmt, __func__, __LINE__
   9
  10#include <linux/debugfs.h>
  11#include <linux/dma-buf.h>
  12
  13#include <drm/drm_atomic.h>
  14#include <drm/drm_atomic_uapi.h>
  15#include <drm/drm_blend.h>
  16#include <drm/drm_damage_helper.h>
  17#include <drm/drm_framebuffer.h>
  18#include <drm/drm_gem_atomic_helper.h>
  19
  20#include <linux/soc/qcom/ubwc.h>
  21
  22#include "msm_drv.h"
  23#include "dpu_kms.h"
  24#include "dpu_hw_sspp.h"
  25#include "dpu_hw_util.h"
  26#include "dpu_trace.h"
  27#include "dpu_crtc.h"
  28#include "dpu_vbif.h"
  29#include "dpu_plane.h"
  30
  31#define DPU_DEBUG_PLANE(pl, fmt, ...) DRM_DEBUG_ATOMIC("plane%d " fmt,\
  32		(pl) ? (pl)->base.base.id : -1, ##__VA_ARGS__)
  33
  34#define DPU_ERROR_PLANE(pl, fmt, ...) DPU_ERROR("plane%d " fmt,\
  35		(pl) ? (pl)->base.base.id : -1, ##__VA_ARGS__)
  36
  37#define DECIMATED_DIMENSION(dim, deci) (((dim) + ((1 << (deci)) - 1)) >> (deci))
  38#define PHASE_STEP_SHIFT	21
  39#define PHASE_STEP_UNIT_SCALE   ((int) (1 << PHASE_STEP_SHIFT))
  40#define PHASE_RESIDUAL		15
  41
  42#define SHARP_STRENGTH_DEFAULT	32
  43#define SHARP_EDGE_THR_DEFAULT	112
  44#define SHARP_SMOOTH_THR_DEFAULT	8
  45#define SHARP_NOISE_THR_DEFAULT	2
  46
  47#define DPU_PLANE_COLOR_FILL_FLAG	BIT(31)
  48#define DPU_ZPOS_MAX 255
  49
  50/*
  51 * Default Preload Values
  52 */
  53#define DPU_QSEED3_DEFAULT_PRELOAD_H 0x4
  54#define DPU_QSEED3_DEFAULT_PRELOAD_V 0x3
  55#define DPU_QSEED4_DEFAULT_PRELOAD_V 0x2
  56#define DPU_QSEED4_DEFAULT_PRELOAD_H 0x4
  57
  58#define DEFAULT_REFRESH_RATE	60
  59
  60static const uint32_t qcom_compressed_supported_formats[] = {
  61	DRM_FORMAT_ABGR8888,
  62	DRM_FORMAT_ARGB8888,
  63	DRM_FORMAT_XBGR8888,
  64	DRM_FORMAT_XRGB8888,
  65	DRM_FORMAT_ARGB2101010,
  66	DRM_FORMAT_XRGB2101010,
  67	DRM_FORMAT_BGR565,
  68
  69	DRM_FORMAT_NV12,
  70	DRM_FORMAT_P010,
  71};
  72
  73/*
  74 * struct dpu_plane - local dpu plane structure
  75 * @vm: address space pointer
  76 * @csc_ptr: Points to dpu_csc_cfg structure to use for current
  77 * @catalog: Points to dpu catalog structure
  78 * @revalidate: force revalidation of all the plane properties
  79 */
  80struct dpu_plane {
  81	struct drm_plane base;
  82
  83	enum dpu_sspp pipe;
  84
  85	uint32_t color_fill;
  86	bool is_error;
  87	bool is_rt_pipe;
  88	const struct dpu_mdss_cfg *catalog;
  89};
  90
  91static const uint64_t supported_format_modifiers[] = {
  92	DRM_FORMAT_MOD_QCOM_COMPRESSED,
  93	DRM_FORMAT_MOD_LINEAR,
  94	DRM_FORMAT_MOD_INVALID
  95};
  96
  97#define to_dpu_plane(x) container_of(x, struct dpu_plane, base)
  98
  99static struct dpu_kms *_dpu_plane_get_kms(struct drm_plane *plane)
 100{
 101	struct msm_drm_private *priv = plane->dev->dev_private;
 102
 103	return to_dpu_kms(priv->kms);
 104}
 105
 106/**
 107 * _dpu_plane_calc_bw - calculate bandwidth required for a plane
 108 * @catalog: Points to dpu catalog structure
 109 * @fmt: Pointer to source buffer format
 110 * @mode: Pointer to drm display mode
 111 * @pipe_cfg: Pointer to pipe configuration
 112 * Result: Updates calculated bandwidth in the plane state.
 113 * BW Equation: src_w * src_h * bpp * fps * (v_total / v_dest)
 114 * Prefill BW Equation: line src bytes * line_time
 115 */
 116static u64 _dpu_plane_calc_bw(const struct dpu_mdss_cfg *catalog,
 117	const struct msm_format *fmt,
 118	const struct drm_display_mode *mode,
 119	struct dpu_sw_pipe_cfg *pipe_cfg)
 120{
 121	int src_width, src_height, dst_height, fps;
 122	u64 plane_pixel_rate, plane_bit_rate;
 123	u64 plane_prefill_bw;
 124	u64 plane_bw;
 125	u32 hw_latency_lines;
 126	u64 scale_factor;
 127	int vbp, vpw, vfp;
 128
 129	src_width = drm_rect_width(&pipe_cfg->src_rect);
 130	src_height = drm_rect_height(&pipe_cfg->src_rect);
 131	dst_height = drm_rect_height(&pipe_cfg->dst_rect);
 132	fps = drm_mode_vrefresh(mode);
 133	vbp = mode->vtotal - mode->vsync_end;
 134	vpw = mode->vsync_end - mode->vsync_start;
 135	vfp = mode->vsync_start - mode->vdisplay;
 136	hw_latency_lines =  catalog->perf->min_prefill_lines;
 137	scale_factor = src_height > dst_height ?
 138		mult_frac(src_height, 1, dst_height) : 1;
 139
 140	plane_pixel_rate = src_width * mode->vtotal * fps;
 141	plane_bit_rate = plane_pixel_rate * fmt->bpp;
 142
 143	plane_bw = plane_bit_rate * scale_factor;
 144
 145	plane_prefill_bw = plane_bw * hw_latency_lines;
 146
 147	if ((vbp+vpw) > hw_latency_lines)
 148		do_div(plane_prefill_bw, (vbp+vpw));
 149	else if ((vbp+vpw+vfp) < hw_latency_lines)
 150		do_div(plane_prefill_bw, (vbp+vpw+vfp));
 151	else
 152		do_div(plane_prefill_bw, hw_latency_lines);
 153
 154
 155	return max(plane_bw, plane_prefill_bw);
 156}
 157
 158/**
 159 * _dpu_plane_calc_clk - calculate clock required for a plane
 160 * @mode: Pointer to drm display mode
 161 * @pipe_cfg: Pointer to pipe configuration
 162 * Result: Updates calculated clock in the plane state.
 163 * Clock equation: dst_w * v_total * fps * (src_h / dst_h)
 164 */
 165static u64 _dpu_plane_calc_clk(const struct drm_display_mode *mode,
 166		struct dpu_sw_pipe_cfg *pipe_cfg)
 167{
 168	int dst_width, src_height, dst_height, fps;
 169	u64 plane_clk;
 170
 171	src_height = drm_rect_height(&pipe_cfg->src_rect);
 172	dst_width = drm_rect_width(&pipe_cfg->dst_rect);
 173	dst_height = drm_rect_height(&pipe_cfg->dst_rect);
 174	fps = drm_mode_vrefresh(mode);
 175
 176	plane_clk =
 177		dst_width * mode->vtotal * fps;
 178
 179	if (src_height > dst_height) {
 180		plane_clk *= src_height;
 181		do_div(plane_clk, dst_height);
 182	}
 183
 184	return plane_clk;
 185}
 186
 187/**
 188 * _dpu_plane_calc_fill_level - calculate fill level of the given source format
 189 * @plane:		Pointer to drm plane
 190 * @pipe:		Pointer to software pipe
 191 * @lut_usage:		LUT usecase
 192 * @fmt:		Pointer to source buffer format
 193 * @src_width:		width of source buffer
 194 * Return: fill level corresponding to the source buffer/format or 0 if error
 195 */
 196static int _dpu_plane_calc_fill_level(struct drm_plane *plane,
 197		struct dpu_sw_pipe *pipe,
 198		enum dpu_qos_lut_usage lut_usage,
 199		const struct msm_format *fmt, u32 src_width)
 200{
 201	struct dpu_plane *pdpu;
 202	u32 fixed_buff_size;
 203	u32 total_fl;
 204
 205	if (!fmt || !pipe || !src_width || !fmt->bpp) {
 206		DPU_ERROR("invalid arguments\n");
 207		return 0;
 208	}
 209
 210	if (lut_usage == DPU_QOS_LUT_USAGE_NRT)
 211		return 0;
 212
 213	pdpu = to_dpu_plane(plane);
 214	fixed_buff_size = pdpu->catalog->caps->pixel_ram_size;
 215
 216	/* FIXME: in multirect case account for the src_width of all the planes */
 217
 218	if (fmt->fetch_type == MDP_PLANE_PSEUDO_PLANAR) {
 219		if (fmt->chroma_sample == CHROMA_420) {
 220			/* NV12 */
 221			total_fl = (fixed_buff_size / 2) /
 222				((src_width + 32) * fmt->bpp);
 223		} else {
 224			/* non NV12 */
 225			total_fl = (fixed_buff_size / 2) * 2 /
 226				((src_width + 32) * fmt->bpp);
 227		}
 228	} else {
 229		if (pipe->multirect_mode == DPU_SSPP_MULTIRECT_PARALLEL) {
 230			total_fl = (fixed_buff_size / 2) * 2 /
 231				((src_width + 32) * fmt->bpp);
 232		} else {
 233			total_fl = (fixed_buff_size) * 2 /
 234				((src_width + 32) * fmt->bpp);
 235		}
 236	}
 237
 238	DPU_DEBUG_PLANE(pdpu, "pnum:%d fmt: %p4cc w:%u fl:%u\n",
 239			pipe->sspp->idx - SSPP_VIG0,
 240			&fmt->pixel_format,
 241			src_width, total_fl);
 242
 243	return total_fl;
 244}
 245
 246/**
 247 * _dpu_plane_set_qos_lut - set QoS LUT of the given plane
 248 * @plane:		Pointer to drm plane
 249 * @pipe:		Pointer to software pipe
 250 * @fmt:		Pointer to source buffer format
 251 * @pipe_cfg:		Pointer to pipe configuration
 252 */
 253static void _dpu_plane_set_qos_lut(struct drm_plane *plane,
 254		struct dpu_sw_pipe *pipe,
 255		const struct msm_format *fmt, struct dpu_sw_pipe_cfg *pipe_cfg)
 256{
 257	struct dpu_plane *pdpu = to_dpu_plane(plane);
 258	struct dpu_hw_qos_cfg cfg;
 259	u32 total_fl, lut_usage;
 260
 261	if (!pdpu->is_rt_pipe) {
 262		lut_usage = DPU_QOS_LUT_USAGE_NRT;
 263	} else {
 264		if (fmt && MSM_FORMAT_IS_LINEAR(fmt))
 265			lut_usage = DPU_QOS_LUT_USAGE_LINEAR;
 266		else
 267			lut_usage = DPU_QOS_LUT_USAGE_MACROTILE;
 268	}
 269
 270	total_fl = _dpu_plane_calc_fill_level(plane, pipe, lut_usage, fmt,
 271				drm_rect_width(&pipe_cfg->src_rect));
 272
 273	cfg.creq_lut = _dpu_hw_get_qos_lut(&pdpu->catalog->perf->qos_lut_tbl[lut_usage], total_fl);
 274	cfg.danger_lut = pdpu->catalog->perf->danger_lut_tbl[lut_usage];
 275	cfg.safe_lut = pdpu->catalog->perf->safe_lut_tbl[lut_usage];
 276
 277	if (pipe->sspp->idx != SSPP_CURSOR0 &&
 278	    pipe->sspp->idx != SSPP_CURSOR1 &&
 279	    pdpu->is_rt_pipe)
 280		cfg.danger_safe_en = true;
 281
 282	DPU_DEBUG_PLANE(pdpu, "pnum:%d ds:%d is_rt:%d\n",
 283		pdpu->pipe - SSPP_VIG0,
 284		cfg.danger_safe_en,
 285		pdpu->is_rt_pipe);
 286
 287	trace_dpu_perf_set_qos_luts(pipe->sspp->idx - SSPP_VIG0,
 288			(fmt) ? fmt->pixel_format : 0,
 289			pdpu->is_rt_pipe, total_fl, cfg.creq_lut, lut_usage);
 290
 291	DPU_DEBUG_PLANE(pdpu, "pnum:%d fmt: %p4cc rt:%d fl:%u lut:0x%llx\n",
 292			pdpu->pipe - SSPP_VIG0,
 293			fmt ? &fmt->pixel_format : NULL,
 294			pdpu->is_rt_pipe, total_fl, cfg.creq_lut);
 295
 296	trace_dpu_perf_set_danger_luts(pdpu->pipe - SSPP_VIG0,
 297			(fmt) ? fmt->pixel_format : 0,
 298			(fmt) ? fmt->fetch_mode : 0,
 299			cfg.danger_lut,
 300			cfg.safe_lut);
 301
 302	DPU_DEBUG_PLANE(pdpu, "pnum:%d fmt: %p4cc mode:%d luts[0x%x, 0x%x]\n",
 303			pdpu->pipe - SSPP_VIG0,
 304			fmt ? &fmt->pixel_format : NULL,
 305			fmt ? fmt->fetch_mode : -1,
 306			cfg.danger_lut,
 307			cfg.safe_lut);
 308
 309	pipe->sspp->ops.setup_qos_lut(pipe->sspp, &cfg);
 310}
 311
 312/**
 313 * _dpu_plane_set_qos_ctrl - set QoS control of the given plane
 314 * @plane:		Pointer to drm plane
 315 * @pipe:		Pointer to software pipe
 316 * @enable:		true to enable QoS control
 317 */
 318static void _dpu_plane_set_qos_ctrl(struct drm_plane *plane,
 319	struct dpu_sw_pipe *pipe,
 320	bool enable)
 321{
 322	struct dpu_plane *pdpu = to_dpu_plane(plane);
 323
 324	if (!pdpu->is_rt_pipe)
 325		enable = false;
 326
 327	DPU_DEBUG_PLANE(pdpu, "pnum:%d ds:%d is_rt:%d\n",
 328		pdpu->pipe - SSPP_VIG0,
 329		enable,
 330		pdpu->is_rt_pipe);
 331
 332	pipe->sspp->ops.setup_qos_ctrl(pipe->sspp,
 333				       enable);
 334}
 335
 336static bool _dpu_plane_sspp_clk_force_ctrl(struct dpu_hw_sspp *sspp,
 337					   struct dpu_hw_mdp *mdp,
 338					   bool enable, bool *forced_on)
 339{
 340	if (sspp->ops.setup_clk_force_ctrl) {
 341		*forced_on = sspp->ops.setup_clk_force_ctrl(sspp, enable);
 342		return true;
 343	}
 344
 345	if (mdp->ops.setup_clk_force_ctrl) {
 346		*forced_on = mdp->ops.setup_clk_force_ctrl(mdp, sspp->cap->clk_ctrl, enable);
 347		return true;
 348	}
 349
 350	return false;
 351}
 352
 353/**
 354 * _dpu_plane_set_ot_limit - set OT limit for the given plane
 355 * @plane:		Pointer to drm plane
 356 * @pipe:		Pointer to software pipe
 357 * @pipe_cfg:		Pointer to pipe configuration
 358 * @frame_rate:		CRTC's frame rate
 359 */
 360static void _dpu_plane_set_ot_limit(struct drm_plane *plane,
 361		struct dpu_sw_pipe *pipe,
 362		struct dpu_sw_pipe_cfg *pipe_cfg,
 363		int frame_rate)
 364{
 365	struct dpu_plane *pdpu = to_dpu_plane(plane);
 366	struct dpu_vbif_set_ot_params ot_params;
 367	struct dpu_kms *dpu_kms = _dpu_plane_get_kms(plane);
 368	bool forced_on = false;
 369
 370	memset(&ot_params, 0, sizeof(ot_params));
 371	ot_params.xin_id = pipe->sspp->cap->xin_id;
 372	ot_params.num = pipe->sspp->idx - SSPP_NONE;
 373	ot_params.width = drm_rect_width(&pipe_cfg->src_rect);
 374	ot_params.height = drm_rect_height(&pipe_cfg->src_rect);
 375	ot_params.is_wfd = !pdpu->is_rt_pipe;
 376	ot_params.frame_rate = frame_rate;
 377	ot_params.vbif_idx = VBIF_RT;
 378	ot_params.rd = true;
 379
 380	if (!_dpu_plane_sspp_clk_force_ctrl(pipe->sspp, dpu_kms->hw_mdp,
 381					    true, &forced_on))
 382		return;
 383
 384	dpu_vbif_set_ot_limit(dpu_kms, &ot_params);
 385
 386	if (forced_on)
 387		_dpu_plane_sspp_clk_force_ctrl(pipe->sspp, dpu_kms->hw_mdp,
 388					       false, &forced_on);
 389}
 390
 391/**
 392 * _dpu_plane_set_qos_remap - set vbif QoS for the given plane
 393 * @plane:		Pointer to drm plane
 394 * @pipe:		Pointer to software pipe
 395 */
 396static void _dpu_plane_set_qos_remap(struct drm_plane *plane,
 397		struct dpu_sw_pipe *pipe)
 398{
 399	struct dpu_plane *pdpu = to_dpu_plane(plane);
 400	struct dpu_vbif_set_qos_params qos_params;
 401	struct dpu_kms *dpu_kms = _dpu_plane_get_kms(plane);
 402	bool forced_on = false;
 403
 404	memset(&qos_params, 0, sizeof(qos_params));
 405	qos_params.vbif_idx = VBIF_RT;
 406	qos_params.xin_id = pipe->sspp->cap->xin_id;
 407	qos_params.num = pipe->sspp->idx - SSPP_VIG0;
 408	qos_params.is_rt = pdpu->is_rt_pipe;
 409
 410	DPU_DEBUG_PLANE(pdpu, "pipe:%d vbif:%d xin:%d rt:%d\n",
 411			qos_params.num,
 412			qos_params.vbif_idx,
 413			qos_params.xin_id, qos_params.is_rt);
 414
 415	if (!_dpu_plane_sspp_clk_force_ctrl(pipe->sspp, dpu_kms->hw_mdp,
 416					    true, &forced_on))
 417		return;
 418
 419	dpu_vbif_set_qos_remap(dpu_kms, &qos_params);
 420
 421	if (forced_on)
 422		_dpu_plane_sspp_clk_force_ctrl(pipe->sspp, dpu_kms->hw_mdp,
 423					       false, &forced_on);
 424}
 425
 426static void _dpu_plane_setup_scaler3(struct dpu_hw_sspp *pipe_hw,
 427		uint32_t src_w, uint32_t src_h, uint32_t dst_w, uint32_t dst_h,
 428		struct dpu_hw_scaler3_cfg *scale_cfg,
 429		const struct msm_format *fmt,
 430		uint32_t chroma_subsmpl_h, uint32_t chroma_subsmpl_v,
 431		unsigned int rotation)
 432{
 433	uint32_t i;
 434	bool inline_rotation = rotation & DRM_MODE_ROTATE_90;
 435
 436	/*
 437	 * For inline rotation cases, scaler config is post-rotation,
 438	 * so swap the dimensions here. However, pixel extension will
 439	 * need pre-rotation settings.
 440	 */
 441	if (inline_rotation)
 442		swap(src_w, src_h);
 443
 444	scale_cfg->phase_step_x[DPU_SSPP_COMP_0] =
 445		mult_frac((1 << PHASE_STEP_SHIFT), src_w, dst_w);
 446	scale_cfg->phase_step_y[DPU_SSPP_COMP_0] =
 447		mult_frac((1 << PHASE_STEP_SHIFT), src_h, dst_h);
 448
 449
 450	scale_cfg->phase_step_y[DPU_SSPP_COMP_1_2] =
 451		scale_cfg->phase_step_y[DPU_SSPP_COMP_0] / chroma_subsmpl_v;
 452	scale_cfg->phase_step_x[DPU_SSPP_COMP_1_2] =
 453		scale_cfg->phase_step_x[DPU_SSPP_COMP_0] / chroma_subsmpl_h;
 454
 455	scale_cfg->phase_step_x[DPU_SSPP_COMP_2] =
 456		scale_cfg->phase_step_x[DPU_SSPP_COMP_1_2];
 457	scale_cfg->phase_step_y[DPU_SSPP_COMP_2] =
 458		scale_cfg->phase_step_y[DPU_SSPP_COMP_1_2];
 459
 460	scale_cfg->phase_step_x[DPU_SSPP_COMP_3] =
 461		scale_cfg->phase_step_x[DPU_SSPP_COMP_0];
 462	scale_cfg->phase_step_y[DPU_SSPP_COMP_3] =
 463		scale_cfg->phase_step_y[DPU_SSPP_COMP_0];
 464
 465	for (i = 0; i < DPU_MAX_PLANES; i++) {
 466		scale_cfg->src_width[i] = src_w;
 467		scale_cfg->src_height[i] = src_h;
 468		if (i == DPU_SSPP_COMP_1_2 || i == DPU_SSPP_COMP_2) {
 469			scale_cfg->src_width[i] /= chroma_subsmpl_h;
 470			scale_cfg->src_height[i] /= chroma_subsmpl_v;
 471		}
 472
 473		if (pipe_hw->cap->sblk->scaler_blk.version >= 0x3000) {
 474			scale_cfg->preload_x[i] = DPU_QSEED4_DEFAULT_PRELOAD_H;
 475			scale_cfg->preload_y[i] = DPU_QSEED4_DEFAULT_PRELOAD_V;
 476		} else {
 477			scale_cfg->preload_x[i] = DPU_QSEED3_DEFAULT_PRELOAD_H;
 478			scale_cfg->preload_y[i] = DPU_QSEED3_DEFAULT_PRELOAD_V;
 479		}
 480	}
 481	if (!(MSM_FORMAT_IS_YUV(fmt)) && (src_h == dst_h)
 482		&& (src_w == dst_w))
 483		return;
 484
 485	scale_cfg->dst_width = dst_w;
 486	scale_cfg->dst_height = dst_h;
 487	scale_cfg->y_rgb_filter_cfg = DPU_SCALE_BIL;
 488	scale_cfg->uv_filter_cfg = DPU_SCALE_BIL;
 489	scale_cfg->alpha_filter_cfg = DPU_SCALE_ALPHA_BIL;
 490	scale_cfg->lut_flag = 0;
 491	scale_cfg->blend_cfg = 1;
 492	scale_cfg->enable = 1;
 493}
 494
 495static void _dpu_plane_setup_pixel_ext(struct dpu_hw_scaler3_cfg *scale_cfg,
 496				struct dpu_hw_pixel_ext *pixel_ext,
 497				uint32_t src_w, uint32_t src_h,
 498				uint32_t chroma_subsmpl_h, uint32_t chroma_subsmpl_v)
 499{
 500	int i;
 501
 502	for (i = 0; i < DPU_MAX_PLANES; i++) {
 503		uint32_t w = src_w, h = src_h;
 504
 505		if (i == DPU_SSPP_COMP_1_2 || i == DPU_SSPP_COMP_2) {
 506			w /= chroma_subsmpl_h;
 507			h /= chroma_subsmpl_v;
 508		}
 509
 510		pixel_ext->num_ext_pxls_top[i] = h;
 511		pixel_ext->num_ext_pxls_left[i] = w;
 512	}
 513}
 514
 515static const struct dpu_csc_cfg *_dpu_plane_get_csc(struct dpu_sw_pipe *pipe,
 516						    const struct msm_format *fmt)
 517{
 518	const struct dpu_csc_cfg *csc_ptr;
 519
 520	if (!MSM_FORMAT_IS_YUV(fmt))
 521		return NULL;
 522
 523	if (BIT(DPU_SSPP_CSC_10BIT) & pipe->sspp->cap->features)
 524		csc_ptr = &dpu_csc10_YUV2RGB_601L;
 525	else
 526		csc_ptr = &dpu_csc_YUV2RGB_601L;
 527
 528	return csc_ptr;
 529}
 530
 531static void _dpu_plane_setup_scaler(struct dpu_sw_pipe *pipe,
 532		const struct msm_format *fmt, bool color_fill,
 533		struct dpu_sw_pipe_cfg *pipe_cfg)
 534{
 535	struct dpu_hw_sspp *pipe_hw = pipe->sspp;
 536	const struct drm_format_info *info = drm_format_info(fmt->pixel_format);
 537	struct dpu_hw_scaler3_cfg scaler3_cfg;
 538	struct dpu_hw_pixel_ext pixel_ext;
 539	u32 src_width = drm_rect_width(&pipe_cfg->src_rect);
 540	u32 src_height = drm_rect_height(&pipe_cfg->src_rect);
 541	u32 dst_width = drm_rect_width(&pipe_cfg->dst_rect);
 542	u32 dst_height = drm_rect_height(&pipe_cfg->dst_rect);
 543
 544	memset(&scaler3_cfg, 0, sizeof(scaler3_cfg));
 545	memset(&pixel_ext, 0, sizeof(pixel_ext));
 546
 547	/* don't chroma subsample if decimating */
 548	/* update scaler. calculate default config for QSEED3 */
 549	_dpu_plane_setup_scaler3(pipe_hw,
 550			src_width,
 551			src_height,
 552			dst_width,
 553			dst_height,
 554			&scaler3_cfg, fmt,
 555			info->hsub, info->vsub,
 556			pipe_cfg->rotation);
 557
 558	/* configure pixel extension based on scalar config */
 559	_dpu_plane_setup_pixel_ext(&scaler3_cfg, &pixel_ext,
 560			src_width, src_height, info->hsub, info->vsub);
 561
 562	if (pipe_hw->ops.setup_pe)
 563		pipe_hw->ops.setup_pe(pipe_hw,
 564				&pixel_ext);
 565
 566	/**
 567	 * when programmed in multirect mode, scalar block will be
 568	 * bypassed. Still we need to update alpha and bitwidth
 569	 * ONLY for RECT0
 570	 */
 571	if (pipe_hw->ops.setup_scaler &&
 572			pipe->multirect_index != DPU_SSPP_RECT_1)
 573		pipe_hw->ops.setup_scaler(pipe_hw,
 574				&scaler3_cfg,
 575				fmt);
 576}
 577
 578static void _dpu_plane_color_fill_pipe(struct dpu_plane_state *pstate,
 579				       struct dpu_sw_pipe *pipe,
 580				       struct drm_rect *dst_rect,
 581				       u32 fill_color,
 582				       const struct msm_format *fmt)
 583{
 584	struct dpu_sw_pipe_cfg pipe_cfg;
 585
 586	/* update sspp */
 587	if (!pipe->sspp->ops.setup_solidfill)
 588		return;
 589
 590	pipe->sspp->ops.setup_solidfill(pipe, fill_color);
 591
 592	/* override scaler/decimation if solid fill */
 593	pipe_cfg.dst_rect = *dst_rect;
 594
 595	pipe_cfg.src_rect.x1 = 0;
 596	pipe_cfg.src_rect.y1 = 0;
 597	pipe_cfg.src_rect.x2 =
 598		drm_rect_width(&pipe_cfg.dst_rect);
 599	pipe_cfg.src_rect.y2 =
 600		drm_rect_height(&pipe_cfg.dst_rect);
 601
 602	if (pipe->sspp->ops.setup_format)
 603		pipe->sspp->ops.setup_format(pipe, fmt, DPU_SSPP_SOLID_FILL);
 604
 605	if (pipe->sspp->ops.setup_rects)
 606		pipe->sspp->ops.setup_rects(pipe, &pipe_cfg);
 607
 608	_dpu_plane_setup_scaler(pipe, fmt, true, &pipe_cfg);
 609}
 610
 611/**
 612 * _dpu_plane_color_fill - enables color fill on plane
 613 * @pdpu:   Pointer to DPU plane object
 614 * @color:  RGB fill color value, [23..16] Blue, [15..8] Green, [7..0] Red
 615 * @alpha:  8-bit fill alpha value, 255 selects 100% alpha
 616 */
 617static void _dpu_plane_color_fill(struct dpu_plane *pdpu,
 618		uint32_t color, uint32_t alpha)
 619{
 620	const struct msm_format *fmt;
 621	const struct drm_plane *plane = &pdpu->base;
 622	struct msm_drm_private *priv = plane->dev->dev_private;
 623	struct dpu_plane_state *pstate = to_dpu_plane_state(plane->state);
 624	u32 fill_color = (color & 0xFFFFFF) | ((alpha & 0xFF) << 24);
 625	int i;
 626
 627	DPU_DEBUG_PLANE(pdpu, "\n");
 628
 629	/*
 630	 * select fill format to match user property expectation,
 631	 * h/w only supports RGB variants
 632	 */
 633	fmt = mdp_get_format(priv->kms, DRM_FORMAT_ABGR8888, 0);
 634	/* should not happen ever */
 635	if (!fmt)
 636		return;
 637
 638	/* update sspp */
 639	for (i = 0; i < PIPES_PER_PLANE; i++) {
 640		if (!pstate->pipe[i].sspp)
 641			continue;
 642		_dpu_plane_color_fill_pipe(pstate, &pstate->pipe[i],
 643					   &pstate->pipe_cfg[i].dst_rect,
 644					   fill_color, fmt);
 645	}
 646}
 647
 648static int dpu_plane_prepare_fb(struct drm_plane *plane,
 649		struct drm_plane_state *new_state)
 650{
 651	struct drm_framebuffer *fb = new_state->fb;
 652	struct dpu_plane *pdpu = to_dpu_plane(plane);
 653	struct dpu_plane_state *pstate = to_dpu_plane_state(new_state);
 654	int ret;
 655
 656	if (!new_state->fb)
 657		return 0;
 658
 659	DPU_DEBUG_PLANE(pdpu, "FB[%u]\n", fb->base.id);
 660
 661	/*
 662	 * TODO: Need to sort out the msm_framebuffer_prepare() call below so
 663	 *       we can use msm_atomic_prepare_fb() instead of doing the
 664	 *       implicit fence and fb prepare by hand here.
 665	 */
 666	drm_gem_plane_helper_prepare_fb(plane, new_state);
 667
 668	ret = msm_framebuffer_prepare(new_state->fb, pstate->needs_dirtyfb);
 669	if (ret) {
 670		DPU_ERROR("failed to prepare framebuffer\n");
 671		return ret;
 672	}
 673
 674	return 0;
 675}
 676
 677static void dpu_plane_cleanup_fb(struct drm_plane *plane,
 678		struct drm_plane_state *old_state)
 679{
 680	struct dpu_plane *pdpu = to_dpu_plane(plane);
 681	struct dpu_plane_state *old_pstate;
 682
 683	if (!old_state || !old_state->fb)
 684		return;
 685
 686	old_pstate = to_dpu_plane_state(old_state);
 687
 688	DPU_DEBUG_PLANE(pdpu, "FB[%u]\n", old_state->fb->base.id);
 689
 690	msm_framebuffer_cleanup(old_state->fb, old_pstate->needs_dirtyfb);
 691}
 692
 693static int dpu_plane_check_inline_rotation(struct dpu_plane *pdpu,
 694					   struct dpu_sw_pipe *pipe,
 695					   struct drm_rect src,
 696					   const struct msm_format *fmt)
 697{
 698	const struct dpu_sspp_sub_blks *sblk = pipe->sspp->cap->sblk;
 699	size_t num_formats;
 700	const u32 *supported_formats;
 701
 702	if (!test_bit(DPU_SSPP_INLINE_ROTATION, &pipe->sspp->cap->features))
 703		return -EINVAL;
 704
 705	if (!sblk->rotation_cfg) {
 706		DPU_ERROR("invalid rotation cfg\n");
 707		return -EINVAL;
 708	}
 709
 710	if (drm_rect_width(&src) > sblk->rotation_cfg->rot_maxheight) {
 711		DPU_DEBUG_PLANE(pdpu, "invalid height for inline rot:%d max:%d\n",
 712				src.y2, sblk->rotation_cfg->rot_maxheight);
 713		return -EINVAL;
 714	}
 715
 716	supported_formats = sblk->rotation_cfg->rot_format_list;
 717	num_formats = sblk->rotation_cfg->rot_num_formats;
 718
 719	if (!MSM_FORMAT_IS_UBWC(fmt) ||
 720		!dpu_find_format(fmt->pixel_format, supported_formats, num_formats))
 721		return -EINVAL;
 722
 723	return 0;
 724}
 725
 726static int dpu_plane_atomic_check_pipe(struct dpu_plane *pdpu,
 727		struct dpu_sw_pipe *pipe,
 728		struct dpu_sw_pipe_cfg *pipe_cfg,
 729		const struct drm_display_mode *mode,
 730		struct drm_plane_state *new_plane_state)
 731{
 732	uint32_t min_src_size;
 733	struct dpu_kms *kms = _dpu_plane_get_kms(&pdpu->base);
 734	int ret;
 735	const struct msm_format *fmt;
 736	uint32_t supported_rotations;
 737	const struct dpu_sspp_cfg *pipe_hw_caps;
 738	const struct dpu_sspp_sub_blks *sblk;
 739
 740	pipe_hw_caps = pipe->sspp->cap;
 741	sblk = pipe->sspp->cap->sblk;
 742
 743	/*
 744	 * We already have verified scaling against platform limitations.
 745	 * Now check if the SSPP supports scaling at all.
 746	 */
 747	if (!(sblk->scaler_blk.len && pipe->sspp->ops.setup_scaler) &&
 748	    ((drm_rect_width(&new_plane_state->src) >> 16 !=
 749	      drm_rect_width(&new_plane_state->dst)) ||
 750	     (drm_rect_height(&new_plane_state->src) >> 16 !=
 751	      drm_rect_height(&new_plane_state->dst))))
 752		return -ERANGE;
 753
 754	fmt = msm_framebuffer_format(new_plane_state->fb);
 755
 756	supported_rotations = DRM_MODE_REFLECT_MASK | DRM_MODE_ROTATE_0;
 757
 758	if (pipe_hw_caps->features & BIT(DPU_SSPP_INLINE_ROTATION))
 759		supported_rotations |= DRM_MODE_ROTATE_90;
 760
 761	pipe_cfg->rotation = drm_rotation_simplify(new_plane_state->rotation,
 762						   supported_rotations);
 763
 764	min_src_size = MSM_FORMAT_IS_YUV(fmt) ? 2 : 1;
 765
 766	if (MSM_FORMAT_IS_YUV(fmt) &&
 767	    !pipe->sspp->cap->sblk->csc_blk.len) {
 768		DPU_DEBUG_PLANE(pdpu,
 769				"plane doesn't have csc for yuv\n");
 770		return -EINVAL;
 771	}
 772
 773	/* check src bounds */
 774	if (drm_rect_width(&pipe_cfg->src_rect) < min_src_size ||
 775	    drm_rect_height(&pipe_cfg->src_rect) < min_src_size) {
 776		DPU_DEBUG_PLANE(pdpu, "invalid source " DRM_RECT_FMT "\n",
 777				DRM_RECT_ARG(&pipe_cfg->src_rect));
 778		return -E2BIG;
 779	}
 780
 781	/* valid yuv image */
 782	if (MSM_FORMAT_IS_YUV(fmt) &&
 783	    (pipe_cfg->src_rect.x1 & 0x1 ||
 784	     pipe_cfg->src_rect.y1 & 0x1 ||
 785	     drm_rect_width(&pipe_cfg->src_rect) & 0x1 ||
 786	     drm_rect_height(&pipe_cfg->src_rect) & 0x1)) {
 787		DPU_DEBUG_PLANE(pdpu, "invalid yuv source " DRM_RECT_FMT "\n",
 788				DRM_RECT_ARG(&pipe_cfg->src_rect));
 789		return -EINVAL;
 790	}
 791
 792	/* min dst support */
 793	if (drm_rect_width(&pipe_cfg->dst_rect) < 0x1 ||
 794	    drm_rect_height(&pipe_cfg->dst_rect) < 0x1) {
 795		DPU_DEBUG_PLANE(pdpu, "invalid dest rect " DRM_RECT_FMT "\n",
 796				DRM_RECT_ARG(&pipe_cfg->dst_rect));
 797		return -EINVAL;
 798	}
 799
 800	if (pipe_cfg->rotation & DRM_MODE_ROTATE_90) {
 801		ret = dpu_plane_check_inline_rotation(pdpu, pipe, pipe_cfg->src_rect, fmt);
 802		if (ret)
 803			return ret;
 804	}
 805
 806	/* max clk check */
 807	if (_dpu_plane_calc_clk(mode, pipe_cfg) > kms->perf.max_core_clk_rate) {
 808		DPU_DEBUG_PLANE(pdpu, "plane exceeds max mdp core clk limits\n");
 809		return -E2BIG;
 810	}
 811
 812	return 0;
 813}
 814
 815#define MAX_UPSCALE_RATIO	20
 816#define MAX_DOWNSCALE_RATIO	4
 817
 818static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane,
 819					 struct drm_plane_state *new_plane_state,
 820					 const struct drm_crtc_state *crtc_state)
 821{
 822	int i, ret = 0, min_scale, max_scale;
 823	struct dpu_plane *pdpu = to_dpu_plane(plane);
 824	struct dpu_kms *kms = _dpu_plane_get_kms(&pdpu->base);
 825	u64 max_mdp_clk_rate = kms->perf.max_core_clk_rate;
 826	struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state);
 827	struct dpu_sw_pipe_cfg *pipe_cfg;
 828	struct dpu_sw_pipe_cfg *r_pipe_cfg;
 829	struct drm_rect fb_rect = { 0 };
 830	uint32_t max_linewidth;
 831
 832	min_scale = FRAC_16_16(1, MAX_UPSCALE_RATIO);
 833	max_scale = MAX_DOWNSCALE_RATIO << 16;
 834
 835	ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
 836						  min_scale,
 837						  max_scale,
 838						  true, true);
 839	if (ret) {
 840		DPU_DEBUG_PLANE(pdpu, "Check plane state failed (%d)\n", ret);
 841		return ret;
 842	}
 843	if (!new_plane_state->visible)
 844		return 0;
 845
 846	pstate->stage = DPU_STAGE_0 + pstate->base.normalized_zpos;
 847	if (pstate->stage >= pdpu->catalog->caps->max_mixer_blendstages) {
 848		DPU_ERROR("> %d plane stages assigned\n",
 849			  pdpu->catalog->caps->max_mixer_blendstages - DPU_STAGE_0);
 850		return -EINVAL;
 851	}
 852
 853	/* move the assignment here, to ease handling to another pairs later */
 854	pipe_cfg = &pstate->pipe_cfg[0];
 855	r_pipe_cfg = &pstate->pipe_cfg[1];
 856	/* state->src is 16.16, src_rect is not */
 857	drm_rect_fp_to_int(&pipe_cfg->src_rect, &new_plane_state->src);
 858
 859	pipe_cfg->dst_rect = new_plane_state->dst;
 860
 861	fb_rect.x2 = new_plane_state->fb->width;
 862	fb_rect.y2 = new_plane_state->fb->height;
 863
 864	/* Ensure fb size is supported */
 865	if (drm_rect_width(&fb_rect) > DPU_MAX_IMG_WIDTH ||
 866	    drm_rect_height(&fb_rect) > DPU_MAX_IMG_HEIGHT) {
 867		DPU_DEBUG_PLANE(pdpu, "invalid framebuffer " DRM_RECT_FMT "\n",
 868				DRM_RECT_ARG(&fb_rect));
 869		return -E2BIG;
 870	}
 871
 872	ret = dpu_format_populate_plane_sizes(new_plane_state->fb, &pstate->layout);
 873	if (ret) {
 874		DPU_ERROR_PLANE(pdpu, "failed to get format plane sizes, %d\n", ret);
 875		return ret;
 876	}
 877
 878	for (i = 0; i < pstate->layout.num_planes; i++)
 879		if (pstate->layout.plane_pitch[i] > DPU_SSPP_MAX_PITCH_SIZE)
 880			return -E2BIG;
 881
 882	max_linewidth = pdpu->catalog->caps->max_linewidth;
 883
 884	drm_rect_rotate(&pipe_cfg->src_rect,
 885			new_plane_state->fb->width, new_plane_state->fb->height,
 886			new_plane_state->rotation);
 887
 888	if ((drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) ||
 889	     _dpu_plane_calc_clk(&crtc_state->adjusted_mode, pipe_cfg) > max_mdp_clk_rate) {
 890		if (drm_rect_width(&pipe_cfg->src_rect) > 2 * max_linewidth) {
 891			DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u\n",
 892					DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth);
 893			return -E2BIG;
 894		}
 895
 896		*r_pipe_cfg = *pipe_cfg;
 897		pipe_cfg->src_rect.x2 = (pipe_cfg->src_rect.x1 + pipe_cfg->src_rect.x2) >> 1;
 898		pipe_cfg->dst_rect.x2 = (pipe_cfg->dst_rect.x1 + pipe_cfg->dst_rect.x2) >> 1;
 899		r_pipe_cfg->src_rect.x1 = pipe_cfg->src_rect.x2;
 900		r_pipe_cfg->dst_rect.x1 = pipe_cfg->dst_rect.x2;
 901	} else {
 902		memset(r_pipe_cfg, 0, sizeof(*r_pipe_cfg));
 903	}
 904
 905	drm_rect_rotate_inv(&pipe_cfg->src_rect,
 906			    new_plane_state->fb->width, new_plane_state->fb->height,
 907			    new_plane_state->rotation);
 908	if (drm_rect_width(&r_pipe_cfg->src_rect) != 0)
 909		drm_rect_rotate_inv(&r_pipe_cfg->src_rect,
 910				    new_plane_state->fb->width, new_plane_state->fb->height,
 911				    new_plane_state->rotation);
 912
 913	pstate->needs_qos_remap = drm_atomic_crtc_needs_modeset(crtc_state);
 914
 915	return 0;
 916}
 917
 918static int dpu_plane_is_multirect_capable(struct dpu_hw_sspp *sspp,
 919					  struct dpu_sw_pipe_cfg *pipe_cfg,
 920					  const struct msm_format *fmt)
 921{
 922	if (drm_rect_width(&pipe_cfg->src_rect) != drm_rect_width(&pipe_cfg->dst_rect) ||
 923	    drm_rect_height(&pipe_cfg->src_rect) != drm_rect_height(&pipe_cfg->dst_rect))
 924		return false;
 925
 926	if (pipe_cfg->rotation & DRM_MODE_ROTATE_90)
 927		return false;
 928
 929	if (MSM_FORMAT_IS_YUV(fmt))
 930		return false;
 931
 932	if (!sspp)
 933		return true;
 934
 935	if (!test_bit(DPU_SSPP_SMART_DMA_V1, &sspp->cap->features) &&
 936	    !test_bit(DPU_SSPP_SMART_DMA_V2, &sspp->cap->features))
 937		return false;
 938
 939	return true;
 940}
 941
 942static int dpu_plane_is_parallel_capable(struct dpu_sw_pipe_cfg *pipe_cfg,
 943					 const struct msm_format *fmt,
 944					 uint32_t max_linewidth)
 945{
 946	if (MSM_FORMAT_IS_UBWC(fmt) &&
 947	    drm_rect_width(&pipe_cfg->src_rect) > max_linewidth / 2)
 948		return false;
 949
 950	return true;
 951}
 952
 953static int dpu_plane_is_multirect_parallel_capable(struct dpu_hw_sspp *sspp,
 954						   struct dpu_sw_pipe_cfg *pipe_cfg,
 955						   const struct msm_format *fmt,
 956						   uint32_t max_linewidth)
 957{
 958	return dpu_plane_is_multirect_capable(sspp, pipe_cfg, fmt) &&
 959		dpu_plane_is_parallel_capable(pipe_cfg, fmt, max_linewidth);
 960}
 961
 962static bool dpu_plane_get_single_pipe_in_stage(struct dpu_plane_state *pstate,
 963					       struct dpu_sw_pipe **single_pipe,
 964					       struct dpu_sw_pipe_cfg **single_pipe_cfg,
 965					       int stage_index)
 966{
 967	int pipe_idx;
 968
 969	pipe_idx = stage_index * PIPES_PER_STAGE;
 970	if (drm_rect_width(&pstate->pipe_cfg[pipe_idx].src_rect) != 0 &&
 971	    drm_rect_width(&pstate->pipe_cfg[pipe_idx + 1].src_rect) == 0) {
 972		*single_pipe = &pstate->pipe[pipe_idx];
 973		*single_pipe_cfg = &pstate->pipe_cfg[pipe_idx];
 974		return true;
 975	}
 976
 977	return false;
 978}
 979
 980static int dpu_plane_atomic_check_sspp(struct drm_plane *plane,
 981				       struct drm_atomic_state *state,
 982				       const struct drm_crtc_state *crtc_state)
 983{
 984	struct drm_plane_state *new_plane_state =
 985		drm_atomic_get_new_plane_state(state, plane);
 986	struct dpu_plane *pdpu = to_dpu_plane(plane);
 987	struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state);
 988	struct dpu_sw_pipe *pipe = &pstate->pipe[0];
 989	struct dpu_sw_pipe *r_pipe = &pstate->pipe[1];
 990	struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg[0];
 991	struct dpu_sw_pipe_cfg *r_pipe_cfg = &pstate->pipe_cfg[1];
 992	int ret = 0;
 993
 994	ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg,
 995					  &crtc_state->adjusted_mode,
 996					  new_plane_state);
 997	if (ret)
 998		return ret;
 999
1000	if (drm_rect_width(&r_pipe_cfg->src_rect) != 0) {
1001		ret = dpu_plane_atomic_check_pipe(pdpu, r_pipe, r_pipe_cfg,
1002						  &crtc_state->adjusted_mode,
1003						  new_plane_state);
1004		if (ret)
1005			return ret;
1006	}
1007
1008	return 0;
1009}
1010
1011static bool dpu_plane_try_multirect_parallel(struct dpu_sw_pipe *pipe, struct dpu_sw_pipe_cfg *pipe_cfg,
1012					     struct dpu_sw_pipe *r_pipe, struct dpu_sw_pipe_cfg *r_pipe_cfg,
1013					     struct dpu_hw_sspp *sspp, const struct msm_format *fmt,
1014					     uint32_t max_linewidth)
1015{
1016	r_pipe->sspp = NULL;
1017
1018	pipe->multirect_index = DPU_SSPP_RECT_SOLO;
1019	pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE;
1020
1021	r_pipe->multirect_index = DPU_SSPP_RECT_SOLO;
1022	r_pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE;
1023
1024	if (drm_rect_width(&r_pipe_cfg->src_rect) != 0) {
1025		if (!dpu_plane_is_multirect_parallel_capable(pipe->sspp, pipe_cfg, fmt, max_linewidth) ||
1026		    !dpu_plane_is_multirect_parallel_capable(pipe->sspp, r_pipe_cfg, fmt, max_linewidth))
1027			return false;
1028
1029		r_pipe->sspp = pipe->sspp;
1030
1031		pipe->multirect_index = DPU_SSPP_RECT_0;
1032		pipe->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL;
1033
1034		r_pipe->multirect_index = DPU_SSPP_RECT_1;
1035		r_pipe->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL;
1036	}
1037
1038	return true;
1039}
1040
1041static int dpu_plane_try_multirect_shared(struct dpu_plane_state *pstate,
1042					  struct dpu_plane_state *prev_adjacent_pstate,
1043					  const struct msm_format *fmt,
1044					  uint32_t max_linewidth, int stage_index)
1045{
1046	struct dpu_sw_pipe *pipe, *prev_pipe;
1047	struct dpu_sw_pipe_cfg *pipe_cfg, *prev_pipe_cfg;
1048	const struct msm_format *prev_fmt = msm_framebuffer_format(prev_adjacent_pstate->base.fb);
1049	u16 max_tile_height = 1;
1050
1051	if (!dpu_plane_get_single_pipe_in_stage(pstate, &pipe,
1052						&pipe_cfg, stage_index))
1053		return false;
1054
1055	if (!dpu_plane_get_single_pipe_in_stage(prev_adjacent_pstate,
1056						&prev_pipe, &prev_pipe_cfg,
1057						stage_index) ||
1058	    prev_pipe->multirect_mode != DPU_SSPP_MULTIRECT_NONE)
1059		return false;
1060
1061	/* Do not validate SSPP of current plane when it is not ready */
1062	if (!dpu_plane_is_multirect_capable(pipe->sspp, pipe_cfg, fmt) ||
1063	    !dpu_plane_is_multirect_capable(prev_pipe->sspp, prev_pipe_cfg, prev_fmt))
1064		return false;
1065
1066	if (MSM_FORMAT_IS_UBWC(fmt))
1067		max_tile_height = max(max_tile_height, fmt->tile_height);
1068
1069	if (MSM_FORMAT_IS_UBWC(prev_fmt))
1070		max_tile_height = max(max_tile_height, prev_fmt->tile_height);
1071
1072	if (dpu_plane_is_parallel_capable(pipe_cfg, fmt, max_linewidth) &&
1073	    dpu_plane_is_parallel_capable(prev_pipe_cfg, prev_fmt, max_linewidth) &&
1074	    (pipe_cfg->dst_rect.x1 >= prev_pipe_cfg->dst_rect.x2 ||
1075	     prev_pipe_cfg->dst_rect.x1 >= pipe_cfg->dst_rect.x2)) {
1076		pipe->sspp = prev_pipe->sspp;
1077
1078		pipe->multirect_index = DPU_SSPP_RECT_1;
1079		pipe->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL;
1080
1081		prev_pipe->multirect_index = DPU_SSPP_RECT_0;
1082		prev_pipe->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL;
1083
1084		return true;
1085	}
1086
1087	if (pipe_cfg->dst_rect.y1 >= prev_pipe_cfg->dst_rect.y2 + 2 * max_tile_height ||
1088	    prev_pipe_cfg->dst_rect.y1 >= pipe_cfg->dst_rect.y2 + 2 * max_tile_height) {
1089		pipe->sspp = prev_pipe->sspp;
1090
1091		pipe->multirect_index = DPU_SSPP_RECT_1;
1092		pipe->multirect_mode = DPU_SSPP_MULTIRECT_TIME_MX;
1093
1094		prev_pipe->multirect_index = DPU_SSPP_RECT_0;
1095		prev_pipe->multirect_mode = DPU_SSPP_MULTIRECT_TIME_MX;
1096
1097		return true;
1098	}
1099
1100	return false;
1101}
1102
1103static int dpu_plane_atomic_check(struct drm_plane *plane,
1104				  struct drm_atomic_state *state)
1105{
1106	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
1107										 plane);
1108	int ret = 0;
1109	struct dpu_plane *pdpu = to_dpu_plane(plane);
1110	struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state);
1111	struct dpu_kms *dpu_kms = _dpu_plane_get_kms(plane);
1112	struct dpu_sw_pipe *pipe = &pstate->pipe[0];
1113	struct dpu_sw_pipe *r_pipe = &pstate->pipe[1];
1114	struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg[0];
1115	struct dpu_sw_pipe_cfg *r_pipe_cfg = &pstate->pipe_cfg[1];
1116	const struct drm_crtc_state *crtc_state = NULL;
1117	uint32_t max_linewidth = dpu_kms->catalog->caps->max_linewidth;
1118
1119	if (new_plane_state->crtc)
1120		crtc_state = drm_atomic_get_new_crtc_state(state,
1121							   new_plane_state->crtc);
1122
1123	pipe->sspp = dpu_rm_get_sspp(&dpu_kms->rm, pdpu->pipe);
1124
1125	if (!pipe->sspp)
1126		return -EINVAL;
1127
1128	ret = dpu_plane_atomic_check_nosspp(plane, new_plane_state, crtc_state);
1129	if (ret)
1130		return ret;
1131
1132	if (!new_plane_state->visible)
1133		return 0;
1134
1135	if (!dpu_plane_try_multirect_parallel(pipe, pipe_cfg, r_pipe, r_pipe_cfg,
1136					      pipe->sspp,
1137					      msm_framebuffer_format(new_plane_state->fb),
1138					      max_linewidth)) {
1139		DPU_DEBUG_PLANE(pdpu, "invalid " DRM_RECT_FMT " /" DRM_RECT_FMT
1140				" max_line:%u, can't use split source\n",
1141				DRM_RECT_ARG(&pipe_cfg->src_rect),
1142				DRM_RECT_ARG(&r_pipe_cfg->src_rect),
1143				max_linewidth);
1144		return -E2BIG;
1145	}
1146
1147	return dpu_plane_atomic_check_sspp(plane, state, crtc_state);
1148}
1149
1150static int dpu_plane_virtual_atomic_check(struct drm_plane *plane,
1151					  struct drm_atomic_state *state)
1152{
1153	struct drm_plane_state *plane_state =
1154		drm_atomic_get_plane_state(state, plane);
1155	struct drm_plane_state *old_plane_state =
1156		drm_atomic_get_old_plane_state(state, plane);
1157	struct dpu_plane_state *pstate = to_dpu_plane_state(plane_state);
1158	struct drm_crtc_state *crtc_state = NULL;
1159	int ret, i;
1160
1161	if (IS_ERR(plane_state))
1162		return PTR_ERR(plane_state);
1163
1164	if (plane_state->crtc)
1165		crtc_state = drm_atomic_get_new_crtc_state(state,
1166							   plane_state->crtc);
1167
1168	ret = dpu_plane_atomic_check_nosspp(plane, plane_state, crtc_state);
1169	if (ret)
1170		return ret;
1171
1172	if (!plane_state->visible) {
1173		/*
1174		 * resources are freed by dpu_crtc_assign_plane_resources(),
1175		 * but clean them here.
1176		 */
1177		for (i = 0; i < PIPES_PER_PLANE; i++)
1178			pstate->pipe[i].sspp = NULL;
1179
1180		return 0;
1181	}
1182
1183	/*
1184	 * Force resource reallocation if the format of FB or src/dst have
1185	 * changed. We might need to allocate different SSPP or SSPPs for this
1186	 * plane than the one used previously.
1187	 */
1188	if (!old_plane_state || !old_plane_state->fb ||
1189	    old_plane_state->src_w != plane_state->src_w ||
1190	    old_plane_state->src_h != plane_state->src_h ||
1191	    old_plane_state->crtc_w != plane_state->crtc_w ||
1192	    old_plane_state->crtc_h != plane_state->crtc_h ||
1193	    msm_framebuffer_format(old_plane_state->fb) !=
1194	    msm_framebuffer_format(plane_state->fb))
1195		crtc_state->planes_changed = true;
1196
1197	return 0;
1198}
1199
1200static int dpu_plane_assign_resource_in_stage(struct dpu_sw_pipe *pipe,
1201					      struct dpu_sw_pipe_cfg *pipe_cfg,
1202					      struct drm_plane_state *plane_state,
1203					      struct dpu_global_state *global_state,
1204					      struct drm_crtc *crtc,
1205					      struct dpu_rm_sspp_requirements *reqs)
1206{
1207	struct drm_plane *plane = plane_state->plane;
1208	struct dpu_kms *dpu_kms = _dpu_plane_get_kms(plane);
1209	struct dpu_sw_pipe *r_pipe = pipe + 1;
1210	struct dpu_sw_pipe_cfg *r_pipe_cfg = pipe_cfg + 1;
1211
1212	if (drm_rect_width(&pipe_cfg->src_rect) == 0)
1213		return 0;
1214
1215	pipe->sspp = dpu_rm_reserve_sspp(&dpu_kms->rm, global_state, crtc, reqs);
1216	if (!pipe->sspp)
1217		return -ENODEV;
1218	pipe->multirect_index = DPU_SSPP_RECT_SOLO;
1219	pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE;
1220
1221	if (drm_rect_width(&r_pipe_cfg->src_rect) == 0)
1222		return 0;
1223
1224	if (dpu_plane_try_multirect_parallel(pipe, pipe_cfg, r_pipe, r_pipe_cfg,
1225					      pipe->sspp,
1226					      msm_framebuffer_format(plane_state->fb),
1227					      dpu_kms->catalog->caps->max_linewidth))
1228		return 0;
1229
1230	r_pipe->sspp = dpu_rm_reserve_sspp(&dpu_kms->rm, global_state, crtc, reqs);
1231	if (!r_pipe->sspp)
1232		return -ENODEV;
1233	r_pipe->multirect_index = DPU_SSPP_RECT_SOLO;
1234	r_pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE;
1235
1236	return 0;
1237}
1238
1239static int dpu_plane_virtual_assign_resources(struct drm_crtc *crtc,
1240					      struct dpu_global_state *global_state,
1241					      struct drm_atomic_state *state,
1242					      struct drm_plane_state *plane_state,
1243					      struct drm_plane_state **prev_adjacent_plane_state)
1244{
1245	const struct drm_crtc_state *crtc_state = NULL;
1246	struct drm_plane *plane = plane_state->plane;
1247	struct dpu_kms *dpu_kms = _dpu_plane_get_kms(plane);
1248	struct dpu_rm_sspp_requirements reqs;
1249	struct dpu_plane_state *pstate, *prev_adjacent_pstate[STAGES_PER_PLANE];
1250	struct dpu_sw_pipe *pipe;
1251	struct dpu_sw_pipe_cfg *pipe_cfg;
1252	const struct msm_format *fmt;
1253	int i, ret;
1254
1255	if (plane_state->crtc)
1256		crtc_state = drm_atomic_get_new_crtc_state(state,
1257							   plane_state->crtc);
1258
1259	pstate = to_dpu_plane_state(plane_state);
1260	for (i = 0; i < STAGES_PER_PLANE; i++)
1261		prev_adjacent_pstate[i] = prev_adjacent_plane_state[i] ?
1262			to_dpu_plane_state(prev_adjacent_plane_state[i]) : NULL;
1263
1264	for (i = 0; i < PIPES_PER_PLANE; i++)
1265		pstate->pipe[i].sspp = NULL;
1266
1267	if (!plane_state->fb)
1268		return -EINVAL;
1269
1270	fmt = msm_framebuffer_format(plane_state->fb);
1271	reqs.yuv = MSM_FORMAT_IS_YUV(fmt);
1272	reqs.scale = (plane_state->src_w >> 16 != plane_state->crtc_w) ||
1273		(plane_state->src_h >> 16 != plane_state->crtc_h);
1274
1275	reqs.rot90 = drm_rotation_90_or_270(plane_state->rotation);
1276
1277	for (i = 0; i < STAGES_PER_PLANE; i++) {
1278		if (prev_adjacent_pstate[i] &&
1279		    dpu_plane_try_multirect_shared(pstate, prev_adjacent_pstate[i], fmt,
1280						   dpu_kms->catalog->caps->max_linewidth,
1281						   i))
1282			continue;
1283
1284		if (dpu_plane_get_single_pipe_in_stage(pstate, &pipe, &pipe_cfg, i))
1285			prev_adjacent_plane_state[i] = plane_state;
1286
1287		pipe = &pstate->pipe[i * PIPES_PER_STAGE];
1288		pipe_cfg = &pstate->pipe_cfg[i * PIPES_PER_STAGE];
1289		ret = dpu_plane_assign_resource_in_stage(pipe, pipe_cfg,
1290							 plane_state,
1291							 global_state,
1292							 crtc, &reqs);
1293		if (ret)
1294			return ret;
1295	}
1296
1297	return dpu_plane_atomic_check_sspp(plane, state, crtc_state);
1298}
1299
1300int dpu_assign_plane_resources(struct dpu_global_state *global_state,
1301			       struct drm_atomic_state *state,
1302			       struct drm_crtc *crtc,
1303			       struct drm_plane_state **states,
1304			       unsigned int num_planes)
1305{
1306	unsigned int i;
1307	struct drm_plane_state *prev_adjacent_plane_state[STAGES_PER_PLANE] = { NULL };
1308
1309	for (i = 0; i < num_planes; i++) {
1310		struct drm_plane_state *plane_state = states[i];
1311
1312		if (!plane_state ||
1313		    !plane_state->visible)
1314			continue;
1315
1316		int ret = dpu_plane_virtual_assign_resources(crtc, global_state,
1317							     state, plane_state,
1318							     prev_adjacent_plane_state);
1319		if (ret)
1320			return ret;
1321	}
1322
1323	return 0;
1324}
1325
1326static void dpu_plane_flush_csc(struct dpu_plane *pdpu, struct dpu_sw_pipe *pipe)
1327{
1328	const struct msm_format *format =
1329		msm_framebuffer_format(pdpu->base.state->fb);
1330	const struct dpu_csc_cfg *csc_ptr;
1331
1332	if (!pipe->sspp || !pipe->sspp->ops.setup_csc)
1333		return;
1334
1335	csc_ptr = _dpu_plane_get_csc(pipe, format);
1336	if (!csc_ptr)
1337		return;
1338
1339	DPU_DEBUG_PLANE(pdpu, "using 0x%X 0x%X 0x%X...\n",
1340			csc_ptr->csc_mv[0],
1341			csc_ptr->csc_mv[1],
1342			csc_ptr->csc_mv[2]);
1343
1344	pipe->sspp->ops.setup_csc(pipe->sspp, csc_ptr);
1345
1346}
1347
1348/**
1349 * dpu_plane_flush - final plane operations before commit flush
1350 * @plane: Pointer to drm plane structure
1351 */
1352void dpu_plane_flush(struct drm_plane *plane)
1353{
1354	struct dpu_plane *pdpu;
1355	struct dpu_plane_state *pstate;
1356	int i;
1357
1358	if (!plane || !plane->state) {
1359		DPU_ERROR("invalid plane\n");
1360		return;
1361	}
1362
1363	pdpu = to_dpu_plane(plane);
1364	pstate = to_dpu_plane_state(plane->state);
1365
1366	/*
1367	 * These updates have to be done immediately before the plane flush
1368	 * timing, and may not be moved to the atomic_update/mode_set functions.
1369	 */
1370	if (pdpu->is_error)
1371		/* force white frame with 100% alpha pipe output on error */
1372		_dpu_plane_color_fill(pdpu, 0xFFFFFF, 0xFF);
1373	else if (pdpu->color_fill & DPU_PLANE_COLOR_FILL_FLAG)
1374		/* force 100% alpha */
1375		_dpu_plane_color_fill(pdpu, pdpu->color_fill, 0xFF);
1376	else {
1377		for (i = 0; i < PIPES_PER_PLANE; i++)
1378			dpu_plane_flush_csc(pdpu, &pstate->pipe[i]);
1379	}
1380
1381	/* flag h/w flush complete */
1382	if (plane->state)
1383		pstate->pending = false;
1384}
1385
1386/**
1387 * dpu_plane_set_error: enable/disable error condition
1388 * @plane: pointer to drm_plane structure
1389 * @error: error value to set
1390 */
1391void dpu_plane_set_error(struct drm_plane *plane, bool error)
1392{
1393	struct dpu_plane *pdpu;
1394
1395	if (!plane)
1396		return;
1397
1398	pdpu = to_dpu_plane(plane);
1399	pdpu->is_error = error;
1400}
1401
1402static void dpu_plane_sspp_update_pipe(struct drm_plane *plane,
1403				       struct dpu_sw_pipe *pipe,
1404				       struct dpu_sw_pipe_cfg *pipe_cfg,
1405				       const struct msm_format *fmt,
1406				       int frame_rate,
1407				       struct dpu_hw_fmt_layout *layout)
1408{
1409	uint32_t src_flags;
1410	struct dpu_plane *pdpu = to_dpu_plane(plane);
1411	struct drm_plane_state *state = plane->state;
1412	struct dpu_plane_state *pstate = to_dpu_plane_state(state);
1413
1414	if (layout && pipe->sspp->ops.setup_sourceaddress) {
1415		trace_dpu_plane_set_scanout(pipe, layout);
1416		pipe->sspp->ops.setup_sourceaddress(pipe, layout);
1417	}
1418
1419	/* override for color fill */
1420	if (pdpu->color_fill & DPU_PLANE_COLOR_FILL_FLAG) {
1421		_dpu_plane_set_qos_ctrl(plane, pipe, false);
1422
1423		/* skip remaining processing on color fill */
1424		return;
1425	}
1426
1427	if (pipe->sspp->ops.setup_rects) {
1428		pipe->sspp->ops.setup_rects(pipe,
1429				pipe_cfg);
1430	}
1431
1432	_dpu_plane_setup_scaler(pipe, fmt, false, pipe_cfg);
1433
1434	if (pipe->sspp->ops.setup_multirect)
1435		pipe->sspp->ops.setup_multirect(
1436				pipe);
1437
1438	if (pipe->sspp->ops.setup_format) {
1439		unsigned int rotation = pipe_cfg->rotation;
1440
1441		src_flags = 0x0;
1442
1443		if (rotation & DRM_MODE_REFLECT_X)
1444			src_flags |= DPU_SSPP_FLIP_LR;
1445
1446		if (rotation & DRM_MODE_REFLECT_Y)
1447			src_flags |= DPU_SSPP_FLIP_UD;
1448
1449		if (rotation & DRM_MODE_ROTATE_90)
1450			src_flags |= DPU_SSPP_ROT_90;
1451
1452		/* update format */
1453		pipe->sspp->ops.setup_format(pipe, fmt, src_flags);
1454
1455		if (pipe->sspp->ops.setup_cdp) {
1456			const struct dpu_perf_cfg *perf = pdpu->catalog->perf;
1457
1458			pipe->sspp->ops.setup_cdp(pipe, fmt,
1459						  perf->cdp_cfg[DPU_PERF_CDP_USAGE_RT].rd_enable);
1460		}
1461	}
1462
1463	_dpu_plane_set_qos_lut(plane, pipe, fmt, pipe_cfg);
1464
1465	if (pipe->sspp->idx != SSPP_CURSOR0 &&
1466	    pipe->sspp->idx != SSPP_CURSOR1)
1467		_dpu_plane_set_ot_limit(plane, pipe, pipe_cfg, frame_rate);
1468
1469	if (pstate->needs_qos_remap)
1470		_dpu_plane_set_qos_remap(plane, pipe);
1471}
1472
1473static void dpu_plane_sspp_atomic_update(struct drm_plane *plane,
1474					 struct drm_plane_state *new_state)
1475{
1476	struct dpu_plane *pdpu = to_dpu_plane(plane);
1477	struct drm_plane_state *state = plane->state;
1478	struct dpu_plane_state *pstate = to_dpu_plane_state(state);
1479	struct drm_crtc *crtc = state->crtc;
1480	struct drm_framebuffer *fb = state->fb;
1481	bool is_rt_pipe;
1482	const struct msm_format *fmt =
1483		msm_framebuffer_format(fb);
1484	int i;
1485
1486	pstate->pending = true;
1487
1488	is_rt_pipe = (dpu_crtc_get_client_type(crtc) != NRT_CLIENT);
1489	pstate->needs_qos_remap |= (is_rt_pipe != pdpu->is_rt_pipe);
1490	pdpu->is_rt_pipe = is_rt_pipe;
1491
1492	dpu_format_populate_addrs(new_state->fb, &pstate->layout);
1493
1494	DPU_DEBUG_PLANE(pdpu, "FB[%u] " DRM_RECT_FP_FMT "->crtc%u " DRM_RECT_FMT
1495			", %p4cc ubwc %d\n", fb->base.id, DRM_RECT_FP_ARG(&state->src),
1496			crtc->base.id, DRM_RECT_ARG(&state->dst),
1497			&fmt->pixel_format, MSM_FORMAT_IS_UBWC(fmt));
1498
1499	for (i = 0; i < PIPES_PER_PLANE; i++) {
1500		if (!drm_rect_width(&pstate->pipe_cfg[i].src_rect))
1501			continue;
1502		dpu_plane_sspp_update_pipe(plane, &pstate->pipe[i],
1503					   &pstate->pipe_cfg[i], fmt,
1504					   drm_mode_vrefresh(&crtc->mode),
1505					   &pstate->layout);
1506	}
1507
1508	if (pstate->needs_qos_remap)
1509		pstate->needs_qos_remap = false;
1510
1511	pstate->plane_fetch_bw = 0;
1512	pstate->plane_clk = 0;
1513	for (i = 0; i < PIPES_PER_PLANE; i++) {
1514		if (!drm_rect_width(&pstate->pipe_cfg[i].src_rect))
1515			continue;
1516		pstate->plane_fetch_bw += _dpu_plane_calc_bw(pdpu->catalog, fmt,
1517							     &crtc->mode, &pstate->pipe_cfg[i]);
1518
1519		pstate->plane_clk = max(pstate->plane_clk,
1520					_dpu_plane_calc_clk(&crtc->mode,
1521							    &pstate->pipe_cfg[i]));
1522	}
1523}
1524
1525static void _dpu_plane_atomic_disable(struct drm_plane *plane)
1526{
1527	struct drm_plane_state *state = plane->state;
1528	struct dpu_plane_state *pstate = to_dpu_plane_state(state);
1529	struct dpu_sw_pipe *pipe;
1530	int i;
1531
1532	for (i = 0; i < PIPES_PER_PLANE; i += 1) {
1533		pipe = &pstate->pipe[i];
1534		if (!pipe->sspp)
1535			continue;
1536
1537		trace_dpu_plane_disable(DRMID(plane), false,
1538					pstate->pipe[i].multirect_mode);
1539
1540		if (i % PIPES_PER_STAGE == 0)
1541			continue;
1542
1543		/*
1544		 * clear multirect for the right pipe so that the SSPP
1545		 * can be further reused in the solo mode
1546		 */
1547		pipe->multirect_index = DPU_SSPP_RECT_SOLO;
1548		pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE;
1549		if (pipe->sspp->ops.setup_multirect)
1550			pipe->sspp->ops.setup_multirect(pipe);
1551	}
1552
1553	pstate->pending = true;
1554}
1555
1556static void dpu_plane_atomic_update(struct drm_plane *plane,
1557				struct drm_atomic_state *state)
1558{
1559	struct dpu_plane *pdpu = to_dpu_plane(plane);
1560	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
1561									   plane);
1562
1563	pdpu->is_error = false;
1564
1565	DPU_DEBUG_PLANE(pdpu, "\n");
1566
1567	if (!new_state->visible) {
1568		_dpu_plane_atomic_disable(plane);
1569	} else {
1570		dpu_plane_sspp_atomic_update(plane, new_state);
1571	}
1572}
1573
1574static void dpu_plane_destroy_state(struct drm_plane *plane,
1575		struct drm_plane_state *state)
1576{
1577	__drm_atomic_helper_plane_destroy_state(state);
1578	kfree(to_dpu_plane_state(state));
1579}
1580
1581static struct drm_plane_state *
1582dpu_plane_duplicate_state(struct drm_plane *plane)
1583{
1584	struct dpu_plane *pdpu;
1585	struct dpu_plane_state *pstate;
1586	struct dpu_plane_state *old_state;
1587
1588	if (!plane) {
1589		DPU_ERROR("invalid plane\n");
1590		return NULL;
1591	} else if (!plane->state) {
1592		DPU_ERROR("invalid plane state\n");
1593		return NULL;
1594	}
1595
1596	old_state = to_dpu_plane_state(plane->state);
1597	pdpu = to_dpu_plane(plane);
1598	pstate = kmemdup(old_state, sizeof(*old_state), GFP_KERNEL);
1599	if (!pstate) {
1600		DPU_ERROR_PLANE(pdpu, "failed to allocate state\n");
1601		return NULL;
1602	}
1603
1604	DPU_DEBUG_PLANE(pdpu, "\n");
1605
1606	pstate->pending = false;
1607
1608	__drm_atomic_helper_plane_duplicate_state(plane, &pstate->base);
1609
1610	return &pstate->base;
1611}
1612
1613static const char * const multirect_mode_name[] = {
1614	[DPU_SSPP_MULTIRECT_NONE] = "none",
1615	[DPU_SSPP_MULTIRECT_PARALLEL] = "parallel",
1616	[DPU_SSPP_MULTIRECT_TIME_MX] = "time_mx",
1617};
1618
1619static const char * const multirect_index_name[] = {
1620	[DPU_SSPP_RECT_SOLO] = "solo",
1621	[DPU_SSPP_RECT_0] = "rect_0",
1622	[DPU_SSPP_RECT_1] = "rect_1",
1623};
1624
1625static const char *dpu_get_multirect_mode(enum dpu_sspp_multirect_mode mode)
1626{
1627	if (WARN_ON(mode >= ARRAY_SIZE(multirect_mode_name)))
1628		return "unknown";
1629
1630	return multirect_mode_name[mode];
1631}
1632
1633static const char *dpu_get_multirect_index(enum dpu_sspp_multirect_index index)
1634{
1635	if (WARN_ON(index >= ARRAY_SIZE(multirect_index_name)))
1636		return "unknown";
1637
1638	return multirect_index_name[index];
1639}
1640
1641static void dpu_plane_atomic_print_state(struct drm_printer *p,
1642		const struct drm_plane_state *state)
1643{
1644	const struct dpu_plane_state *pstate = to_dpu_plane_state(state);
1645	const struct dpu_sw_pipe *pipe;
1646	const struct dpu_sw_pipe_cfg *pipe_cfg;
1647	int i;
1648
1649	drm_printf(p, "\tstage=%d\n", pstate->stage);
1650
1651	for (i = 0; i < PIPES_PER_PLANE; i++) {
1652		pipe = &pstate->pipe[i];
1653		if (!pipe->sspp)
1654			continue;
1655		pipe_cfg = &pstate->pipe_cfg[i];
1656		drm_printf(p, "\tsspp[%d]=%s\n", i, pipe->sspp->cap->name);
1657		drm_printf(p, "\tmultirect_mode[%d]=%s\n", i,
1658			   dpu_get_multirect_mode(pipe->multirect_mode));
1659		drm_printf(p, "\tmultirect_index[%d]=%s\n", i,
1660			   dpu_get_multirect_index(pipe->multirect_index));
1661		drm_printf(p, "\tsrc[%d]=" DRM_RECT_FMT "\n", i,
1662			   DRM_RECT_ARG(&pipe_cfg->src_rect));
1663		drm_printf(p, "\tdst[%d]=" DRM_RECT_FMT "\n", i,
1664			   DRM_RECT_ARG(&pipe_cfg->dst_rect));
1665	}
1666}
1667
1668static void dpu_plane_reset(struct drm_plane *plane)
1669{
1670	struct dpu_plane *pdpu;
1671	struct dpu_plane_state *pstate;
1672
1673	if (!plane) {
1674		DPU_ERROR("invalid plane\n");
1675		return;
1676	}
1677
1678	pdpu = to_dpu_plane(plane);
1679	DPU_DEBUG_PLANE(pdpu, "\n");
1680
1681	/* remove previous state, if present */
1682	if (plane->state) {
1683		dpu_plane_destroy_state(plane, plane->state);
1684		plane->state = NULL;
1685	}
1686
1687	pstate = kzalloc(sizeof(*pstate), GFP_KERNEL);
1688	if (!pstate) {
1689		DPU_ERROR_PLANE(pdpu, "failed to allocate state\n");
1690		return;
1691	}
1692
1693	__drm_atomic_helper_plane_reset(plane, &pstate->base);
1694}
1695
1696#ifdef CONFIG_DEBUG_FS
1697void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable)
1698{
1699	struct dpu_plane *pdpu = to_dpu_plane(plane);
1700	struct dpu_plane_state *pstate = to_dpu_plane_state(plane->state);
1701	struct dpu_kms *dpu_kms = _dpu_plane_get_kms(plane);
1702	int i;
1703
1704	if (!pdpu->is_rt_pipe)
1705		return;
1706
1707	pm_runtime_get_sync(&dpu_kms->pdev->dev);
1708	for (i = 0; i < PIPES_PER_PLANE; i++) {
1709		if (!pstate->pipe[i].sspp)
1710			continue;
1711		_dpu_plane_set_qos_ctrl(plane, &pstate->pipe[i], enable);
1712	}
1713	pm_runtime_put_sync(&dpu_kms->pdev->dev);
1714}
1715#endif
1716
1717static bool dpu_plane_format_mod_supported(struct drm_plane *plane,
1718		uint32_t format, uint64_t modifier)
1719{
1720	struct dpu_kms *dpu_kms = _dpu_plane_get_kms(plane);
1721	bool has_no_ubwc = (dpu_kms->mdss->ubwc_enc_version == 0) &&
1722			   (dpu_kms->mdss->ubwc_dec_version == 0);
1723
1724	if (modifier == DRM_FORMAT_MOD_LINEAR)
1725		return true;
1726
1727	if (modifier == DRM_FORMAT_MOD_QCOM_COMPRESSED && !has_no_ubwc)
1728		return dpu_find_format(format, qcom_compressed_supported_formats,
1729				ARRAY_SIZE(qcom_compressed_supported_formats));
1730
1731	return false;
1732}
1733
1734static const struct drm_plane_funcs dpu_plane_funcs = {
1735		.update_plane = drm_atomic_helper_update_plane,
1736		.disable_plane = drm_atomic_helper_disable_plane,
1737		.reset = dpu_plane_reset,
1738		.atomic_duplicate_state = dpu_plane_duplicate_state,
1739		.atomic_destroy_state = dpu_plane_destroy_state,
1740		.atomic_print_state = dpu_plane_atomic_print_state,
1741		.format_mod_supported = dpu_plane_format_mod_supported,
1742};
1743
1744static const struct drm_plane_helper_funcs dpu_plane_helper_funcs = {
1745		.prepare_fb = dpu_plane_prepare_fb,
1746		.cleanup_fb = dpu_plane_cleanup_fb,
1747		.atomic_check = dpu_plane_atomic_check,
1748		.atomic_update = dpu_plane_atomic_update,
1749};
1750
1751static const struct drm_plane_helper_funcs dpu_plane_virtual_helper_funcs = {
1752	.prepare_fb = dpu_plane_prepare_fb,
1753	.cleanup_fb = dpu_plane_cleanup_fb,
1754	.atomic_check = dpu_plane_virtual_atomic_check,
1755	.atomic_update = dpu_plane_atomic_update,
1756};
1757
1758/* initialize plane */
1759static struct drm_plane *dpu_plane_init_common(struct drm_device *dev,
1760					       enum drm_plane_type type,
1761					       unsigned long possible_crtcs,
1762					       bool inline_rotation,
1763					       const uint32_t *format_list,
1764					       uint32_t num_formats,
1765					       enum dpu_sspp pipe)
1766{
1767	struct drm_plane *plane = NULL;
1768	struct dpu_plane *pdpu;
1769	struct msm_drm_private *priv = dev->dev_private;
1770	struct dpu_kms *kms = to_dpu_kms(priv->kms);
1771	uint32_t supported_rotations;
1772	int ret;
1773
1774	pdpu = drmm_universal_plane_alloc(dev, struct dpu_plane, base,
1775				0xff, &dpu_plane_funcs,
1776				format_list, num_formats,
1777				supported_format_modifiers, type, NULL);
1778	if (IS_ERR(pdpu))
1779		return ERR_CAST(pdpu);
1780
1781	/* cache local stuff for later */
1782	plane = &pdpu->base;
1783	pdpu->pipe = pipe;
1784
1785	pdpu->catalog = kms->catalog;
1786
1787	ret = drm_plane_create_zpos_property(plane, 0, 0, DPU_ZPOS_MAX);
1788	if (ret)
1789		DPU_ERROR("failed to install zpos property, rc = %d\n", ret);
1790
1791	drm_plane_create_alpha_property(plane);
1792	drm_plane_create_blend_mode_property(plane,
1793			BIT(DRM_MODE_BLEND_PIXEL_NONE) |
1794			BIT(DRM_MODE_BLEND_PREMULTI) |
1795			BIT(DRM_MODE_BLEND_COVERAGE));
1796
1797	supported_rotations = DRM_MODE_REFLECT_MASK | DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180;
1798
1799	if (inline_rotation)
1800		supported_rotations |= DRM_MODE_ROTATE_MASK;
1801
1802	drm_plane_create_rotation_property(plane,
1803		    DRM_MODE_ROTATE_0, supported_rotations);
1804
1805	drm_plane_enable_fb_damage_clips(plane);
1806
1807	DPU_DEBUG("%s created for pipe:%u id:%u\n", plane->name,
1808					pipe, plane->base.id);
1809	return plane;
1810}
1811
1812/**
1813 * dpu_plane_init - create new dpu plane for the given pipe
1814 * @dev:   Pointer to DRM device
1815 * @pipe:  dpu hardware pipe identifier
1816 * @type:  Plane type - PRIMARY/OVERLAY/CURSOR
1817 * @possible_crtcs: bitmask of crtc that can be attached to the given pipe
1818 *
1819 * Initialize the plane.
1820 */
1821struct drm_plane *dpu_plane_init(struct drm_device *dev,
1822				 uint32_t pipe, enum drm_plane_type type,
1823				 unsigned long possible_crtcs)
1824{
1825	struct drm_plane *plane = NULL;
1826	struct msm_drm_private *priv = dev->dev_private;
1827	struct dpu_kms *kms = to_dpu_kms(priv->kms);
1828	struct dpu_hw_sspp *pipe_hw;
1829
1830	/* initialize underlying h/w driver */
1831	pipe_hw = dpu_rm_get_sspp(&kms->rm, pipe);
1832	if (!pipe_hw || !pipe_hw->cap || !pipe_hw->cap->sblk) {
1833		DPU_ERROR("[%u]SSPP is invalid\n", pipe);
1834		return ERR_PTR(-EINVAL);
1835	}
1836
1837
1838	plane = dpu_plane_init_common(dev, type, possible_crtcs,
1839				      pipe_hw->cap->features & BIT(DPU_SSPP_INLINE_ROTATION),
1840				      pipe_hw->cap->sblk->format_list,
1841				      pipe_hw->cap->sblk->num_formats,
1842				      pipe);
1843	if (IS_ERR(plane))
1844		return plane;
1845
1846	drm_plane_helper_add(plane, &dpu_plane_helper_funcs);
1847
1848	DPU_DEBUG("%s created for pipe:%u id:%u\n", plane->name,
1849					pipe, plane->base.id);
1850
1851	return plane;
1852}
1853
1854/**
1855 * dpu_plane_init_virtual - create new virtualized DPU plane
1856 * @dev:   Pointer to DRM device
1857 * @type:  Plane type - PRIMARY/OVERLAY/CURSOR
1858 * @possible_crtcs: bitmask of crtc that can be attached to the given pipe
1859 *
1860 * Initialize the virtual plane with no backing SSPP / pipe.
1861 */
1862struct drm_plane *dpu_plane_init_virtual(struct drm_device *dev,
1863					 enum drm_plane_type type,
1864					 unsigned long possible_crtcs)
1865{
1866	struct drm_plane *plane = NULL;
1867	struct msm_drm_private *priv = dev->dev_private;
1868	struct dpu_kms *kms = to_dpu_kms(priv->kms);
1869	bool has_inline_rotation = false;
1870	const u32 *format_list = NULL;
1871	u32 num_formats = 0;
1872	int i;
1873
1874	/* Determine the largest configuration that we can implement */
1875	for (i = 0; i < kms->catalog->sspp_count; i++) {
1876		const struct dpu_sspp_cfg *cfg = &kms->catalog->sspp[i];
1877
1878		if (test_bit(DPU_SSPP_INLINE_ROTATION, &cfg->features))
1879			has_inline_rotation = true;
1880
1881		if (!format_list ||
1882		    cfg->sblk->csc_blk.len) {
1883			format_list = cfg->sblk->format_list;
1884			num_formats = cfg->sblk->num_formats;
1885		}
1886	}
1887
1888	plane = dpu_plane_init_common(dev, type, possible_crtcs,
1889				      has_inline_rotation,
1890				      format_list,
1891				      num_formats,
1892				      SSPP_NONE);
1893	if (IS_ERR(plane))
1894		return plane;
1895
1896	drm_plane_helper_add(plane, &dpu_plane_virtual_helper_funcs);
1897
1898	DPU_DEBUG("%s created virtual id:%u\n", plane->name, plane->base.id);
1899
1900	return plane;
1901}
~/ Read-only file preview.