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