GNU Linux-libre 4.19.245-gnu1
[releases.git] / drivers / gpu / drm / msm / disp / dpu1 / dpu_plane.c
1 /*
2  * Copyright (C) 2014-2018 The Linux Foundation. All rights reserved.
3  * Copyright (C) 2013 Red Hat
4  * Author: Rob Clark <robdclark@gmail.com>
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License version 2 as published by
8  * the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #define pr_fmt(fmt)     "[drm:%s:%d] " fmt, __func__, __LINE__
20
21 #include <linux/debugfs.h>
22 #include <linux/dma-buf.h>
23
24 #include "msm_drv.h"
25 #include "dpu_kms.h"
26 #include "dpu_formats.h"
27 #include "dpu_hw_sspp.h"
28 #include "dpu_hw_catalog_format.h"
29 #include "dpu_trace.h"
30 #include "dpu_crtc.h"
31 #include "dpu_vbif.h"
32 #include "dpu_plane.h"
33
34 #define DPU_DEBUG_PLANE(pl, fmt, ...) DPU_DEBUG("plane%d " fmt,\
35                 (pl) ? (pl)->base.base.id : -1, ##__VA_ARGS__)
36
37 #define DPU_ERROR_PLANE(pl, fmt, ...) DPU_ERROR("plane%d " fmt,\
38                 (pl) ? (pl)->base.base.id : -1, ##__VA_ARGS__)
39
40 #define DECIMATED_DIMENSION(dim, deci) (((dim) + ((1 << (deci)) - 1)) >> (deci))
41 #define PHASE_STEP_SHIFT        21
42 #define PHASE_STEP_UNIT_SCALE   ((int) (1 << PHASE_STEP_SHIFT))
43 #define PHASE_RESIDUAL          15
44
45 #define SHARP_STRENGTH_DEFAULT  32
46 #define SHARP_EDGE_THR_DEFAULT  112
47 #define SHARP_SMOOTH_THR_DEFAULT        8
48 #define SHARP_NOISE_THR_DEFAULT 2
49
50 #define DPU_NAME_SIZE  12
51
52 #define DPU_PLANE_COLOR_FILL_FLAG       BIT(31)
53 #define DPU_ZPOS_MAX 255
54
55 /* multirect rect index */
56 enum {
57         R0,
58         R1,
59         R_MAX
60 };
61
62 #define DPU_QSEED3_DEFAULT_PRELOAD_H 0x4
63 #define DPU_QSEED3_DEFAULT_PRELOAD_V 0x3
64
65 #define DEFAULT_REFRESH_RATE    60
66
67 /**
68  * enum dpu_plane_qos - Different qos configurations for each pipe
69  *
70  * @DPU_PLANE_QOS_VBLANK_CTRL: Setup VBLANK qos for the pipe.
71  * @DPU_PLANE_QOS_VBLANK_AMORTIZE: Enables Amortization within pipe.
72  *      this configuration is mutually exclusive from VBLANK_CTRL.
73  * @DPU_PLANE_QOS_PANIC_CTRL: Setup panic for the pipe.
74  */
75 enum dpu_plane_qos {
76         DPU_PLANE_QOS_VBLANK_CTRL = BIT(0),
77         DPU_PLANE_QOS_VBLANK_AMORTIZE = BIT(1),
78         DPU_PLANE_QOS_PANIC_CTRL = BIT(2),
79 };
80
81 /*
82  * struct dpu_plane - local dpu plane structure
83  * @aspace: address space pointer
84  * @csc_ptr: Points to dpu_csc_cfg structure to use for current
85  * @mplane_list: List of multirect planes of the same pipe
86  * @catalog: Points to dpu catalog structure
87  * @revalidate: force revalidation of all the plane properties
88  */
89 struct dpu_plane {
90         struct drm_plane base;
91
92         struct mutex lock;
93
94         enum dpu_sspp pipe;
95         uint32_t features;      /* capabilities from catalog */
96         uint32_t nformats;
97         uint32_t formats[64];
98
99         struct dpu_hw_pipe *pipe_hw;
100         struct dpu_hw_pipe_cfg pipe_cfg;
101         struct dpu_hw_pipe_qos_cfg pipe_qos_cfg;
102         uint32_t color_fill;
103         bool is_error;
104         bool is_rt_pipe;
105         bool is_virtual;
106         struct list_head mplane_list;
107         struct dpu_mdss_cfg *catalog;
108
109         struct dpu_csc_cfg *csc_ptr;
110
111         const struct dpu_sspp_sub_blks *pipe_sblk;
112         char pipe_name[DPU_NAME_SIZE];
113
114         /* debugfs related stuff */
115         struct dentry *debugfs_root;
116         struct dpu_debugfs_regset32 debugfs_src;
117         struct dpu_debugfs_regset32 debugfs_scaler;
118         struct dpu_debugfs_regset32 debugfs_csc;
119         bool debugfs_default_scale;
120 };
121
122 #define to_dpu_plane(x) container_of(x, struct dpu_plane, base)
123
124 static struct dpu_kms *_dpu_plane_get_kms(struct drm_plane *plane)
125 {
126         struct msm_drm_private *priv;
127
128         if (!plane || !plane->dev)
129                 return NULL;
130         priv = plane->dev->dev_private;
131         if (!priv)
132                 return NULL;
133         return to_dpu_kms(priv->kms);
134 }
135
136 static bool dpu_plane_enabled(struct drm_plane_state *state)
137 {
138         return state && state->fb && state->crtc;
139 }
140
141 static bool dpu_plane_sspp_enabled(struct drm_plane_state *state)
142 {
143         return state && state->crtc;
144 }
145
146 /**
147  * _dpu_plane_calc_fill_level - calculate fill level of the given source format
148  * @plane:              Pointer to drm plane
149  * @fmt:                Pointer to source buffer format
150  * @src_wdith:          width of source buffer
151  * Return: fill level corresponding to the source buffer/format or 0 if error
152  */
153 static inline int _dpu_plane_calc_fill_level(struct drm_plane *plane,
154                 const struct dpu_format *fmt, u32 src_width)
155 {
156         struct dpu_plane *pdpu, *tmp;
157         struct dpu_plane_state *pstate;
158         u32 fixed_buff_size;
159         u32 total_fl;
160
161         if (!plane || !fmt || !plane->state || !src_width || !fmt->bpp) {
162                 DPU_ERROR("invalid arguments\n");
163                 return 0;
164         }
165
166         pdpu = to_dpu_plane(plane);
167         pstate = to_dpu_plane_state(plane->state);
168         fixed_buff_size = pdpu->pipe_sblk->common->pixel_ram_size;
169
170         list_for_each_entry(tmp, &pdpu->mplane_list, mplane_list) {
171                 if (!dpu_plane_enabled(tmp->base.state))
172                         continue;
173                 DPU_DEBUG("plane%d/%d src_width:%d/%d\n",
174                                 pdpu->base.base.id, tmp->base.base.id,
175                                 src_width,
176                                 drm_rect_width(&tmp->pipe_cfg.src_rect));
177                 src_width = max_t(u32, src_width,
178                                   drm_rect_width(&tmp->pipe_cfg.src_rect));
179         }
180
181         if (fmt->fetch_planes == DPU_PLANE_PSEUDO_PLANAR) {
182                 if (fmt->chroma_sample == DPU_CHROMA_420) {
183                         /* NV12 */
184                         total_fl = (fixed_buff_size / 2) /
185                                 ((src_width + 32) * fmt->bpp);
186                 } else {
187                         /* non NV12 */
188                         total_fl = (fixed_buff_size / 2) * 2 /
189                                 ((src_width + 32) * fmt->bpp);
190                 }
191         } else {
192                 if (pstate->multirect_mode == DPU_SSPP_MULTIRECT_PARALLEL) {
193                         total_fl = (fixed_buff_size / 2) * 2 /
194                                 ((src_width + 32) * fmt->bpp);
195                 } else {
196                         total_fl = (fixed_buff_size) * 2 /
197                                 ((src_width + 32) * fmt->bpp);
198                 }
199         }
200
201         DPU_DEBUG("plane%u: pnum:%d fmt: %4.4s w:%u fl:%u\n",
202                         plane->base.id, pdpu->pipe - SSPP_VIG0,
203                         (char *)&fmt->base.pixel_format,
204                         src_width, total_fl);
205
206         return total_fl;
207 }
208
209 /**
210  * _dpu_plane_get_qos_lut - get LUT mapping based on fill level
211  * @tbl:                Pointer to LUT table
212  * @total_fl:           fill level
213  * Return: LUT setting corresponding to the fill level
214  */
215 static u64 _dpu_plane_get_qos_lut(const struct dpu_qos_lut_tbl *tbl,
216                 u32 total_fl)
217 {
218         int i;
219
220         if (!tbl || !tbl->nentry || !tbl->entries)
221                 return 0;
222
223         for (i = 0; i < tbl->nentry; i++)
224                 if (total_fl <= tbl->entries[i].fl)
225                         return tbl->entries[i].lut;
226
227         /* if last fl is zero, use as default */
228         if (!tbl->entries[i-1].fl)
229                 return tbl->entries[i-1].lut;
230
231         return 0;
232 }
233
234 /**
235  * _dpu_plane_set_qos_lut - set QoS LUT of the given plane
236  * @plane:              Pointer to drm plane
237  * @fb:                 Pointer to framebuffer associated with the given plane
238  */
239 static void _dpu_plane_set_qos_lut(struct drm_plane *plane,
240                 struct drm_framebuffer *fb)
241 {
242         struct dpu_plane *pdpu;
243         const struct dpu_format *fmt = NULL;
244         u64 qos_lut;
245         u32 total_fl = 0, lut_usage;
246
247         if (!plane || !fb) {
248                 DPU_ERROR("invalid arguments plane %d fb %d\n",
249                                 plane != 0, fb != 0);
250                 return;
251         }
252
253         pdpu = to_dpu_plane(plane);
254
255         if (!pdpu->pipe_hw || !pdpu->pipe_sblk || !pdpu->catalog) {
256                 DPU_ERROR("invalid arguments\n");
257                 return;
258         } else if (!pdpu->pipe_hw->ops.setup_creq_lut) {
259                 return;
260         }
261
262         if (!pdpu->is_rt_pipe) {
263                 lut_usage = DPU_QOS_LUT_USAGE_NRT;
264         } else {
265                 fmt = dpu_get_dpu_format_ext(
266                                 fb->format->format,
267                                 fb->modifier);
268                 total_fl = _dpu_plane_calc_fill_level(plane, fmt,
269                                 drm_rect_width(&pdpu->pipe_cfg.src_rect));
270
271                 if (fmt && DPU_FORMAT_IS_LINEAR(fmt))
272                         lut_usage = DPU_QOS_LUT_USAGE_LINEAR;
273                 else
274                         lut_usage = DPU_QOS_LUT_USAGE_MACROTILE;
275         }
276
277         qos_lut = _dpu_plane_get_qos_lut(
278                         &pdpu->catalog->perf.qos_lut_tbl[lut_usage], total_fl);
279
280         pdpu->pipe_qos_cfg.creq_lut = qos_lut;
281
282         trace_dpu_perf_set_qos_luts(pdpu->pipe - SSPP_VIG0,
283                         (fmt) ? fmt->base.pixel_format : 0,
284                         pdpu->is_rt_pipe, total_fl, qos_lut, lut_usage);
285
286         DPU_DEBUG("plane%u: pnum:%d fmt: %4.4s rt:%d fl:%u lut:0x%llx\n",
287                         plane->base.id,
288                         pdpu->pipe - SSPP_VIG0,
289                         fmt ? (char *)&fmt->base.pixel_format : NULL,
290                         pdpu->is_rt_pipe, total_fl, qos_lut);
291
292         pdpu->pipe_hw->ops.setup_creq_lut(pdpu->pipe_hw, &pdpu->pipe_qos_cfg);
293 }
294
295 /**
296  * _dpu_plane_set_panic_lut - set danger/safe LUT of the given plane
297  * @plane:              Pointer to drm plane
298  * @fb:                 Pointer to framebuffer associated with the given plane
299  */
300 static void _dpu_plane_set_danger_lut(struct drm_plane *plane,
301                 struct drm_framebuffer *fb)
302 {
303         struct dpu_plane *pdpu;
304         const struct dpu_format *fmt = NULL;
305         u32 danger_lut, safe_lut;
306
307         if (!plane || !fb) {
308                 DPU_ERROR("invalid arguments\n");
309                 return;
310         }
311
312         pdpu = to_dpu_plane(plane);
313
314         if (!pdpu->pipe_hw || !pdpu->pipe_sblk || !pdpu->catalog) {
315                 DPU_ERROR("invalid arguments\n");
316                 return;
317         } else if (!pdpu->pipe_hw->ops.setup_danger_safe_lut) {
318                 return;
319         }
320
321         if (!pdpu->is_rt_pipe) {
322                 danger_lut = pdpu->catalog->perf.danger_lut_tbl
323                                 [DPU_QOS_LUT_USAGE_NRT];
324                 safe_lut = pdpu->catalog->perf.safe_lut_tbl
325                                 [DPU_QOS_LUT_USAGE_NRT];
326         } else {
327                 fmt = dpu_get_dpu_format_ext(
328                                 fb->format->format,
329                                 fb->modifier);
330
331                 if (fmt && DPU_FORMAT_IS_LINEAR(fmt)) {
332                         danger_lut = pdpu->catalog->perf.danger_lut_tbl
333                                         [DPU_QOS_LUT_USAGE_LINEAR];
334                         safe_lut = pdpu->catalog->perf.safe_lut_tbl
335                                         [DPU_QOS_LUT_USAGE_LINEAR];
336                 } else {
337                         danger_lut = pdpu->catalog->perf.danger_lut_tbl
338                                         [DPU_QOS_LUT_USAGE_MACROTILE];
339                         safe_lut = pdpu->catalog->perf.safe_lut_tbl
340                                         [DPU_QOS_LUT_USAGE_MACROTILE];
341                 }
342         }
343
344         pdpu->pipe_qos_cfg.danger_lut = danger_lut;
345         pdpu->pipe_qos_cfg.safe_lut = safe_lut;
346
347         trace_dpu_perf_set_danger_luts(pdpu->pipe - SSPP_VIG0,
348                         (fmt) ? fmt->base.pixel_format : 0,
349                         (fmt) ? fmt->fetch_mode : 0,
350                         pdpu->pipe_qos_cfg.danger_lut,
351                         pdpu->pipe_qos_cfg.safe_lut);
352
353         DPU_DEBUG("plane%u: pnum:%d fmt: %4.4s mode:%d luts[0x%x, 0x%x]\n",
354                 plane->base.id,
355                 pdpu->pipe - SSPP_VIG0,
356                 fmt ? (char *)&fmt->base.pixel_format : NULL,
357                 fmt ? fmt->fetch_mode : -1,
358                 pdpu->pipe_qos_cfg.danger_lut,
359                 pdpu->pipe_qos_cfg.safe_lut);
360
361         pdpu->pipe_hw->ops.setup_danger_safe_lut(pdpu->pipe_hw,
362                         &pdpu->pipe_qos_cfg);
363 }
364
365 /**
366  * _dpu_plane_set_qos_ctrl - set QoS control of the given plane
367  * @plane:              Pointer to drm plane
368  * @enable:             true to enable QoS control
369  * @flags:              QoS control mode (enum dpu_plane_qos)
370  */
371 static void _dpu_plane_set_qos_ctrl(struct drm_plane *plane,
372         bool enable, u32 flags)
373 {
374         struct dpu_plane *pdpu;
375
376         if (!plane) {
377                 DPU_ERROR("invalid arguments\n");
378                 return;
379         }
380
381         pdpu = to_dpu_plane(plane);
382
383         if (!pdpu->pipe_hw || !pdpu->pipe_sblk) {
384                 DPU_ERROR("invalid arguments\n");
385                 return;
386         } else if (!pdpu->pipe_hw->ops.setup_qos_ctrl) {
387                 return;
388         }
389
390         if (flags & DPU_PLANE_QOS_VBLANK_CTRL) {
391                 pdpu->pipe_qos_cfg.creq_vblank = pdpu->pipe_sblk->creq_vblank;
392                 pdpu->pipe_qos_cfg.danger_vblank =
393                                 pdpu->pipe_sblk->danger_vblank;
394                 pdpu->pipe_qos_cfg.vblank_en = enable;
395         }
396
397         if (flags & DPU_PLANE_QOS_VBLANK_AMORTIZE) {
398                 /* this feature overrules previous VBLANK_CTRL */
399                 pdpu->pipe_qos_cfg.vblank_en = false;
400                 pdpu->pipe_qos_cfg.creq_vblank = 0; /* clear vblank bits */
401         }
402
403         if (flags & DPU_PLANE_QOS_PANIC_CTRL)
404                 pdpu->pipe_qos_cfg.danger_safe_en = enable;
405
406         if (!pdpu->is_rt_pipe) {
407                 pdpu->pipe_qos_cfg.vblank_en = false;
408                 pdpu->pipe_qos_cfg.danger_safe_en = false;
409         }
410
411         DPU_DEBUG("plane%u: pnum:%d ds:%d vb:%d pri[0x%x, 0x%x] is_rt:%d\n",
412                 plane->base.id,
413                 pdpu->pipe - SSPP_VIG0,
414                 pdpu->pipe_qos_cfg.danger_safe_en,
415                 pdpu->pipe_qos_cfg.vblank_en,
416                 pdpu->pipe_qos_cfg.creq_vblank,
417                 pdpu->pipe_qos_cfg.danger_vblank,
418                 pdpu->is_rt_pipe);
419
420         pdpu->pipe_hw->ops.setup_qos_ctrl(pdpu->pipe_hw,
421                         &pdpu->pipe_qos_cfg);
422 }
423
424 int dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable)
425 {
426         struct dpu_plane *pdpu;
427         struct msm_drm_private *priv;
428         struct dpu_kms *dpu_kms;
429
430         if (!plane || !plane->dev) {
431                 DPU_ERROR("invalid arguments\n");
432                 return -EINVAL;
433         }
434
435         priv = plane->dev->dev_private;
436         if (!priv || !priv->kms) {
437                 DPU_ERROR("invalid KMS reference\n");
438                 return -EINVAL;
439         }
440
441         dpu_kms = to_dpu_kms(priv->kms);
442         pdpu = to_dpu_plane(plane);
443
444         if (!pdpu->is_rt_pipe)
445                 goto end;
446
447         pm_runtime_get_sync(&dpu_kms->pdev->dev);
448         _dpu_plane_set_qos_ctrl(plane, enable, DPU_PLANE_QOS_PANIC_CTRL);
449         pm_runtime_put_sync(&dpu_kms->pdev->dev);
450
451 end:
452         return 0;
453 }
454
455 /**
456  * _dpu_plane_set_ot_limit - set OT limit for the given plane
457  * @plane:              Pointer to drm plane
458  * @crtc:               Pointer to drm crtc
459  */
460 static void _dpu_plane_set_ot_limit(struct drm_plane *plane,
461                 struct drm_crtc *crtc)
462 {
463         struct dpu_plane *pdpu;
464         struct dpu_vbif_set_ot_params ot_params;
465         struct msm_drm_private *priv;
466         struct dpu_kms *dpu_kms;
467
468         if (!plane || !plane->dev || !crtc) {
469                 DPU_ERROR("invalid arguments plane %d crtc %d\n",
470                                 plane != 0, crtc != 0);
471                 return;
472         }
473
474         priv = plane->dev->dev_private;
475         if (!priv || !priv->kms) {
476                 DPU_ERROR("invalid KMS reference\n");
477                 return;
478         }
479
480         dpu_kms = to_dpu_kms(priv->kms);
481         pdpu = to_dpu_plane(plane);
482         if (!pdpu->pipe_hw) {
483                 DPU_ERROR("invalid pipe reference\n");
484                 return;
485         }
486
487         memset(&ot_params, 0, sizeof(ot_params));
488         ot_params.xin_id = pdpu->pipe_hw->cap->xin_id;
489         ot_params.num = pdpu->pipe_hw->idx - SSPP_NONE;
490         ot_params.width = drm_rect_width(&pdpu->pipe_cfg.src_rect);
491         ot_params.height = drm_rect_height(&pdpu->pipe_cfg.src_rect);
492         ot_params.is_wfd = !pdpu->is_rt_pipe;
493         ot_params.frame_rate = crtc->mode.vrefresh;
494         ot_params.vbif_idx = VBIF_RT;
495         ot_params.clk_ctrl = pdpu->pipe_hw->cap->clk_ctrl;
496         ot_params.rd = true;
497
498         dpu_vbif_set_ot_limit(dpu_kms, &ot_params);
499 }
500
501 /**
502  * _dpu_plane_set_vbif_qos - set vbif QoS for the given plane
503  * @plane:              Pointer to drm plane
504  */
505 static void _dpu_plane_set_qos_remap(struct drm_plane *plane)
506 {
507         struct dpu_plane *pdpu;
508         struct dpu_vbif_set_qos_params qos_params;
509         struct msm_drm_private *priv;
510         struct dpu_kms *dpu_kms;
511
512         if (!plane || !plane->dev) {
513                 DPU_ERROR("invalid arguments\n");
514                 return;
515         }
516
517         priv = plane->dev->dev_private;
518         if (!priv || !priv->kms) {
519                 DPU_ERROR("invalid KMS reference\n");
520                 return;
521         }
522
523         dpu_kms = to_dpu_kms(priv->kms);
524         pdpu = to_dpu_plane(plane);
525         if (!pdpu->pipe_hw) {
526                 DPU_ERROR("invalid pipe reference\n");
527                 return;
528         }
529
530         memset(&qos_params, 0, sizeof(qos_params));
531         qos_params.vbif_idx = VBIF_RT;
532         qos_params.clk_ctrl = pdpu->pipe_hw->cap->clk_ctrl;
533         qos_params.xin_id = pdpu->pipe_hw->cap->xin_id;
534         qos_params.num = pdpu->pipe_hw->idx - SSPP_VIG0;
535         qos_params.is_rt = pdpu->is_rt_pipe;
536
537         DPU_DEBUG("plane%d pipe:%d vbif:%d xin:%d rt:%d, clk_ctrl:%d\n",
538                         plane->base.id, qos_params.num,
539                         qos_params.vbif_idx,
540                         qos_params.xin_id, qos_params.is_rt,
541                         qos_params.clk_ctrl);
542
543         dpu_vbif_set_qos_remap(dpu_kms, &qos_params);
544 }
545
546 /**
547  * _dpu_plane_get_aspace: gets the address space
548  */
549 static int _dpu_plane_get_aspace(
550                 struct dpu_plane *pdpu,
551                 struct dpu_plane_state *pstate,
552                 struct msm_gem_address_space **aspace)
553 {
554         struct dpu_kms *kms;
555
556         if (!pdpu || !pstate || !aspace) {
557                 DPU_ERROR("invalid parameters\n");
558                 return -EINVAL;
559         }
560
561         kms = _dpu_plane_get_kms(&pdpu->base);
562         if (!kms) {
563                 DPU_ERROR("invalid kms\n");
564                 return -EINVAL;
565         }
566
567         *aspace = kms->base.aspace;
568
569         return 0;
570 }
571
572 static inline void _dpu_plane_set_scanout(struct drm_plane *plane,
573                 struct dpu_plane_state *pstate,
574                 struct dpu_hw_pipe_cfg *pipe_cfg,
575                 struct drm_framebuffer *fb)
576 {
577         struct dpu_plane *pdpu;
578         struct msm_gem_address_space *aspace = NULL;
579         int ret;
580
581         if (!plane || !pstate || !pipe_cfg || !fb) {
582                 DPU_ERROR(
583                         "invalid arg(s), plane %d state %d cfg %d fb %d\n",
584                         plane != 0, pstate != 0, pipe_cfg != 0, fb != 0);
585                 return;
586         }
587
588         pdpu = to_dpu_plane(plane);
589         if (!pdpu->pipe_hw) {
590                 DPU_ERROR_PLANE(pdpu, "invalid pipe_hw\n");
591                 return;
592         }
593
594         ret = _dpu_plane_get_aspace(pdpu, pstate, &aspace);
595         if (ret) {
596                 DPU_ERROR_PLANE(pdpu, "Failed to get aspace %d\n", ret);
597                 return;
598         }
599
600         ret = dpu_format_populate_layout(aspace, fb, &pipe_cfg->layout);
601         if (ret == -EAGAIN)
602                 DPU_DEBUG_PLANE(pdpu, "not updating same src addrs\n");
603         else if (ret)
604                 DPU_ERROR_PLANE(pdpu, "failed to get format layout, %d\n", ret);
605         else if (pdpu->pipe_hw->ops.setup_sourceaddress) {
606                 trace_dpu_plane_set_scanout(pdpu->pipe_hw->idx,
607                                             &pipe_cfg->layout,
608                                             pstate->multirect_index);
609                 pdpu->pipe_hw->ops.setup_sourceaddress(pdpu->pipe_hw, pipe_cfg,
610                                                 pstate->multirect_index);
611         }
612 }
613
614 static void _dpu_plane_setup_scaler3(struct dpu_plane *pdpu,
615                 struct dpu_plane_state *pstate,
616                 uint32_t src_w, uint32_t src_h, uint32_t dst_w, uint32_t dst_h,
617                 struct dpu_hw_scaler3_cfg *scale_cfg,
618                 const struct dpu_format *fmt,
619                 uint32_t chroma_subsmpl_h, uint32_t chroma_subsmpl_v)
620 {
621         uint32_t i;
622
623         if (!pdpu || !pstate || !scale_cfg || !fmt || !chroma_subsmpl_h ||
624                         !chroma_subsmpl_v) {
625                 DPU_ERROR(
626                         "pdpu %d pstate %d scale_cfg %d fmt %d smp_h %d smp_v %d\n",
627                         !!pdpu, !!pstate, !!scale_cfg, !!fmt, chroma_subsmpl_h,
628                         chroma_subsmpl_v);
629                 return;
630         }
631
632         memset(scale_cfg, 0, sizeof(*scale_cfg));
633         memset(&pstate->pixel_ext, 0, sizeof(struct dpu_hw_pixel_ext));
634
635         scale_cfg->phase_step_x[DPU_SSPP_COMP_0] =
636                 mult_frac((1 << PHASE_STEP_SHIFT), src_w, dst_w);
637         scale_cfg->phase_step_y[DPU_SSPP_COMP_0] =
638                 mult_frac((1 << PHASE_STEP_SHIFT), src_h, dst_h);
639
640
641         scale_cfg->phase_step_y[DPU_SSPP_COMP_1_2] =
642                 scale_cfg->phase_step_y[DPU_SSPP_COMP_0] / chroma_subsmpl_v;
643         scale_cfg->phase_step_x[DPU_SSPP_COMP_1_2] =
644                 scale_cfg->phase_step_x[DPU_SSPP_COMP_0] / chroma_subsmpl_h;
645
646         scale_cfg->phase_step_x[DPU_SSPP_COMP_2] =
647                 scale_cfg->phase_step_x[DPU_SSPP_COMP_1_2];
648         scale_cfg->phase_step_y[DPU_SSPP_COMP_2] =
649                 scale_cfg->phase_step_y[DPU_SSPP_COMP_1_2];
650
651         scale_cfg->phase_step_x[DPU_SSPP_COMP_3] =
652                 scale_cfg->phase_step_x[DPU_SSPP_COMP_0];
653         scale_cfg->phase_step_y[DPU_SSPP_COMP_3] =
654                 scale_cfg->phase_step_y[DPU_SSPP_COMP_0];
655
656         for (i = 0; i < DPU_MAX_PLANES; i++) {
657                 scale_cfg->src_width[i] = src_w;
658                 scale_cfg->src_height[i] = src_h;
659                 if (i == DPU_SSPP_COMP_1_2 || i == DPU_SSPP_COMP_2) {
660                         scale_cfg->src_width[i] /= chroma_subsmpl_h;
661                         scale_cfg->src_height[i] /= chroma_subsmpl_v;
662                 }
663                 scale_cfg->preload_x[i] = DPU_QSEED3_DEFAULT_PRELOAD_H;
664                 scale_cfg->preload_y[i] = DPU_QSEED3_DEFAULT_PRELOAD_V;
665                 pstate->pixel_ext.num_ext_pxls_top[i] =
666                         scale_cfg->src_height[i];
667                 pstate->pixel_ext.num_ext_pxls_left[i] =
668                         scale_cfg->src_width[i];
669         }
670         if (!(DPU_FORMAT_IS_YUV(fmt)) && (src_h == dst_h)
671                 && (src_w == dst_w))
672                 return;
673
674         scale_cfg->dst_width = dst_w;
675         scale_cfg->dst_height = dst_h;
676         scale_cfg->y_rgb_filter_cfg = DPU_SCALE_BIL;
677         scale_cfg->uv_filter_cfg = DPU_SCALE_BIL;
678         scale_cfg->alpha_filter_cfg = DPU_SCALE_ALPHA_BIL;
679         scale_cfg->lut_flag = 0;
680         scale_cfg->blend_cfg = 1;
681         scale_cfg->enable = 1;
682 }
683
684 static inline void _dpu_plane_setup_csc(struct dpu_plane *pdpu)
685 {
686         static const struct dpu_csc_cfg dpu_csc_YUV2RGB_601L = {
687                 {
688                         /* S15.16 format */
689                         0x00012A00, 0x00000000, 0x00019880,
690                         0x00012A00, 0xFFFF9B80, 0xFFFF3000,
691                         0x00012A00, 0x00020480, 0x00000000,
692                 },
693                 /* signed bias */
694                 { 0xfff0, 0xff80, 0xff80,},
695                 { 0x0, 0x0, 0x0,},
696                 /* unsigned clamp */
697                 { 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0,},
698                 { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,},
699         };
700         static const struct dpu_csc_cfg dpu_csc10_YUV2RGB_601L = {
701                 {
702                         /* S15.16 format */
703                         0x00012A00, 0x00000000, 0x00019880,
704                         0x00012A00, 0xFFFF9B80, 0xFFFF3000,
705                         0x00012A00, 0x00020480, 0x00000000,
706                         },
707                 /* signed bias */
708                 { 0xffc0, 0xfe00, 0xfe00,},
709                 { 0x0, 0x0, 0x0,},
710                 /* unsigned clamp */
711                 { 0x40, 0x3ac, 0x40, 0x3c0, 0x40, 0x3c0,},
712                 { 0x00, 0x3ff, 0x00, 0x3ff, 0x00, 0x3ff,},
713         };
714
715         if (!pdpu) {
716                 DPU_ERROR("invalid plane\n");
717                 return;
718         }
719
720         if (BIT(DPU_SSPP_CSC_10BIT) & pdpu->features)
721                 pdpu->csc_ptr = (struct dpu_csc_cfg *)&dpu_csc10_YUV2RGB_601L;
722         else
723                 pdpu->csc_ptr = (struct dpu_csc_cfg *)&dpu_csc_YUV2RGB_601L;
724
725         DPU_DEBUG_PLANE(pdpu, "using 0x%X 0x%X 0x%X...\n",
726                         pdpu->csc_ptr->csc_mv[0],
727                         pdpu->csc_ptr->csc_mv[1],
728                         pdpu->csc_ptr->csc_mv[2]);
729 }
730
731 static void _dpu_plane_setup_scaler(struct dpu_plane *pdpu,
732                 struct dpu_plane_state *pstate,
733                 const struct dpu_format *fmt, bool color_fill)
734 {
735         struct dpu_hw_pixel_ext *pe;
736         uint32_t chroma_subsmpl_h, chroma_subsmpl_v;
737
738         if (!pdpu || !fmt || !pstate) {
739                 DPU_ERROR("invalid arg(s), plane %d fmt %d state %d\n",
740                                 pdpu != 0, fmt != 0, pstate != 0);
741                 return;
742         }
743
744         pe = &pstate->pixel_ext;
745
746         /* don't chroma subsample if decimating */
747         chroma_subsmpl_h =
748                 drm_format_horz_chroma_subsampling(fmt->base.pixel_format);
749         chroma_subsmpl_v =
750                 drm_format_vert_chroma_subsampling(fmt->base.pixel_format);
751
752         /* update scaler. calculate default config for QSEED3 */
753         _dpu_plane_setup_scaler3(pdpu, pstate,
754                         drm_rect_width(&pdpu->pipe_cfg.src_rect),
755                         drm_rect_height(&pdpu->pipe_cfg.src_rect),
756                         drm_rect_width(&pdpu->pipe_cfg.dst_rect),
757                         drm_rect_height(&pdpu->pipe_cfg.dst_rect),
758                         &pstate->scaler3_cfg, fmt,
759                         chroma_subsmpl_h, chroma_subsmpl_v);
760 }
761
762 /**
763  * _dpu_plane_color_fill - enables color fill on plane
764  * @pdpu:   Pointer to DPU plane object
765  * @color:  RGB fill color value, [23..16] Blue, [15..8] Green, [7..0] Red
766  * @alpha:  8-bit fill alpha value, 255 selects 100% alpha
767  * Returns: 0 on success
768  */
769 static int _dpu_plane_color_fill(struct dpu_plane *pdpu,
770                 uint32_t color, uint32_t alpha)
771 {
772         const struct dpu_format *fmt;
773         const struct drm_plane *plane;
774         struct dpu_plane_state *pstate;
775
776         if (!pdpu || !pdpu->base.state) {
777                 DPU_ERROR("invalid plane\n");
778                 return -EINVAL;
779         }
780
781         if (!pdpu->pipe_hw) {
782                 DPU_ERROR_PLANE(pdpu, "invalid plane h/w pointer\n");
783                 return -EINVAL;
784         }
785
786         plane = &pdpu->base;
787         pstate = to_dpu_plane_state(plane->state);
788
789         DPU_DEBUG_PLANE(pdpu, "\n");
790
791         /*
792          * select fill format to match user property expectation,
793          * h/w only supports RGB variants
794          */
795         fmt = dpu_get_dpu_format(DRM_FORMAT_ABGR8888);
796
797         /* update sspp */
798         if (fmt && pdpu->pipe_hw->ops.setup_solidfill) {
799                 pdpu->pipe_hw->ops.setup_solidfill(pdpu->pipe_hw,
800                                 (color & 0xFFFFFF) | ((alpha & 0xFF) << 24),
801                                 pstate->multirect_index);
802
803                 /* override scaler/decimation if solid fill */
804                 pdpu->pipe_cfg.src_rect.x1 = 0;
805                 pdpu->pipe_cfg.src_rect.y1 = 0;
806                 pdpu->pipe_cfg.src_rect.x2 =
807                         drm_rect_width(&pdpu->pipe_cfg.dst_rect);
808                 pdpu->pipe_cfg.src_rect.y2 =
809                         drm_rect_height(&pdpu->pipe_cfg.dst_rect);
810                 _dpu_plane_setup_scaler(pdpu, pstate, fmt, true);
811
812                 if (pdpu->pipe_hw->ops.setup_format)
813                         pdpu->pipe_hw->ops.setup_format(pdpu->pipe_hw,
814                                         fmt, DPU_SSPP_SOLID_FILL,
815                                         pstate->multirect_index);
816
817                 if (pdpu->pipe_hw->ops.setup_rects)
818                         pdpu->pipe_hw->ops.setup_rects(pdpu->pipe_hw,
819                                         &pdpu->pipe_cfg,
820                                         pstate->multirect_index);
821
822                 if (pdpu->pipe_hw->ops.setup_pe)
823                         pdpu->pipe_hw->ops.setup_pe(pdpu->pipe_hw,
824                                         &pstate->pixel_ext);
825
826                 if (pdpu->pipe_hw->ops.setup_scaler &&
827                                 pstate->multirect_index != DPU_SSPP_RECT_1)
828                         pdpu->pipe_hw->ops.setup_scaler(pdpu->pipe_hw,
829                                         &pdpu->pipe_cfg, &pstate->pixel_ext,
830                                         &pstate->scaler3_cfg);
831         }
832
833         return 0;
834 }
835
836 void dpu_plane_clear_multirect(const struct drm_plane_state *drm_state)
837 {
838         struct dpu_plane_state *pstate;
839
840         if (!drm_state)
841                 return;
842
843         pstate = to_dpu_plane_state(drm_state);
844
845         pstate->multirect_index = DPU_SSPP_RECT_SOLO;
846         pstate->multirect_mode = DPU_SSPP_MULTIRECT_NONE;
847 }
848
849 int dpu_plane_validate_multirect_v2(struct dpu_multirect_plane_states *plane)
850 {
851         struct dpu_plane_state *pstate[R_MAX];
852         const struct drm_plane_state *drm_state[R_MAX];
853         struct drm_rect src[R_MAX], dst[R_MAX];
854         struct dpu_plane *dpu_plane[R_MAX];
855         const struct dpu_format *fmt[R_MAX];
856         int i, buffer_lines;
857         unsigned int max_tile_height = 1;
858         bool parallel_fetch_qualified = true;
859         bool has_tiled_rect = false;
860
861         for (i = 0; i < R_MAX; i++) {
862                 const struct msm_format *msm_fmt;
863
864                 drm_state[i] = i ? plane->r1 : plane->r0;
865                 msm_fmt = msm_framebuffer_format(drm_state[i]->fb);
866                 fmt[i] = to_dpu_format(msm_fmt);
867
868                 if (DPU_FORMAT_IS_UBWC(fmt[i])) {
869                         has_tiled_rect = true;
870                         if (fmt[i]->tile_height > max_tile_height)
871                                 max_tile_height = fmt[i]->tile_height;
872                 }
873         }
874
875         for (i = 0; i < R_MAX; i++) {
876                 int width_threshold;
877
878                 pstate[i] = to_dpu_plane_state(drm_state[i]);
879                 dpu_plane[i] = to_dpu_plane(drm_state[i]->plane);
880
881                 if (pstate[i] == NULL) {
882                         DPU_ERROR("DPU plane state of plane id %d is NULL\n",
883                                 drm_state[i]->plane->base.id);
884                         return -EINVAL;
885                 }
886
887                 src[i].x1 = drm_state[i]->src_x >> 16;
888                 src[i].y1 = drm_state[i]->src_y >> 16;
889                 src[i].x2 = src[i].x1 + (drm_state[i]->src_w >> 16);
890                 src[i].y2 = src[i].y1 + (drm_state[i]->src_h >> 16);
891
892                 dst[i] = drm_plane_state_dest(drm_state[i]);
893
894                 if (drm_rect_calc_hscale(&src[i], &dst[i], 1, 1) != 1 ||
895                     drm_rect_calc_vscale(&src[i], &dst[i], 1, 1) != 1) {
896                         DPU_ERROR_PLANE(dpu_plane[i],
897                                 "scaling is not supported in multirect mode\n");
898                         return -EINVAL;
899                 }
900
901                 if (DPU_FORMAT_IS_YUV(fmt[i])) {
902                         DPU_ERROR_PLANE(dpu_plane[i],
903                                 "Unsupported format for multirect mode\n");
904                         return -EINVAL;
905                 }
906
907                 /**
908                  * SSPP PD_MEM is split half - one for each RECT.
909                  * Tiled formats need 5 lines of buffering while fetching
910                  * whereas linear formats need only 2 lines.
911                  * So we cannot support more than half of the supported SSPP
912                  * width for tiled formats.
913                  */
914                 width_threshold = dpu_plane[i]->pipe_sblk->common->maxlinewidth;
915                 if (has_tiled_rect)
916                         width_threshold /= 2;
917
918                 if (parallel_fetch_qualified &&
919                     drm_rect_width(&src[i]) > width_threshold)
920                         parallel_fetch_qualified = false;
921
922         }
923
924         /* Validate RECT's and set the mode */
925
926         /* Prefer PARALLEL FETCH Mode over TIME_MX Mode */
927         if (parallel_fetch_qualified) {
928                 pstate[R0]->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL;
929                 pstate[R1]->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL;
930
931                 goto done;
932         }
933
934         /* TIME_MX Mode */
935         buffer_lines = 2 * max_tile_height;
936
937         if (dst[R1].y1 >= dst[R0].y2 + buffer_lines ||
938             dst[R0].y1 >= dst[R1].y2 + buffer_lines) {
939                 pstate[R0]->multirect_mode = DPU_SSPP_MULTIRECT_TIME_MX;
940                 pstate[R1]->multirect_mode = DPU_SSPP_MULTIRECT_TIME_MX;
941         } else {
942                 DPU_ERROR(
943                         "No multirect mode possible for the planes (%d - %d)\n",
944                         drm_state[R0]->plane->base.id,
945                         drm_state[R1]->plane->base.id);
946                 return -EINVAL;
947         }
948
949 done:
950         if (dpu_plane[R0]->is_virtual) {
951                 pstate[R0]->multirect_index = DPU_SSPP_RECT_1;
952                 pstate[R1]->multirect_index = DPU_SSPP_RECT_0;
953         } else {
954                 pstate[R0]->multirect_index = DPU_SSPP_RECT_0;
955                 pstate[R1]->multirect_index = DPU_SSPP_RECT_1;
956         };
957
958         DPU_DEBUG_PLANE(dpu_plane[R0], "R0: %d - %d\n",
959                 pstate[R0]->multirect_mode, pstate[R0]->multirect_index);
960         DPU_DEBUG_PLANE(dpu_plane[R1], "R1: %d - %d\n",
961                 pstate[R1]->multirect_mode, pstate[R1]->multirect_index);
962         return 0;
963 }
964
965 /**
966  * dpu_plane_get_ctl_flush - get control flush for the given plane
967  * @plane: Pointer to drm plane structure
968  * @ctl: Pointer to hardware control driver
969  * @flush_sspp: Pointer to sspp flush control word
970  */
971 void dpu_plane_get_ctl_flush(struct drm_plane *plane, struct dpu_hw_ctl *ctl,
972                 u32 *flush_sspp)
973 {
974         struct dpu_plane_state *pstate;
975
976         if (!plane || !flush_sspp) {
977                 DPU_ERROR("invalid parameters\n");
978                 return;
979         }
980
981         pstate = to_dpu_plane_state(plane->state);
982
983         *flush_sspp = ctl->ops.get_bitmask_sspp(ctl, dpu_plane_pipe(plane));
984 }
985
986 static int dpu_plane_prepare_fb(struct drm_plane *plane,
987                 struct drm_plane_state *new_state)
988 {
989         struct drm_framebuffer *fb = new_state->fb;
990         struct dpu_plane *pdpu = to_dpu_plane(plane);
991         struct dpu_plane_state *pstate = to_dpu_plane_state(new_state);
992         struct dpu_hw_fmt_layout layout;
993         struct drm_gem_object *obj;
994         struct msm_gem_object *msm_obj;
995         struct dma_fence *fence;
996         struct msm_gem_address_space *aspace;
997         int ret;
998
999         if (!new_state->fb)
1000                 return 0;
1001
1002         DPU_DEBUG_PLANE(pdpu, "FB[%u]\n", fb->base.id);
1003
1004         ret = _dpu_plane_get_aspace(pdpu, pstate, &aspace);
1005         if (ret) {
1006                 DPU_ERROR_PLANE(pdpu, "Failed to get aspace\n");
1007                 return ret;
1008         }
1009
1010         /* cache aspace */
1011         pstate->aspace = aspace;
1012
1013         /*
1014          * TODO: Need to sort out the msm_framebuffer_prepare() call below so
1015          *       we can use msm_atomic_prepare_fb() instead of doing the
1016          *       implicit fence and fb prepare by hand here.
1017          */
1018         obj = msm_framebuffer_bo(new_state->fb, 0);
1019         msm_obj = to_msm_bo(obj);
1020         fence = reservation_object_get_excl_rcu(msm_obj->resv);
1021         if (fence)
1022                 drm_atomic_set_fence_for_plane(new_state, fence);
1023
1024         if (pstate->aspace) {
1025                 ret = msm_framebuffer_prepare(new_state->fb,
1026                                 pstate->aspace);
1027                 if (ret) {
1028                         DPU_ERROR("failed to prepare framebuffer\n");
1029                         return ret;
1030                 }
1031         }
1032
1033         /* validate framebuffer layout before commit */
1034         ret = dpu_format_populate_layout(pstate->aspace,
1035                         new_state->fb, &layout);
1036         if (ret) {
1037                 DPU_ERROR_PLANE(pdpu, "failed to get format layout, %d\n", ret);
1038                 return ret;
1039         }
1040
1041         return 0;
1042 }
1043
1044 static void dpu_plane_cleanup_fb(struct drm_plane *plane,
1045                 struct drm_plane_state *old_state)
1046 {
1047         struct dpu_plane *pdpu = to_dpu_plane(plane);
1048         struct dpu_plane_state *old_pstate;
1049
1050         if (!old_state || !old_state->fb)
1051                 return;
1052
1053         old_pstate = to_dpu_plane_state(old_state);
1054
1055         DPU_DEBUG_PLANE(pdpu, "FB[%u]\n", old_state->fb->base.id);
1056
1057         msm_framebuffer_cleanup(old_state->fb, old_pstate->aspace);
1058 }
1059
1060 static bool dpu_plane_validate_src(struct drm_rect *src,
1061                                    struct drm_rect *fb_rect,
1062                                    uint32_t min_src_size)
1063 {
1064         /* Ensure fb size is supported */
1065         if (drm_rect_width(fb_rect) > MAX_IMG_WIDTH ||
1066             drm_rect_height(fb_rect) > MAX_IMG_HEIGHT)
1067                 return false;
1068
1069         /* Ensure src rect is above the minimum size */
1070         if (drm_rect_width(src) < min_src_size ||
1071             drm_rect_height(src) < min_src_size)
1072                 return false;
1073
1074         /* Ensure src is fully encapsulated in fb */
1075         return drm_rect_intersect(fb_rect, src) &&
1076                 drm_rect_equals(fb_rect, src);
1077 }
1078
1079 static int dpu_plane_sspp_atomic_check(struct drm_plane *plane,
1080                 struct drm_plane_state *state)
1081 {
1082         int ret = 0;
1083         struct dpu_plane *pdpu;
1084         struct dpu_plane_state *pstate;
1085         const struct dpu_format *fmt;
1086         struct drm_rect src, dst, fb_rect = { 0 };
1087         uint32_t max_upscale = 1, max_downscale = 1;
1088         uint32_t min_src_size, max_linewidth;
1089         int hscale = 1, vscale = 1;
1090
1091         if (!plane || !state) {
1092                 DPU_ERROR("invalid arg(s), plane %d state %d\n",
1093                                 plane != 0, state != 0);
1094                 ret = -EINVAL;
1095                 goto exit;
1096         }
1097
1098         pdpu = to_dpu_plane(plane);
1099         pstate = to_dpu_plane_state(state);
1100
1101         if (!pdpu->pipe_sblk) {
1102                 DPU_ERROR_PLANE(pdpu, "invalid catalog\n");
1103                 ret = -EINVAL;
1104                 goto exit;
1105         }
1106
1107         src.x1 = state->src_x >> 16;
1108         src.y1 = state->src_y >> 16;
1109         src.x2 = src.x1 + (state->src_w >> 16);
1110         src.y2 = src.y1 + (state->src_h >> 16);
1111
1112         dst = drm_plane_state_dest(state);
1113
1114         fb_rect.x2 = state->fb->width;
1115         fb_rect.y2 = state->fb->height;
1116
1117         max_linewidth = pdpu->pipe_sblk->common->maxlinewidth;
1118
1119         if (pdpu->features & DPU_SSPP_SCALER) {
1120                 max_downscale = pdpu->pipe_sblk->maxdwnscale;
1121                 max_upscale = pdpu->pipe_sblk->maxupscale;
1122         }
1123         if (drm_rect_width(&src) < drm_rect_width(&dst))
1124                 hscale = drm_rect_calc_hscale(&src, &dst, 1, max_upscale);
1125         else
1126                 hscale = drm_rect_calc_hscale(&dst, &src, 1, max_downscale);
1127         if (drm_rect_height(&src) < drm_rect_height(&dst))
1128                 vscale = drm_rect_calc_vscale(&src, &dst, 1, max_upscale);
1129         else
1130                 vscale = drm_rect_calc_vscale(&dst, &src, 1, max_downscale);
1131
1132         DPU_DEBUG_PLANE(pdpu, "check %d -> %d\n",
1133                 dpu_plane_enabled(plane->state), dpu_plane_enabled(state));
1134
1135         if (!dpu_plane_enabled(state))
1136                 goto exit;
1137
1138         fmt = to_dpu_format(msm_framebuffer_format(state->fb));
1139
1140         min_src_size = DPU_FORMAT_IS_YUV(fmt) ? 2 : 1;
1141
1142         if (DPU_FORMAT_IS_YUV(fmt) &&
1143                 (!(pdpu->features & DPU_SSPP_SCALER) ||
1144                  !(pdpu->features & (BIT(DPU_SSPP_CSC)
1145                  | BIT(DPU_SSPP_CSC_10BIT))))) {
1146                 DPU_ERROR_PLANE(pdpu,
1147                                 "plane doesn't have scaler/csc for yuv\n");
1148                 ret = -EINVAL;
1149
1150         /* check src bounds */
1151         } else if (!dpu_plane_validate_src(&src, &fb_rect, min_src_size)) {
1152                 DPU_ERROR_PLANE(pdpu, "invalid source " DRM_RECT_FMT "\n",
1153                                 DRM_RECT_ARG(&src));
1154                 ret = -E2BIG;
1155
1156         /* valid yuv image */
1157         } else if (DPU_FORMAT_IS_YUV(fmt) &&
1158                    (src.x1 & 0x1 || src.y1 & 0x1 ||
1159                     drm_rect_width(&src) & 0x1 ||
1160                     drm_rect_height(&src) & 0x1)) {
1161                 DPU_ERROR_PLANE(pdpu, "invalid yuv source " DRM_RECT_FMT "\n",
1162                                 DRM_RECT_ARG(&src));
1163                 ret = -EINVAL;
1164
1165         /* min dst support */
1166         } else if (drm_rect_width(&dst) < 0x1 || drm_rect_height(&dst) < 0x1) {
1167                 DPU_ERROR_PLANE(pdpu, "invalid dest rect " DRM_RECT_FMT "\n",
1168                                 DRM_RECT_ARG(&dst));
1169                 ret = -EINVAL;
1170
1171         /* check decimated source width */
1172         } else if (drm_rect_width(&src) > max_linewidth) {
1173                 DPU_ERROR_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u\n",
1174                                 DRM_RECT_ARG(&src), max_linewidth);
1175                 ret = -E2BIG;
1176
1177         /* check scaler capability */
1178         } else if (hscale < 0 || vscale < 0) {
1179                 DPU_ERROR_PLANE(pdpu, "invalid scaling requested src="
1180                                 DRM_RECT_FMT " dst=" DRM_RECT_FMT "\n",
1181                                 DRM_RECT_ARG(&src), DRM_RECT_ARG(&dst));
1182                 ret = -E2BIG;
1183         }
1184
1185 exit:
1186         return ret;
1187 }
1188
1189 static int dpu_plane_atomic_check(struct drm_plane *plane,
1190                 struct drm_plane_state *state)
1191 {
1192         if (!state->fb)
1193                 return 0;
1194
1195         DPU_DEBUG_PLANE(to_dpu_plane(plane), "\n");
1196
1197         return dpu_plane_sspp_atomic_check(plane, state);
1198 }
1199
1200 void dpu_plane_flush(struct drm_plane *plane)
1201 {
1202         struct dpu_plane *pdpu;
1203         struct dpu_plane_state *pstate;
1204
1205         if (!plane || !plane->state) {
1206                 DPU_ERROR("invalid plane\n");
1207                 return;
1208         }
1209
1210         pdpu = to_dpu_plane(plane);
1211         pstate = to_dpu_plane_state(plane->state);
1212
1213         /*
1214          * These updates have to be done immediately before the plane flush
1215          * timing, and may not be moved to the atomic_update/mode_set functions.
1216          */
1217         if (pdpu->is_error)
1218                 /* force white frame with 100% alpha pipe output on error */
1219                 _dpu_plane_color_fill(pdpu, 0xFFFFFF, 0xFF);
1220         else if (pdpu->color_fill & DPU_PLANE_COLOR_FILL_FLAG)
1221                 /* force 100% alpha */
1222                 _dpu_plane_color_fill(pdpu, pdpu->color_fill, 0xFF);
1223         else if (pdpu->pipe_hw && pdpu->csc_ptr && pdpu->pipe_hw->ops.setup_csc)
1224                 pdpu->pipe_hw->ops.setup_csc(pdpu->pipe_hw, pdpu->csc_ptr);
1225
1226         /* flag h/w flush complete */
1227         if (plane->state)
1228                 pstate->pending = false;
1229 }
1230
1231 /**
1232  * dpu_plane_set_error: enable/disable error condition
1233  * @plane: pointer to drm_plane structure
1234  */
1235 void dpu_plane_set_error(struct drm_plane *plane, bool error)
1236 {
1237         struct dpu_plane *pdpu;
1238
1239         if (!plane)
1240                 return;
1241
1242         pdpu = to_dpu_plane(plane);
1243         pdpu->is_error = error;
1244 }
1245
1246 static int dpu_plane_sspp_atomic_update(struct drm_plane *plane,
1247                                 struct drm_plane_state *old_state)
1248 {
1249         uint32_t nplanes, src_flags;
1250         struct dpu_plane *pdpu;
1251         struct drm_plane_state *state;
1252         struct dpu_plane_state *pstate;
1253         struct dpu_plane_state *old_pstate;
1254         const struct dpu_format *fmt;
1255         struct drm_crtc *crtc;
1256         struct drm_framebuffer *fb;
1257         int ret, min_scale;
1258
1259         if (!plane) {
1260                 DPU_ERROR("invalid plane\n");
1261                 return -EINVAL;
1262         } else if (!plane->state) {
1263                 DPU_ERROR("invalid plane state\n");
1264                 return -EINVAL;
1265         } else if (!old_state) {
1266                 DPU_ERROR("invalid old state\n");
1267                 return -EINVAL;
1268         }
1269
1270         pdpu = to_dpu_plane(plane);
1271         state = plane->state;
1272
1273         pstate = to_dpu_plane_state(state);
1274
1275         old_pstate = to_dpu_plane_state(old_state);
1276
1277         crtc = state->crtc;
1278         fb = state->fb;
1279         if (!crtc || !fb) {
1280                 DPU_ERROR_PLANE(pdpu, "invalid crtc %d or fb %d\n",
1281                                 crtc != 0, fb != 0);
1282                 return -EINVAL;
1283         }
1284         fmt = to_dpu_format(msm_framebuffer_format(fb));
1285         nplanes = fmt->num_planes;
1286
1287         memset(&(pdpu->pipe_cfg), 0, sizeof(struct dpu_hw_pipe_cfg));
1288
1289         _dpu_plane_set_scanout(plane, pstate, &pdpu->pipe_cfg, fb);
1290
1291         pstate->pending = true;
1292
1293         pdpu->is_rt_pipe = (dpu_crtc_get_client_type(crtc) != NRT_CLIENT);
1294         _dpu_plane_set_qos_ctrl(plane, false, DPU_PLANE_QOS_PANIC_CTRL);
1295
1296         min_scale = FRAC_16_16(1, pdpu->pipe_sblk->maxdwnscale);
1297         ret = drm_atomic_helper_check_plane_state(state, crtc->state, min_scale,
1298                                           pdpu->pipe_sblk->maxupscale << 16,
1299                                           true, false);
1300         if (ret) {
1301                 DPU_ERROR_PLANE(pdpu, "Check plane state failed (%d)\n", ret);
1302                 return ret;
1303         }
1304
1305         DPU_DEBUG_PLANE(pdpu, "FB[%u] " DRM_RECT_FP_FMT "->crtc%u " DRM_RECT_FMT
1306                         ", %4.4s ubwc %d\n", fb->base.id, DRM_RECT_FP_ARG(&state->src),
1307                         crtc->base.id, DRM_RECT_ARG(&state->dst),
1308                         (char *)&fmt->base.pixel_format, DPU_FORMAT_IS_UBWC(fmt));
1309
1310         pdpu->pipe_cfg.src_rect = state->src;
1311
1312         /* state->src is 16.16, src_rect is not */
1313         pdpu->pipe_cfg.src_rect.x1 >>= 16;
1314         pdpu->pipe_cfg.src_rect.x2 >>= 16;
1315         pdpu->pipe_cfg.src_rect.y1 >>= 16;
1316         pdpu->pipe_cfg.src_rect.y2 >>= 16;
1317
1318         pdpu->pipe_cfg.dst_rect = state->dst;
1319
1320         _dpu_plane_setup_scaler(pdpu, pstate, fmt, false);
1321
1322         /* override for color fill */
1323         if (pdpu->color_fill & DPU_PLANE_COLOR_FILL_FLAG) {
1324                 /* skip remaining processing on color fill */
1325                 return 0;
1326         }
1327
1328         if (pdpu->pipe_hw->ops.setup_rects) {
1329                 pdpu->pipe_hw->ops.setup_rects(pdpu->pipe_hw,
1330                                 &pdpu->pipe_cfg,
1331                                 pstate->multirect_index);
1332         }
1333
1334         if (pdpu->pipe_hw->ops.setup_pe &&
1335                         (pstate->multirect_index != DPU_SSPP_RECT_1))
1336                 pdpu->pipe_hw->ops.setup_pe(pdpu->pipe_hw,
1337                                 &pstate->pixel_ext);
1338
1339         /**
1340          * when programmed in multirect mode, scalar block will be
1341          * bypassed. Still we need to update alpha and bitwidth
1342          * ONLY for RECT0
1343          */
1344         if (pdpu->pipe_hw->ops.setup_scaler &&
1345                         pstate->multirect_index != DPU_SSPP_RECT_1)
1346                 pdpu->pipe_hw->ops.setup_scaler(pdpu->pipe_hw,
1347                                 &pdpu->pipe_cfg, &pstate->pixel_ext,
1348                                 &pstate->scaler3_cfg);
1349
1350         if (pdpu->pipe_hw->ops.setup_multirect)
1351                 pdpu->pipe_hw->ops.setup_multirect(
1352                                 pdpu->pipe_hw,
1353                                 pstate->multirect_index,
1354                                 pstate->multirect_mode);
1355
1356         if (pdpu->pipe_hw->ops.setup_format) {
1357                 src_flags = 0x0;
1358
1359                 /* update format */
1360                 pdpu->pipe_hw->ops.setup_format(pdpu->pipe_hw, fmt, src_flags,
1361                                 pstate->multirect_index);
1362
1363                 if (pdpu->pipe_hw->ops.setup_cdp) {
1364                         struct dpu_hw_pipe_cdp_cfg *cdp_cfg = &pstate->cdp_cfg;
1365
1366                         memset(cdp_cfg, 0, sizeof(struct dpu_hw_pipe_cdp_cfg));
1367
1368                         cdp_cfg->enable = pdpu->catalog->perf.cdp_cfg
1369                                         [DPU_PERF_CDP_USAGE_RT].rd_enable;
1370                         cdp_cfg->ubwc_meta_enable =
1371                                         DPU_FORMAT_IS_UBWC(fmt);
1372                         cdp_cfg->tile_amortize_enable =
1373                                         DPU_FORMAT_IS_UBWC(fmt) ||
1374                                         DPU_FORMAT_IS_TILE(fmt);
1375                         cdp_cfg->preload_ahead = DPU_SSPP_CDP_PRELOAD_AHEAD_64;
1376
1377                         pdpu->pipe_hw->ops.setup_cdp(pdpu->pipe_hw, cdp_cfg);
1378                 }
1379
1380                 /* update csc */
1381                 if (DPU_FORMAT_IS_YUV(fmt))
1382                         _dpu_plane_setup_csc(pdpu);
1383                 else
1384                         pdpu->csc_ptr = 0;
1385         }
1386
1387         _dpu_plane_set_qos_lut(plane, fb);
1388         _dpu_plane_set_danger_lut(plane, fb);
1389
1390         if (plane->type != DRM_PLANE_TYPE_CURSOR) {
1391                 _dpu_plane_set_qos_ctrl(plane, true, DPU_PLANE_QOS_PANIC_CTRL);
1392                 _dpu_plane_set_ot_limit(plane, crtc);
1393         }
1394
1395         _dpu_plane_set_qos_remap(plane);
1396         return 0;
1397 }
1398
1399 static void _dpu_plane_atomic_disable(struct drm_plane *plane,
1400                                 struct drm_plane_state *old_state)
1401 {
1402         struct dpu_plane *pdpu;
1403         struct drm_plane_state *state;
1404         struct dpu_plane_state *pstate;
1405
1406         if (!plane) {
1407                 DPU_ERROR("invalid plane\n");
1408                 return;
1409         } else if (!plane->state) {
1410                 DPU_ERROR("invalid plane state\n");
1411                 return;
1412         } else if (!old_state) {
1413                 DPU_ERROR("invalid old state\n");
1414                 return;
1415         }
1416
1417         pdpu = to_dpu_plane(plane);
1418         state = plane->state;
1419         pstate = to_dpu_plane_state(state);
1420
1421         trace_dpu_plane_disable(DRMID(plane), is_dpu_plane_virtual(plane),
1422                                 pstate->multirect_mode);
1423
1424         pstate->pending = true;
1425
1426         if (is_dpu_plane_virtual(plane) &&
1427                         pdpu->pipe_hw && pdpu->pipe_hw->ops.setup_multirect)
1428                 pdpu->pipe_hw->ops.setup_multirect(pdpu->pipe_hw,
1429                                 DPU_SSPP_RECT_SOLO, DPU_SSPP_MULTIRECT_NONE);
1430 }
1431
1432 static void dpu_plane_atomic_update(struct drm_plane *plane,
1433                                 struct drm_plane_state *old_state)
1434 {
1435         struct dpu_plane *pdpu;
1436         struct drm_plane_state *state;
1437
1438         if (!plane) {
1439                 DPU_ERROR("invalid plane\n");
1440                 return;
1441         } else if (!plane->state) {
1442                 DPU_ERROR("invalid plane state\n");
1443                 return;
1444         }
1445
1446         pdpu = to_dpu_plane(plane);
1447         pdpu->is_error = false;
1448         state = plane->state;
1449
1450         DPU_DEBUG_PLANE(pdpu, "\n");
1451
1452         if (!dpu_plane_sspp_enabled(state)) {
1453                 _dpu_plane_atomic_disable(plane, old_state);
1454         } else {
1455                 int ret;
1456
1457                 ret = dpu_plane_sspp_atomic_update(plane, old_state);
1458                 /* atomic_check should have ensured that this doesn't fail */
1459                 WARN_ON(ret < 0);
1460         }
1461 }
1462
1463 void dpu_plane_restore(struct drm_plane *plane)
1464 {
1465         struct dpu_plane *pdpu;
1466
1467         if (!plane || !plane->state) {
1468                 DPU_ERROR("invalid plane\n");
1469                 return;
1470         }
1471
1472         pdpu = to_dpu_plane(plane);
1473
1474         DPU_DEBUG_PLANE(pdpu, "\n");
1475
1476         /* last plane state is same as current state */
1477         dpu_plane_atomic_update(plane, plane->state);
1478 }
1479
1480 static void dpu_plane_destroy(struct drm_plane *plane)
1481 {
1482         struct dpu_plane *pdpu = plane ? to_dpu_plane(plane) : NULL;
1483
1484         DPU_DEBUG_PLANE(pdpu, "\n");
1485
1486         if (pdpu) {
1487                 _dpu_plane_set_qos_ctrl(plane, false, DPU_PLANE_QOS_PANIC_CTRL);
1488
1489                 mutex_destroy(&pdpu->lock);
1490
1491                 drm_plane_helper_disable(plane, NULL);
1492
1493                 /* this will destroy the states as well */
1494                 drm_plane_cleanup(plane);
1495
1496                 if (pdpu->pipe_hw)
1497                         dpu_hw_sspp_destroy(pdpu->pipe_hw);
1498
1499                 kfree(pdpu);
1500         }
1501 }
1502
1503 static void dpu_plane_destroy_state(struct drm_plane *plane,
1504                 struct drm_plane_state *state)
1505 {
1506         struct dpu_plane_state *pstate;
1507
1508         if (!plane || !state) {
1509                 DPU_ERROR("invalid arg(s), plane %d state %d\n",
1510                                 plane != 0, state != 0);
1511                 return;
1512         }
1513
1514         pstate = to_dpu_plane_state(state);
1515
1516         /* remove ref count for frame buffers */
1517         if (state->fb)
1518                 drm_framebuffer_put(state->fb);
1519
1520         kfree(pstate);
1521 }
1522
1523 static struct drm_plane_state *
1524 dpu_plane_duplicate_state(struct drm_plane *plane)
1525 {
1526         struct dpu_plane *pdpu;
1527         struct dpu_plane_state *pstate;
1528         struct dpu_plane_state *old_state;
1529
1530         if (!plane) {
1531                 DPU_ERROR("invalid plane\n");
1532                 return NULL;
1533         } else if (!plane->state) {
1534                 DPU_ERROR("invalid plane state\n");
1535                 return NULL;
1536         }
1537
1538         old_state = to_dpu_plane_state(plane->state);
1539         pdpu = to_dpu_plane(plane);
1540         pstate = kmemdup(old_state, sizeof(*old_state), GFP_KERNEL);
1541         if (!pstate) {
1542                 DPU_ERROR_PLANE(pdpu, "failed to allocate state\n");
1543                 return NULL;
1544         }
1545
1546         DPU_DEBUG_PLANE(pdpu, "\n");
1547
1548         pstate->pending = false;
1549
1550         __drm_atomic_helper_plane_duplicate_state(plane, &pstate->base);
1551
1552         return &pstate->base;
1553 }
1554
1555 static void dpu_plane_reset(struct drm_plane *plane)
1556 {
1557         struct dpu_plane *pdpu;
1558         struct dpu_plane_state *pstate;
1559
1560         if (!plane) {
1561                 DPU_ERROR("invalid plane\n");
1562                 return;
1563         }
1564
1565         pdpu = to_dpu_plane(plane);
1566         DPU_DEBUG_PLANE(pdpu, "\n");
1567
1568         /* remove previous state, if present */
1569         if (plane->state) {
1570                 dpu_plane_destroy_state(plane, plane->state);
1571                 plane->state = 0;
1572         }
1573
1574         pstate = kzalloc(sizeof(*pstate), GFP_KERNEL);
1575         if (!pstate) {
1576                 DPU_ERROR_PLANE(pdpu, "failed to allocate state\n");
1577                 return;
1578         }
1579
1580         pstate->base.plane = plane;
1581
1582         plane->state = &pstate->base;
1583 }
1584
1585 #ifdef CONFIG_DEBUG_FS
1586 static ssize_t _dpu_plane_danger_read(struct file *file,
1587                         char __user *buff, size_t count, loff_t *ppos)
1588 {
1589         struct dpu_kms *kms = file->private_data;
1590         struct dpu_mdss_cfg *cfg = kms->catalog;
1591         int len = 0;
1592         char buf[40] = {'\0'};
1593
1594         if (!cfg)
1595                 return -ENODEV;
1596
1597         if (*ppos)
1598                 return 0; /* the end */
1599
1600         len = snprintf(buf, sizeof(buf), "%d\n", !kms->has_danger_ctrl);
1601         if (len < 0 || len >= sizeof(buf))
1602                 return 0;
1603
1604         if ((count < sizeof(buf)) || copy_to_user(buff, buf, len))
1605                 return -EFAULT;
1606
1607         *ppos += len;   /* increase offset */
1608
1609         return len;
1610 }
1611
1612 static void _dpu_plane_set_danger_state(struct dpu_kms *kms, bool enable)
1613 {
1614         struct drm_plane *plane;
1615
1616         drm_for_each_plane(plane, kms->dev) {
1617                 if (plane->fb && plane->state) {
1618                         dpu_plane_danger_signal_ctrl(plane, enable);
1619                         DPU_DEBUG("plane:%d img:%dx%d ",
1620                                 plane->base.id, plane->fb->width,
1621                                 plane->fb->height);
1622                         DPU_DEBUG("src[%d,%d,%d,%d] dst[%d,%d,%d,%d]\n",
1623                                 plane->state->src_x >> 16,
1624                                 plane->state->src_y >> 16,
1625                                 plane->state->src_w >> 16,
1626                                 plane->state->src_h >> 16,
1627                                 plane->state->crtc_x, plane->state->crtc_y,
1628                                 plane->state->crtc_w, plane->state->crtc_h);
1629                 } else {
1630                         DPU_DEBUG("Inactive plane:%d\n", plane->base.id);
1631                 }
1632         }
1633 }
1634
1635 static ssize_t _dpu_plane_danger_write(struct file *file,
1636                     const char __user *user_buf, size_t count, loff_t *ppos)
1637 {
1638         struct dpu_kms *kms = file->private_data;
1639         struct dpu_mdss_cfg *cfg = kms->catalog;
1640         int disable_panic;
1641         char buf[10];
1642
1643         if (!cfg)
1644                 return -EFAULT;
1645
1646         if (count >= sizeof(buf))
1647                 return -EFAULT;
1648
1649         if (copy_from_user(buf, user_buf, count))
1650                 return -EFAULT;
1651
1652         buf[count] = 0; /* end of string */
1653
1654         if (kstrtoint(buf, 0, &disable_panic))
1655                 return -EFAULT;
1656
1657         if (disable_panic) {
1658                 /* Disable panic signal for all active pipes */
1659                 DPU_DEBUG("Disabling danger:\n");
1660                 _dpu_plane_set_danger_state(kms, false);
1661                 kms->has_danger_ctrl = false;
1662         } else {
1663                 /* Enable panic signal for all active pipes */
1664                 DPU_DEBUG("Enabling danger:\n");
1665                 kms->has_danger_ctrl = true;
1666                 _dpu_plane_set_danger_state(kms, true);
1667         }
1668
1669         return count;
1670 }
1671
1672 static const struct file_operations dpu_plane_danger_enable = {
1673         .open = simple_open,
1674         .read = _dpu_plane_danger_read,
1675         .write = _dpu_plane_danger_write,
1676 };
1677
1678 static int _dpu_plane_init_debugfs(struct drm_plane *plane)
1679 {
1680         struct dpu_plane *pdpu;
1681         struct dpu_kms *kms;
1682         struct msm_drm_private *priv;
1683         const struct dpu_sspp_sub_blks *sblk = 0;
1684         const struct dpu_sspp_cfg *cfg = 0;
1685
1686         if (!plane || !plane->dev) {
1687                 DPU_ERROR("invalid arguments\n");
1688                 return -EINVAL;
1689         }
1690
1691         priv = plane->dev->dev_private;
1692         if (!priv || !priv->kms) {
1693                 DPU_ERROR("invalid KMS reference\n");
1694                 return -EINVAL;
1695         }
1696
1697         kms = to_dpu_kms(priv->kms);
1698         pdpu = to_dpu_plane(plane);
1699
1700         if (pdpu && pdpu->pipe_hw)
1701                 cfg = pdpu->pipe_hw->cap;
1702         if (cfg)
1703                 sblk = cfg->sblk;
1704
1705         if (!sblk)
1706                 return 0;
1707
1708         /* create overall sub-directory for the pipe */
1709         pdpu->debugfs_root =
1710                 debugfs_create_dir(pdpu->pipe_name,
1711                                 plane->dev->primary->debugfs_root);
1712
1713         if (!pdpu->debugfs_root)
1714                 return -ENOMEM;
1715
1716         /* don't error check these */
1717         debugfs_create_x32("features", 0600,
1718                         pdpu->debugfs_root, &pdpu->features);
1719
1720         /* add register dump support */
1721         dpu_debugfs_setup_regset32(&pdpu->debugfs_src,
1722                         sblk->src_blk.base + cfg->base,
1723                         sblk->src_blk.len,
1724                         kms);
1725         dpu_debugfs_create_regset32("src_blk", 0400,
1726                         pdpu->debugfs_root, &pdpu->debugfs_src);
1727
1728         if (cfg->features & BIT(DPU_SSPP_SCALER_QSEED3) ||
1729                         cfg->features & BIT(DPU_SSPP_SCALER_QSEED2)) {
1730                 dpu_debugfs_setup_regset32(&pdpu->debugfs_scaler,
1731                                 sblk->scaler_blk.base + cfg->base,
1732                                 sblk->scaler_blk.len,
1733                                 kms);
1734                 dpu_debugfs_create_regset32("scaler_blk", 0400,
1735                                 pdpu->debugfs_root,
1736                                 &pdpu->debugfs_scaler);
1737                 debugfs_create_bool("default_scaling",
1738                                 0600,
1739                                 pdpu->debugfs_root,
1740                                 &pdpu->debugfs_default_scale);
1741         }
1742
1743         if (cfg->features & BIT(DPU_SSPP_CSC) ||
1744                         cfg->features & BIT(DPU_SSPP_CSC_10BIT)) {
1745                 dpu_debugfs_setup_regset32(&pdpu->debugfs_csc,
1746                                 sblk->csc_blk.base + cfg->base,
1747                                 sblk->csc_blk.len,
1748                                 kms);
1749                 dpu_debugfs_create_regset32("csc_blk", 0400,
1750                                 pdpu->debugfs_root, &pdpu->debugfs_csc);
1751         }
1752
1753         debugfs_create_u32("xin_id",
1754                         0400,
1755                         pdpu->debugfs_root,
1756                         (u32 *) &cfg->xin_id);
1757         debugfs_create_u32("clk_ctrl",
1758                         0400,
1759                         pdpu->debugfs_root,
1760                         (u32 *) &cfg->clk_ctrl);
1761         debugfs_create_x32("creq_vblank",
1762                         0600,
1763                         pdpu->debugfs_root,
1764                         (u32 *) &sblk->creq_vblank);
1765         debugfs_create_x32("danger_vblank",
1766                         0600,
1767                         pdpu->debugfs_root,
1768                         (u32 *) &sblk->danger_vblank);
1769
1770         debugfs_create_file("disable_danger",
1771                         0600,
1772                         pdpu->debugfs_root,
1773                         kms, &dpu_plane_danger_enable);
1774
1775         return 0;
1776 }
1777
1778 static void _dpu_plane_destroy_debugfs(struct drm_plane *plane)
1779 {
1780         struct dpu_plane *pdpu;
1781
1782         if (!plane)
1783                 return;
1784         pdpu = to_dpu_plane(plane);
1785
1786         debugfs_remove_recursive(pdpu->debugfs_root);
1787 }
1788 #else
1789 static int _dpu_plane_init_debugfs(struct drm_plane *plane)
1790 {
1791         return 0;
1792 }
1793 static void _dpu_plane_destroy_debugfs(struct drm_plane *plane)
1794 {
1795 }
1796 #endif
1797
1798 static int dpu_plane_late_register(struct drm_plane *plane)
1799 {
1800         return _dpu_plane_init_debugfs(plane);
1801 }
1802
1803 static void dpu_plane_early_unregister(struct drm_plane *plane)
1804 {
1805         _dpu_plane_destroy_debugfs(plane);
1806 }
1807
1808 static const struct drm_plane_funcs dpu_plane_funcs = {
1809                 .update_plane = drm_atomic_helper_update_plane,
1810                 .disable_plane = drm_atomic_helper_disable_plane,
1811                 .destroy = dpu_plane_destroy,
1812                 .reset = dpu_plane_reset,
1813                 .atomic_duplicate_state = dpu_plane_duplicate_state,
1814                 .atomic_destroy_state = dpu_plane_destroy_state,
1815                 .late_register = dpu_plane_late_register,
1816                 .early_unregister = dpu_plane_early_unregister,
1817 };
1818
1819 static const struct drm_plane_helper_funcs dpu_plane_helper_funcs = {
1820                 .prepare_fb = dpu_plane_prepare_fb,
1821                 .cleanup_fb = dpu_plane_cleanup_fb,
1822                 .atomic_check = dpu_plane_atomic_check,
1823                 .atomic_update = dpu_plane_atomic_update,
1824 };
1825
1826 enum dpu_sspp dpu_plane_pipe(struct drm_plane *plane)
1827 {
1828         return plane ? to_dpu_plane(plane)->pipe : SSPP_NONE;
1829 }
1830
1831 bool is_dpu_plane_virtual(struct drm_plane *plane)
1832 {
1833         return plane ? to_dpu_plane(plane)->is_virtual : false;
1834 }
1835
1836 /* initialize plane */
1837 struct drm_plane *dpu_plane_init(struct drm_device *dev,
1838                 uint32_t pipe, bool primary_plane,
1839                 unsigned long possible_crtcs, u32 master_plane_id)
1840 {
1841         struct drm_plane *plane = NULL, *master_plane = NULL;
1842         const struct dpu_format_extended *format_list;
1843         struct dpu_plane *pdpu;
1844         struct msm_drm_private *priv;
1845         struct dpu_kms *kms;
1846         enum drm_plane_type type;
1847         int zpos_max = DPU_ZPOS_MAX;
1848         int ret = -EINVAL;
1849
1850         if (!dev) {
1851                 DPU_ERROR("[%u]device is NULL\n", pipe);
1852                 goto exit;
1853         }
1854
1855         priv = dev->dev_private;
1856         if (!priv) {
1857                 DPU_ERROR("[%u]private data is NULL\n", pipe);
1858                 goto exit;
1859         }
1860
1861         if (!priv->kms) {
1862                 DPU_ERROR("[%u]invalid KMS reference\n", pipe);
1863                 goto exit;
1864         }
1865         kms = to_dpu_kms(priv->kms);
1866
1867         if (!kms->catalog) {
1868                 DPU_ERROR("[%u]invalid catalog reference\n", pipe);
1869                 goto exit;
1870         }
1871
1872         /* create and zero local structure */
1873         pdpu = kzalloc(sizeof(*pdpu), GFP_KERNEL);
1874         if (!pdpu) {
1875                 DPU_ERROR("[%u]failed to allocate local plane struct\n", pipe);
1876                 ret = -ENOMEM;
1877                 goto exit;
1878         }
1879
1880         /* cache local stuff for later */
1881         plane = &pdpu->base;
1882         pdpu->pipe = pipe;
1883         pdpu->is_virtual = (master_plane_id != 0);
1884         INIT_LIST_HEAD(&pdpu->mplane_list);
1885         master_plane = drm_plane_find(dev, NULL, master_plane_id);
1886         if (master_plane) {
1887                 struct dpu_plane *mpdpu = to_dpu_plane(master_plane);
1888
1889                 list_add_tail(&pdpu->mplane_list, &mpdpu->mplane_list);
1890         }
1891
1892         /* initialize underlying h/w driver */
1893         pdpu->pipe_hw = dpu_hw_sspp_init(pipe, kms->mmio, kms->catalog,
1894                                                         master_plane_id != 0);
1895         if (IS_ERR(pdpu->pipe_hw)) {
1896                 DPU_ERROR("[%u]SSPP init failed\n", pipe);
1897                 ret = PTR_ERR(pdpu->pipe_hw);
1898                 goto clean_plane;
1899         } else if (!pdpu->pipe_hw->cap || !pdpu->pipe_hw->cap->sblk) {
1900                 DPU_ERROR("[%u]SSPP init returned invalid cfg\n", pipe);
1901                 goto clean_sspp;
1902         }
1903
1904         /* cache features mask for later */
1905         pdpu->features = pdpu->pipe_hw->cap->features;
1906         pdpu->pipe_sblk = pdpu->pipe_hw->cap->sblk;
1907         if (!pdpu->pipe_sblk) {
1908                 DPU_ERROR("[%u]invalid sblk\n", pipe);
1909                 goto clean_sspp;
1910         }
1911
1912         if (!master_plane_id)
1913                 format_list = pdpu->pipe_sblk->format_list;
1914         else
1915                 format_list = pdpu->pipe_sblk->virt_format_list;
1916
1917         pdpu->nformats = dpu_populate_formats(format_list,
1918                                 pdpu->formats,
1919                                 0,
1920                                 ARRAY_SIZE(pdpu->formats));
1921
1922         if (!pdpu->nformats) {
1923                 DPU_ERROR("[%u]no valid formats for plane\n", pipe);
1924                 goto clean_sspp;
1925         }
1926
1927         if (pdpu->features & BIT(DPU_SSPP_CURSOR))
1928                 type = DRM_PLANE_TYPE_CURSOR;
1929         else if (primary_plane)
1930                 type = DRM_PLANE_TYPE_PRIMARY;
1931         else
1932                 type = DRM_PLANE_TYPE_OVERLAY;
1933         ret = drm_universal_plane_init(dev, plane, 0xff, &dpu_plane_funcs,
1934                                 pdpu->formats, pdpu->nformats,
1935                                 NULL, type, NULL);
1936         if (ret)
1937                 goto clean_sspp;
1938
1939         pdpu->catalog = kms->catalog;
1940
1941         if (kms->catalog->mixer_count &&
1942                 kms->catalog->mixer[0].sblk->maxblendstages) {
1943                 zpos_max = kms->catalog->mixer[0].sblk->maxblendstages - 1;
1944                 if (zpos_max > DPU_STAGE_MAX - DPU_STAGE_0 - 1)
1945                         zpos_max = DPU_STAGE_MAX - DPU_STAGE_0 - 1;
1946         }
1947
1948         ret = drm_plane_create_zpos_property(plane, 0, 0, zpos_max);
1949         if (ret)
1950                 DPU_ERROR("failed to install zpos property, rc = %d\n", ret);
1951
1952         /* success! finalize initialization */
1953         drm_plane_helper_add(plane, &dpu_plane_helper_funcs);
1954
1955         /* save user friendly pipe name for later */
1956         snprintf(pdpu->pipe_name, DPU_NAME_SIZE, "plane%u", plane->base.id);
1957
1958         mutex_init(&pdpu->lock);
1959
1960         DPU_DEBUG("%s created for pipe:%u id:%u virtual:%u\n", pdpu->pipe_name,
1961                                         pipe, plane->base.id, master_plane_id);
1962         return plane;
1963
1964 clean_sspp:
1965         if (pdpu && pdpu->pipe_hw)
1966                 dpu_hw_sspp_destroy(pdpu->pipe_hw);
1967 clean_plane:
1968         kfree(pdpu);
1969 exit:
1970         return ERR_PTR(ret);
1971 }