brintos

brintos / linux-shallow public Read only

0
0
Text · 41.6 KiB · 29298e0 Raw
1456 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2014-2018 The Linux Foundation. All rights reserved.4 * Copyright (C) 2013 Red Hat5 * 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 "msm_drv.h"21#include "msm_mdss.h"22#include "dpu_kms.h"23#include "dpu_formats.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	2139#define PHASE_STEP_UNIT_SCALE   ((int) (1 << PHASE_STEP_SHIFT))40#define PHASE_RESIDUAL		1541 42#define SHARP_STRENGTH_DEFAULT	3243#define SHARP_EDGE_THR_DEFAULT	11244#define SHARP_SMOOTH_THR_DEFAULT	845#define SHARP_NOISE_THR_DEFAULT	246 47#define DPU_PLANE_COLOR_FILL_FLAG	BIT(31)48#define DPU_ZPOS_MAX 25549 50/*51 * Default Preload Values52 */53#define DPU_QSEED3_DEFAULT_PRELOAD_H 0x454#define DPU_QSEED3_DEFAULT_PRELOAD_V 0x355#define DPU_QSEED4_DEFAULT_PRELOAD_V 0x256#define DPU_QSEED4_DEFAULT_PRELOAD_H 0x457 58#define DEFAULT_REFRESH_RATE	6059 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 structure75 * @aspace: address space pointer76 * @csc_ptr: Points to dpu_csc_cfg structure to use for current77 * @catalog: Points to dpu catalog structure78 * @revalidate: force revalidation of all the plane properties79 */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_INVALID95};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 plane108 * @catalog: Points to dpu catalog structure109 * @fmt: Pointer to source buffer format110 * @mode: Pointer to drm display mode111 * @pipe_cfg: Pointer to pipe configuration112 * 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_time115 */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	else152		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 plane160 * @mode: Pointer to drm display mode161 * @pipe_cfg: Pointer to pipe configuration162 * 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 format189 * @plane:		Pointer to drm plane190 * @pipe:		Pointer to software pipe191 * @lut_usage:		LUT usecase192 * @fmt:		Pointer to source buffer format193 * @src_width:		width of source buffer194 * Return: fill level corresponding to the source buffer/format or 0 if error195 */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 plane248 * @plane:		Pointer to drm plane249 * @pipe:		Pointer to software pipe250 * @fmt:		Pointer to source buffer format251 * @pipe_cfg:		Pointer to pipe configuration252 */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		else267			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 plane314 * @plane:		Pointer to drm plane315 * @pipe:		Pointer to software pipe316 * @enable:		true to enable QoS control317 */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 plane355 * @plane:		Pointer to drm plane356 * @pipe:		Pointer to software pipe357 * @pipe_cfg:		Pointer to pipe configuration358 * @frame_rate:		CRTC's frame rate359 */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 plane393 * @plane:		Pointer to drm plane394 * @pipe:		Pointer to software pipe395 */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 will439	 * 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		if (i == DPU_SSPP_COMP_1_2 || i == DPU_SSPP_COMP_2) {504			src_w /= chroma_subsmpl_h;505			src_h /= chroma_subsmpl_v;506		}507 508		pixel_ext->num_ext_pxls_top[i] = src_h;509		pixel_ext->num_ext_pxls_left[i] = src_w;510	}511}512 513static const struct dpu_csc_cfg *_dpu_plane_get_csc(struct dpu_sw_pipe *pipe,514						    const struct msm_format *fmt)515{516	const struct dpu_csc_cfg *csc_ptr;517 518	if (!MSM_FORMAT_IS_YUV(fmt))519		return NULL;520 521	if (BIT(DPU_SSPP_CSC_10BIT) & pipe->sspp->cap->features)522		csc_ptr = &dpu_csc10_YUV2RGB_601L;523	else524		csc_ptr = &dpu_csc_YUV2RGB_601L;525 526	return csc_ptr;527}528 529static void _dpu_plane_setup_scaler(struct dpu_sw_pipe *pipe,530		const struct msm_format *fmt, bool color_fill,531		struct dpu_sw_pipe_cfg *pipe_cfg,532		unsigned int rotation)533{534	struct dpu_hw_sspp *pipe_hw = pipe->sspp;535	const struct drm_format_info *info = drm_format_info(fmt->pixel_format);536	struct dpu_hw_scaler3_cfg scaler3_cfg;537	struct dpu_hw_pixel_ext pixel_ext;538	u32 src_width = drm_rect_width(&pipe_cfg->src_rect);539	u32 src_height = drm_rect_height(&pipe_cfg->src_rect);540	u32 dst_width = drm_rect_width(&pipe_cfg->dst_rect);541	u32 dst_height = drm_rect_height(&pipe_cfg->dst_rect);542 543	memset(&scaler3_cfg, 0, sizeof(scaler3_cfg));544	memset(&pixel_ext, 0, sizeof(pixel_ext));545 546	/* don't chroma subsample if decimating */547	/* update scaler. calculate default config for QSEED3 */548	_dpu_plane_setup_scaler3(pipe_hw,549			src_width,550			src_height,551			dst_width,552			dst_height,553			&scaler3_cfg, fmt,554			info->hsub, info->vsub,555			rotation);556 557	/* configure pixel extension based on scalar config */558	_dpu_plane_setup_pixel_ext(&scaler3_cfg, &pixel_ext,559			src_width, src_height, info->hsub, info->vsub);560 561	if (pipe_hw->ops.setup_pe)562		pipe_hw->ops.setup_pe(pipe_hw,563				&pixel_ext);564 565	/**566	 * when programmed in multirect mode, scalar block will be567	 * bypassed. Still we need to update alpha and bitwidth568	 * ONLY for RECT0569	 */570	if (pipe_hw->ops.setup_scaler &&571			pipe->multirect_index != DPU_SSPP_RECT_1)572		pipe_hw->ops.setup_scaler(pipe_hw,573				&scaler3_cfg,574				fmt);575}576 577static void _dpu_plane_color_fill_pipe(struct dpu_plane_state *pstate,578				       struct dpu_sw_pipe *pipe,579				       struct drm_rect *dst_rect,580				       u32 fill_color,581				       const struct msm_format *fmt)582{583	struct dpu_sw_pipe_cfg pipe_cfg;584 585	/* update sspp */586	if (!pipe->sspp->ops.setup_solidfill)587		return;588 589	pipe->sspp->ops.setup_solidfill(pipe, fill_color);590 591	/* override scaler/decimation if solid fill */592	pipe_cfg.dst_rect = *dst_rect;593 594	pipe_cfg.src_rect.x1 = 0;595	pipe_cfg.src_rect.y1 = 0;596	pipe_cfg.src_rect.x2 =597		drm_rect_width(&pipe_cfg.dst_rect);598	pipe_cfg.src_rect.y2 =599		drm_rect_height(&pipe_cfg.dst_rect);600 601	if (pipe->sspp->ops.setup_format)602		pipe->sspp->ops.setup_format(pipe, fmt, DPU_SSPP_SOLID_FILL);603 604	if (pipe->sspp->ops.setup_rects)605		pipe->sspp->ops.setup_rects(pipe, &pipe_cfg);606 607	_dpu_plane_setup_scaler(pipe, fmt, true, &pipe_cfg, pstate->rotation);608}609 610/**611 * _dpu_plane_color_fill - enables color fill on plane612 * @pdpu:   Pointer to DPU plane object613 * @color:  RGB fill color value, [23..16] Blue, [15..8] Green, [7..0] Red614 * @alpha:  8-bit fill alpha value, 255 selects 100% alpha615 */616static void _dpu_plane_color_fill(struct dpu_plane *pdpu,617		uint32_t color, uint32_t alpha)618{619	const struct msm_format *fmt;620	const struct drm_plane *plane = &pdpu->base;621	struct msm_drm_private *priv = plane->dev->dev_private;622	struct dpu_plane_state *pstate = to_dpu_plane_state(plane->state);623	u32 fill_color = (color & 0xFFFFFF) | ((alpha & 0xFF) << 24);624 625	DPU_DEBUG_PLANE(pdpu, "\n");626 627	/*628	 * select fill format to match user property expectation,629	 * h/w only supports RGB variants630	 */631	fmt = mdp_get_format(priv->kms, DRM_FORMAT_ABGR8888, 0);632	/* should not happen ever */633	if (!fmt)634		return;635 636	/* update sspp */637	_dpu_plane_color_fill_pipe(pstate, &pstate->pipe, &pstate->pipe_cfg.dst_rect,638				   fill_color, fmt);639 640	if (pstate->r_pipe.sspp)641		_dpu_plane_color_fill_pipe(pstate, &pstate->r_pipe, &pstate->r_pipe_cfg.dst_rect,642					   fill_color, fmt);643}644 645static int dpu_plane_prepare_fb(struct drm_plane *plane,646		struct drm_plane_state *new_state)647{648	struct drm_framebuffer *fb = new_state->fb;649	struct dpu_plane *pdpu = to_dpu_plane(plane);650	struct dpu_plane_state *pstate = to_dpu_plane_state(new_state);651	struct dpu_hw_fmt_layout layout;652	struct dpu_kms *kms = _dpu_plane_get_kms(&pdpu->base);653	int ret;654 655	if (!new_state->fb)656		return 0;657 658	DPU_DEBUG_PLANE(pdpu, "FB[%u]\n", fb->base.id);659 660	/* cache aspace */661	pstate->aspace = kms->base.aspace;662 663	/*664	 * TODO: Need to sort out the msm_framebuffer_prepare() call below so665	 *       we can use msm_atomic_prepare_fb() instead of doing the666	 *       implicit fence and fb prepare by hand here.667	 */668	drm_gem_plane_helper_prepare_fb(plane, new_state);669 670	if (pstate->aspace) {671		ret = msm_framebuffer_prepare(new_state->fb,672				pstate->aspace, pstate->needs_dirtyfb);673		if (ret) {674			DPU_ERROR("failed to prepare framebuffer\n");675			return ret;676		}677	}678 679	/* validate framebuffer layout before commit */680	ret = dpu_format_populate_layout(pstate->aspace,681			new_state->fb, &layout);682	if (ret) {683		DPU_ERROR_PLANE(pdpu, "failed to get format layout, %d\n", ret);684		if (pstate->aspace)685			msm_framebuffer_cleanup(new_state->fb, pstate->aspace,686						pstate->needs_dirtyfb);687		return ret;688	}689 690	return 0;691}692 693static void dpu_plane_cleanup_fb(struct drm_plane *plane,694		struct drm_plane_state *old_state)695{696	struct dpu_plane *pdpu = to_dpu_plane(plane);697	struct dpu_plane_state *old_pstate;698 699	if (!old_state || !old_state->fb)700		return;701 702	old_pstate = to_dpu_plane_state(old_state);703 704	DPU_DEBUG_PLANE(pdpu, "FB[%u]\n", old_state->fb->base.id);705 706	msm_framebuffer_cleanup(old_state->fb, old_pstate->aspace,707				old_pstate->needs_dirtyfb);708}709 710static int dpu_plane_check_inline_rotation(struct dpu_plane *pdpu,711						const struct dpu_sspp_sub_blks *sblk,712						struct drm_rect src, const struct msm_format *fmt)713{714	size_t num_formats;715	const u32 *supported_formats;716 717	if (!sblk->rotation_cfg) {718		DPU_ERROR("invalid rotation cfg\n");719		return -EINVAL;720	}721 722	if (drm_rect_width(&src) > sblk->rotation_cfg->rot_maxheight) {723		DPU_DEBUG_PLANE(pdpu, "invalid height for inline rot:%d max:%d\n",724				src.y2, sblk->rotation_cfg->rot_maxheight);725		return -EINVAL;726	}727 728	supported_formats = sblk->rotation_cfg->rot_format_list;729	num_formats = sblk->rotation_cfg->rot_num_formats;730 731	if (!MSM_FORMAT_IS_UBWC(fmt) ||732		!dpu_find_format(fmt->pixel_format, supported_formats, num_formats))733		return -EINVAL;734 735	return 0;736}737 738static int dpu_plane_atomic_check_pipe(struct dpu_plane *pdpu,739		struct dpu_sw_pipe *pipe,740		struct dpu_sw_pipe_cfg *pipe_cfg,741		const struct msm_format *fmt,742		const struct drm_display_mode *mode)743{744	uint32_t min_src_size;745	struct dpu_kms *kms = _dpu_plane_get_kms(&pdpu->base);746 747	min_src_size = MSM_FORMAT_IS_YUV(fmt) ? 2 : 1;748 749	if (MSM_FORMAT_IS_YUV(fmt) &&750	    !pipe->sspp->cap->sblk->csc_blk.len) {751		DPU_DEBUG_PLANE(pdpu,752				"plane doesn't have csc for yuv\n");753		return -EINVAL;754	}755 756	/* check src bounds */757	if (drm_rect_width(&pipe_cfg->src_rect) < min_src_size ||758	    drm_rect_height(&pipe_cfg->src_rect) < min_src_size) {759		DPU_DEBUG_PLANE(pdpu, "invalid source " DRM_RECT_FMT "\n",760				DRM_RECT_ARG(&pipe_cfg->src_rect));761		return -E2BIG;762	}763 764	/* valid yuv image */765	if (MSM_FORMAT_IS_YUV(fmt) &&766	    (pipe_cfg->src_rect.x1 & 0x1 ||767	     pipe_cfg->src_rect.y1 & 0x1 ||768	     drm_rect_width(&pipe_cfg->src_rect) & 0x1 ||769	     drm_rect_height(&pipe_cfg->src_rect) & 0x1)) {770		DPU_DEBUG_PLANE(pdpu, "invalid yuv source " DRM_RECT_FMT "\n",771				DRM_RECT_ARG(&pipe_cfg->src_rect));772		return -EINVAL;773	}774 775	/* min dst support */776	if (drm_rect_width(&pipe_cfg->dst_rect) < 0x1 ||777	    drm_rect_height(&pipe_cfg->dst_rect) < 0x1) {778		DPU_DEBUG_PLANE(pdpu, "invalid dest rect " DRM_RECT_FMT "\n",779				DRM_RECT_ARG(&pipe_cfg->dst_rect));780		return -EINVAL;781	}782 783	/* max clk check */784	if (_dpu_plane_calc_clk(mode, pipe_cfg) > kms->perf.max_core_clk_rate) {785		DPU_DEBUG_PLANE(pdpu, "plane exceeds max mdp core clk limits\n");786		return -E2BIG;787	}788 789	return 0;790}791 792static int dpu_plane_atomic_check(struct drm_plane *plane,793				  struct drm_atomic_state *state)794{795	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,796										 plane);797	int ret = 0, min_scale;798	struct dpu_plane *pdpu = to_dpu_plane(plane);799	struct dpu_kms *kms = _dpu_plane_get_kms(&pdpu->base);800	u64 max_mdp_clk_rate = kms->perf.max_core_clk_rate;801	struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state);802	struct dpu_sw_pipe *pipe = &pstate->pipe;803	struct dpu_sw_pipe *r_pipe = &pstate->r_pipe;804	const struct drm_crtc_state *crtc_state = NULL;805	const struct msm_format *fmt;806	struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg;807	struct dpu_sw_pipe_cfg *r_pipe_cfg = &pstate->r_pipe_cfg;808	struct drm_rect fb_rect = { 0 };809	uint32_t max_linewidth;810	unsigned int rotation;811	uint32_t supported_rotations;812	const struct dpu_sspp_cfg *pipe_hw_caps = pstate->pipe.sspp->cap;813	const struct dpu_sspp_sub_blks *sblk = pstate->pipe.sspp->cap->sblk;814 815	if (new_plane_state->crtc)816		crtc_state = drm_atomic_get_new_crtc_state(state,817							   new_plane_state->crtc);818 819	min_scale = FRAC_16_16(1, sblk->maxupscale);820	ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,821						  min_scale,822						  sblk->maxdwnscale << 16,823						  true, true);824	if (ret) {825		DPU_DEBUG_PLANE(pdpu, "Check plane state failed (%d)\n", ret);826		return ret;827	}828	if (!new_plane_state->visible)829		return 0;830 831	pipe->multirect_index = DPU_SSPP_RECT_SOLO;832	pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE;833	r_pipe->multirect_index = DPU_SSPP_RECT_SOLO;834	r_pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE;835	r_pipe->sspp = NULL;836 837	pstate->stage = DPU_STAGE_0 + pstate->base.normalized_zpos;838	if (pstate->stage >= pdpu->catalog->caps->max_mixer_blendstages) {839		DPU_ERROR("> %d plane stages assigned\n",840			  pdpu->catalog->caps->max_mixer_blendstages - DPU_STAGE_0);841		return -EINVAL;842	}843 844	pipe_cfg->src_rect = new_plane_state->src;845 846	/* state->src is 16.16, src_rect is not */847	pipe_cfg->src_rect.x1 >>= 16;848	pipe_cfg->src_rect.x2 >>= 16;849	pipe_cfg->src_rect.y1 >>= 16;850	pipe_cfg->src_rect.y2 >>= 16;851 852	pipe_cfg->dst_rect = new_plane_state->dst;853 854	fb_rect.x2 = new_plane_state->fb->width;855	fb_rect.y2 = new_plane_state->fb->height;856 857	/* Ensure fb size is supported */858	if (drm_rect_width(&fb_rect) > MAX_IMG_WIDTH ||859	    drm_rect_height(&fb_rect) > MAX_IMG_HEIGHT) {860		DPU_DEBUG_PLANE(pdpu, "invalid framebuffer " DRM_RECT_FMT "\n",861				DRM_RECT_ARG(&fb_rect));862		return -E2BIG;863	}864 865	fmt = msm_framebuffer_format(new_plane_state->fb);866 867	max_linewidth = pdpu->catalog->caps->max_linewidth;868 869	drm_rect_rotate(&pipe_cfg->src_rect,870			new_plane_state->fb->width, new_plane_state->fb->height,871			new_plane_state->rotation);872 873	if ((drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) ||874	     _dpu_plane_calc_clk(&crtc_state->adjusted_mode, pipe_cfg) > max_mdp_clk_rate) {875		/*876		 * In parallel multirect case only the half of the usual width877		 * is supported for tiled formats. If we are here, we know that878		 * full width is more than max_linewidth, thus each rect is879		 * wider than allowed.880		 */881		if (MSM_FORMAT_IS_UBWC(fmt) &&882		    drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) {883			DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u, tiled format\n",884					DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth);885			return -E2BIG;886		}887 888		if (drm_rect_width(&pipe_cfg->src_rect) > 2 * max_linewidth) {889			DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u\n",890					DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth);891			return -E2BIG;892		}893 894		if (drm_rect_width(&pipe_cfg->src_rect) != drm_rect_width(&pipe_cfg->dst_rect) ||895		    drm_rect_height(&pipe_cfg->src_rect) != drm_rect_height(&pipe_cfg->dst_rect) ||896		    (!test_bit(DPU_SSPP_SMART_DMA_V1, &pipe->sspp->cap->features) &&897		     !test_bit(DPU_SSPP_SMART_DMA_V2, &pipe->sspp->cap->features)) ||898		    MSM_FORMAT_IS_YUV(fmt)) {899			DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u, can't use split source\n",900					DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth);901			return -E2BIG;902		}903 904		/*905		 * Use multirect for wide plane. We do not support dynamic906		 * assignment of SSPPs, so we know the configuration.907		 */908		pipe->multirect_index = DPU_SSPP_RECT_0;909		pipe->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL;910 911		r_pipe->sspp = pipe->sspp;912		r_pipe->multirect_index = DPU_SSPP_RECT_1;913		r_pipe->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL;914 915		*r_pipe_cfg = *pipe_cfg;916		pipe_cfg->src_rect.x2 = (pipe_cfg->src_rect.x1 + pipe_cfg->src_rect.x2) >> 1;917		pipe_cfg->dst_rect.x2 = (pipe_cfg->dst_rect.x1 + pipe_cfg->dst_rect.x2) >> 1;918		r_pipe_cfg->src_rect.x1 = pipe_cfg->src_rect.x2;919		r_pipe_cfg->dst_rect.x1 = pipe_cfg->dst_rect.x2;920	}921 922	drm_rect_rotate_inv(&pipe_cfg->src_rect,923			    new_plane_state->fb->width, new_plane_state->fb->height,924			    new_plane_state->rotation);925	if (r_pipe->sspp)926		drm_rect_rotate_inv(&r_pipe_cfg->src_rect,927				    new_plane_state->fb->width, new_plane_state->fb->height,928				    new_plane_state->rotation);929 930	ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg, fmt, &crtc_state->adjusted_mode);931	if (ret)932		return ret;933 934	if (r_pipe->sspp) {935		ret = dpu_plane_atomic_check_pipe(pdpu, r_pipe, r_pipe_cfg, fmt,936						  &crtc_state->adjusted_mode);937		if (ret)938			return ret;939	}940 941	supported_rotations = DRM_MODE_REFLECT_MASK | DRM_MODE_ROTATE_0;942 943	if (pipe_hw_caps->features & BIT(DPU_SSPP_INLINE_ROTATION))944		supported_rotations |= DRM_MODE_ROTATE_90;945 946	rotation = drm_rotation_simplify(new_plane_state->rotation,947					supported_rotations);948 949	if ((pipe_hw_caps->features & BIT(DPU_SSPP_INLINE_ROTATION)) &&950		(rotation & DRM_MODE_ROTATE_90)) {951		ret = dpu_plane_check_inline_rotation(pdpu, sblk, pipe_cfg->src_rect, fmt);952		if (ret)953			return ret;954	}955 956	pstate->rotation = rotation;957	pstate->needs_qos_remap = drm_atomic_crtc_needs_modeset(crtc_state);958 959	return 0;960}961 962static void dpu_plane_flush_csc(struct dpu_plane *pdpu, struct dpu_sw_pipe *pipe)963{964	const struct msm_format *format =965		msm_framebuffer_format(pdpu->base.state->fb);966	const struct dpu_csc_cfg *csc_ptr;967 968	if (!pipe->sspp || !pipe->sspp->ops.setup_csc)969		return;970 971	csc_ptr = _dpu_plane_get_csc(pipe, format);972	if (!csc_ptr)973		return;974 975	DPU_DEBUG_PLANE(pdpu, "using 0x%X 0x%X 0x%X...\n",976			csc_ptr->csc_mv[0],977			csc_ptr->csc_mv[1],978			csc_ptr->csc_mv[2]);979 980	pipe->sspp->ops.setup_csc(pipe->sspp, csc_ptr);981 982}983 984void dpu_plane_flush(struct drm_plane *plane)985{986	struct dpu_plane *pdpu;987	struct dpu_plane_state *pstate;988 989	if (!plane || !plane->state) {990		DPU_ERROR("invalid plane\n");991		return;992	}993 994	pdpu = to_dpu_plane(plane);995	pstate = to_dpu_plane_state(plane->state);996 997	/*998	 * These updates have to be done immediately before the plane flush999	 * timing, and may not be moved to the atomic_update/mode_set functions.1000	 */1001	if (pdpu->is_error)1002		/* force white frame with 100% alpha pipe output on error */1003		_dpu_plane_color_fill(pdpu, 0xFFFFFF, 0xFF);1004	else if (pdpu->color_fill & DPU_PLANE_COLOR_FILL_FLAG)1005		/* force 100% alpha */1006		_dpu_plane_color_fill(pdpu, pdpu->color_fill, 0xFF);1007	else {1008		dpu_plane_flush_csc(pdpu, &pstate->pipe);1009		dpu_plane_flush_csc(pdpu, &pstate->r_pipe);1010	}1011 1012	/* flag h/w flush complete */1013	if (plane->state)1014		pstate->pending = false;1015}1016 1017/**1018 * dpu_plane_set_error: enable/disable error condition1019 * @plane: pointer to drm_plane structure1020 * @error: error value to set1021 */1022void dpu_plane_set_error(struct drm_plane *plane, bool error)1023{1024	struct dpu_plane *pdpu;1025 1026	if (!plane)1027		return;1028 1029	pdpu = to_dpu_plane(plane);1030	pdpu->is_error = error;1031}1032 1033static void dpu_plane_sspp_update_pipe(struct drm_plane *plane,1034				       struct dpu_sw_pipe *pipe,1035				       struct dpu_sw_pipe_cfg *pipe_cfg,1036				       const struct msm_format *fmt,1037				       int frame_rate,1038				       struct dpu_hw_fmt_layout *layout)1039{1040	uint32_t src_flags;1041	struct dpu_plane *pdpu = to_dpu_plane(plane);1042	struct drm_plane_state *state = plane->state;1043	struct dpu_plane_state *pstate = to_dpu_plane_state(state);1044 1045	if (layout && pipe->sspp->ops.setup_sourceaddress) {1046		trace_dpu_plane_set_scanout(pipe, layout);1047		pipe->sspp->ops.setup_sourceaddress(pipe, layout);1048	}1049 1050	/* override for color fill */1051	if (pdpu->color_fill & DPU_PLANE_COLOR_FILL_FLAG) {1052		_dpu_plane_set_qos_ctrl(plane, pipe, false);1053 1054		/* skip remaining processing on color fill */1055		return;1056	}1057 1058	if (pipe->sspp->ops.setup_rects) {1059		pipe->sspp->ops.setup_rects(pipe,1060				pipe_cfg);1061	}1062 1063	_dpu_plane_setup_scaler(pipe, fmt, false, pipe_cfg, pstate->rotation);1064 1065	if (pipe->sspp->ops.setup_multirect)1066		pipe->sspp->ops.setup_multirect(1067				pipe);1068 1069	if (pipe->sspp->ops.setup_format) {1070		unsigned int rotation = pstate->rotation;1071 1072		src_flags = 0x0;1073 1074		if (rotation & DRM_MODE_REFLECT_X)1075			src_flags |= DPU_SSPP_FLIP_LR;1076 1077		if (rotation & DRM_MODE_REFLECT_Y)1078			src_flags |= DPU_SSPP_FLIP_UD;1079 1080		if (rotation & DRM_MODE_ROTATE_90)1081			src_flags |= DPU_SSPP_ROT_90;1082 1083		/* update format */1084		pipe->sspp->ops.setup_format(pipe, fmt, src_flags);1085 1086		if (pipe->sspp->ops.setup_cdp) {1087			const struct dpu_perf_cfg *perf = pdpu->catalog->perf;1088 1089			pipe->sspp->ops.setup_cdp(pipe, fmt,1090						  perf->cdp_cfg[DPU_PERF_CDP_USAGE_RT].rd_enable);1091		}1092	}1093 1094	_dpu_plane_set_qos_lut(plane, pipe, fmt, pipe_cfg);1095 1096	if (pipe->sspp->idx != SSPP_CURSOR0 &&1097	    pipe->sspp->idx != SSPP_CURSOR1)1098		_dpu_plane_set_ot_limit(plane, pipe, pipe_cfg, frame_rate);1099 1100	if (pstate->needs_qos_remap)1101		_dpu_plane_set_qos_remap(plane, pipe);1102}1103 1104static void dpu_plane_sspp_atomic_update(struct drm_plane *plane)1105{1106	struct dpu_plane *pdpu = to_dpu_plane(plane);1107	struct drm_plane_state *state = plane->state;1108	struct dpu_plane_state *pstate = to_dpu_plane_state(state);1109	struct dpu_sw_pipe *pipe = &pstate->pipe;1110	struct dpu_sw_pipe *r_pipe = &pstate->r_pipe;1111	struct drm_crtc *crtc = state->crtc;1112	struct drm_framebuffer *fb = state->fb;1113	bool is_rt_pipe;1114	const struct msm_format *fmt =1115		msm_framebuffer_format(fb);1116	struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg;1117	struct dpu_sw_pipe_cfg *r_pipe_cfg = &pstate->r_pipe_cfg;1118	struct dpu_kms *kms = _dpu_plane_get_kms(&pdpu->base);1119	struct msm_gem_address_space *aspace = kms->base.aspace;1120	struct dpu_hw_fmt_layout layout;1121	bool layout_valid = false;1122	int ret;1123 1124	ret = dpu_format_populate_layout(aspace, fb, &layout);1125	if (ret)1126		DPU_ERROR_PLANE(pdpu, "failed to get format layout, %d\n", ret);1127	else1128		layout_valid = true;1129 1130	pstate->pending = true;1131 1132	is_rt_pipe = (dpu_crtc_get_client_type(crtc) != NRT_CLIENT);1133	pstate->needs_qos_remap |= (is_rt_pipe != pdpu->is_rt_pipe);1134	pdpu->is_rt_pipe = is_rt_pipe;1135 1136	DPU_DEBUG_PLANE(pdpu, "FB[%u] " DRM_RECT_FP_FMT "->crtc%u " DRM_RECT_FMT1137			", %p4cc ubwc %d\n", fb->base.id, DRM_RECT_FP_ARG(&state->src),1138			crtc->base.id, DRM_RECT_ARG(&state->dst),1139			&fmt->pixel_format, MSM_FORMAT_IS_UBWC(fmt));1140 1141	dpu_plane_sspp_update_pipe(plane, pipe, pipe_cfg, fmt,1142				   drm_mode_vrefresh(&crtc->mode),1143				   layout_valid ? &layout : NULL);1144 1145	if (r_pipe->sspp) {1146		dpu_plane_sspp_update_pipe(plane, r_pipe, r_pipe_cfg, fmt,1147					   drm_mode_vrefresh(&crtc->mode),1148					   layout_valid ? &layout : NULL);1149	}1150 1151	if (pstate->needs_qos_remap)1152		pstate->needs_qos_remap = false;1153 1154	pstate->plane_fetch_bw = _dpu_plane_calc_bw(pdpu->catalog, fmt,1155						    &crtc->mode, pipe_cfg);1156 1157	pstate->plane_clk = _dpu_plane_calc_clk(&crtc->mode, pipe_cfg);1158 1159	if (r_pipe->sspp) {1160		pstate->plane_fetch_bw += _dpu_plane_calc_bw(pdpu->catalog, fmt, &crtc->mode, r_pipe_cfg);1161 1162		pstate->plane_clk = max(pstate->plane_clk, _dpu_plane_calc_clk(&crtc->mode, r_pipe_cfg));1163	}1164}1165 1166static void _dpu_plane_atomic_disable(struct drm_plane *plane)1167{1168	struct drm_plane_state *state = plane->state;1169	struct dpu_plane_state *pstate = to_dpu_plane_state(state);1170	struct dpu_sw_pipe *r_pipe = &pstate->r_pipe;1171 1172	trace_dpu_plane_disable(DRMID(plane), false,1173				pstate->pipe.multirect_mode);1174 1175	if (r_pipe->sspp) {1176		r_pipe->multirect_index = DPU_SSPP_RECT_SOLO;1177		r_pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE;1178 1179		if (r_pipe->sspp->ops.setup_multirect)1180			r_pipe->sspp->ops.setup_multirect(r_pipe);1181	}1182 1183	pstate->pending = true;1184}1185 1186static void dpu_plane_atomic_update(struct drm_plane *plane,1187				struct drm_atomic_state *state)1188{1189	struct dpu_plane *pdpu = to_dpu_plane(plane);1190	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,1191									   plane);1192 1193	pdpu->is_error = false;1194 1195	DPU_DEBUG_PLANE(pdpu, "\n");1196 1197	if (!new_state->visible) {1198		_dpu_plane_atomic_disable(plane);1199	} else {1200		dpu_plane_sspp_atomic_update(plane);1201	}1202}1203 1204static void dpu_plane_destroy_state(struct drm_plane *plane,1205		struct drm_plane_state *state)1206{1207	__drm_atomic_helper_plane_destroy_state(state);1208	kfree(to_dpu_plane_state(state));1209}1210 1211static struct drm_plane_state *1212dpu_plane_duplicate_state(struct drm_plane *plane)1213{1214	struct dpu_plane *pdpu;1215	struct dpu_plane_state *pstate;1216	struct dpu_plane_state *old_state;1217 1218	if (!plane) {1219		DPU_ERROR("invalid plane\n");1220		return NULL;1221	} else if (!plane->state) {1222		DPU_ERROR("invalid plane state\n");1223		return NULL;1224	}1225 1226	old_state = to_dpu_plane_state(plane->state);1227	pdpu = to_dpu_plane(plane);1228	pstate = kmemdup(old_state, sizeof(*old_state), GFP_KERNEL);1229	if (!pstate) {1230		DPU_ERROR_PLANE(pdpu, "failed to allocate state\n");1231		return NULL;1232	}1233 1234	DPU_DEBUG_PLANE(pdpu, "\n");1235 1236	pstate->pending = false;1237 1238	__drm_atomic_helper_plane_duplicate_state(plane, &pstate->base);1239 1240	return &pstate->base;1241}1242 1243static const char * const multirect_mode_name[] = {1244	[DPU_SSPP_MULTIRECT_NONE] = "none",1245	[DPU_SSPP_MULTIRECT_PARALLEL] = "parallel",1246	[DPU_SSPP_MULTIRECT_TIME_MX] = "time_mx",1247};1248 1249static const char * const multirect_index_name[] = {1250	[DPU_SSPP_RECT_SOLO] = "solo",1251	[DPU_SSPP_RECT_0] = "rect_0",1252	[DPU_SSPP_RECT_1] = "rect_1",1253};1254 1255static const char *dpu_get_multirect_mode(enum dpu_sspp_multirect_mode mode)1256{1257	if (WARN_ON(mode >= ARRAY_SIZE(multirect_mode_name)))1258		return "unknown";1259 1260	return multirect_mode_name[mode];1261}1262 1263static const char *dpu_get_multirect_index(enum dpu_sspp_multirect_index index)1264{1265	if (WARN_ON(index >= ARRAY_SIZE(multirect_index_name)))1266		return "unknown";1267 1268	return multirect_index_name[index];1269}1270 1271static void dpu_plane_atomic_print_state(struct drm_printer *p,1272		const struct drm_plane_state *state)1273{1274	const struct dpu_plane_state *pstate = to_dpu_plane_state(state);1275	const struct dpu_sw_pipe *pipe = &pstate->pipe;1276	const struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg;1277	const struct dpu_sw_pipe *r_pipe = &pstate->r_pipe;1278	const struct dpu_sw_pipe_cfg *r_pipe_cfg = &pstate->r_pipe_cfg;1279 1280	drm_printf(p, "\tstage=%d\n", pstate->stage);1281 1282	drm_printf(p, "\tsspp[0]=%s\n", pipe->sspp->cap->name);1283	drm_printf(p, "\tmultirect_mode[0]=%s\n", dpu_get_multirect_mode(pipe->multirect_mode));1284	drm_printf(p, "\tmultirect_index[0]=%s\n",1285		   dpu_get_multirect_index(pipe->multirect_index));1286	drm_printf(p, "\tsrc[0]=" DRM_RECT_FMT "\n", DRM_RECT_ARG(&pipe_cfg->src_rect));1287	drm_printf(p, "\tdst[0]=" DRM_RECT_FMT "\n", DRM_RECT_ARG(&pipe_cfg->dst_rect));1288 1289	if (r_pipe->sspp) {1290		drm_printf(p, "\tsspp[1]=%s\n", r_pipe->sspp->cap->name);1291		drm_printf(p, "\tmultirect_mode[1]=%s\n",1292			   dpu_get_multirect_mode(r_pipe->multirect_mode));1293		drm_printf(p, "\tmultirect_index[1]=%s\n",1294			   dpu_get_multirect_index(r_pipe->multirect_index));1295		drm_printf(p, "\tsrc[1]=" DRM_RECT_FMT "\n", DRM_RECT_ARG(&r_pipe_cfg->src_rect));1296		drm_printf(p, "\tdst[1]=" DRM_RECT_FMT "\n", DRM_RECT_ARG(&r_pipe_cfg->dst_rect));1297	}1298}1299 1300static void dpu_plane_reset(struct drm_plane *plane)1301{1302	struct dpu_plane *pdpu;1303	struct dpu_plane_state *pstate;1304	struct dpu_kms *dpu_kms = _dpu_plane_get_kms(plane);1305 1306	if (!plane) {1307		DPU_ERROR("invalid plane\n");1308		return;1309	}1310 1311	pdpu = to_dpu_plane(plane);1312	DPU_DEBUG_PLANE(pdpu, "\n");1313 1314	/* remove previous state, if present */1315	if (plane->state) {1316		dpu_plane_destroy_state(plane, plane->state);1317		plane->state = NULL;1318	}1319 1320	pstate = kzalloc(sizeof(*pstate), GFP_KERNEL);1321	if (!pstate) {1322		DPU_ERROR_PLANE(pdpu, "failed to allocate state\n");1323		return;1324	}1325 1326	/*1327	 * Set the SSPP here until we have proper virtualized DPU planes.1328	 * This is the place where the state is allocated, so fill it fully.1329	 */1330	pstate->pipe.sspp = dpu_rm_get_sspp(&dpu_kms->rm, pdpu->pipe);1331	pstate->pipe.multirect_index = DPU_SSPP_RECT_SOLO;1332	pstate->pipe.multirect_mode = DPU_SSPP_MULTIRECT_NONE;1333 1334	pstate->r_pipe.sspp = NULL;1335 1336	__drm_atomic_helper_plane_reset(plane, &pstate->base);1337}1338 1339#ifdef CONFIG_DEBUG_FS1340void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable)1341{1342	struct dpu_plane *pdpu = to_dpu_plane(plane);1343	struct dpu_plane_state *pstate = to_dpu_plane_state(plane->state);1344	struct dpu_kms *dpu_kms = _dpu_plane_get_kms(plane);1345 1346	if (!pdpu->is_rt_pipe)1347		return;1348 1349	pm_runtime_get_sync(&dpu_kms->pdev->dev);1350	_dpu_plane_set_qos_ctrl(plane, &pstate->pipe, enable);1351	if (pstate->r_pipe.sspp)1352		_dpu_plane_set_qos_ctrl(plane, &pstate->r_pipe, enable);1353	pm_runtime_put_sync(&dpu_kms->pdev->dev);1354}1355#endif1356 1357static bool dpu_plane_format_mod_supported(struct drm_plane *plane,1358		uint32_t format, uint64_t modifier)1359{1360	struct dpu_kms *dpu_kms = _dpu_plane_get_kms(plane);1361	bool has_no_ubwc = (dpu_kms->mdss->ubwc_enc_version == 0) &&1362			   (dpu_kms->mdss->ubwc_dec_version == 0);1363 1364	if (modifier == DRM_FORMAT_MOD_LINEAR)1365		return true;1366 1367	if (modifier == DRM_FORMAT_MOD_QCOM_COMPRESSED && !has_no_ubwc)1368		return dpu_find_format(format, qcom_compressed_supported_formats,1369				ARRAY_SIZE(qcom_compressed_supported_formats));1370 1371	return false;1372}1373 1374static const struct drm_plane_funcs dpu_plane_funcs = {1375		.update_plane = drm_atomic_helper_update_plane,1376		.disable_plane = drm_atomic_helper_disable_plane,1377		.reset = dpu_plane_reset,1378		.atomic_duplicate_state = dpu_plane_duplicate_state,1379		.atomic_destroy_state = dpu_plane_destroy_state,1380		.atomic_print_state = dpu_plane_atomic_print_state,1381		.format_mod_supported = dpu_plane_format_mod_supported,1382};1383 1384static const struct drm_plane_helper_funcs dpu_plane_helper_funcs = {1385		.prepare_fb = dpu_plane_prepare_fb,1386		.cleanup_fb = dpu_plane_cleanup_fb,1387		.atomic_check = dpu_plane_atomic_check,1388		.atomic_update = dpu_plane_atomic_update,1389};1390 1391/* initialize plane */1392struct drm_plane *dpu_plane_init(struct drm_device *dev,1393		uint32_t pipe, enum drm_plane_type type,1394		unsigned long possible_crtcs)1395{1396	struct drm_plane *plane = NULL;1397	const uint32_t *format_list;1398	struct dpu_plane *pdpu;1399	struct msm_drm_private *priv = dev->dev_private;1400	struct dpu_kms *kms = to_dpu_kms(priv->kms);1401	struct dpu_hw_sspp *pipe_hw;1402	uint32_t num_formats;1403	uint32_t supported_rotations;1404	int ret;1405 1406	/* initialize underlying h/w driver */1407	pipe_hw = dpu_rm_get_sspp(&kms->rm, pipe);1408	if (!pipe_hw || !pipe_hw->cap || !pipe_hw->cap->sblk) {1409		DPU_ERROR("[%u]SSPP is invalid\n", pipe);1410		return ERR_PTR(-EINVAL);1411	}1412 1413	format_list = pipe_hw->cap->sblk->format_list;1414	num_formats = pipe_hw->cap->sblk->num_formats;1415 1416	pdpu = drmm_universal_plane_alloc(dev, struct dpu_plane, base,1417				0xff, &dpu_plane_funcs,1418				format_list, num_formats,1419				supported_format_modifiers, type, NULL);1420	if (IS_ERR(pdpu))1421		return ERR_CAST(pdpu);1422 1423	/* cache local stuff for later */1424	plane = &pdpu->base;1425	pdpu->pipe = pipe;1426 1427	pdpu->catalog = kms->catalog;1428 1429	ret = drm_plane_create_zpos_property(plane, 0, 0, DPU_ZPOS_MAX);1430	if (ret)1431		DPU_ERROR("failed to install zpos property, rc = %d\n", ret);1432 1433	drm_plane_create_alpha_property(plane);1434	drm_plane_create_blend_mode_property(plane,1435			BIT(DRM_MODE_BLEND_PIXEL_NONE) |1436			BIT(DRM_MODE_BLEND_PREMULTI) |1437			BIT(DRM_MODE_BLEND_COVERAGE));1438 1439	supported_rotations = DRM_MODE_REFLECT_MASK | DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180;1440 1441	if (pipe_hw->cap->features & BIT(DPU_SSPP_INLINE_ROTATION))1442		supported_rotations |= DRM_MODE_ROTATE_MASK;1443 1444	drm_plane_create_rotation_property(plane,1445		    DRM_MODE_ROTATE_0, supported_rotations);1446 1447	drm_plane_enable_fb_damage_clips(plane);1448 1449	/* success! finalize initialization */1450	drm_plane_helper_add(plane, &dpu_plane_helper_funcs);1451 1452	DPU_DEBUG("%s created for pipe:%u id:%u\n", plane->name,1453					pipe, plane->base.id);1454	return plane;1455}1456