root/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. _dpu_plane_get_kms
  2. _dpu_plane_calc_fill_level
  3. _dpu_plane_get_qos_lut
  4. _dpu_plane_set_qos_lut
  5. _dpu_plane_set_danger_lut
  6. _dpu_plane_set_qos_ctrl
  7. _dpu_plane_set_ot_limit
  8. _dpu_plane_set_qos_remap
  9. _dpu_plane_set_scanout
  10. _dpu_plane_setup_scaler3
  11. _dpu_plane_setup_csc
  12. _dpu_plane_setup_scaler
  13. _dpu_plane_color_fill
  14. dpu_plane_clear_multirect
  15. dpu_plane_validate_multirect_v2
  16. dpu_plane_get_ctl_flush
  17. dpu_plane_prepare_fb
  18. dpu_plane_cleanup_fb
  19. dpu_plane_validate_src
  20. dpu_plane_atomic_check
  21. dpu_plane_flush
  22. dpu_plane_set_error
  23. dpu_plane_sspp_atomic_update
  24. _dpu_plane_atomic_disable
  25. dpu_plane_atomic_update
  26. dpu_plane_restore
  27. dpu_plane_destroy
  28. dpu_plane_destroy_state
  29. dpu_plane_duplicate_state
  30. dpu_plane_reset
  31. dpu_plane_danger_signal_ctrl
  32. _dpu_plane_danger_read
  33. _dpu_plane_set_danger_state
  34. _dpu_plane_danger_write
  35. _dpu_plane_init_debugfs
  36. _dpu_plane_init_debugfs
  37. dpu_plane_late_register
  38. dpu_plane_early_unregister
  39. dpu_plane_format_mod_supported
  40. dpu_plane_pipe
  41. is_dpu_plane_virtual
  42. dpu_plane_init

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

/* [<][>][^][v][top][bottom][index][help] */