1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2014-2018 The Linux Foundation. All rights reserved.
4 * Copyright (C) 2013 Red Hat
5 * Author: Rob Clark <robdclark@gmail.com>
8 #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
10 #include <linux/debugfs.h>
11 #include <linux/dma-buf.h>
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>
20 #include "dpu_formats.h"
21 #include "dpu_hw_sspp.h"
22 #include "dpu_hw_catalog_format.h"
23 #include "dpu_trace.h"
26 #include "dpu_plane.h"
28 #define DPU_DEBUG_PLANE(pl, fmt, ...) DPU_DEBUG("plane%d " fmt,\
29 (pl) ? (pl)->base.base.id : -1, ##__VA_ARGS__)
31 #define DPU_ERROR_PLANE(pl, fmt, ...) DPU_ERROR("plane%d " fmt,\
32 (pl) ? (pl)->base.base.id : -1, ##__VA_ARGS__)
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
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
44 #define DPU_NAME_SIZE 12
46 #define DPU_PLANE_COLOR_FILL_FLAG BIT(31)
47 #define DPU_ZPOS_MAX 255
49 /* multirect rect index */
57 * Default Preload Values
59 #define DPU_QSEED3_DEFAULT_PRELOAD_H 0x4
60 #define DPU_QSEED3_DEFAULT_PRELOAD_V 0x3
61 #define DPU_QSEED4_DEFAULT_PRELOAD_V 0x2
62 #define DPU_QSEED4_DEFAULT_PRELOAD_H 0x4
64 #define DEFAULT_REFRESH_RATE 60
67 * enum dpu_plane_qos - Different qos configurations for each pipe
69 * @DPU_PLANE_QOS_VBLANK_CTRL: Setup VBLANK qos for the pipe.
70 * @DPU_PLANE_QOS_VBLANK_AMORTIZE: Enables Amortization within pipe.
71 * this configuration is mutually exclusive from VBLANK_CTRL.
72 * @DPU_PLANE_QOS_PANIC_CTRL: Setup panic for the pipe.
75 DPU_PLANE_QOS_VBLANK_CTRL
= BIT(0),
76 DPU_PLANE_QOS_VBLANK_AMORTIZE
= BIT(1),
77 DPU_PLANE_QOS_PANIC_CTRL
= BIT(2),
81 * struct dpu_plane - local dpu plane structure
82 * @aspace: address space pointer
83 * @csc_ptr: Points to dpu_csc_cfg structure to use for current
84 * @mplane_list: List of multirect planes of the same pipe
85 * @catalog: Points to dpu catalog structure
86 * @revalidate: force revalidation of all the plane properties
89 struct drm_plane base
;
94 uint32_t features
; /* capabilities from catalog */
96 struct dpu_hw_pipe
*pipe_hw
;
97 struct dpu_hw_pipe_cfg pipe_cfg
;
98 struct dpu_hw_pipe_qos_cfg pipe_qos_cfg
;
103 struct list_head mplane_list
;
104 struct dpu_mdss_cfg
*catalog
;
106 struct dpu_csc_cfg
*csc_ptr
;
108 const struct dpu_sspp_sub_blks
*pipe_sblk
;
109 char pipe_name
[DPU_NAME_SIZE
];
111 /* debugfs related stuff */
112 struct dentry
*debugfs_root
;
113 struct dpu_debugfs_regset32 debugfs_src
;
114 struct dpu_debugfs_regset32 debugfs_scaler
;
115 struct dpu_debugfs_regset32 debugfs_csc
;
116 bool debugfs_default_scale
;
119 static const uint64_t supported_format_modifiers
[] = {
120 DRM_FORMAT_MOD_QCOM_COMPRESSED
,
121 DRM_FORMAT_MOD_LINEAR
,
122 DRM_FORMAT_MOD_INVALID
125 #define to_dpu_plane(x) container_of(x, struct dpu_plane, base)
127 static struct dpu_kms
*_dpu_plane_get_kms(struct drm_plane
*plane
)
129 struct msm_drm_private
*priv
= plane
->dev
->dev_private
;
131 return to_dpu_kms(priv
->kms
);
135 * _dpu_plane_calc_fill_level - calculate fill level of the given source format
136 * @plane: Pointer to drm plane
137 * @fmt: Pointer to source buffer format
138 * @src_wdith: width of source buffer
139 * Return: fill level corresponding to the source buffer/format or 0 if error
141 static int _dpu_plane_calc_fill_level(struct drm_plane
*plane
,
142 const struct dpu_format
*fmt
, u32 src_width
)
144 struct dpu_plane
*pdpu
, *tmp
;
145 struct dpu_plane_state
*pstate
;
149 if (!fmt
|| !plane
->state
|| !src_width
|| !fmt
->bpp
) {
150 DPU_ERROR("invalid arguments\n");
154 pdpu
= to_dpu_plane(plane
);
155 pstate
= to_dpu_plane_state(plane
->state
);
156 fixed_buff_size
= pdpu
->pipe_sblk
->common
->pixel_ram_size
;
158 list_for_each_entry(tmp
, &pdpu
->mplane_list
, mplane_list
) {
159 if (!tmp
->base
.state
->visible
)
161 DPU_DEBUG("plane%d/%d src_width:%d/%d\n",
162 pdpu
->base
.base
.id
, tmp
->base
.base
.id
,
164 drm_rect_width(&tmp
->pipe_cfg
.src_rect
));
165 src_width
= max_t(u32
, src_width
,
166 drm_rect_width(&tmp
->pipe_cfg
.src_rect
));
169 if (fmt
->fetch_planes
== DPU_PLANE_PSEUDO_PLANAR
) {
170 if (fmt
->chroma_sample
== DPU_CHROMA_420
) {
172 total_fl
= (fixed_buff_size
/ 2) /
173 ((src_width
+ 32) * fmt
->bpp
);
176 total_fl
= (fixed_buff_size
/ 2) * 2 /
177 ((src_width
+ 32) * fmt
->bpp
);
180 if (pstate
->multirect_mode
== DPU_SSPP_MULTIRECT_PARALLEL
) {
181 total_fl
= (fixed_buff_size
/ 2) * 2 /
182 ((src_width
+ 32) * fmt
->bpp
);
184 total_fl
= (fixed_buff_size
) * 2 /
185 ((src_width
+ 32) * fmt
->bpp
);
189 DPU_DEBUG("plane%u: pnum:%d fmt: %4.4s w:%u fl:%u\n",
190 plane
->base
.id
, pdpu
->pipe
- SSPP_VIG0
,
191 (char *)&fmt
->base
.pixel_format
,
192 src_width
, total_fl
);
198 * _dpu_plane_get_qos_lut - get LUT mapping based on fill level
199 * @tbl: Pointer to LUT table
200 * @total_fl: fill level
201 * Return: LUT setting corresponding to the fill level
203 static u64
_dpu_plane_get_qos_lut(const struct dpu_qos_lut_tbl
*tbl
,
208 if (!tbl
|| !tbl
->nentry
|| !tbl
->entries
)
211 for (i
= 0; i
< tbl
->nentry
; i
++)
212 if (total_fl
<= tbl
->entries
[i
].fl
)
213 return tbl
->entries
[i
].lut
;
215 /* if last fl is zero, use as default */
216 if (!tbl
->entries
[i
-1].fl
)
217 return tbl
->entries
[i
-1].lut
;
223 * _dpu_plane_set_qos_lut - set QoS LUT of the given plane
224 * @plane: Pointer to drm plane
225 * @fb: Pointer to framebuffer associated with the given plane
227 static void _dpu_plane_set_qos_lut(struct drm_plane
*plane
,
228 struct drm_framebuffer
*fb
)
230 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
231 const struct dpu_format
*fmt
= NULL
;
233 u32 total_fl
= 0, lut_usage
;
235 if (!pdpu
->is_rt_pipe
) {
236 lut_usage
= DPU_QOS_LUT_USAGE_NRT
;
238 fmt
= dpu_get_dpu_format_ext(
241 total_fl
= _dpu_plane_calc_fill_level(plane
, fmt
,
242 drm_rect_width(&pdpu
->pipe_cfg
.src_rect
));
244 if (fmt
&& DPU_FORMAT_IS_LINEAR(fmt
))
245 lut_usage
= DPU_QOS_LUT_USAGE_LINEAR
;
247 lut_usage
= DPU_QOS_LUT_USAGE_MACROTILE
;
250 qos_lut
= _dpu_plane_get_qos_lut(
251 &pdpu
->catalog
->perf
.qos_lut_tbl
[lut_usage
], total_fl
);
253 pdpu
->pipe_qos_cfg
.creq_lut
= qos_lut
;
255 trace_dpu_perf_set_qos_luts(pdpu
->pipe
- SSPP_VIG0
,
256 (fmt
) ? fmt
->base
.pixel_format
: 0,
257 pdpu
->is_rt_pipe
, total_fl
, qos_lut
, lut_usage
);
259 DPU_DEBUG("plane%u: pnum:%d fmt: %4.4s rt:%d fl:%u lut:0x%llx\n",
261 pdpu
->pipe
- SSPP_VIG0
,
262 fmt
? (char *)&fmt
->base
.pixel_format
: NULL
,
263 pdpu
->is_rt_pipe
, total_fl
, qos_lut
);
265 pdpu
->pipe_hw
->ops
.setup_creq_lut(pdpu
->pipe_hw
, &pdpu
->pipe_qos_cfg
);
269 * _dpu_plane_set_panic_lut - set danger/safe LUT of the given plane
270 * @plane: Pointer to drm plane
271 * @fb: Pointer to framebuffer associated with the given plane
273 static void _dpu_plane_set_danger_lut(struct drm_plane
*plane
,
274 struct drm_framebuffer
*fb
)
276 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
277 const struct dpu_format
*fmt
= NULL
;
278 u32 danger_lut
, safe_lut
;
280 if (!pdpu
->is_rt_pipe
) {
281 danger_lut
= pdpu
->catalog
->perf
.danger_lut_tbl
282 [DPU_QOS_LUT_USAGE_NRT
];
283 safe_lut
= pdpu
->catalog
->perf
.safe_lut_tbl
284 [DPU_QOS_LUT_USAGE_NRT
];
286 fmt
= dpu_get_dpu_format_ext(
290 if (fmt
&& DPU_FORMAT_IS_LINEAR(fmt
)) {
291 danger_lut
= pdpu
->catalog
->perf
.danger_lut_tbl
292 [DPU_QOS_LUT_USAGE_LINEAR
];
293 safe_lut
= pdpu
->catalog
->perf
.safe_lut_tbl
294 [DPU_QOS_LUT_USAGE_LINEAR
];
296 danger_lut
= pdpu
->catalog
->perf
.danger_lut_tbl
297 [DPU_QOS_LUT_USAGE_MACROTILE
];
298 safe_lut
= pdpu
->catalog
->perf
.safe_lut_tbl
299 [DPU_QOS_LUT_USAGE_MACROTILE
];
303 pdpu
->pipe_qos_cfg
.danger_lut
= danger_lut
;
304 pdpu
->pipe_qos_cfg
.safe_lut
= safe_lut
;
306 trace_dpu_perf_set_danger_luts(pdpu
->pipe
- SSPP_VIG0
,
307 (fmt
) ? fmt
->base
.pixel_format
: 0,
308 (fmt
) ? fmt
->fetch_mode
: 0,
309 pdpu
->pipe_qos_cfg
.danger_lut
,
310 pdpu
->pipe_qos_cfg
.safe_lut
);
312 DPU_DEBUG("plane%u: pnum:%d fmt: %4.4s mode:%d luts[0x%x, 0x%x]\n",
314 pdpu
->pipe
- SSPP_VIG0
,
315 fmt
? (char *)&fmt
->base
.pixel_format
: NULL
,
316 fmt
? fmt
->fetch_mode
: -1,
317 pdpu
->pipe_qos_cfg
.danger_lut
,
318 pdpu
->pipe_qos_cfg
.safe_lut
);
320 pdpu
->pipe_hw
->ops
.setup_danger_safe_lut(pdpu
->pipe_hw
,
321 &pdpu
->pipe_qos_cfg
);
325 * _dpu_plane_set_qos_ctrl - set QoS control of the given plane
326 * @plane: Pointer to drm plane
327 * @enable: true to enable QoS control
328 * @flags: QoS control mode (enum dpu_plane_qos)
330 static void _dpu_plane_set_qos_ctrl(struct drm_plane
*plane
,
331 bool enable
, u32 flags
)
333 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
335 if (flags
& DPU_PLANE_QOS_VBLANK_CTRL
) {
336 pdpu
->pipe_qos_cfg
.creq_vblank
= pdpu
->pipe_sblk
->creq_vblank
;
337 pdpu
->pipe_qos_cfg
.danger_vblank
=
338 pdpu
->pipe_sblk
->danger_vblank
;
339 pdpu
->pipe_qos_cfg
.vblank_en
= enable
;
342 if (flags
& DPU_PLANE_QOS_VBLANK_AMORTIZE
) {
343 /* this feature overrules previous VBLANK_CTRL */
344 pdpu
->pipe_qos_cfg
.vblank_en
= false;
345 pdpu
->pipe_qos_cfg
.creq_vblank
= 0; /* clear vblank bits */
348 if (flags
& DPU_PLANE_QOS_PANIC_CTRL
)
349 pdpu
->pipe_qos_cfg
.danger_safe_en
= enable
;
351 if (!pdpu
->is_rt_pipe
) {
352 pdpu
->pipe_qos_cfg
.vblank_en
= false;
353 pdpu
->pipe_qos_cfg
.danger_safe_en
= false;
356 DPU_DEBUG("plane%u: pnum:%d ds:%d vb:%d pri[0x%x, 0x%x] is_rt:%d\n",
358 pdpu
->pipe
- SSPP_VIG0
,
359 pdpu
->pipe_qos_cfg
.danger_safe_en
,
360 pdpu
->pipe_qos_cfg
.vblank_en
,
361 pdpu
->pipe_qos_cfg
.creq_vblank
,
362 pdpu
->pipe_qos_cfg
.danger_vblank
,
365 pdpu
->pipe_hw
->ops
.setup_qos_ctrl(pdpu
->pipe_hw
,
366 &pdpu
->pipe_qos_cfg
);
370 * _dpu_plane_set_ot_limit - set OT limit for the given plane
371 * @plane: Pointer to drm plane
372 * @crtc: Pointer to drm crtc
374 static void _dpu_plane_set_ot_limit(struct drm_plane
*plane
,
375 struct drm_crtc
*crtc
)
377 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
378 struct dpu_vbif_set_ot_params ot_params
;
379 struct dpu_kms
*dpu_kms
= _dpu_plane_get_kms(plane
);
381 memset(&ot_params
, 0, sizeof(ot_params
));
382 ot_params
.xin_id
= pdpu
->pipe_hw
->cap
->xin_id
;
383 ot_params
.num
= pdpu
->pipe_hw
->idx
- SSPP_NONE
;
384 ot_params
.width
= drm_rect_width(&pdpu
->pipe_cfg
.src_rect
);
385 ot_params
.height
= drm_rect_height(&pdpu
->pipe_cfg
.src_rect
);
386 ot_params
.is_wfd
= !pdpu
->is_rt_pipe
;
387 ot_params
.frame_rate
= drm_mode_vrefresh(&crtc
->mode
);
388 ot_params
.vbif_idx
= VBIF_RT
;
389 ot_params
.clk_ctrl
= pdpu
->pipe_hw
->cap
->clk_ctrl
;
392 dpu_vbif_set_ot_limit(dpu_kms
, &ot_params
);
396 * _dpu_plane_set_vbif_qos - set vbif QoS for the given plane
397 * @plane: Pointer to drm plane
399 static void _dpu_plane_set_qos_remap(struct drm_plane
*plane
)
401 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
402 struct dpu_vbif_set_qos_params qos_params
;
403 struct dpu_kms
*dpu_kms
= _dpu_plane_get_kms(plane
);
405 memset(&qos_params
, 0, sizeof(qos_params
));
406 qos_params
.vbif_idx
= VBIF_RT
;
407 qos_params
.clk_ctrl
= pdpu
->pipe_hw
->cap
->clk_ctrl
;
408 qos_params
.xin_id
= pdpu
->pipe_hw
->cap
->xin_id
;
409 qos_params
.num
= pdpu
->pipe_hw
->idx
- SSPP_VIG0
;
410 qos_params
.is_rt
= pdpu
->is_rt_pipe
;
412 DPU_DEBUG("plane%d pipe:%d vbif:%d xin:%d rt:%d, clk_ctrl:%d\n",
413 plane
->base
.id
, qos_params
.num
,
415 qos_params
.xin_id
, qos_params
.is_rt
,
416 qos_params
.clk_ctrl
);
418 dpu_vbif_set_qos_remap(dpu_kms
, &qos_params
);
421 static void _dpu_plane_set_scanout(struct drm_plane
*plane
,
422 struct dpu_plane_state
*pstate
,
423 struct dpu_hw_pipe_cfg
*pipe_cfg
,
424 struct drm_framebuffer
*fb
)
426 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
427 struct dpu_kms
*kms
= _dpu_plane_get_kms(&pdpu
->base
);
428 struct msm_gem_address_space
*aspace
= kms
->base
.aspace
;
431 ret
= dpu_format_populate_layout(aspace
, fb
, &pipe_cfg
->layout
);
433 DPU_DEBUG_PLANE(pdpu
, "not updating same src addrs\n");
435 DPU_ERROR_PLANE(pdpu
, "failed to get format layout, %d\n", ret
);
436 else if (pdpu
->pipe_hw
->ops
.setup_sourceaddress
) {
437 trace_dpu_plane_set_scanout(pdpu
->pipe_hw
->idx
,
439 pstate
->multirect_index
);
440 pdpu
->pipe_hw
->ops
.setup_sourceaddress(pdpu
->pipe_hw
, pipe_cfg
,
441 pstate
->multirect_index
);
445 static void _dpu_plane_setup_scaler3(struct dpu_plane
*pdpu
,
446 struct dpu_plane_state
*pstate
,
447 uint32_t src_w
, uint32_t src_h
, uint32_t dst_w
, uint32_t dst_h
,
448 struct dpu_hw_scaler3_cfg
*scale_cfg
,
449 const struct dpu_format
*fmt
,
450 uint32_t chroma_subsmpl_h
, uint32_t chroma_subsmpl_v
)
454 memset(scale_cfg
, 0, sizeof(*scale_cfg
));
455 memset(&pstate
->pixel_ext
, 0, sizeof(struct dpu_hw_pixel_ext
));
457 scale_cfg
->phase_step_x
[DPU_SSPP_COMP_0
] =
458 mult_frac((1 << PHASE_STEP_SHIFT
), src_w
, dst_w
);
459 scale_cfg
->phase_step_y
[DPU_SSPP_COMP_0
] =
460 mult_frac((1 << PHASE_STEP_SHIFT
), src_h
, dst_h
);
463 scale_cfg
->phase_step_y
[DPU_SSPP_COMP_1_2
] =
464 scale_cfg
->phase_step_y
[DPU_SSPP_COMP_0
] / chroma_subsmpl_v
;
465 scale_cfg
->phase_step_x
[DPU_SSPP_COMP_1_2
] =
466 scale_cfg
->phase_step_x
[DPU_SSPP_COMP_0
] / chroma_subsmpl_h
;
468 scale_cfg
->phase_step_x
[DPU_SSPP_COMP_2
] =
469 scale_cfg
->phase_step_x
[DPU_SSPP_COMP_1_2
];
470 scale_cfg
->phase_step_y
[DPU_SSPP_COMP_2
] =
471 scale_cfg
->phase_step_y
[DPU_SSPP_COMP_1_2
];
473 scale_cfg
->phase_step_x
[DPU_SSPP_COMP_3
] =
474 scale_cfg
->phase_step_x
[DPU_SSPP_COMP_0
];
475 scale_cfg
->phase_step_y
[DPU_SSPP_COMP_3
] =
476 scale_cfg
->phase_step_y
[DPU_SSPP_COMP_0
];
478 for (i
= 0; i
< DPU_MAX_PLANES
; i
++) {
479 scale_cfg
->src_width
[i
] = src_w
;
480 scale_cfg
->src_height
[i
] = src_h
;
481 if (i
== DPU_SSPP_COMP_1_2
|| i
== DPU_SSPP_COMP_2
) {
482 scale_cfg
->src_width
[i
] /= chroma_subsmpl_h
;
483 scale_cfg
->src_height
[i
] /= chroma_subsmpl_v
;
486 if (pdpu
->pipe_hw
->cap
->features
&
487 BIT(DPU_SSPP_SCALER_QSEED4
)) {
488 scale_cfg
->preload_x
[i
] = DPU_QSEED4_DEFAULT_PRELOAD_H
;
489 scale_cfg
->preload_y
[i
] = DPU_QSEED4_DEFAULT_PRELOAD_V
;
491 scale_cfg
->preload_x
[i
] = DPU_QSEED3_DEFAULT_PRELOAD_H
;
492 scale_cfg
->preload_y
[i
] = DPU_QSEED3_DEFAULT_PRELOAD_V
;
495 pstate
->pixel_ext
.num_ext_pxls_top
[i
] =
496 scale_cfg
->src_height
[i
];
497 pstate
->pixel_ext
.num_ext_pxls_left
[i
] =
498 scale_cfg
->src_width
[i
];
500 if (!(DPU_FORMAT_IS_YUV(fmt
)) && (src_h
== dst_h
)
504 scale_cfg
->dst_width
= dst_w
;
505 scale_cfg
->dst_height
= dst_h
;
506 scale_cfg
->y_rgb_filter_cfg
= DPU_SCALE_BIL
;
507 scale_cfg
->uv_filter_cfg
= DPU_SCALE_BIL
;
508 scale_cfg
->alpha_filter_cfg
= DPU_SCALE_ALPHA_BIL
;
509 scale_cfg
->lut_flag
= 0;
510 scale_cfg
->blend_cfg
= 1;
511 scale_cfg
->enable
= 1;
514 static void _dpu_plane_setup_csc(struct dpu_plane
*pdpu
)
516 static const struct dpu_csc_cfg dpu_csc_YUV2RGB_601L
= {
519 0x00012A00, 0x00000000, 0x00019880,
520 0x00012A00, 0xFFFF9B80, 0xFFFF3000,
521 0x00012A00, 0x00020480, 0x00000000,
524 { 0xfff0, 0xff80, 0xff80,},
527 { 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0,},
528 { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,},
530 static const struct dpu_csc_cfg dpu_csc10_YUV2RGB_601L
= {
533 0x00012A00, 0x00000000, 0x00019880,
534 0x00012A00, 0xFFFF9B80, 0xFFFF3000,
535 0x00012A00, 0x00020480, 0x00000000,
538 { 0xffc0, 0xfe00, 0xfe00,},
541 { 0x40, 0x3ac, 0x40, 0x3c0, 0x40, 0x3c0,},
542 { 0x00, 0x3ff, 0x00, 0x3ff, 0x00, 0x3ff,},
546 DPU_ERROR("invalid plane\n");
550 if (BIT(DPU_SSPP_CSC_10BIT
) & pdpu
->features
)
551 pdpu
->csc_ptr
= (struct dpu_csc_cfg
*)&dpu_csc10_YUV2RGB_601L
;
553 pdpu
->csc_ptr
= (struct dpu_csc_cfg
*)&dpu_csc_YUV2RGB_601L
;
555 DPU_DEBUG_PLANE(pdpu
, "using 0x%X 0x%X 0x%X...\n",
556 pdpu
->csc_ptr
->csc_mv
[0],
557 pdpu
->csc_ptr
->csc_mv
[1],
558 pdpu
->csc_ptr
->csc_mv
[2]);
561 static void _dpu_plane_setup_scaler(struct dpu_plane
*pdpu
,
562 struct dpu_plane_state
*pstate
,
563 const struct dpu_format
*fmt
, bool color_fill
)
565 const struct drm_format_info
*info
= drm_format_info(fmt
->base
.pixel_format
);
567 /* don't chroma subsample if decimating */
568 /* update scaler. calculate default config for QSEED3 */
569 _dpu_plane_setup_scaler3(pdpu
, pstate
,
570 drm_rect_width(&pdpu
->pipe_cfg
.src_rect
),
571 drm_rect_height(&pdpu
->pipe_cfg
.src_rect
),
572 drm_rect_width(&pdpu
->pipe_cfg
.dst_rect
),
573 drm_rect_height(&pdpu
->pipe_cfg
.dst_rect
),
574 &pstate
->scaler3_cfg
, fmt
,
575 info
->hsub
, info
->vsub
);
579 * _dpu_plane_color_fill - enables color fill on plane
580 * @pdpu: Pointer to DPU plane object
581 * @color: RGB fill color value, [23..16] Blue, [15..8] Green, [7..0] Red
582 * @alpha: 8-bit fill alpha value, 255 selects 100% alpha
583 * Returns: 0 on success
585 static int _dpu_plane_color_fill(struct dpu_plane
*pdpu
,
586 uint32_t color
, uint32_t alpha
)
588 const struct dpu_format
*fmt
;
589 const struct drm_plane
*plane
= &pdpu
->base
;
590 struct dpu_plane_state
*pstate
= to_dpu_plane_state(plane
->state
);
592 DPU_DEBUG_PLANE(pdpu
, "\n");
595 * select fill format to match user property expectation,
596 * h/w only supports RGB variants
598 fmt
= dpu_get_dpu_format(DRM_FORMAT_ABGR8888
);
601 if (fmt
&& pdpu
->pipe_hw
->ops
.setup_solidfill
) {
602 pdpu
->pipe_hw
->ops
.setup_solidfill(pdpu
->pipe_hw
,
603 (color
& 0xFFFFFF) | ((alpha
& 0xFF) << 24),
604 pstate
->multirect_index
);
606 /* override scaler/decimation if solid fill */
607 pdpu
->pipe_cfg
.src_rect
.x1
= 0;
608 pdpu
->pipe_cfg
.src_rect
.y1
= 0;
609 pdpu
->pipe_cfg
.src_rect
.x2
=
610 drm_rect_width(&pdpu
->pipe_cfg
.dst_rect
);
611 pdpu
->pipe_cfg
.src_rect
.y2
=
612 drm_rect_height(&pdpu
->pipe_cfg
.dst_rect
);
613 _dpu_plane_setup_scaler(pdpu
, pstate
, fmt
, true);
615 if (pdpu
->pipe_hw
->ops
.setup_format
)
616 pdpu
->pipe_hw
->ops
.setup_format(pdpu
->pipe_hw
,
617 fmt
, DPU_SSPP_SOLID_FILL
,
618 pstate
->multirect_index
);
620 if (pdpu
->pipe_hw
->ops
.setup_rects
)
621 pdpu
->pipe_hw
->ops
.setup_rects(pdpu
->pipe_hw
,
623 pstate
->multirect_index
);
625 if (pdpu
->pipe_hw
->ops
.setup_pe
)
626 pdpu
->pipe_hw
->ops
.setup_pe(pdpu
->pipe_hw
,
629 if (pdpu
->pipe_hw
->ops
.setup_scaler
&&
630 pstate
->multirect_index
!= DPU_SSPP_RECT_1
)
631 pdpu
->pipe_hw
->ops
.setup_scaler(pdpu
->pipe_hw
,
632 &pdpu
->pipe_cfg
, &pstate
->pixel_ext
,
633 &pstate
->scaler3_cfg
);
639 void dpu_plane_clear_multirect(const struct drm_plane_state
*drm_state
)
641 struct dpu_plane_state
*pstate
= to_dpu_plane_state(drm_state
);
643 pstate
->multirect_index
= DPU_SSPP_RECT_SOLO
;
644 pstate
->multirect_mode
= DPU_SSPP_MULTIRECT_NONE
;
647 int dpu_plane_validate_multirect_v2(struct dpu_multirect_plane_states
*plane
)
649 struct dpu_plane_state
*pstate
[R_MAX
];
650 const struct drm_plane_state
*drm_state
[R_MAX
];
651 struct drm_rect src
[R_MAX
], dst
[R_MAX
];
652 struct dpu_plane
*dpu_plane
[R_MAX
];
653 const struct dpu_format
*fmt
[R_MAX
];
655 unsigned int max_tile_height
= 1;
656 bool parallel_fetch_qualified
= true;
657 bool has_tiled_rect
= false;
659 for (i
= 0; i
< R_MAX
; i
++) {
660 const struct msm_format
*msm_fmt
;
662 drm_state
[i
] = i
? plane
->r1
: plane
->r0
;
663 msm_fmt
= msm_framebuffer_format(drm_state
[i
]->fb
);
664 fmt
[i
] = to_dpu_format(msm_fmt
);
666 if (DPU_FORMAT_IS_UBWC(fmt
[i
])) {
667 has_tiled_rect
= true;
668 if (fmt
[i
]->tile_height
> max_tile_height
)
669 max_tile_height
= fmt
[i
]->tile_height
;
673 for (i
= 0; i
< R_MAX
; i
++) {
676 pstate
[i
] = to_dpu_plane_state(drm_state
[i
]);
677 dpu_plane
[i
] = to_dpu_plane(drm_state
[i
]->plane
);
679 if (pstate
[i
] == NULL
) {
680 DPU_ERROR("DPU plane state of plane id %d is NULL\n",
681 drm_state
[i
]->plane
->base
.id
);
685 src
[i
].x1
= drm_state
[i
]->src_x
>> 16;
686 src
[i
].y1
= drm_state
[i
]->src_y
>> 16;
687 src
[i
].x2
= src
[i
].x1
+ (drm_state
[i
]->src_w
>> 16);
688 src
[i
].y2
= src
[i
].y1
+ (drm_state
[i
]->src_h
>> 16);
690 dst
[i
] = drm_plane_state_dest(drm_state
[i
]);
692 if (drm_rect_calc_hscale(&src
[i
], &dst
[i
], 1, 1) != 1 ||
693 drm_rect_calc_vscale(&src
[i
], &dst
[i
], 1, 1) != 1) {
694 DPU_ERROR_PLANE(dpu_plane
[i
],
695 "scaling is not supported in multirect mode\n");
699 if (DPU_FORMAT_IS_YUV(fmt
[i
])) {
700 DPU_ERROR_PLANE(dpu_plane
[i
],
701 "Unsupported format for multirect mode\n");
706 * SSPP PD_MEM is split half - one for each RECT.
707 * Tiled formats need 5 lines of buffering while fetching
708 * whereas linear formats need only 2 lines.
709 * So we cannot support more than half of the supported SSPP
710 * width for tiled formats.
712 width_threshold
= dpu_plane
[i
]->pipe_sblk
->common
->maxlinewidth
;
714 width_threshold
/= 2;
716 if (parallel_fetch_qualified
&&
717 drm_rect_width(&src
[i
]) > width_threshold
)
718 parallel_fetch_qualified
= false;
722 /* Validate RECT's and set the mode */
724 /* Prefer PARALLEL FETCH Mode over TIME_MX Mode */
725 if (parallel_fetch_qualified
) {
726 pstate
[R0
]->multirect_mode
= DPU_SSPP_MULTIRECT_PARALLEL
;
727 pstate
[R1
]->multirect_mode
= DPU_SSPP_MULTIRECT_PARALLEL
;
733 buffer_lines
= 2 * max_tile_height
;
735 if (dst
[R1
].y1
>= dst
[R0
].y2
+ buffer_lines
||
736 dst
[R0
].y1
>= dst
[R1
].y2
+ buffer_lines
) {
737 pstate
[R0
]->multirect_mode
= DPU_SSPP_MULTIRECT_TIME_MX
;
738 pstate
[R1
]->multirect_mode
= DPU_SSPP_MULTIRECT_TIME_MX
;
741 "No multirect mode possible for the planes (%d - %d)\n",
742 drm_state
[R0
]->plane
->base
.id
,
743 drm_state
[R1
]->plane
->base
.id
);
748 if (dpu_plane
[R0
]->is_virtual
) {
749 pstate
[R0
]->multirect_index
= DPU_SSPP_RECT_1
;
750 pstate
[R1
]->multirect_index
= DPU_SSPP_RECT_0
;
752 pstate
[R0
]->multirect_index
= DPU_SSPP_RECT_0
;
753 pstate
[R1
]->multirect_index
= DPU_SSPP_RECT_1
;
756 DPU_DEBUG_PLANE(dpu_plane
[R0
], "R0: %d - %d\n",
757 pstate
[R0
]->multirect_mode
, pstate
[R0
]->multirect_index
);
758 DPU_DEBUG_PLANE(dpu_plane
[R1
], "R1: %d - %d\n",
759 pstate
[R1
]->multirect_mode
, pstate
[R1
]->multirect_index
);
764 * dpu_plane_get_ctl_flush - get control flush for the given plane
765 * @plane: Pointer to drm plane structure
766 * @ctl: Pointer to hardware control driver
767 * @flush_sspp: Pointer to sspp flush control word
769 void dpu_plane_get_ctl_flush(struct drm_plane
*plane
, struct dpu_hw_ctl
*ctl
,
772 *flush_sspp
= ctl
->ops
.get_bitmask_sspp(ctl
, dpu_plane_pipe(plane
));
775 static int dpu_plane_prepare_fb(struct drm_plane
*plane
,
776 struct drm_plane_state
*new_state
)
778 struct drm_framebuffer
*fb
= new_state
->fb
;
779 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
780 struct dpu_plane_state
*pstate
= to_dpu_plane_state(new_state
);
781 struct dpu_hw_fmt_layout layout
;
782 struct dpu_kms
*kms
= _dpu_plane_get_kms(&pdpu
->base
);
788 DPU_DEBUG_PLANE(pdpu
, "FB[%u]\n", fb
->base
.id
);
791 pstate
->aspace
= kms
->base
.aspace
;
794 * TODO: Need to sort out the msm_framebuffer_prepare() call below so
795 * we can use msm_atomic_prepare_fb() instead of doing the
796 * implicit fence and fb prepare by hand here.
798 drm_gem_fb_prepare_fb(plane
, new_state
);
800 if (pstate
->aspace
) {
801 ret
= msm_framebuffer_prepare(new_state
->fb
,
804 DPU_ERROR("failed to prepare framebuffer\n");
809 /* validate framebuffer layout before commit */
810 ret
= dpu_format_populate_layout(pstate
->aspace
,
811 new_state
->fb
, &layout
);
813 DPU_ERROR_PLANE(pdpu
, "failed to get format layout, %d\n", ret
);
820 static void dpu_plane_cleanup_fb(struct drm_plane
*plane
,
821 struct drm_plane_state
*old_state
)
823 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
824 struct dpu_plane_state
*old_pstate
;
826 if (!old_state
|| !old_state
->fb
)
829 old_pstate
= to_dpu_plane_state(old_state
);
831 DPU_DEBUG_PLANE(pdpu
, "FB[%u]\n", old_state
->fb
->base
.id
);
833 msm_framebuffer_cleanup(old_state
->fb
, old_pstate
->aspace
);
836 static bool dpu_plane_validate_src(struct drm_rect
*src
,
837 struct drm_rect
*fb_rect
,
838 uint32_t min_src_size
)
840 /* Ensure fb size is supported */
841 if (drm_rect_width(fb_rect
) > MAX_IMG_WIDTH
||
842 drm_rect_height(fb_rect
) > MAX_IMG_HEIGHT
)
845 /* Ensure src rect is above the minimum size */
846 if (drm_rect_width(src
) < min_src_size
||
847 drm_rect_height(src
) < min_src_size
)
850 /* Ensure src is fully encapsulated in fb */
851 return drm_rect_intersect(fb_rect
, src
) &&
852 drm_rect_equals(fb_rect
, src
);
855 static int dpu_plane_atomic_check(struct drm_plane
*plane
,
856 struct drm_plane_state
*state
)
858 int ret
= 0, min_scale
;
859 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
860 const struct drm_crtc_state
*crtc_state
= NULL
;
861 const struct dpu_format
*fmt
;
862 struct drm_rect src
, dst
, fb_rect
= { 0 };
863 uint32_t min_src_size
, max_linewidth
;
866 crtc_state
= drm_atomic_get_new_crtc_state(state
->state
,
869 min_scale
= FRAC_16_16(1, pdpu
->pipe_sblk
->maxdwnscale
);
870 ret
= drm_atomic_helper_check_plane_state(state
, crtc_state
, min_scale
,
871 pdpu
->pipe_sblk
->maxupscale
<< 16,
874 DPU_DEBUG_PLANE(pdpu
, "Check plane state failed (%d)\n", ret
);
880 src
.x1
= state
->src_x
>> 16;
881 src
.y1
= state
->src_y
>> 16;
882 src
.x2
= src
.x1
+ (state
->src_w
>> 16);
883 src
.y2
= src
.y1
+ (state
->src_h
>> 16);
885 dst
= drm_plane_state_dest(state
);
887 fb_rect
.x2
= state
->fb
->width
;
888 fb_rect
.y2
= state
->fb
->height
;
890 max_linewidth
= pdpu
->pipe_sblk
->common
->maxlinewidth
;
892 fmt
= to_dpu_format(msm_framebuffer_format(state
->fb
));
894 min_src_size
= DPU_FORMAT_IS_YUV(fmt
) ? 2 : 1;
896 if (DPU_FORMAT_IS_YUV(fmt
) &&
897 (!(pdpu
->features
& DPU_SSPP_SCALER
) ||
898 !(pdpu
->features
& (BIT(DPU_SSPP_CSC
)
899 | BIT(DPU_SSPP_CSC_10BIT
))))) {
900 DPU_DEBUG_PLANE(pdpu
,
901 "plane doesn't have scaler/csc for yuv\n");
904 /* check src bounds */
905 } else if (!dpu_plane_validate_src(&src
, &fb_rect
, min_src_size
)) {
906 DPU_DEBUG_PLANE(pdpu
, "invalid source " DRM_RECT_FMT
"\n",
910 /* valid yuv image */
911 } else if (DPU_FORMAT_IS_YUV(fmt
) &&
912 (src
.x1
& 0x1 || src
.y1
& 0x1 ||
913 drm_rect_width(&src
) & 0x1 ||
914 drm_rect_height(&src
) & 0x1)) {
915 DPU_DEBUG_PLANE(pdpu
, "invalid yuv source " DRM_RECT_FMT
"\n",
919 /* min dst support */
920 } else if (drm_rect_width(&dst
) < 0x1 || drm_rect_height(&dst
) < 0x1) {
921 DPU_DEBUG_PLANE(pdpu
, "invalid dest rect " DRM_RECT_FMT
"\n",
925 /* check decimated source width */
926 } else if (drm_rect_width(&src
) > max_linewidth
) {
927 DPU_DEBUG_PLANE(pdpu
, "invalid src " DRM_RECT_FMT
" line:%u\n",
928 DRM_RECT_ARG(&src
), max_linewidth
);
935 void dpu_plane_flush(struct drm_plane
*plane
)
937 struct dpu_plane
*pdpu
;
938 struct dpu_plane_state
*pstate
;
940 if (!plane
|| !plane
->state
) {
941 DPU_ERROR("invalid plane\n");
945 pdpu
= to_dpu_plane(plane
);
946 pstate
= to_dpu_plane_state(plane
->state
);
949 * These updates have to be done immediately before the plane flush
950 * timing, and may not be moved to the atomic_update/mode_set functions.
953 /* force white frame with 100% alpha pipe output on error */
954 _dpu_plane_color_fill(pdpu
, 0xFFFFFF, 0xFF);
955 else if (pdpu
->color_fill
& DPU_PLANE_COLOR_FILL_FLAG
)
956 /* force 100% alpha */
957 _dpu_plane_color_fill(pdpu
, pdpu
->color_fill
, 0xFF);
958 else if (pdpu
->pipe_hw
&& pdpu
->csc_ptr
&& pdpu
->pipe_hw
->ops
.setup_csc
)
959 pdpu
->pipe_hw
->ops
.setup_csc(pdpu
->pipe_hw
, pdpu
->csc_ptr
);
961 /* flag h/w flush complete */
963 pstate
->pending
= false;
967 * dpu_plane_set_error: enable/disable error condition
968 * @plane: pointer to drm_plane structure
970 void dpu_plane_set_error(struct drm_plane
*plane
, bool error
)
972 struct dpu_plane
*pdpu
;
977 pdpu
= to_dpu_plane(plane
);
978 pdpu
->is_error
= error
;
981 static void dpu_plane_sspp_atomic_update(struct drm_plane
*plane
)
984 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
985 struct drm_plane_state
*state
= plane
->state
;
986 struct dpu_plane_state
*pstate
= to_dpu_plane_state(state
);
987 struct drm_crtc
*crtc
= state
->crtc
;
988 struct drm_framebuffer
*fb
= state
->fb
;
989 const struct dpu_format
*fmt
=
990 to_dpu_format(msm_framebuffer_format(fb
));
992 memset(&(pdpu
->pipe_cfg
), 0, sizeof(struct dpu_hw_pipe_cfg
));
994 _dpu_plane_set_scanout(plane
, pstate
, &pdpu
->pipe_cfg
, fb
);
996 pstate
->pending
= true;
998 pdpu
->is_rt_pipe
= (dpu_crtc_get_client_type(crtc
) != NRT_CLIENT
);
999 _dpu_plane_set_qos_ctrl(plane
, false, DPU_PLANE_QOS_PANIC_CTRL
);
1001 DPU_DEBUG_PLANE(pdpu
, "FB[%u] " DRM_RECT_FP_FMT
"->crtc%u " DRM_RECT_FMT
1002 ", %4.4s ubwc %d\n", fb
->base
.id
, DRM_RECT_FP_ARG(&state
->src
),
1003 crtc
->base
.id
, DRM_RECT_ARG(&state
->dst
),
1004 (char *)&fmt
->base
.pixel_format
, DPU_FORMAT_IS_UBWC(fmt
));
1006 pdpu
->pipe_cfg
.src_rect
= state
->src
;
1008 /* state->src is 16.16, src_rect is not */
1009 pdpu
->pipe_cfg
.src_rect
.x1
>>= 16;
1010 pdpu
->pipe_cfg
.src_rect
.x2
>>= 16;
1011 pdpu
->pipe_cfg
.src_rect
.y1
>>= 16;
1012 pdpu
->pipe_cfg
.src_rect
.y2
>>= 16;
1014 pdpu
->pipe_cfg
.dst_rect
= state
->dst
;
1016 _dpu_plane_setup_scaler(pdpu
, pstate
, fmt
, false);
1018 /* override for color fill */
1019 if (pdpu
->color_fill
& DPU_PLANE_COLOR_FILL_FLAG
) {
1020 /* skip remaining processing on color fill */
1024 if (pdpu
->pipe_hw
->ops
.setup_rects
) {
1025 pdpu
->pipe_hw
->ops
.setup_rects(pdpu
->pipe_hw
,
1027 pstate
->multirect_index
);
1030 if (pdpu
->pipe_hw
->ops
.setup_pe
&&
1031 (pstate
->multirect_index
!= DPU_SSPP_RECT_1
))
1032 pdpu
->pipe_hw
->ops
.setup_pe(pdpu
->pipe_hw
,
1033 &pstate
->pixel_ext
);
1036 * when programmed in multirect mode, scalar block will be
1037 * bypassed. Still we need to update alpha and bitwidth
1040 if (pdpu
->pipe_hw
->ops
.setup_scaler
&&
1041 pstate
->multirect_index
!= DPU_SSPP_RECT_1
)
1042 pdpu
->pipe_hw
->ops
.setup_scaler(pdpu
->pipe_hw
,
1043 &pdpu
->pipe_cfg
, &pstate
->pixel_ext
,
1044 &pstate
->scaler3_cfg
);
1046 if (pdpu
->pipe_hw
->ops
.setup_multirect
)
1047 pdpu
->pipe_hw
->ops
.setup_multirect(
1049 pstate
->multirect_index
,
1050 pstate
->multirect_mode
);
1052 if (pdpu
->pipe_hw
->ops
.setup_format
) {
1053 unsigned int rotation
;
1057 rotation
= drm_rotation_simplify(state
->rotation
,
1059 DRM_MODE_REFLECT_X
|
1060 DRM_MODE_REFLECT_Y
);
1062 if (rotation
& DRM_MODE_REFLECT_X
)
1063 src_flags
|= DPU_SSPP_FLIP_LR
;
1065 if (rotation
& DRM_MODE_REFLECT_Y
)
1066 src_flags
|= DPU_SSPP_FLIP_UD
;
1069 pdpu
->pipe_hw
->ops
.setup_format(pdpu
->pipe_hw
, fmt
, src_flags
,
1070 pstate
->multirect_index
);
1072 if (pdpu
->pipe_hw
->ops
.setup_cdp
) {
1073 struct dpu_hw_pipe_cdp_cfg
*cdp_cfg
= &pstate
->cdp_cfg
;
1075 memset(cdp_cfg
, 0, sizeof(struct dpu_hw_pipe_cdp_cfg
));
1077 cdp_cfg
->enable
= pdpu
->catalog
->perf
.cdp_cfg
1078 [DPU_PERF_CDP_USAGE_RT
].rd_enable
;
1079 cdp_cfg
->ubwc_meta_enable
=
1080 DPU_FORMAT_IS_UBWC(fmt
);
1081 cdp_cfg
->tile_amortize_enable
=
1082 DPU_FORMAT_IS_UBWC(fmt
) ||
1083 DPU_FORMAT_IS_TILE(fmt
);
1084 cdp_cfg
->preload_ahead
= DPU_SSPP_CDP_PRELOAD_AHEAD_64
;
1086 pdpu
->pipe_hw
->ops
.setup_cdp(pdpu
->pipe_hw
, cdp_cfg
);
1090 if (DPU_FORMAT_IS_YUV(fmt
))
1091 _dpu_plane_setup_csc(pdpu
);
1096 _dpu_plane_set_qos_lut(plane
, fb
);
1097 _dpu_plane_set_danger_lut(plane
, fb
);
1099 if (plane
->type
!= DRM_PLANE_TYPE_CURSOR
) {
1100 _dpu_plane_set_qos_ctrl(plane
, true, DPU_PLANE_QOS_PANIC_CTRL
);
1101 _dpu_plane_set_ot_limit(plane
, crtc
);
1104 _dpu_plane_set_qos_remap(plane
);
1107 static void _dpu_plane_atomic_disable(struct drm_plane
*plane
)
1109 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
1110 struct drm_plane_state
*state
= plane
->state
;
1111 struct dpu_plane_state
*pstate
= to_dpu_plane_state(state
);
1113 trace_dpu_plane_disable(DRMID(plane
), is_dpu_plane_virtual(plane
),
1114 pstate
->multirect_mode
);
1116 pstate
->pending
= true;
1118 if (is_dpu_plane_virtual(plane
) &&
1119 pdpu
->pipe_hw
&& pdpu
->pipe_hw
->ops
.setup_multirect
)
1120 pdpu
->pipe_hw
->ops
.setup_multirect(pdpu
->pipe_hw
,
1121 DPU_SSPP_RECT_SOLO
, DPU_SSPP_MULTIRECT_NONE
);
1124 static void dpu_plane_atomic_update(struct drm_plane
*plane
,
1125 struct drm_plane_state
*old_state
)
1127 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
1128 struct drm_plane_state
*state
= plane
->state
;
1130 pdpu
->is_error
= false;
1132 DPU_DEBUG_PLANE(pdpu
, "\n");
1134 if (!state
->visible
) {
1135 _dpu_plane_atomic_disable(plane
);
1137 dpu_plane_sspp_atomic_update(plane
);
1141 void dpu_plane_restore(struct drm_plane
*plane
)
1143 struct dpu_plane
*pdpu
;
1145 if (!plane
|| !plane
->state
) {
1146 DPU_ERROR("invalid plane\n");
1150 pdpu
= to_dpu_plane(plane
);
1152 DPU_DEBUG_PLANE(pdpu
, "\n");
1154 /* last plane state is same as current state */
1155 dpu_plane_atomic_update(plane
, plane
->state
);
1158 static void dpu_plane_destroy(struct drm_plane
*plane
)
1160 struct dpu_plane
*pdpu
= plane
? to_dpu_plane(plane
) : NULL
;
1162 DPU_DEBUG_PLANE(pdpu
, "\n");
1165 _dpu_plane_set_qos_ctrl(plane
, false, DPU_PLANE_QOS_PANIC_CTRL
);
1167 mutex_destroy(&pdpu
->lock
);
1169 /* this will destroy the states as well */
1170 drm_plane_cleanup(plane
);
1172 dpu_hw_sspp_destroy(pdpu
->pipe_hw
);
1178 static void dpu_plane_destroy_state(struct drm_plane
*plane
,
1179 struct drm_plane_state
*state
)
1181 __drm_atomic_helper_plane_destroy_state(state
);
1182 kfree(to_dpu_plane_state(state
));
1185 static struct drm_plane_state
*
1186 dpu_plane_duplicate_state(struct drm_plane
*plane
)
1188 struct dpu_plane
*pdpu
;
1189 struct dpu_plane_state
*pstate
;
1190 struct dpu_plane_state
*old_state
;
1193 DPU_ERROR("invalid plane\n");
1195 } else if (!plane
->state
) {
1196 DPU_ERROR("invalid plane state\n");
1200 old_state
= to_dpu_plane_state(plane
->state
);
1201 pdpu
= to_dpu_plane(plane
);
1202 pstate
= kmemdup(old_state
, sizeof(*old_state
), GFP_KERNEL
);
1204 DPU_ERROR_PLANE(pdpu
, "failed to allocate state\n");
1208 DPU_DEBUG_PLANE(pdpu
, "\n");
1210 pstate
->pending
= false;
1212 __drm_atomic_helper_plane_duplicate_state(plane
, &pstate
->base
);
1214 return &pstate
->base
;
1217 static void dpu_plane_reset(struct drm_plane
*plane
)
1219 struct dpu_plane
*pdpu
;
1220 struct dpu_plane_state
*pstate
;
1223 DPU_ERROR("invalid plane\n");
1227 pdpu
= to_dpu_plane(plane
);
1228 DPU_DEBUG_PLANE(pdpu
, "\n");
1230 /* remove previous state, if present */
1232 dpu_plane_destroy_state(plane
, plane
->state
);
1236 pstate
= kzalloc(sizeof(*pstate
), GFP_KERNEL
);
1238 DPU_ERROR_PLANE(pdpu
, "failed to allocate state\n");
1242 pstate
->base
.plane
= plane
;
1244 plane
->state
= &pstate
->base
;
1247 #ifdef CONFIG_DEBUG_FS
1248 static void dpu_plane_danger_signal_ctrl(struct drm_plane
*plane
, bool enable
)
1250 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
1251 struct dpu_kms
*dpu_kms
= _dpu_plane_get_kms(plane
);
1253 if (!pdpu
->is_rt_pipe
)
1256 pm_runtime_get_sync(&dpu_kms
->pdev
->dev
);
1257 _dpu_plane_set_qos_ctrl(plane
, enable
, DPU_PLANE_QOS_PANIC_CTRL
);
1258 pm_runtime_put_sync(&dpu_kms
->pdev
->dev
);
1261 static ssize_t
_dpu_plane_danger_read(struct file
*file
,
1262 char __user
*buff
, size_t count
, loff_t
*ppos
)
1264 struct dpu_kms
*kms
= file
->private_data
;
1268 len
= scnprintf(buf
, sizeof(buf
), "%d\n", !kms
->has_danger_ctrl
);
1270 return simple_read_from_buffer(buff
, count
, ppos
, buf
, len
);
1273 static void _dpu_plane_set_danger_state(struct dpu_kms
*kms
, bool enable
)
1275 struct drm_plane
*plane
;
1277 drm_for_each_plane(plane
, kms
->dev
) {
1278 if (plane
->fb
&& plane
->state
) {
1279 dpu_plane_danger_signal_ctrl(plane
, enable
);
1280 DPU_DEBUG("plane:%d img:%dx%d ",
1281 plane
->base
.id
, plane
->fb
->width
,
1283 DPU_DEBUG("src[%d,%d,%d,%d] dst[%d,%d,%d,%d]\n",
1284 plane
->state
->src_x
>> 16,
1285 plane
->state
->src_y
>> 16,
1286 plane
->state
->src_w
>> 16,
1287 plane
->state
->src_h
>> 16,
1288 plane
->state
->crtc_x
, plane
->state
->crtc_y
,
1289 plane
->state
->crtc_w
, plane
->state
->crtc_h
);
1291 DPU_DEBUG("Inactive plane:%d\n", plane
->base
.id
);
1296 static ssize_t
_dpu_plane_danger_write(struct file
*file
,
1297 const char __user
*user_buf
, size_t count
, loff_t
*ppos
)
1299 struct dpu_kms
*kms
= file
->private_data
;
1303 ret
= kstrtouint_from_user(user_buf
, count
, 0, &disable_panic
);
1307 if (disable_panic
) {
1308 /* Disable panic signal for all active pipes */
1309 DPU_DEBUG("Disabling danger:\n");
1310 _dpu_plane_set_danger_state(kms
, false);
1311 kms
->has_danger_ctrl
= false;
1313 /* Enable panic signal for all active pipes */
1314 DPU_DEBUG("Enabling danger:\n");
1315 kms
->has_danger_ctrl
= true;
1316 _dpu_plane_set_danger_state(kms
, true);
1322 static const struct file_operations dpu_plane_danger_enable
= {
1323 .open
= simple_open
,
1324 .read
= _dpu_plane_danger_read
,
1325 .write
= _dpu_plane_danger_write
,
1328 static int _dpu_plane_init_debugfs(struct drm_plane
*plane
)
1330 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
1331 struct dpu_kms
*kms
= _dpu_plane_get_kms(plane
);
1332 const struct dpu_sspp_cfg
*cfg
= pdpu
->pipe_hw
->cap
;
1333 const struct dpu_sspp_sub_blks
*sblk
= cfg
->sblk
;
1335 /* create overall sub-directory for the pipe */
1336 pdpu
->debugfs_root
=
1337 debugfs_create_dir(pdpu
->pipe_name
,
1338 plane
->dev
->primary
->debugfs_root
);
1340 /* don't error check these */
1341 debugfs_create_x32("features", 0600,
1342 pdpu
->debugfs_root
, &pdpu
->features
);
1344 /* add register dump support */
1345 dpu_debugfs_setup_regset32(&pdpu
->debugfs_src
,
1346 sblk
->src_blk
.base
+ cfg
->base
,
1349 dpu_debugfs_create_regset32("src_blk", 0400,
1350 pdpu
->debugfs_root
, &pdpu
->debugfs_src
);
1352 if (cfg
->features
& BIT(DPU_SSPP_SCALER_QSEED3
) ||
1353 cfg
->features
& BIT(DPU_SSPP_SCALER_QSEED2
) ||
1354 cfg
->features
& BIT(DPU_SSPP_SCALER_QSEED4
)) {
1355 dpu_debugfs_setup_regset32(&pdpu
->debugfs_scaler
,
1356 sblk
->scaler_blk
.base
+ cfg
->base
,
1357 sblk
->scaler_blk
.len
,
1359 dpu_debugfs_create_regset32("scaler_blk", 0400,
1361 &pdpu
->debugfs_scaler
);
1362 debugfs_create_bool("default_scaling",
1365 &pdpu
->debugfs_default_scale
);
1368 if (cfg
->features
& BIT(DPU_SSPP_CSC
) ||
1369 cfg
->features
& BIT(DPU_SSPP_CSC_10BIT
)) {
1370 dpu_debugfs_setup_regset32(&pdpu
->debugfs_csc
,
1371 sblk
->csc_blk
.base
+ cfg
->base
,
1374 dpu_debugfs_create_regset32("csc_blk", 0400,
1375 pdpu
->debugfs_root
, &pdpu
->debugfs_csc
);
1378 debugfs_create_u32("xin_id",
1381 (u32
*) &cfg
->xin_id
);
1382 debugfs_create_u32("clk_ctrl",
1385 (u32
*) &cfg
->clk_ctrl
);
1386 debugfs_create_x32("creq_vblank",
1389 (u32
*) &sblk
->creq_vblank
);
1390 debugfs_create_x32("danger_vblank",
1393 (u32
*) &sblk
->danger_vblank
);
1395 debugfs_create_file("disable_danger",
1398 kms
, &dpu_plane_danger_enable
);
1403 static int _dpu_plane_init_debugfs(struct drm_plane
*plane
)
1409 static int dpu_plane_late_register(struct drm_plane
*plane
)
1411 return _dpu_plane_init_debugfs(plane
);
1414 static void dpu_plane_early_unregister(struct drm_plane
*plane
)
1416 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
1418 debugfs_remove_recursive(pdpu
->debugfs_root
);
1421 static bool dpu_plane_format_mod_supported(struct drm_plane
*plane
,
1422 uint32_t format
, uint64_t modifier
)
1424 if (modifier
== DRM_FORMAT_MOD_LINEAR
)
1427 if (modifier
== DRM_FORMAT_MOD_QCOM_COMPRESSED
) {
1429 for (i
= 0; i
< ARRAY_SIZE(qcom_compressed_supported_formats
); i
++) {
1430 if (format
== qcom_compressed_supported_formats
[i
])
1438 static const struct drm_plane_funcs dpu_plane_funcs
= {
1439 .update_plane
= drm_atomic_helper_update_plane
,
1440 .disable_plane
= drm_atomic_helper_disable_plane
,
1441 .destroy
= dpu_plane_destroy
,
1442 .reset
= dpu_plane_reset
,
1443 .atomic_duplicate_state
= dpu_plane_duplicate_state
,
1444 .atomic_destroy_state
= dpu_plane_destroy_state
,
1445 .late_register
= dpu_plane_late_register
,
1446 .early_unregister
= dpu_plane_early_unregister
,
1447 .format_mod_supported
= dpu_plane_format_mod_supported
,
1450 static const struct drm_plane_helper_funcs dpu_plane_helper_funcs
= {
1451 .prepare_fb
= dpu_plane_prepare_fb
,
1452 .cleanup_fb
= dpu_plane_cleanup_fb
,
1453 .atomic_check
= dpu_plane_atomic_check
,
1454 .atomic_update
= dpu_plane_atomic_update
,
1457 enum dpu_sspp
dpu_plane_pipe(struct drm_plane
*plane
)
1459 return plane
? to_dpu_plane(plane
)->pipe
: SSPP_NONE
;
1462 bool is_dpu_plane_virtual(struct drm_plane
*plane
)
1464 return plane
? to_dpu_plane(plane
)->is_virtual
: false;
1467 /* initialize plane */
1468 struct drm_plane
*dpu_plane_init(struct drm_device
*dev
,
1469 uint32_t pipe
, enum drm_plane_type type
,
1470 unsigned long possible_crtcs
, u32 master_plane_id
)
1472 struct drm_plane
*plane
= NULL
, *master_plane
= NULL
;
1473 const uint32_t *format_list
;
1474 struct dpu_plane
*pdpu
;
1475 struct msm_drm_private
*priv
= dev
->dev_private
;
1476 struct dpu_kms
*kms
= to_dpu_kms(priv
->kms
);
1477 int zpos_max
= DPU_ZPOS_MAX
;
1478 uint32_t num_formats
;
1481 /* create and zero local structure */
1482 pdpu
= kzalloc(sizeof(*pdpu
), GFP_KERNEL
);
1484 DPU_ERROR("[%u]failed to allocate local plane struct\n", pipe
);
1486 return ERR_PTR(ret
);
1489 /* cache local stuff for later */
1490 plane
= &pdpu
->base
;
1492 pdpu
->is_virtual
= (master_plane_id
!= 0);
1493 INIT_LIST_HEAD(&pdpu
->mplane_list
);
1494 master_plane
= drm_plane_find(dev
, NULL
, master_plane_id
);
1496 struct dpu_plane
*mpdpu
= to_dpu_plane(master_plane
);
1498 list_add_tail(&pdpu
->mplane_list
, &mpdpu
->mplane_list
);
1501 /* initialize underlying h/w driver */
1502 pdpu
->pipe_hw
= dpu_hw_sspp_init(pipe
, kms
->mmio
, kms
->catalog
,
1503 master_plane_id
!= 0);
1504 if (IS_ERR(pdpu
->pipe_hw
)) {
1505 DPU_ERROR("[%u]SSPP init failed\n", pipe
);
1506 ret
= PTR_ERR(pdpu
->pipe_hw
);
1508 } else if (!pdpu
->pipe_hw
->cap
|| !pdpu
->pipe_hw
->cap
->sblk
) {
1509 DPU_ERROR("[%u]SSPP init returned invalid cfg\n", pipe
);
1513 /* cache features mask for later */
1514 pdpu
->features
= pdpu
->pipe_hw
->cap
->features
;
1515 pdpu
->pipe_sblk
= pdpu
->pipe_hw
->cap
->sblk
;
1516 if (!pdpu
->pipe_sblk
) {
1517 DPU_ERROR("[%u]invalid sblk\n", pipe
);
1521 if (pdpu
->is_virtual
) {
1522 format_list
= pdpu
->pipe_sblk
->virt_format_list
;
1523 num_formats
= pdpu
->pipe_sblk
->virt_num_formats
;
1526 format_list
= pdpu
->pipe_sblk
->format_list
;
1527 num_formats
= pdpu
->pipe_sblk
->num_formats
;
1530 ret
= drm_universal_plane_init(dev
, plane
, 0xff, &dpu_plane_funcs
,
1531 format_list
, num_formats
,
1532 supported_format_modifiers
, type
, NULL
);
1536 pdpu
->catalog
= kms
->catalog
;
1538 if (kms
->catalog
->mixer_count
&&
1539 kms
->catalog
->mixer
[0].sblk
->maxblendstages
) {
1540 zpos_max
= kms
->catalog
->mixer
[0].sblk
->maxblendstages
- 1;
1541 if (zpos_max
> DPU_STAGE_MAX
- DPU_STAGE_0
- 1)
1542 zpos_max
= DPU_STAGE_MAX
- DPU_STAGE_0
- 1;
1545 ret
= drm_plane_create_zpos_property(plane
, 0, 0, zpos_max
);
1547 DPU_ERROR("failed to install zpos property, rc = %d\n", ret
);
1549 drm_plane_create_rotation_property(plane
,
1552 DRM_MODE_ROTATE_180
|
1553 DRM_MODE_REFLECT_X
|
1554 DRM_MODE_REFLECT_Y
);
1556 drm_plane_enable_fb_damage_clips(plane
);
1558 /* success! finalize initialization */
1559 drm_plane_helper_add(plane
, &dpu_plane_helper_funcs
);
1561 /* save user friendly pipe name for later */
1562 snprintf(pdpu
->pipe_name
, DPU_NAME_SIZE
, "plane%u", plane
->base
.id
);
1564 mutex_init(&pdpu
->lock
);
1566 DPU_DEBUG("%s created for pipe:%u id:%u virtual:%u\n", pdpu
->pipe_name
,
1567 pipe
, plane
->base
.id
, master_plane_id
);
1571 if (pdpu
&& pdpu
->pipe_hw
)
1572 dpu_hw_sspp_destroy(pdpu
->pipe_hw
);
1575 return ERR_PTR(ret
);