drm/msm/dpu: add support for wide planes
[linux-2.6-microblaze.git] / drivers / gpu / drm / msm / disp / dpu1 / dpu_plane.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 "msm_drv.h"
21 #include "dpu_kms.h"
22 #include "dpu_formats.h"
23 #include "dpu_hw_sspp.h"
24 #include "dpu_trace.h"
25 #include "dpu_crtc.h"
26 #include "dpu_vbif.h"
27 #include "dpu_plane.h"
28
29 #define DPU_DEBUG_PLANE(pl, fmt, ...) DRM_DEBUG_ATOMIC("plane%d " fmt,\
30                 (pl) ? (pl)->base.base.id : -1, ##__VA_ARGS__)
31
32 #define DPU_ERROR_PLANE(pl, fmt, ...) DPU_ERROR("plane%d " fmt,\
33                 (pl) ? (pl)->base.base.id : -1, ##__VA_ARGS__)
34
35 #define DECIMATED_DIMENSION(dim, deci) (((dim) + ((1 << (deci)) - 1)) >> (deci))
36 #define PHASE_STEP_SHIFT        21
37 #define PHASE_STEP_UNIT_SCALE   ((int) (1 << PHASE_STEP_SHIFT))
38 #define PHASE_RESIDUAL          15
39
40 #define SHARP_STRENGTH_DEFAULT  32
41 #define SHARP_EDGE_THR_DEFAULT  112
42 #define SHARP_SMOOTH_THR_DEFAULT        8
43 #define SHARP_NOISE_THR_DEFAULT 2
44
45 #define DPU_NAME_SIZE  12
46
47 #define DPU_PLANE_COLOR_FILL_FLAG       BIT(31)
48 #define DPU_ZPOS_MAX 255
49
50 /* multirect rect index */
51 enum {
52         R0,
53         R1,
54         R_MAX
55 };
56
57 /*
58  * Default Preload Values
59  */
60 #define DPU_QSEED3_DEFAULT_PRELOAD_H 0x4
61 #define DPU_QSEED3_DEFAULT_PRELOAD_V 0x3
62 #define DPU_QSEED4_DEFAULT_PRELOAD_V 0x2
63 #define DPU_QSEED4_DEFAULT_PRELOAD_H 0x4
64
65 #define DEFAULT_REFRESH_RATE    60
66
67 static const uint32_t qcom_compressed_supported_formats[] = {
68         DRM_FORMAT_ABGR8888,
69         DRM_FORMAT_ARGB8888,
70         DRM_FORMAT_XBGR8888,
71         DRM_FORMAT_XRGB8888,
72         DRM_FORMAT_ARGB2101010,
73         DRM_FORMAT_XRGB2101010,
74         DRM_FORMAT_BGR565,
75
76         DRM_FORMAT_NV12,
77         DRM_FORMAT_P010,
78 };
79
80 /**
81  * enum dpu_plane_qos - Different qos configurations for each pipe
82  *
83  * @DPU_PLANE_QOS_VBLANK_CTRL: Setup VBLANK qos for the pipe.
84  * @DPU_PLANE_QOS_VBLANK_AMORTIZE: Enables Amortization within pipe.
85  *      this configuration is mutually exclusive from VBLANK_CTRL.
86  * @DPU_PLANE_QOS_PANIC_CTRL: Setup panic for the pipe.
87  */
88 enum dpu_plane_qos {
89         DPU_PLANE_QOS_VBLANK_CTRL = BIT(0),
90         DPU_PLANE_QOS_VBLANK_AMORTIZE = BIT(1),
91         DPU_PLANE_QOS_PANIC_CTRL = BIT(2),
92 };
93
94 /*
95  * struct dpu_plane - local dpu plane structure
96  * @aspace: address space pointer
97  * @csc_ptr: Points to dpu_csc_cfg structure to use for current
98  * @catalog: Points to dpu catalog structure
99  * @revalidate: force revalidation of all the plane properties
100  */
101 struct dpu_plane {
102         struct drm_plane base;
103
104         struct mutex lock;
105
106         enum dpu_sspp pipe;
107
108         uint32_t color_fill;
109         bool is_error;
110         bool is_rt_pipe;
111         const struct dpu_mdss_cfg *catalog;
112 };
113
114 static const uint64_t supported_format_modifiers[] = {
115         DRM_FORMAT_MOD_QCOM_COMPRESSED,
116         DRM_FORMAT_MOD_LINEAR,
117         DRM_FORMAT_MOD_INVALID
118 };
119
120 #define to_dpu_plane(x) container_of(x, struct dpu_plane, base)
121
122 static struct dpu_kms *_dpu_plane_get_kms(struct drm_plane *plane)
123 {
124         struct msm_drm_private *priv = plane->dev->dev_private;
125
126         return to_dpu_kms(priv->kms);
127 }
128
129 /**
130  * _dpu_plane_calc_bw - calculate bandwidth required for a plane
131  * @catalog: Points to dpu catalog structure
132  * @fmt: Pointer to source buffer format
133  * @mode: Pointer to drm display mode
134  * @pipe_cfg: Pointer to pipe configuration
135  * Result: Updates calculated bandwidth in the plane state.
136  * BW Equation: src_w * src_h * bpp * fps * (v_total / v_dest)
137  * Prefill BW Equation: line src bytes * line_time
138  */
139 static u64 _dpu_plane_calc_bw(const struct dpu_mdss_cfg *catalog,
140         const struct dpu_format *fmt,
141         const struct drm_display_mode *mode,
142         struct dpu_sw_pipe_cfg *pipe_cfg)
143 {
144         int src_width, src_height, dst_height, fps;
145         u64 plane_prefill_bw;
146         u64 plane_bw;
147         u32 hw_latency_lines;
148         u64 scale_factor;
149         int vbp, vpw, vfp;
150
151         src_width = drm_rect_width(&pipe_cfg->src_rect);
152         src_height = drm_rect_height(&pipe_cfg->src_rect);
153         dst_height = drm_rect_height(&pipe_cfg->dst_rect);
154         fps = drm_mode_vrefresh(mode);
155         vbp = mode->vtotal - mode->vsync_end;
156         vpw = mode->vsync_end - mode->vsync_start;
157         vfp = mode->vsync_start - mode->vdisplay;
158         hw_latency_lines =  catalog->perf->min_prefill_lines;
159         scale_factor = src_height > dst_height ?
160                 mult_frac(src_height, 1, dst_height) : 1;
161
162         plane_bw =
163                 src_width * mode->vtotal * fps * fmt->bpp *
164                 scale_factor;
165
166         plane_prefill_bw =
167                 src_width * hw_latency_lines * fps * fmt->bpp *
168                 scale_factor * mode->vtotal;
169
170         if ((vbp+vpw) > hw_latency_lines)
171                 do_div(plane_prefill_bw, (vbp+vpw));
172         else if ((vbp+vpw+vfp) < hw_latency_lines)
173                 do_div(plane_prefill_bw, (vbp+vpw+vfp));
174         else
175                 do_div(plane_prefill_bw, hw_latency_lines);
176
177
178         return max(plane_bw, plane_prefill_bw);
179 }
180
181 /**
182  * _dpu_plane_calc_clk - calculate clock required for a plane
183  * @mode: Pointer to drm display mode
184  * @pipe_cfg: Pointer to pipe configuration
185  * Result: Updates calculated clock in the plane state.
186  * Clock equation: dst_w * v_total * fps * (src_h / dst_h)
187  */
188 static u64 _dpu_plane_calc_clk(const struct drm_display_mode *mode,
189                 struct dpu_sw_pipe_cfg *pipe_cfg)
190 {
191         int dst_width, src_height, dst_height, fps;
192         u64 plane_clk;
193
194         src_height = drm_rect_height(&pipe_cfg->src_rect);
195         dst_width = drm_rect_width(&pipe_cfg->dst_rect);
196         dst_height = drm_rect_height(&pipe_cfg->dst_rect);
197         fps = drm_mode_vrefresh(mode);
198
199         plane_clk =
200                 dst_width * mode->vtotal * fps;
201
202         if (src_height > dst_height) {
203                 plane_clk *= src_height;
204                 do_div(plane_clk, dst_height);
205         }
206
207         return plane_clk;
208 }
209
210 /**
211  * _dpu_plane_calc_fill_level - calculate fill level of the given source format
212  * @plane:              Pointer to drm plane
213  * @pipe:               Pointer to software pipe
214  * @fmt:                Pointer to source buffer format
215  * @src_width:          width of source buffer
216  * Return: fill level corresponding to the source buffer/format or 0 if error
217  */
218 static int _dpu_plane_calc_fill_level(struct drm_plane *plane,
219                 struct dpu_sw_pipe *pipe,
220                 const struct dpu_format *fmt, u32 src_width)
221 {
222         struct dpu_plane *pdpu;
223         u32 fixed_buff_size;
224         u32 total_fl;
225
226         if (!fmt || !pipe || !src_width || !fmt->bpp) {
227                 DPU_ERROR("invalid arguments\n");
228                 return 0;
229         }
230
231         pdpu = to_dpu_plane(plane);
232         fixed_buff_size = pdpu->catalog->caps->pixel_ram_size;
233
234         /* FIXME: in multirect case account for the src_width of all the planes */
235
236         if (fmt->fetch_planes == DPU_PLANE_PSEUDO_PLANAR) {
237                 if (fmt->chroma_sample == DPU_CHROMA_420) {
238                         /* NV12 */
239                         total_fl = (fixed_buff_size / 2) /
240                                 ((src_width + 32) * fmt->bpp);
241                 } else {
242                         /* non NV12 */
243                         total_fl = (fixed_buff_size / 2) * 2 /
244                                 ((src_width + 32) * fmt->bpp);
245                 }
246         } else {
247                 if (pipe->multirect_mode == DPU_SSPP_MULTIRECT_PARALLEL) {
248                         total_fl = (fixed_buff_size / 2) * 2 /
249                                 ((src_width + 32) * fmt->bpp);
250                 } else {
251                         total_fl = (fixed_buff_size) * 2 /
252                                 ((src_width + 32) * fmt->bpp);
253                 }
254         }
255
256         DPU_DEBUG_PLANE(pdpu, "pnum:%d fmt: %4.4s w:%u fl:%u\n",
257                         pipe->sspp->idx - SSPP_VIG0,
258                         (char *)&fmt->base.pixel_format,
259                         src_width, total_fl);
260
261         return total_fl;
262 }
263
264 /**
265  * _dpu_plane_set_qos_lut - set QoS LUT of the given plane
266  * @plane:              Pointer to drm plane
267  * @pipe:               Pointer to software pipe
268  * @fmt:                Pointer to source buffer format
269  * @pipe_cfg:           Pointer to pipe configuration
270  */
271 static void _dpu_plane_set_qos_lut(struct drm_plane *plane,
272                 struct dpu_sw_pipe *pipe,
273                 const struct dpu_format *fmt, struct dpu_sw_pipe_cfg *pipe_cfg)
274 {
275         struct dpu_plane *pdpu = to_dpu_plane(plane);
276         u64 qos_lut;
277         u32 total_fl = 0, lut_usage;
278
279         if (!pdpu->is_rt_pipe) {
280                 lut_usage = DPU_QOS_LUT_USAGE_NRT;
281         } else {
282                 total_fl = _dpu_plane_calc_fill_level(plane, pipe, fmt,
283                                 drm_rect_width(&pipe_cfg->src_rect));
284
285                 if (fmt && DPU_FORMAT_IS_LINEAR(fmt))
286                         lut_usage = DPU_QOS_LUT_USAGE_LINEAR;
287                 else
288                         lut_usage = DPU_QOS_LUT_USAGE_MACROTILE;
289         }
290
291         qos_lut = _dpu_hw_get_qos_lut(
292                         &pdpu->catalog->perf->qos_lut_tbl[lut_usage], total_fl);
293
294         trace_dpu_perf_set_qos_luts(pipe->sspp->idx - SSPP_VIG0,
295                         (fmt) ? fmt->base.pixel_format : 0,
296                         pdpu->is_rt_pipe, total_fl, qos_lut, lut_usage);
297
298         DPU_DEBUG_PLANE(pdpu, "pnum:%d fmt: %4.4s rt:%d fl:%u lut:0x%llx\n",
299                         pdpu->pipe - SSPP_VIG0,
300                         fmt ? (char *)&fmt->base.pixel_format : NULL,
301                         pdpu->is_rt_pipe, total_fl, qos_lut);
302
303         pipe->sspp->ops.setup_creq_lut(pipe->sspp, qos_lut);
304 }
305
306 /**
307  * _dpu_plane_set_danger_lut - set danger/safe LUT of the given plane
308  * @plane:              Pointer to drm plane
309  * @pipe:               Pointer to software pipe
310  * @fmt:                Pointer to source buffer format
311  */
312 static void _dpu_plane_set_danger_lut(struct drm_plane *plane,
313                 struct dpu_sw_pipe *pipe,
314                 const struct dpu_format *fmt)
315 {
316         struct dpu_plane *pdpu = to_dpu_plane(plane);
317         u32 danger_lut, safe_lut;
318
319         if (!pdpu->is_rt_pipe) {
320                 danger_lut = pdpu->catalog->perf->danger_lut_tbl
321                                 [DPU_QOS_LUT_USAGE_NRT];
322                 safe_lut = pdpu->catalog->perf->safe_lut_tbl
323                                 [DPU_QOS_LUT_USAGE_NRT];
324         } else {
325                 if (fmt && DPU_FORMAT_IS_LINEAR(fmt)) {
326                         danger_lut = pdpu->catalog->perf->danger_lut_tbl
327                                         [DPU_QOS_LUT_USAGE_LINEAR];
328                         safe_lut = pdpu->catalog->perf->safe_lut_tbl
329                                         [DPU_QOS_LUT_USAGE_LINEAR];
330                 } else {
331                         danger_lut = pdpu->catalog->perf->danger_lut_tbl
332                                         [DPU_QOS_LUT_USAGE_MACROTILE];
333                         safe_lut = pdpu->catalog->perf->safe_lut_tbl
334                                         [DPU_QOS_LUT_USAGE_MACROTILE];
335                 }
336         }
337
338         trace_dpu_perf_set_danger_luts(pdpu->pipe - SSPP_VIG0,
339                         (fmt) ? fmt->base.pixel_format : 0,
340                         (fmt) ? fmt->fetch_mode : 0,
341                         danger_lut,
342                         safe_lut);
343
344         DPU_DEBUG_PLANE(pdpu, "pnum:%d fmt: %4.4s mode:%d luts[0x%x, 0x%x]\n",
345                 pdpu->pipe - SSPP_VIG0,
346                 fmt ? (char *)&fmt->base.pixel_format : NULL,
347                 fmt ? fmt->fetch_mode : -1,
348                 danger_lut,
349                 safe_lut);
350
351         pipe->sspp->ops.setup_danger_safe_lut(pipe->sspp,
352                         danger_lut, safe_lut);
353 }
354
355 /**
356  * _dpu_plane_set_qos_ctrl - set QoS control of the given plane
357  * @plane:              Pointer to drm plane
358  * @pipe:               Pointer to software pipe
359  * @enable:             true to enable QoS control
360  * @flags:              QoS control mode (enum dpu_plane_qos)
361  */
362 static void _dpu_plane_set_qos_ctrl(struct drm_plane *plane,
363         struct dpu_sw_pipe *pipe,
364         bool enable, u32 flags)
365 {
366         struct dpu_plane *pdpu = to_dpu_plane(plane);
367         struct dpu_hw_pipe_qos_cfg pipe_qos_cfg;
368
369         memset(&pipe_qos_cfg, 0, sizeof(pipe_qos_cfg));
370
371         if (flags & DPU_PLANE_QOS_VBLANK_CTRL) {
372                 pipe_qos_cfg.creq_vblank = pipe->sspp->cap->sblk->creq_vblank;
373                 pipe_qos_cfg.danger_vblank =
374                                 pipe->sspp->cap->sblk->danger_vblank;
375                 pipe_qos_cfg.vblank_en = enable;
376         }
377
378         if (flags & DPU_PLANE_QOS_VBLANK_AMORTIZE) {
379                 /* this feature overrules previous VBLANK_CTRL */
380                 pipe_qos_cfg.vblank_en = false;
381                 pipe_qos_cfg.creq_vblank = 0; /* clear vblank bits */
382         }
383
384         if (flags & DPU_PLANE_QOS_PANIC_CTRL)
385                 pipe_qos_cfg.danger_safe_en = enable;
386
387         if (!pdpu->is_rt_pipe) {
388                 pipe_qos_cfg.vblank_en = false;
389                 pipe_qos_cfg.danger_safe_en = false;
390         }
391
392         DPU_DEBUG_PLANE(pdpu, "pnum:%d ds:%d vb:%d pri[0x%x, 0x%x] is_rt:%d\n",
393                 pdpu->pipe - SSPP_VIG0,
394                 pipe_qos_cfg.danger_safe_en,
395                 pipe_qos_cfg.vblank_en,
396                 pipe_qos_cfg.creq_vblank,
397                 pipe_qos_cfg.danger_vblank,
398                 pdpu->is_rt_pipe);
399
400         pipe->sspp->ops.setup_qos_ctrl(pipe->sspp,
401                         &pipe_qos_cfg);
402 }
403
404 /**
405  * _dpu_plane_set_ot_limit - set OT limit for the given plane
406  * @plane:              Pointer to drm plane
407  * @pipe:               Pointer to software pipe
408  * @pipe_cfg:           Pointer to pipe configuration
409  * @frame_rate:         CRTC's frame rate
410  */
411 static void _dpu_plane_set_ot_limit(struct drm_plane *plane,
412                 struct dpu_sw_pipe *pipe,
413                 struct dpu_sw_pipe_cfg *pipe_cfg,
414                 int frame_rate)
415 {
416         struct dpu_plane *pdpu = to_dpu_plane(plane);
417         struct dpu_vbif_set_ot_params ot_params;
418         struct dpu_kms *dpu_kms = _dpu_plane_get_kms(plane);
419
420         memset(&ot_params, 0, sizeof(ot_params));
421         ot_params.xin_id = pipe->sspp->cap->xin_id;
422         ot_params.num = pipe->sspp->idx - SSPP_NONE;
423         ot_params.width = drm_rect_width(&pipe_cfg->src_rect);
424         ot_params.height = drm_rect_height(&pipe_cfg->src_rect);
425         ot_params.is_wfd = !pdpu->is_rt_pipe;
426         ot_params.frame_rate = frame_rate;
427         ot_params.vbif_idx = VBIF_RT;
428         ot_params.clk_ctrl = pipe->sspp->cap->clk_ctrl;
429         ot_params.rd = true;
430
431         dpu_vbif_set_ot_limit(dpu_kms, &ot_params);
432 }
433
434 /**
435  * _dpu_plane_set_qos_remap - set vbif QoS for the given plane
436  * @plane:              Pointer to drm plane
437  * @pipe:               Pointer to software pipe
438  */
439 static void _dpu_plane_set_qos_remap(struct drm_plane *plane,
440                 struct dpu_sw_pipe *pipe)
441 {
442         struct dpu_plane *pdpu = to_dpu_plane(plane);
443         struct dpu_vbif_set_qos_params qos_params;
444         struct dpu_kms *dpu_kms = _dpu_plane_get_kms(plane);
445
446         memset(&qos_params, 0, sizeof(qos_params));
447         qos_params.vbif_idx = VBIF_RT;
448         qos_params.clk_ctrl = pipe->sspp->cap->clk_ctrl;
449         qos_params.xin_id = pipe->sspp->cap->xin_id;
450         qos_params.num = pipe->sspp->idx - SSPP_VIG0;
451         qos_params.is_rt = pdpu->is_rt_pipe;
452
453         DPU_DEBUG_PLANE(pdpu, "pipe:%d vbif:%d xin:%d rt:%d, clk_ctrl:%d\n",
454                         qos_params.num,
455                         qos_params.vbif_idx,
456                         qos_params.xin_id, qos_params.is_rt,
457                         qos_params.clk_ctrl);
458
459         dpu_vbif_set_qos_remap(dpu_kms, &qos_params);
460 }
461
462 static void _dpu_plane_setup_scaler3(struct dpu_hw_sspp *pipe_hw,
463                 uint32_t src_w, uint32_t src_h, uint32_t dst_w, uint32_t dst_h,
464                 struct dpu_hw_scaler3_cfg *scale_cfg,
465                 const struct dpu_format *fmt,
466                 uint32_t chroma_subsmpl_h, uint32_t chroma_subsmpl_v,
467                 unsigned int rotation)
468 {
469         uint32_t i;
470         bool inline_rotation = rotation & DRM_MODE_ROTATE_90;
471
472         /*
473          * For inline rotation cases, scaler config is post-rotation,
474          * so swap the dimensions here. However, pixel extension will
475          * need pre-rotation settings.
476          */
477         if (inline_rotation)
478                 swap(src_w, src_h);
479
480         scale_cfg->phase_step_x[DPU_SSPP_COMP_0] =
481                 mult_frac((1 << PHASE_STEP_SHIFT), src_w, dst_w);
482         scale_cfg->phase_step_y[DPU_SSPP_COMP_0] =
483                 mult_frac((1 << PHASE_STEP_SHIFT), src_h, dst_h);
484
485
486         scale_cfg->phase_step_y[DPU_SSPP_COMP_1_2] =
487                 scale_cfg->phase_step_y[DPU_SSPP_COMP_0] / chroma_subsmpl_v;
488         scale_cfg->phase_step_x[DPU_SSPP_COMP_1_2] =
489                 scale_cfg->phase_step_x[DPU_SSPP_COMP_0] / chroma_subsmpl_h;
490
491         scale_cfg->phase_step_x[DPU_SSPP_COMP_2] =
492                 scale_cfg->phase_step_x[DPU_SSPP_COMP_1_2];
493         scale_cfg->phase_step_y[DPU_SSPP_COMP_2] =
494                 scale_cfg->phase_step_y[DPU_SSPP_COMP_1_2];
495
496         scale_cfg->phase_step_x[DPU_SSPP_COMP_3] =
497                 scale_cfg->phase_step_x[DPU_SSPP_COMP_0];
498         scale_cfg->phase_step_y[DPU_SSPP_COMP_3] =
499                 scale_cfg->phase_step_y[DPU_SSPP_COMP_0];
500
501         for (i = 0; i < DPU_MAX_PLANES; i++) {
502                 scale_cfg->src_width[i] = src_w;
503                 scale_cfg->src_height[i] = src_h;
504                 if (i == DPU_SSPP_COMP_1_2 || i == DPU_SSPP_COMP_2) {
505                         scale_cfg->src_width[i] /= chroma_subsmpl_h;
506                         scale_cfg->src_height[i] /= chroma_subsmpl_v;
507                 }
508
509                 if (pipe_hw->cap->features &
510                         BIT(DPU_SSPP_SCALER_QSEED4)) {
511                         scale_cfg->preload_x[i] = DPU_QSEED4_DEFAULT_PRELOAD_H;
512                         scale_cfg->preload_y[i] = DPU_QSEED4_DEFAULT_PRELOAD_V;
513                 } else {
514                         scale_cfg->preload_x[i] = DPU_QSEED3_DEFAULT_PRELOAD_H;
515                         scale_cfg->preload_y[i] = DPU_QSEED3_DEFAULT_PRELOAD_V;
516                 }
517         }
518         if (!(DPU_FORMAT_IS_YUV(fmt)) && (src_h == dst_h)
519                 && (src_w == dst_w))
520                 return;
521
522         scale_cfg->dst_width = dst_w;
523         scale_cfg->dst_height = dst_h;
524         scale_cfg->y_rgb_filter_cfg = DPU_SCALE_BIL;
525         scale_cfg->uv_filter_cfg = DPU_SCALE_BIL;
526         scale_cfg->alpha_filter_cfg = DPU_SCALE_ALPHA_BIL;
527         scale_cfg->lut_flag = 0;
528         scale_cfg->blend_cfg = 1;
529         scale_cfg->enable = 1;
530 }
531
532 static void _dpu_plane_setup_pixel_ext(struct dpu_hw_scaler3_cfg *scale_cfg,
533                                 struct dpu_hw_pixel_ext *pixel_ext,
534                                 uint32_t src_w, uint32_t src_h,
535                                 uint32_t chroma_subsmpl_h, uint32_t chroma_subsmpl_v)
536 {
537         int i;
538
539         for (i = 0; i < DPU_MAX_PLANES; i++) {
540                 if (i == DPU_SSPP_COMP_1_2 || i == DPU_SSPP_COMP_2) {
541                         src_w /= chroma_subsmpl_h;
542                         src_h /= chroma_subsmpl_v;
543                 }
544
545                 pixel_ext->num_ext_pxls_top[i] = src_h;
546                 pixel_ext->num_ext_pxls_left[i] = src_w;
547         }
548 }
549
550 static const struct dpu_csc_cfg dpu_csc_YUV2RGB_601L = {
551         {
552                 /* S15.16 format */
553                 0x00012A00, 0x00000000, 0x00019880,
554                 0x00012A00, 0xFFFF9B80, 0xFFFF3000,
555                 0x00012A00, 0x00020480, 0x00000000,
556         },
557         /* signed bias */
558         { 0xfff0, 0xff80, 0xff80,},
559         { 0x0, 0x0, 0x0,},
560         /* unsigned clamp */
561         { 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0,},
562         { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,},
563 };
564
565 static const struct dpu_csc_cfg dpu_csc10_YUV2RGB_601L = {
566         {
567                 /* S15.16 format */
568                 0x00012A00, 0x00000000, 0x00019880,
569                 0x00012A00, 0xFFFF9B80, 0xFFFF3000,
570                 0x00012A00, 0x00020480, 0x00000000,
571                 },
572         /* signed bias */
573         { 0xffc0, 0xfe00, 0xfe00,},
574         { 0x0, 0x0, 0x0,},
575         /* unsigned clamp */
576         { 0x40, 0x3ac, 0x40, 0x3c0, 0x40, 0x3c0,},
577         { 0x00, 0x3ff, 0x00, 0x3ff, 0x00, 0x3ff,},
578 };
579
580 static const struct dpu_csc_cfg *_dpu_plane_get_csc(struct dpu_sw_pipe *pipe,
581                                                     const struct dpu_format *fmt)
582 {
583         const struct dpu_csc_cfg *csc_ptr;
584
585         if (!DPU_FORMAT_IS_YUV(fmt))
586                 return NULL;
587
588         if (BIT(DPU_SSPP_CSC_10BIT) & pipe->sspp->cap->features)
589                 csc_ptr = &dpu_csc10_YUV2RGB_601L;
590         else
591                 csc_ptr = &dpu_csc_YUV2RGB_601L;
592
593         return csc_ptr;
594 }
595
596 static void _dpu_plane_setup_scaler(struct dpu_sw_pipe *pipe,
597                 const struct dpu_format *fmt, bool color_fill,
598                 struct dpu_sw_pipe_cfg *pipe_cfg,
599                 unsigned int rotation)
600 {
601         struct dpu_hw_sspp *pipe_hw = pipe->sspp;
602         const struct drm_format_info *info = drm_format_info(fmt->base.pixel_format);
603         struct dpu_hw_scaler3_cfg scaler3_cfg;
604         struct dpu_hw_pixel_ext pixel_ext;
605         u32 src_width = drm_rect_width(&pipe_cfg->src_rect);
606         u32 src_height = drm_rect_height(&pipe_cfg->src_rect);
607         u32 dst_width = drm_rect_width(&pipe_cfg->dst_rect);
608         u32 dst_height = drm_rect_height(&pipe_cfg->dst_rect);
609
610         memset(&scaler3_cfg, 0, sizeof(scaler3_cfg));
611         memset(&pixel_ext, 0, sizeof(pixel_ext));
612
613         /* don't chroma subsample if decimating */
614         /* update scaler. calculate default config for QSEED3 */
615         _dpu_plane_setup_scaler3(pipe_hw,
616                         src_width,
617                         src_height,
618                         dst_width,
619                         dst_height,
620                         &scaler3_cfg, fmt,
621                         info->hsub, info->vsub,
622                         rotation);
623
624         /* configure pixel extension based on scalar config */
625         _dpu_plane_setup_pixel_ext(&scaler3_cfg, &pixel_ext,
626                         src_width, src_height, info->hsub, info->vsub);
627
628         if (pipe_hw->ops.setup_pe)
629                 pipe_hw->ops.setup_pe(pipe_hw,
630                                 &pixel_ext);
631
632         /**
633          * when programmed in multirect mode, scalar block will be
634          * bypassed. Still we need to update alpha and bitwidth
635          * ONLY for RECT0
636          */
637         if (pipe_hw->ops.setup_scaler &&
638                         pipe->multirect_index != DPU_SSPP_RECT_1)
639                 pipe_hw->ops.setup_scaler(pipe_hw,
640                                 &scaler3_cfg,
641                                 fmt);
642 }
643
644 static void _dpu_plane_color_fill_pipe(struct dpu_plane_state *pstate,
645                                        struct dpu_sw_pipe *pipe,
646                                        struct drm_rect *dst_rect,
647                                        u32 fill_color,
648                                        const struct dpu_format *fmt)
649 {
650         struct dpu_sw_pipe_cfg pipe_cfg;
651
652         /* update sspp */
653         if (!pipe->sspp->ops.setup_solidfill)
654                 return;
655
656         pipe->sspp->ops.setup_solidfill(pipe, fill_color);
657
658         /* override scaler/decimation if solid fill */
659         pipe_cfg.dst_rect = *dst_rect;
660
661         pipe_cfg.src_rect.x1 = 0;
662         pipe_cfg.src_rect.y1 = 0;
663         pipe_cfg.src_rect.x2 =
664                 drm_rect_width(&pipe_cfg.dst_rect);
665         pipe_cfg.src_rect.y2 =
666                 drm_rect_height(&pipe_cfg.dst_rect);
667
668         if (pipe->sspp->ops.setup_format)
669                 pipe->sspp->ops.setup_format(pipe, fmt, DPU_SSPP_SOLID_FILL);
670
671         if (pipe->sspp->ops.setup_rects)
672                 pipe->sspp->ops.setup_rects(pipe, &pipe_cfg);
673
674         _dpu_plane_setup_scaler(pipe, fmt, true, &pipe_cfg, pstate->rotation);
675 }
676
677 /**
678  * _dpu_plane_color_fill - enables color fill on plane
679  * @pdpu:   Pointer to DPU plane object
680  * @color:  RGB fill color value, [23..16] Blue, [15..8] Green, [7..0] Red
681  * @alpha:  8-bit fill alpha value, 255 selects 100% alpha
682  */
683 static void _dpu_plane_color_fill(struct dpu_plane *pdpu,
684                 uint32_t color, uint32_t alpha)
685 {
686         const struct dpu_format *fmt;
687         const struct drm_plane *plane = &pdpu->base;
688         struct dpu_plane_state *pstate = to_dpu_plane_state(plane->state);
689         u32 fill_color = (color & 0xFFFFFF) | ((alpha & 0xFF) << 24);
690
691         DPU_DEBUG_PLANE(pdpu, "\n");
692
693         /*
694          * select fill format to match user property expectation,
695          * h/w only supports RGB variants
696          */
697         fmt = dpu_get_dpu_format(DRM_FORMAT_ABGR8888);
698         /* should not happen ever */
699         if (!fmt)
700                 return;
701
702         /* update sspp */
703         _dpu_plane_color_fill_pipe(pstate, &pstate->pipe, &pstate->pipe_cfg.dst_rect,
704                                    fill_color, fmt);
705
706         if (pstate->r_pipe.sspp)
707                 _dpu_plane_color_fill_pipe(pstate, &pstate->r_pipe, &pstate->r_pipe_cfg.dst_rect,
708                                            fill_color, fmt);
709 }
710
711 int dpu_plane_validate_multirect_v2(struct dpu_multirect_plane_states *plane)
712 {
713         struct dpu_plane_state *pstate[R_MAX];
714         const struct drm_plane_state *drm_state[R_MAX];
715         struct drm_rect src[R_MAX], dst[R_MAX];
716         struct dpu_plane *dpu_plane[R_MAX];
717         const struct dpu_format *fmt[R_MAX];
718         int i, buffer_lines;
719         unsigned int max_tile_height = 1;
720         bool parallel_fetch_qualified = true;
721         bool has_tiled_rect = false;
722
723         for (i = 0; i < R_MAX; i++) {
724                 const struct msm_format *msm_fmt;
725
726                 drm_state[i] = i ? plane->r1 : plane->r0;
727                 msm_fmt = msm_framebuffer_format(drm_state[i]->fb);
728                 fmt[i] = to_dpu_format(msm_fmt);
729
730                 if (DPU_FORMAT_IS_UBWC(fmt[i])) {
731                         has_tiled_rect = true;
732                         if (fmt[i]->tile_height > max_tile_height)
733                                 max_tile_height = fmt[i]->tile_height;
734                 }
735         }
736
737         for (i = 0; i < R_MAX; i++) {
738                 int width_threshold;
739
740                 pstate[i] = to_dpu_plane_state(drm_state[i]);
741                 dpu_plane[i] = to_dpu_plane(drm_state[i]->plane);
742
743                 if (pstate[i] == NULL) {
744                         DPU_ERROR("DPU plane state of plane id %d is NULL\n",
745                                 drm_state[i]->plane->base.id);
746                         return -EINVAL;
747                 }
748
749                 src[i].x1 = drm_state[i]->src_x >> 16;
750                 src[i].y1 = drm_state[i]->src_y >> 16;
751                 src[i].x2 = src[i].x1 + (drm_state[i]->src_w >> 16);
752                 src[i].y2 = src[i].y1 + (drm_state[i]->src_h >> 16);
753
754                 dst[i] = drm_plane_state_dest(drm_state[i]);
755
756                 if (drm_rect_calc_hscale(&src[i], &dst[i], 1, 1) != 1 ||
757                     drm_rect_calc_vscale(&src[i], &dst[i], 1, 1) != 1) {
758                         DPU_ERROR_PLANE(dpu_plane[i],
759                                 "scaling is not supported in multirect mode\n");
760                         return -EINVAL;
761                 }
762
763                 if (DPU_FORMAT_IS_YUV(fmt[i])) {
764                         DPU_ERROR_PLANE(dpu_plane[i],
765                                 "Unsupported format for multirect mode\n");
766                         return -EINVAL;
767                 }
768
769                 /**
770                  * SSPP PD_MEM is split half - one for each RECT.
771                  * Tiled formats need 5 lines of buffering while fetching
772                  * whereas linear formats need only 2 lines.
773                  * So we cannot support more than half of the supported SSPP
774                  * width for tiled formats.
775                  */
776                 width_threshold = dpu_plane[i]->catalog->caps->max_linewidth;
777                 if (has_tiled_rect)
778                         width_threshold /= 2;
779
780                 if (parallel_fetch_qualified &&
781                     drm_rect_width(&src[i]) > width_threshold)
782                         parallel_fetch_qualified = false;
783
784         }
785
786         /* Validate RECT's and set the mode */
787
788         /* Prefer PARALLEL FETCH Mode over TIME_MX Mode */
789         if (parallel_fetch_qualified) {
790                 pstate[R0]->pipe.multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL;
791                 pstate[R1]->pipe.multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL;
792
793                 goto done;
794         }
795
796         /* TIME_MX Mode */
797         buffer_lines = 2 * max_tile_height;
798
799         if (dst[R1].y1 >= dst[R0].y2 + buffer_lines ||
800             dst[R0].y1 >= dst[R1].y2 + buffer_lines) {
801                 pstate[R0]->pipe.multirect_mode = DPU_SSPP_MULTIRECT_TIME_MX;
802                 pstate[R1]->pipe.multirect_mode = DPU_SSPP_MULTIRECT_TIME_MX;
803         } else {
804                 DPU_ERROR(
805                         "No multirect mode possible for the planes (%d - %d)\n",
806                         drm_state[R0]->plane->base.id,
807                         drm_state[R1]->plane->base.id);
808                 return -EINVAL;
809         }
810
811 done:
812         pstate[R0]->pipe.multirect_index = DPU_SSPP_RECT_0;
813         pstate[R1]->pipe.multirect_index = DPU_SSPP_RECT_1;
814
815         DPU_DEBUG_PLANE(dpu_plane[R0], "R0: %d - %d\n",
816                 pstate[R0]->pipe.multirect_mode, pstate[R0]->pipe.multirect_index);
817         DPU_DEBUG_PLANE(dpu_plane[R1], "R1: %d - %d\n",
818                 pstate[R1]->pipe.multirect_mode, pstate[R1]->pipe.multirect_index);
819         return 0;
820 }
821
822 static int dpu_plane_prepare_fb(struct drm_plane *plane,
823                 struct drm_plane_state *new_state)
824 {
825         struct drm_framebuffer *fb = new_state->fb;
826         struct dpu_plane *pdpu = to_dpu_plane(plane);
827         struct dpu_plane_state *pstate = to_dpu_plane_state(new_state);
828         struct dpu_hw_fmt_layout layout;
829         struct dpu_kms *kms = _dpu_plane_get_kms(&pdpu->base);
830         int ret;
831
832         if (!new_state->fb)
833                 return 0;
834
835         DPU_DEBUG_PLANE(pdpu, "FB[%u]\n", fb->base.id);
836
837         /* cache aspace */
838         pstate->aspace = kms->base.aspace;
839
840         /*
841          * TODO: Need to sort out the msm_framebuffer_prepare() call below so
842          *       we can use msm_atomic_prepare_fb() instead of doing the
843          *       implicit fence and fb prepare by hand here.
844          */
845         drm_gem_plane_helper_prepare_fb(plane, new_state);
846
847         if (pstate->aspace) {
848                 ret = msm_framebuffer_prepare(new_state->fb,
849                                 pstate->aspace, pstate->needs_dirtyfb);
850                 if (ret) {
851                         DPU_ERROR("failed to prepare framebuffer\n");
852                         return ret;
853                 }
854         }
855
856         /* validate framebuffer layout before commit */
857         ret = dpu_format_populate_layout(pstate->aspace,
858                         new_state->fb, &layout);
859         if (ret) {
860                 DPU_ERROR_PLANE(pdpu, "failed to get format layout, %d\n", ret);
861                 return ret;
862         }
863
864         return 0;
865 }
866
867 static void dpu_plane_cleanup_fb(struct drm_plane *plane,
868                 struct drm_plane_state *old_state)
869 {
870         struct dpu_plane *pdpu = to_dpu_plane(plane);
871         struct dpu_plane_state *old_pstate;
872
873         if (!old_state || !old_state->fb)
874                 return;
875
876         old_pstate = to_dpu_plane_state(old_state);
877
878         DPU_DEBUG_PLANE(pdpu, "FB[%u]\n", old_state->fb->base.id);
879
880         msm_framebuffer_cleanup(old_state->fb, old_pstate->aspace,
881                                 old_pstate->needs_dirtyfb);
882 }
883
884 static int dpu_plane_check_inline_rotation(struct dpu_plane *pdpu,
885                                                 const struct dpu_sspp_sub_blks *sblk,
886                                                 struct drm_rect src, const struct dpu_format *fmt)
887 {
888         size_t num_formats;
889         const u32 *supported_formats;
890
891         if (!sblk->rotation_cfg) {
892                 DPU_ERROR("invalid rotation cfg\n");
893                 return -EINVAL;
894         }
895
896         if (drm_rect_width(&src) > sblk->rotation_cfg->rot_maxheight) {
897                 DPU_DEBUG_PLANE(pdpu, "invalid height for inline rot:%d max:%d\n",
898                                 src.y2, sblk->rotation_cfg->rot_maxheight);
899                 return -EINVAL;
900         }
901
902         supported_formats = sblk->rotation_cfg->rot_format_list;
903         num_formats = sblk->rotation_cfg->rot_num_formats;
904
905         if (!DPU_FORMAT_IS_UBWC(fmt) ||
906                 !dpu_find_format(fmt->base.pixel_format, supported_formats, num_formats))
907                 return -EINVAL;
908
909         return 0;
910 }
911
912 static int dpu_plane_atomic_check_pipe(struct dpu_plane *pdpu,
913                 struct dpu_sw_pipe *pipe,
914                 struct dpu_sw_pipe_cfg *pipe_cfg,
915                 const struct dpu_format *fmt)
916 {
917         uint32_t min_src_size;
918
919         min_src_size = DPU_FORMAT_IS_YUV(fmt) ? 2 : 1;
920
921         if (DPU_FORMAT_IS_YUV(fmt) &&
922             (!(pipe->sspp->cap->features & DPU_SSPP_SCALER) ||
923              !(pipe->sspp->cap->features & DPU_SSPP_CSC_ANY))) {
924                 DPU_DEBUG_PLANE(pdpu,
925                                 "plane doesn't have scaler/csc for yuv\n");
926                 return -EINVAL;
927         }
928
929         /* check src bounds */
930         if (drm_rect_width(&pipe_cfg->src_rect) < min_src_size ||
931             drm_rect_height(&pipe_cfg->src_rect) < min_src_size) {
932                 DPU_DEBUG_PLANE(pdpu, "invalid source " DRM_RECT_FMT "\n",
933                                 DRM_RECT_ARG(&pipe_cfg->src_rect));
934                 return -E2BIG;
935         }
936
937         /* valid yuv image */
938         if (DPU_FORMAT_IS_YUV(fmt) &&
939             (pipe_cfg->src_rect.x1 & 0x1 ||
940              pipe_cfg->src_rect.y1 & 0x1 ||
941              drm_rect_width(&pipe_cfg->src_rect) & 0x1 ||
942              drm_rect_height(&pipe_cfg->src_rect) & 0x1)) {
943                 DPU_DEBUG_PLANE(pdpu, "invalid yuv source " DRM_RECT_FMT "\n",
944                                 DRM_RECT_ARG(&pipe_cfg->src_rect));
945                 return -EINVAL;
946         }
947
948         /* min dst support */
949         if (drm_rect_width(&pipe_cfg->dst_rect) < 0x1 ||
950             drm_rect_height(&pipe_cfg->dst_rect) < 0x1) {
951                 DPU_DEBUG_PLANE(pdpu, "invalid dest rect " DRM_RECT_FMT "\n",
952                                 DRM_RECT_ARG(&pipe_cfg->dst_rect));
953                 return -EINVAL;
954         }
955
956         return 0;
957 }
958
959 static int dpu_plane_atomic_check(struct drm_plane *plane,
960                                   struct drm_atomic_state *state)
961 {
962         struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
963                                                                                  plane);
964         int ret = 0, min_scale;
965         struct dpu_plane *pdpu = to_dpu_plane(plane);
966         struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state);
967         struct dpu_sw_pipe *pipe = &pstate->pipe;
968         struct dpu_sw_pipe *r_pipe = &pstate->r_pipe;
969         const struct drm_crtc_state *crtc_state = NULL;
970         const struct dpu_format *fmt;
971         struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg;
972         struct dpu_sw_pipe_cfg *r_pipe_cfg = &pstate->r_pipe_cfg;
973         struct drm_rect fb_rect = { 0 };
974         uint32_t max_linewidth;
975         unsigned int rotation;
976         uint32_t supported_rotations;
977         const struct dpu_sspp_cfg *pipe_hw_caps = pstate->pipe.sspp->cap;
978         const struct dpu_sspp_sub_blks *sblk = pstate->pipe.sspp->cap->sblk;
979
980         if (new_plane_state->crtc)
981                 crtc_state = drm_atomic_get_new_crtc_state(state,
982                                                            new_plane_state->crtc);
983
984         min_scale = FRAC_16_16(1, sblk->maxupscale);
985         ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
986                                                   min_scale,
987                                                   sblk->maxdwnscale << 16,
988                                                   true, true);
989         if (ret) {
990                 DPU_DEBUG_PLANE(pdpu, "Check plane state failed (%d)\n", ret);
991                 return ret;
992         }
993         if (!new_plane_state->visible)
994                 return 0;
995
996         pipe->multirect_index = DPU_SSPP_RECT_SOLO;
997         pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE;
998         r_pipe->multirect_index = DPU_SSPP_RECT_SOLO;
999         r_pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE;
1000         r_pipe->sspp = NULL;
1001
1002         pstate->stage = DPU_STAGE_0 + pstate->base.normalized_zpos;
1003         if (pstate->stage >= pdpu->catalog->caps->max_mixer_blendstages) {
1004                 DPU_ERROR("> %d plane stages assigned\n",
1005                           pdpu->catalog->caps->max_mixer_blendstages - DPU_STAGE_0);
1006                 return -EINVAL;
1007         }
1008
1009         pipe_cfg->src_rect = new_plane_state->src;
1010
1011         /* state->src is 16.16, src_rect is not */
1012         pipe_cfg->src_rect.x1 >>= 16;
1013         pipe_cfg->src_rect.x2 >>= 16;
1014         pipe_cfg->src_rect.y1 >>= 16;
1015         pipe_cfg->src_rect.y2 >>= 16;
1016
1017         pipe_cfg->dst_rect = new_plane_state->dst;
1018
1019         fb_rect.x2 = new_plane_state->fb->width;
1020         fb_rect.y2 = new_plane_state->fb->height;
1021
1022         /* Ensure fb size is supported */
1023         if (drm_rect_width(&fb_rect) > MAX_IMG_WIDTH ||
1024             drm_rect_height(&fb_rect) > MAX_IMG_HEIGHT) {
1025                 DPU_DEBUG_PLANE(pdpu, "invalid framebuffer " DRM_RECT_FMT "\n",
1026                                 DRM_RECT_ARG(&fb_rect));
1027                 return -E2BIG;
1028         }
1029
1030         fmt = to_dpu_format(msm_framebuffer_format(new_plane_state->fb));
1031
1032         max_linewidth = pdpu->catalog->caps->max_linewidth;
1033
1034         if (drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) {
1035                 /*
1036                  * In parallel multirect case only the half of the usual width
1037                  * is supported for tiled formats. If we are here, we know that
1038                  * full width is more than max_linewidth, thus each rect is
1039                  * wider than allowed.
1040                  */
1041                 if (DPU_FORMAT_IS_UBWC(fmt)) {
1042                         DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u, tiled format\n",
1043                                         DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth);
1044                         return -E2BIG;
1045                 }
1046
1047                 if (drm_rect_width(&pipe_cfg->src_rect) > 2 * max_linewidth) {
1048                         DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u\n",
1049                                         DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth);
1050                         return -E2BIG;
1051                 }
1052
1053                 if (drm_rect_width(&pipe_cfg->src_rect) != drm_rect_width(&pipe_cfg->dst_rect) ||
1054                     drm_rect_height(&pipe_cfg->src_rect) != drm_rect_height(&pipe_cfg->dst_rect) ||
1055                     (!test_bit(DPU_SSPP_SMART_DMA_V1, &pipe->sspp->cap->features) &&
1056                      !test_bit(DPU_SSPP_SMART_DMA_V2, &pipe->sspp->cap->features)) ||
1057                     DPU_FORMAT_IS_YUV(fmt)) {
1058                         DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u, can't use split source\n",
1059                                         DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth);
1060                         return -E2BIG;
1061                 }
1062
1063                 /*
1064                  * Use multirect for wide plane. We do not support dynamic
1065                  * assignment of SSPPs, so we know the configuration.
1066                  */
1067                 pipe->multirect_index = DPU_SSPP_RECT_0;
1068                 pipe->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL;
1069
1070                 r_pipe->sspp = pipe->sspp;
1071                 r_pipe->multirect_index = DPU_SSPP_RECT_1;
1072                 r_pipe->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL;
1073
1074                 *r_pipe_cfg = *pipe_cfg;
1075                 pipe_cfg->src_rect.x2 = (pipe_cfg->src_rect.x1 + pipe_cfg->src_rect.x2) >> 1;
1076                 pipe_cfg->dst_rect.x2 = (pipe_cfg->dst_rect.x1 + pipe_cfg->dst_rect.x2) >> 1;
1077                 r_pipe_cfg->src_rect.x1 = pipe_cfg->src_rect.x2;
1078                 r_pipe_cfg->dst_rect.x1 = pipe_cfg->dst_rect.x2;
1079         }
1080
1081         ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg, fmt);
1082         if (ret)
1083                 return ret;
1084
1085         if (r_pipe->sspp) {
1086                 ret = dpu_plane_atomic_check_pipe(pdpu, r_pipe, r_pipe_cfg, fmt);
1087                 if (ret)
1088                         return ret;
1089         }
1090
1091         supported_rotations = DRM_MODE_REFLECT_MASK | DRM_MODE_ROTATE_0;
1092
1093         if (pipe_hw_caps->features & BIT(DPU_SSPP_INLINE_ROTATION))
1094                 supported_rotations |= DRM_MODE_ROTATE_90;
1095
1096         rotation = drm_rotation_simplify(new_plane_state->rotation,
1097                                         supported_rotations);
1098
1099         if ((pipe_hw_caps->features & BIT(DPU_SSPP_INLINE_ROTATION)) &&
1100                 (rotation & DRM_MODE_ROTATE_90)) {
1101                 ret = dpu_plane_check_inline_rotation(pdpu, sblk, pipe_cfg->src_rect, fmt);
1102                 if (ret)
1103                         return ret;
1104         }
1105
1106         pstate->rotation = rotation;
1107         pstate->needs_qos_remap = drm_atomic_crtc_needs_modeset(crtc_state);
1108
1109         return 0;
1110 }
1111
1112 static void dpu_plane_flush_csc(struct dpu_plane *pdpu, struct dpu_sw_pipe *pipe)
1113 {
1114         const struct dpu_format *format =
1115                 to_dpu_format(msm_framebuffer_format(pdpu->base.state->fb));
1116         const struct dpu_csc_cfg *csc_ptr;
1117
1118         if (!pipe->sspp || !pipe->sspp->ops.setup_csc)
1119                 return;
1120
1121         csc_ptr = _dpu_plane_get_csc(pipe, format);
1122         if (!csc_ptr)
1123                 return;
1124
1125         DPU_DEBUG_PLANE(pdpu, "using 0x%X 0x%X 0x%X...\n",
1126                         csc_ptr->csc_mv[0],
1127                         csc_ptr->csc_mv[1],
1128                         csc_ptr->csc_mv[2]);
1129
1130         pipe->sspp->ops.setup_csc(pipe->sspp, csc_ptr);
1131
1132 }
1133
1134 void dpu_plane_flush(struct drm_plane *plane)
1135 {
1136         struct dpu_plane *pdpu;
1137         struct dpu_plane_state *pstate;
1138
1139         if (!plane || !plane->state) {
1140                 DPU_ERROR("invalid plane\n");
1141                 return;
1142         }
1143
1144         pdpu = to_dpu_plane(plane);
1145         pstate = to_dpu_plane_state(plane->state);
1146
1147         /*
1148          * These updates have to be done immediately before the plane flush
1149          * timing, and may not be moved to the atomic_update/mode_set functions.
1150          */
1151         if (pdpu->is_error)
1152                 /* force white frame with 100% alpha pipe output on error */
1153                 _dpu_plane_color_fill(pdpu, 0xFFFFFF, 0xFF);
1154         else if (pdpu->color_fill & DPU_PLANE_COLOR_FILL_FLAG)
1155                 /* force 100% alpha */
1156                 _dpu_plane_color_fill(pdpu, pdpu->color_fill, 0xFF);
1157         else {
1158                 dpu_plane_flush_csc(pdpu, &pstate->pipe);
1159                 dpu_plane_flush_csc(pdpu, &pstate->r_pipe);
1160         }
1161
1162         /* flag h/w flush complete */
1163         if (plane->state)
1164                 pstate->pending = false;
1165 }
1166
1167 /**
1168  * dpu_plane_set_error: enable/disable error condition
1169  * @plane: pointer to drm_plane structure
1170  * @error: error value to set
1171  */
1172 void dpu_plane_set_error(struct drm_plane *plane, bool error)
1173 {
1174         struct dpu_plane *pdpu;
1175
1176         if (!plane)
1177                 return;
1178
1179         pdpu = to_dpu_plane(plane);
1180         pdpu->is_error = error;
1181 }
1182
1183 static void dpu_plane_sspp_update_pipe(struct drm_plane *plane,
1184                                        struct dpu_sw_pipe *pipe,
1185                                        struct dpu_sw_pipe_cfg *pipe_cfg,
1186                                        const struct dpu_format *fmt,
1187                                        int frame_rate,
1188                                        struct dpu_hw_fmt_layout *layout)
1189 {
1190         uint32_t src_flags;
1191         struct dpu_plane *pdpu = to_dpu_plane(plane);
1192         struct drm_plane_state *state = plane->state;
1193         struct dpu_plane_state *pstate = to_dpu_plane_state(state);
1194
1195         if (layout && pipe->sspp->ops.setup_sourceaddress) {
1196                 trace_dpu_plane_set_scanout(pipe, layout);
1197                 pipe->sspp->ops.setup_sourceaddress(pipe, layout);
1198         }
1199
1200         _dpu_plane_set_qos_ctrl(plane, pipe, false, DPU_PLANE_QOS_PANIC_CTRL);
1201
1202         /* override for color fill */
1203         if (pdpu->color_fill & DPU_PLANE_COLOR_FILL_FLAG) {
1204                 /* skip remaining processing on color fill */
1205                 return;
1206         }
1207
1208         if (pipe->sspp->ops.setup_rects) {
1209                 pipe->sspp->ops.setup_rects(pipe,
1210                                 pipe_cfg);
1211         }
1212
1213         _dpu_plane_setup_scaler(pipe, fmt, false, pipe_cfg, pstate->rotation);
1214
1215         if (pipe->sspp->ops.setup_multirect)
1216                 pipe->sspp->ops.setup_multirect(
1217                                 pipe);
1218
1219         if (pipe->sspp->ops.setup_format) {
1220                 unsigned int rotation = pstate->rotation;
1221
1222                 src_flags = 0x0;
1223
1224                 if (rotation & DRM_MODE_REFLECT_X)
1225                         src_flags |= DPU_SSPP_FLIP_LR;
1226
1227                 if (rotation & DRM_MODE_REFLECT_Y)
1228                         src_flags |= DPU_SSPP_FLIP_UD;
1229
1230                 if (rotation & DRM_MODE_ROTATE_90)
1231                         src_flags |= DPU_SSPP_ROT_90;
1232
1233                 /* update format */
1234                 pipe->sspp->ops.setup_format(pipe, fmt, src_flags);
1235
1236                 if (pipe->sspp->ops.setup_cdp) {
1237                         struct dpu_hw_cdp_cfg cdp_cfg;
1238
1239                         memset(&cdp_cfg, 0, sizeof(struct dpu_hw_cdp_cfg));
1240
1241                         cdp_cfg.enable = pdpu->catalog->perf->cdp_cfg
1242                                         [DPU_PERF_CDP_USAGE_RT].rd_enable;
1243                         cdp_cfg.ubwc_meta_enable =
1244                                         DPU_FORMAT_IS_UBWC(fmt);
1245                         cdp_cfg.tile_amortize_enable =
1246                                         DPU_FORMAT_IS_UBWC(fmt) ||
1247                                         DPU_FORMAT_IS_TILE(fmt);
1248                         cdp_cfg.preload_ahead = DPU_SSPP_CDP_PRELOAD_AHEAD_64;
1249
1250                         pipe->sspp->ops.setup_cdp(pipe, &cdp_cfg);
1251                 }
1252         }
1253
1254         _dpu_plane_set_qos_lut(plane, pipe, fmt, pipe_cfg);
1255         _dpu_plane_set_danger_lut(plane, pipe, fmt);
1256
1257         if (plane->type != DRM_PLANE_TYPE_CURSOR) {
1258                 _dpu_plane_set_qos_ctrl(plane, pipe, true, DPU_PLANE_QOS_PANIC_CTRL);
1259                 _dpu_plane_set_ot_limit(plane, pipe, pipe_cfg, frame_rate);
1260         }
1261
1262         if (pstate->needs_qos_remap)
1263                 _dpu_plane_set_qos_remap(plane, pipe);
1264 }
1265
1266 static void dpu_plane_sspp_atomic_update(struct drm_plane *plane)
1267 {
1268         struct dpu_plane *pdpu = to_dpu_plane(plane);
1269         struct drm_plane_state *state = plane->state;
1270         struct dpu_plane_state *pstate = to_dpu_plane_state(state);
1271         struct dpu_sw_pipe *pipe = &pstate->pipe;
1272         struct dpu_sw_pipe *r_pipe = &pstate->r_pipe;
1273         struct drm_crtc *crtc = state->crtc;
1274         struct drm_framebuffer *fb = state->fb;
1275         bool is_rt_pipe;
1276         const struct dpu_format *fmt =
1277                 to_dpu_format(msm_framebuffer_format(fb));
1278         struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg;
1279         struct dpu_sw_pipe_cfg *r_pipe_cfg = &pstate->r_pipe_cfg;
1280         struct dpu_kms *kms = _dpu_plane_get_kms(&pdpu->base);
1281         struct msm_gem_address_space *aspace = kms->base.aspace;
1282         struct dpu_hw_fmt_layout layout;
1283         bool layout_valid = false;
1284         int ret;
1285
1286         ret = dpu_format_populate_layout(aspace, fb, &layout);
1287         if (ret)
1288                 DPU_ERROR_PLANE(pdpu, "failed to get format layout, %d\n", ret);
1289         else
1290                 layout_valid = true;
1291
1292         pstate->pending = true;
1293
1294         is_rt_pipe = (dpu_crtc_get_client_type(crtc) != NRT_CLIENT);
1295         pstate->needs_qos_remap |= (is_rt_pipe != pdpu->is_rt_pipe);
1296         pdpu->is_rt_pipe = is_rt_pipe;
1297
1298         DPU_DEBUG_PLANE(pdpu, "FB[%u] " DRM_RECT_FP_FMT "->crtc%u " DRM_RECT_FMT
1299                         ", %4.4s ubwc %d\n", fb->base.id, DRM_RECT_FP_ARG(&state->src),
1300                         crtc->base.id, DRM_RECT_ARG(&state->dst),
1301                         (char *)&fmt->base.pixel_format, DPU_FORMAT_IS_UBWC(fmt));
1302
1303         dpu_plane_sspp_update_pipe(plane, pipe, pipe_cfg, fmt,
1304                                    drm_mode_vrefresh(&crtc->mode),
1305                                    layout_valid ? &layout : NULL);
1306
1307         if (r_pipe->sspp) {
1308                 dpu_plane_sspp_update_pipe(plane, r_pipe, r_pipe_cfg, fmt,
1309                                            drm_mode_vrefresh(&crtc->mode),
1310                                            layout_valid ? &layout : NULL);
1311         }
1312
1313         if (pstate->needs_qos_remap)
1314                 pstate->needs_qos_remap = false;
1315
1316         pstate->plane_fetch_bw = _dpu_plane_calc_bw(pdpu->catalog, fmt,
1317                                                     &crtc->mode, pipe_cfg);
1318
1319         pstate->plane_clk = _dpu_plane_calc_clk(&crtc->mode, pipe_cfg);
1320
1321         if (r_pipe->sspp) {
1322                 pstate->plane_fetch_bw += _dpu_plane_calc_bw(pdpu->catalog, fmt, &crtc->mode, r_pipe_cfg);
1323
1324                 pstate->plane_clk = max(pstate->plane_clk, _dpu_plane_calc_clk(&crtc->mode, r_pipe_cfg));
1325         }
1326 }
1327
1328 static void _dpu_plane_atomic_disable(struct drm_plane *plane)
1329 {
1330         struct drm_plane_state *state = plane->state;
1331         struct dpu_plane_state *pstate = to_dpu_plane_state(state);
1332         struct dpu_sw_pipe *r_pipe = &pstate->r_pipe;
1333
1334         trace_dpu_plane_disable(DRMID(plane), false,
1335                                 pstate->pipe.multirect_mode);
1336
1337         if (r_pipe->sspp) {
1338                 r_pipe->multirect_index = DPU_SSPP_RECT_SOLO;
1339                 r_pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE;
1340
1341                 if (r_pipe->sspp->ops.setup_multirect)
1342                         r_pipe->sspp->ops.setup_multirect(r_pipe);
1343         }
1344
1345         pstate->pending = true;
1346 }
1347
1348 static void dpu_plane_atomic_update(struct drm_plane *plane,
1349                                 struct drm_atomic_state *state)
1350 {
1351         struct dpu_plane *pdpu = to_dpu_plane(plane);
1352         struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
1353                                                                            plane);
1354
1355         pdpu->is_error = false;
1356
1357         DPU_DEBUG_PLANE(pdpu, "\n");
1358
1359         if (!new_state->visible) {
1360                 _dpu_plane_atomic_disable(plane);
1361         } else {
1362                 dpu_plane_sspp_atomic_update(plane);
1363         }
1364 }
1365
1366 static void dpu_plane_destroy(struct drm_plane *plane)
1367 {
1368         struct dpu_plane *pdpu = plane ? to_dpu_plane(plane) : NULL;
1369         struct dpu_plane_state *pstate;
1370
1371         DPU_DEBUG_PLANE(pdpu, "\n");
1372
1373         if (pdpu) {
1374                 pstate = to_dpu_plane_state(plane->state);
1375                 _dpu_plane_set_qos_ctrl(plane, &pstate->pipe, false, DPU_PLANE_QOS_PANIC_CTRL);
1376
1377                 if (pstate->r_pipe.sspp)
1378                         _dpu_plane_set_qos_ctrl(plane, &pstate->r_pipe, false, DPU_PLANE_QOS_PANIC_CTRL);
1379
1380                 mutex_destroy(&pdpu->lock);
1381
1382                 /* this will destroy the states as well */
1383                 drm_plane_cleanup(plane);
1384
1385                 kfree(pdpu);
1386         }
1387 }
1388
1389 static void dpu_plane_destroy_state(struct drm_plane *plane,
1390                 struct drm_plane_state *state)
1391 {
1392         __drm_atomic_helper_plane_destroy_state(state);
1393         kfree(to_dpu_plane_state(state));
1394 }
1395
1396 static struct drm_plane_state *
1397 dpu_plane_duplicate_state(struct drm_plane *plane)
1398 {
1399         struct dpu_plane *pdpu;
1400         struct dpu_plane_state *pstate;
1401         struct dpu_plane_state *old_state;
1402
1403         if (!plane) {
1404                 DPU_ERROR("invalid plane\n");
1405                 return NULL;
1406         } else if (!plane->state) {
1407                 DPU_ERROR("invalid plane state\n");
1408                 return NULL;
1409         }
1410
1411         old_state = to_dpu_plane_state(plane->state);
1412         pdpu = to_dpu_plane(plane);
1413         pstate = kmemdup(old_state, sizeof(*old_state), GFP_KERNEL);
1414         if (!pstate) {
1415                 DPU_ERROR_PLANE(pdpu, "failed to allocate state\n");
1416                 return NULL;
1417         }
1418
1419         DPU_DEBUG_PLANE(pdpu, "\n");
1420
1421         pstate->pending = false;
1422
1423         __drm_atomic_helper_plane_duplicate_state(plane, &pstate->base);
1424
1425         return &pstate->base;
1426 }
1427
1428 static const char * const multirect_mode_name[] = {
1429         [DPU_SSPP_MULTIRECT_NONE] = "none",
1430         [DPU_SSPP_MULTIRECT_PARALLEL] = "parallel",
1431         [DPU_SSPP_MULTIRECT_TIME_MX] = "time_mx",
1432 };
1433
1434 static const char * const multirect_index_name[] = {
1435         [DPU_SSPP_RECT_SOLO] = "solo",
1436         [DPU_SSPP_RECT_0] = "rect_0",
1437         [DPU_SSPP_RECT_1] = "rect_1",
1438 };
1439
1440 static const char *dpu_get_multirect_mode(enum dpu_sspp_multirect_mode mode)
1441 {
1442         if (WARN_ON(mode >= ARRAY_SIZE(multirect_mode_name)))
1443                 return "unknown";
1444
1445         return multirect_mode_name[mode];
1446 }
1447
1448 static const char *dpu_get_multirect_index(enum dpu_sspp_multirect_index index)
1449 {
1450         if (WARN_ON(index >= ARRAY_SIZE(multirect_index_name)))
1451                 return "unknown";
1452
1453         return multirect_index_name[index];
1454 }
1455
1456 static void dpu_plane_atomic_print_state(struct drm_printer *p,
1457                 const struct drm_plane_state *state)
1458 {
1459         const struct dpu_plane_state *pstate = to_dpu_plane_state(state);
1460         const struct dpu_sw_pipe *pipe = &pstate->pipe;
1461         const struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg;
1462         const struct dpu_sw_pipe *r_pipe = &pstate->r_pipe;
1463         const struct dpu_sw_pipe_cfg *r_pipe_cfg = &pstate->r_pipe_cfg;
1464
1465         drm_printf(p, "\tstage=%d\n", pstate->stage);
1466
1467         drm_printf(p, "\tsspp[0]=%s\n", pipe->sspp->cap->name);
1468         drm_printf(p, "\tmultirect_mode[0]=%s\n", dpu_get_multirect_mode(pipe->multirect_mode));
1469         drm_printf(p, "\tmultirect_index[0]=%s\n",
1470                    dpu_get_multirect_index(pipe->multirect_index));
1471         drm_printf(p, "\tsrc[0]=" DRM_RECT_FMT "\n", DRM_RECT_ARG(&pipe_cfg->src_rect));
1472         drm_printf(p, "\tdst[0]=" DRM_RECT_FMT "\n", DRM_RECT_ARG(&pipe_cfg->dst_rect));
1473
1474         if (r_pipe->sspp) {
1475                 drm_printf(p, "\tsspp[1]=%s\n", r_pipe->sspp->cap->name);
1476                 drm_printf(p, "\tmultirect_mode[1]=%s\n",
1477                            dpu_get_multirect_mode(r_pipe->multirect_mode));
1478                 drm_printf(p, "\tmultirect_index[1]=%s\n",
1479                            dpu_get_multirect_index(r_pipe->multirect_index));
1480                 drm_printf(p, "\tsrc[1]=" DRM_RECT_FMT "\n", DRM_RECT_ARG(&r_pipe_cfg->src_rect));
1481                 drm_printf(p, "\tdst[1]=" DRM_RECT_FMT "\n", DRM_RECT_ARG(&r_pipe_cfg->dst_rect));
1482         }
1483 }
1484
1485 static void dpu_plane_reset(struct drm_plane *plane)
1486 {
1487         struct dpu_plane *pdpu;
1488         struct dpu_plane_state *pstate;
1489         struct dpu_kms *dpu_kms = _dpu_plane_get_kms(plane);
1490
1491         if (!plane) {
1492                 DPU_ERROR("invalid plane\n");
1493                 return;
1494         }
1495
1496         pdpu = to_dpu_plane(plane);
1497         DPU_DEBUG_PLANE(pdpu, "\n");
1498
1499         /* remove previous state, if present */
1500         if (plane->state) {
1501                 dpu_plane_destroy_state(plane, plane->state);
1502                 plane->state = NULL;
1503         }
1504
1505         pstate = kzalloc(sizeof(*pstate), GFP_KERNEL);
1506         if (!pstate) {
1507                 DPU_ERROR_PLANE(pdpu, "failed to allocate state\n");
1508                 return;
1509         }
1510
1511         /*
1512          * Set the SSPP here until we have proper virtualized DPU planes.
1513          * This is the place where the state is allocated, so fill it fully.
1514          */
1515         pstate->pipe.sspp = dpu_rm_get_sspp(&dpu_kms->rm, pdpu->pipe);
1516         pstate->pipe.multirect_index = DPU_SSPP_RECT_SOLO;
1517         pstate->pipe.multirect_mode = DPU_SSPP_MULTIRECT_NONE;
1518
1519         pstate->r_pipe.sspp = NULL;
1520
1521         __drm_atomic_helper_plane_reset(plane, &pstate->base);
1522 }
1523
1524 #ifdef CONFIG_DEBUG_FS
1525 void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable)
1526 {
1527         struct dpu_plane *pdpu = to_dpu_plane(plane);
1528         struct dpu_plane_state *pstate = to_dpu_plane_state(plane->state);
1529         struct dpu_kms *dpu_kms = _dpu_plane_get_kms(plane);
1530
1531         if (!pdpu->is_rt_pipe)
1532                 return;
1533
1534         pm_runtime_get_sync(&dpu_kms->pdev->dev);
1535         _dpu_plane_set_qos_ctrl(plane, &pstate->pipe, enable, DPU_PLANE_QOS_PANIC_CTRL);
1536         if (pstate->r_pipe.sspp)
1537                 _dpu_plane_set_qos_ctrl(plane, &pstate->r_pipe, enable, DPU_PLANE_QOS_PANIC_CTRL);
1538         pm_runtime_put_sync(&dpu_kms->pdev->dev);
1539 }
1540 #endif
1541
1542 static bool dpu_plane_format_mod_supported(struct drm_plane *plane,
1543                 uint32_t format, uint64_t modifier)
1544 {
1545         if (modifier == DRM_FORMAT_MOD_LINEAR)
1546                 return true;
1547
1548         if (modifier == DRM_FORMAT_MOD_QCOM_COMPRESSED)
1549                 return dpu_find_format(format, qcom_compressed_supported_formats,
1550                                 ARRAY_SIZE(qcom_compressed_supported_formats));
1551
1552         return false;
1553 }
1554
1555 static const struct drm_plane_funcs dpu_plane_funcs = {
1556                 .update_plane = drm_atomic_helper_update_plane,
1557                 .disable_plane = drm_atomic_helper_disable_plane,
1558                 .destroy = dpu_plane_destroy,
1559                 .reset = dpu_plane_reset,
1560                 .atomic_duplicate_state = dpu_plane_duplicate_state,
1561                 .atomic_destroy_state = dpu_plane_destroy_state,
1562                 .atomic_print_state = dpu_plane_atomic_print_state,
1563                 .format_mod_supported = dpu_plane_format_mod_supported,
1564 };
1565
1566 static const struct drm_plane_helper_funcs dpu_plane_helper_funcs = {
1567                 .prepare_fb = dpu_plane_prepare_fb,
1568                 .cleanup_fb = dpu_plane_cleanup_fb,
1569                 .atomic_check = dpu_plane_atomic_check,
1570                 .atomic_update = dpu_plane_atomic_update,
1571 };
1572
1573 /* initialize plane */
1574 struct drm_plane *dpu_plane_init(struct drm_device *dev,
1575                 uint32_t pipe, enum drm_plane_type type,
1576                 unsigned long possible_crtcs)
1577 {
1578         struct drm_plane *plane = NULL;
1579         const uint32_t *format_list;
1580         struct dpu_plane *pdpu;
1581         struct msm_drm_private *priv = dev->dev_private;
1582         struct dpu_kms *kms = to_dpu_kms(priv->kms);
1583         struct dpu_hw_sspp *pipe_hw;
1584         uint32_t num_formats;
1585         uint32_t supported_rotations;
1586         int ret = -EINVAL;
1587
1588         /* create and zero local structure */
1589         pdpu = kzalloc(sizeof(*pdpu), GFP_KERNEL);
1590         if (!pdpu) {
1591                 DPU_ERROR("[%u]failed to allocate local plane struct\n", pipe);
1592                 ret = -ENOMEM;
1593                 return ERR_PTR(ret);
1594         }
1595
1596         /* cache local stuff for later */
1597         plane = &pdpu->base;
1598         pdpu->pipe = pipe;
1599
1600         /* initialize underlying h/w driver */
1601         pipe_hw = dpu_rm_get_sspp(&kms->rm, pipe);
1602         if (!pipe_hw || !pipe_hw->cap || !pipe_hw->cap->sblk) {
1603                 DPU_ERROR("[%u]SSPP is invalid\n", pipe);
1604                 goto clean_plane;
1605         }
1606
1607         format_list = pipe_hw->cap->sblk->format_list;
1608         num_formats = pipe_hw->cap->sblk->num_formats;
1609
1610         ret = drm_universal_plane_init(dev, plane, 0xff, &dpu_plane_funcs,
1611                                 format_list, num_formats,
1612                                 supported_format_modifiers, type, NULL);
1613         if (ret)
1614                 goto clean_plane;
1615
1616         pdpu->catalog = kms->catalog;
1617
1618         ret = drm_plane_create_zpos_property(plane, 0, 0, DPU_ZPOS_MAX);
1619         if (ret)
1620                 DPU_ERROR("failed to install zpos property, rc = %d\n", ret);
1621
1622         drm_plane_create_alpha_property(plane);
1623         drm_plane_create_blend_mode_property(plane,
1624                         BIT(DRM_MODE_BLEND_PIXEL_NONE) |
1625                         BIT(DRM_MODE_BLEND_PREMULTI) |
1626                         BIT(DRM_MODE_BLEND_COVERAGE));
1627
1628         supported_rotations = DRM_MODE_REFLECT_MASK | DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180;
1629
1630         if (pipe_hw->cap->features & BIT(DPU_SSPP_INLINE_ROTATION))
1631                 supported_rotations |= DRM_MODE_ROTATE_MASK;
1632
1633         drm_plane_create_rotation_property(plane,
1634                     DRM_MODE_ROTATE_0, supported_rotations);
1635
1636         drm_plane_enable_fb_damage_clips(plane);
1637
1638         /* success! finalize initialization */
1639         drm_plane_helper_add(plane, &dpu_plane_helper_funcs);
1640
1641         mutex_init(&pdpu->lock);
1642
1643         DPU_DEBUG("%s created for pipe:%u id:%u\n", plane->name,
1644                                         pipe, plane->base.id);
1645         return plane;
1646
1647 clean_plane:
1648         kfree(pdpu);
1649         return ERR_PTR(ret);
1650 }