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_trace.h"
25 #include "dpu_plane.h"
27 #define DPU_DEBUG_PLANE(pl, fmt, ...) DPU_DEBUG("plane%d " fmt,\
28 (pl) ? (pl)->base.base.id : -1, ##__VA_ARGS__)
30 #define DPU_ERROR_PLANE(pl, fmt, ...) DPU_ERROR("plane%d " fmt,\
31 (pl) ? (pl)->base.base.id : -1, ##__VA_ARGS__)
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
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
43 #define DPU_NAME_SIZE 12
45 #define DPU_PLANE_COLOR_FILL_FLAG BIT(31)
46 #define DPU_ZPOS_MAX 255
48 /* multirect rect index */
56 * Default Preload Values
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
63 #define DEFAULT_REFRESH_RATE 60
65 static const uint32_t qcom_compressed_supported_formats
[] = {
76 * enum dpu_plane_qos - Different qos configurations for each pipe
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.
84 DPU_PLANE_QOS_VBLANK_CTRL
= BIT(0),
85 DPU_PLANE_QOS_VBLANK_AMORTIZE
= BIT(1),
86 DPU_PLANE_QOS_PANIC_CTRL
= BIT(2),
90 * struct dpu_plane - local dpu plane structure
91 * @aspace: address space pointer
92 * @csc_ptr: Points to dpu_csc_cfg structure to use for current
93 * @mplane_list: List of multirect planes of the same pipe
94 * @catalog: Points to dpu catalog structure
95 * @revalidate: force revalidation of all the plane properties
98 struct drm_plane base
;
103 uint32_t features
; /* capabilities from catalog */
105 struct dpu_hw_pipe
*pipe_hw
;
106 struct dpu_hw_pipe_cfg pipe_cfg
;
107 struct dpu_hw_pipe_qos_cfg pipe_qos_cfg
;
112 struct list_head mplane_list
;
113 struct dpu_mdss_cfg
*catalog
;
115 struct dpu_csc_cfg
*csc_ptr
;
117 const struct dpu_sspp_sub_blks
*pipe_sblk
;
118 char pipe_name
[DPU_NAME_SIZE
];
120 /* debugfs related stuff */
121 struct dentry
*debugfs_root
;
122 struct dpu_debugfs_regset32 debugfs_src
;
123 struct dpu_debugfs_regset32 debugfs_scaler
;
124 struct dpu_debugfs_regset32 debugfs_csc
;
125 bool debugfs_default_scale
;
128 static const uint64_t supported_format_modifiers
[] = {
129 DRM_FORMAT_MOD_QCOM_COMPRESSED
,
130 DRM_FORMAT_MOD_LINEAR
,
131 DRM_FORMAT_MOD_INVALID
134 #define to_dpu_plane(x) container_of(x, struct dpu_plane, base)
136 static struct dpu_kms
*_dpu_plane_get_kms(struct drm_plane
*plane
)
138 struct msm_drm_private
*priv
= plane
->dev
->dev_private
;
140 return to_dpu_kms(priv
->kms
);
144 * _dpu_plane_calc_bw - calculate bandwidth required for a plane
145 * @plane: Pointer to drm plane.
146 * @fb: Pointer to framebuffer associated with the given plane
147 * Result: Updates calculated bandwidth in the plane state.
148 * BW Equation: src_w * src_h * bpp * fps * (v_total / v_dest)
149 * Prefill BW Equation: line src bytes * line_time
151 static void _dpu_plane_calc_bw(struct drm_plane
*plane
,
152 struct drm_framebuffer
*fb
)
154 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
155 struct dpu_plane_state
*pstate
;
156 struct drm_display_mode
*mode
;
157 const struct dpu_format
*fmt
= NULL
;
158 struct dpu_kms
*dpu_kms
= _dpu_plane_get_kms(plane
);
159 int src_width
, src_height
, dst_height
, fps
;
160 u64 plane_prefill_bw
;
162 u32 hw_latency_lines
;
166 pstate
= to_dpu_plane_state(plane
->state
);
167 mode
= &plane
->state
->crtc
->mode
;
169 fmt
= dpu_get_dpu_format_ext(fb
->format
->format
, fb
->modifier
);
171 src_width
= drm_rect_width(&pdpu
->pipe_cfg
.src_rect
);
172 src_height
= drm_rect_height(&pdpu
->pipe_cfg
.src_rect
);
173 dst_height
= drm_rect_height(&pdpu
->pipe_cfg
.dst_rect
);
174 fps
= drm_mode_vrefresh(mode
);
175 vbp
= mode
->vtotal
- mode
->vsync_end
;
176 vpw
= mode
->vsync_end
- mode
->vsync_start
;
177 vfp
= mode
->vsync_start
- mode
->vdisplay
;
178 hw_latency_lines
= dpu_kms
->catalog
->perf
.min_prefill_lines
;
179 scale_factor
= src_height
> dst_height
?
180 mult_frac(src_height
, 1, dst_height
) : 1;
183 src_width
* mode
->vtotal
* fps
* fmt
->bpp
*
187 src_width
* hw_latency_lines
* fps
* fmt
->bpp
*
188 scale_factor
* mode
->vtotal
;
190 if ((vbp
+vpw
) > hw_latency_lines
)
191 do_div(plane_prefill_bw
, (vbp
+vpw
));
192 else if ((vbp
+vpw
+vfp
) < hw_latency_lines
)
193 do_div(plane_prefill_bw
, (vbp
+vpw
+vfp
));
195 do_div(plane_prefill_bw
, hw_latency_lines
);
198 pstate
->plane_fetch_bw
= max(plane_bw
, plane_prefill_bw
);
202 * _dpu_plane_calc_clk - calculate clock required for a plane
203 * @plane: Pointer to drm plane.
204 * Result: Updates calculated clock in the plane state.
205 * Clock equation: dst_w * v_total * fps * (src_h / dst_h)
207 static void _dpu_plane_calc_clk(struct drm_plane
*plane
)
209 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
210 struct dpu_plane_state
*pstate
;
211 struct drm_display_mode
*mode
;
212 int dst_width
, src_height
, dst_height
, fps
;
214 pstate
= to_dpu_plane_state(plane
->state
);
215 mode
= &plane
->state
->crtc
->mode
;
217 src_height
= drm_rect_height(&pdpu
->pipe_cfg
.src_rect
);
218 dst_width
= drm_rect_width(&pdpu
->pipe_cfg
.dst_rect
);
219 dst_height
= drm_rect_height(&pdpu
->pipe_cfg
.dst_rect
);
220 fps
= drm_mode_vrefresh(mode
);
223 dst_width
* mode
->vtotal
* fps
;
225 if (src_height
> dst_height
) {
226 pstate
->plane_clk
*= src_height
;
227 do_div(pstate
->plane_clk
, dst_height
);
232 * _dpu_plane_calc_fill_level - calculate fill level of the given source format
233 * @plane: Pointer to drm plane
234 * @fmt: Pointer to source buffer format
235 * @src_width: width of source buffer
236 * Return: fill level corresponding to the source buffer/format or 0 if error
238 static int _dpu_plane_calc_fill_level(struct drm_plane
*plane
,
239 const struct dpu_format
*fmt
, u32 src_width
)
241 struct dpu_plane
*pdpu
, *tmp
;
242 struct dpu_plane_state
*pstate
;
246 if (!fmt
|| !plane
->state
|| !src_width
|| !fmt
->bpp
) {
247 DPU_ERROR("invalid arguments\n");
251 pdpu
= to_dpu_plane(plane
);
252 pstate
= to_dpu_plane_state(plane
->state
);
253 fixed_buff_size
= pdpu
->catalog
->caps
->pixel_ram_size
;
255 list_for_each_entry(tmp
, &pdpu
->mplane_list
, mplane_list
) {
256 if (!tmp
->base
.state
->visible
)
258 DPU_DEBUG("plane%d/%d src_width:%d/%d\n",
259 pdpu
->base
.base
.id
, tmp
->base
.base
.id
,
261 drm_rect_width(&tmp
->pipe_cfg
.src_rect
));
262 src_width
= max_t(u32
, src_width
,
263 drm_rect_width(&tmp
->pipe_cfg
.src_rect
));
266 if (fmt
->fetch_planes
== DPU_PLANE_PSEUDO_PLANAR
) {
267 if (fmt
->chroma_sample
== DPU_CHROMA_420
) {
269 total_fl
= (fixed_buff_size
/ 2) /
270 ((src_width
+ 32) * fmt
->bpp
);
273 total_fl
= (fixed_buff_size
/ 2) * 2 /
274 ((src_width
+ 32) * fmt
->bpp
);
277 if (pstate
->multirect_mode
== DPU_SSPP_MULTIRECT_PARALLEL
) {
278 total_fl
= (fixed_buff_size
/ 2) * 2 /
279 ((src_width
+ 32) * fmt
->bpp
);
281 total_fl
= (fixed_buff_size
) * 2 /
282 ((src_width
+ 32) * fmt
->bpp
);
286 DPU_DEBUG("plane%u: pnum:%d fmt: %4.4s w:%u fl:%u\n",
287 plane
->base
.id
, pdpu
->pipe
- SSPP_VIG0
,
288 (char *)&fmt
->base
.pixel_format
,
289 src_width
, total_fl
);
295 * _dpu_plane_get_qos_lut - get LUT mapping based on fill level
296 * @tbl: Pointer to LUT table
297 * @total_fl: fill level
298 * Return: LUT setting corresponding to the fill level
300 static u64
_dpu_plane_get_qos_lut(const struct dpu_qos_lut_tbl
*tbl
,
305 if (!tbl
|| !tbl
->nentry
|| !tbl
->entries
)
308 for (i
= 0; i
< tbl
->nentry
; i
++)
309 if (total_fl
<= tbl
->entries
[i
].fl
)
310 return tbl
->entries
[i
].lut
;
312 /* if last fl is zero, use as default */
313 if (!tbl
->entries
[i
-1].fl
)
314 return tbl
->entries
[i
-1].lut
;
320 * _dpu_plane_set_qos_lut - set QoS LUT of the given plane
321 * @plane: Pointer to drm plane
322 * @fb: Pointer to framebuffer associated with the given plane
324 static void _dpu_plane_set_qos_lut(struct drm_plane
*plane
,
325 struct drm_framebuffer
*fb
)
327 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
328 const struct dpu_format
*fmt
= NULL
;
330 u32 total_fl
= 0, lut_usage
;
332 if (!pdpu
->is_rt_pipe
) {
333 lut_usage
= DPU_QOS_LUT_USAGE_NRT
;
335 fmt
= dpu_get_dpu_format_ext(
338 total_fl
= _dpu_plane_calc_fill_level(plane
, fmt
,
339 drm_rect_width(&pdpu
->pipe_cfg
.src_rect
));
341 if (fmt
&& DPU_FORMAT_IS_LINEAR(fmt
))
342 lut_usage
= DPU_QOS_LUT_USAGE_LINEAR
;
344 lut_usage
= DPU_QOS_LUT_USAGE_MACROTILE
;
347 qos_lut
= _dpu_plane_get_qos_lut(
348 &pdpu
->catalog
->perf
.qos_lut_tbl
[lut_usage
], total_fl
);
350 pdpu
->pipe_qos_cfg
.creq_lut
= qos_lut
;
352 trace_dpu_perf_set_qos_luts(pdpu
->pipe
- SSPP_VIG0
,
353 (fmt
) ? fmt
->base
.pixel_format
: 0,
354 pdpu
->is_rt_pipe
, total_fl
, qos_lut
, lut_usage
);
356 DPU_DEBUG("plane%u: pnum:%d fmt: %4.4s rt:%d fl:%u lut:0x%llx\n",
358 pdpu
->pipe
- SSPP_VIG0
,
359 fmt
? (char *)&fmt
->base
.pixel_format
: NULL
,
360 pdpu
->is_rt_pipe
, total_fl
, qos_lut
);
362 pdpu
->pipe_hw
->ops
.setup_creq_lut(pdpu
->pipe_hw
, &pdpu
->pipe_qos_cfg
);
366 * _dpu_plane_set_panic_lut - set danger/safe LUT of the given plane
367 * @plane: Pointer to drm plane
368 * @fb: Pointer to framebuffer associated with the given plane
370 static void _dpu_plane_set_danger_lut(struct drm_plane
*plane
,
371 struct drm_framebuffer
*fb
)
373 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
374 const struct dpu_format
*fmt
= NULL
;
375 u32 danger_lut
, safe_lut
;
377 if (!pdpu
->is_rt_pipe
) {
378 danger_lut
= pdpu
->catalog
->perf
.danger_lut_tbl
379 [DPU_QOS_LUT_USAGE_NRT
];
380 safe_lut
= pdpu
->catalog
->perf
.safe_lut_tbl
381 [DPU_QOS_LUT_USAGE_NRT
];
383 fmt
= dpu_get_dpu_format_ext(
387 if (fmt
&& DPU_FORMAT_IS_LINEAR(fmt
)) {
388 danger_lut
= pdpu
->catalog
->perf
.danger_lut_tbl
389 [DPU_QOS_LUT_USAGE_LINEAR
];
390 safe_lut
= pdpu
->catalog
->perf
.safe_lut_tbl
391 [DPU_QOS_LUT_USAGE_LINEAR
];
393 danger_lut
= pdpu
->catalog
->perf
.danger_lut_tbl
394 [DPU_QOS_LUT_USAGE_MACROTILE
];
395 safe_lut
= pdpu
->catalog
->perf
.safe_lut_tbl
396 [DPU_QOS_LUT_USAGE_MACROTILE
];
400 pdpu
->pipe_qos_cfg
.danger_lut
= danger_lut
;
401 pdpu
->pipe_qos_cfg
.safe_lut
= safe_lut
;
403 trace_dpu_perf_set_danger_luts(pdpu
->pipe
- SSPP_VIG0
,
404 (fmt
) ? fmt
->base
.pixel_format
: 0,
405 (fmt
) ? fmt
->fetch_mode
: 0,
406 pdpu
->pipe_qos_cfg
.danger_lut
,
407 pdpu
->pipe_qos_cfg
.safe_lut
);
409 DPU_DEBUG("plane%u: pnum:%d fmt: %4.4s mode:%d luts[0x%x, 0x%x]\n",
411 pdpu
->pipe
- SSPP_VIG0
,
412 fmt
? (char *)&fmt
->base
.pixel_format
: NULL
,
413 fmt
? fmt
->fetch_mode
: -1,
414 pdpu
->pipe_qos_cfg
.danger_lut
,
415 pdpu
->pipe_qos_cfg
.safe_lut
);
417 pdpu
->pipe_hw
->ops
.setup_danger_safe_lut(pdpu
->pipe_hw
,
418 &pdpu
->pipe_qos_cfg
);
422 * _dpu_plane_set_qos_ctrl - set QoS control of the given plane
423 * @plane: Pointer to drm plane
424 * @enable: true to enable QoS control
425 * @flags: QoS control mode (enum dpu_plane_qos)
427 static void _dpu_plane_set_qos_ctrl(struct drm_plane
*plane
,
428 bool enable
, u32 flags
)
430 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
432 if (flags
& DPU_PLANE_QOS_VBLANK_CTRL
) {
433 pdpu
->pipe_qos_cfg
.creq_vblank
= pdpu
->pipe_sblk
->creq_vblank
;
434 pdpu
->pipe_qos_cfg
.danger_vblank
=
435 pdpu
->pipe_sblk
->danger_vblank
;
436 pdpu
->pipe_qos_cfg
.vblank_en
= enable
;
439 if (flags
& DPU_PLANE_QOS_VBLANK_AMORTIZE
) {
440 /* this feature overrules previous VBLANK_CTRL */
441 pdpu
->pipe_qos_cfg
.vblank_en
= false;
442 pdpu
->pipe_qos_cfg
.creq_vblank
= 0; /* clear vblank bits */
445 if (flags
& DPU_PLANE_QOS_PANIC_CTRL
)
446 pdpu
->pipe_qos_cfg
.danger_safe_en
= enable
;
448 if (!pdpu
->is_rt_pipe
) {
449 pdpu
->pipe_qos_cfg
.vblank_en
= false;
450 pdpu
->pipe_qos_cfg
.danger_safe_en
= false;
453 DPU_DEBUG("plane%u: pnum:%d ds:%d vb:%d pri[0x%x, 0x%x] is_rt:%d\n",
455 pdpu
->pipe
- SSPP_VIG0
,
456 pdpu
->pipe_qos_cfg
.danger_safe_en
,
457 pdpu
->pipe_qos_cfg
.vblank_en
,
458 pdpu
->pipe_qos_cfg
.creq_vblank
,
459 pdpu
->pipe_qos_cfg
.danger_vblank
,
462 pdpu
->pipe_hw
->ops
.setup_qos_ctrl(pdpu
->pipe_hw
,
463 &pdpu
->pipe_qos_cfg
);
467 * _dpu_plane_set_ot_limit - set OT limit for the given plane
468 * @plane: Pointer to drm plane
469 * @crtc: Pointer to drm crtc
471 static void _dpu_plane_set_ot_limit(struct drm_plane
*plane
,
472 struct drm_crtc
*crtc
)
474 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
475 struct dpu_vbif_set_ot_params ot_params
;
476 struct dpu_kms
*dpu_kms
= _dpu_plane_get_kms(plane
);
478 memset(&ot_params
, 0, sizeof(ot_params
));
479 ot_params
.xin_id
= pdpu
->pipe_hw
->cap
->xin_id
;
480 ot_params
.num
= pdpu
->pipe_hw
->idx
- SSPP_NONE
;
481 ot_params
.width
= drm_rect_width(&pdpu
->pipe_cfg
.src_rect
);
482 ot_params
.height
= drm_rect_height(&pdpu
->pipe_cfg
.src_rect
);
483 ot_params
.is_wfd
= !pdpu
->is_rt_pipe
;
484 ot_params
.frame_rate
= drm_mode_vrefresh(&crtc
->mode
);
485 ot_params
.vbif_idx
= VBIF_RT
;
486 ot_params
.clk_ctrl
= pdpu
->pipe_hw
->cap
->clk_ctrl
;
489 dpu_vbif_set_ot_limit(dpu_kms
, &ot_params
);
493 * _dpu_plane_set_vbif_qos - set vbif QoS for the given plane
494 * @plane: Pointer to drm plane
496 static void _dpu_plane_set_qos_remap(struct drm_plane
*plane
)
498 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
499 struct dpu_vbif_set_qos_params qos_params
;
500 struct dpu_kms
*dpu_kms
= _dpu_plane_get_kms(plane
);
502 memset(&qos_params
, 0, sizeof(qos_params
));
503 qos_params
.vbif_idx
= VBIF_RT
;
504 qos_params
.clk_ctrl
= pdpu
->pipe_hw
->cap
->clk_ctrl
;
505 qos_params
.xin_id
= pdpu
->pipe_hw
->cap
->xin_id
;
506 qos_params
.num
= pdpu
->pipe_hw
->idx
- SSPP_VIG0
;
507 qos_params
.is_rt
= pdpu
->is_rt_pipe
;
509 DPU_DEBUG("plane%d pipe:%d vbif:%d xin:%d rt:%d, clk_ctrl:%d\n",
510 plane
->base
.id
, qos_params
.num
,
512 qos_params
.xin_id
, qos_params
.is_rt
,
513 qos_params
.clk_ctrl
);
515 dpu_vbif_set_qos_remap(dpu_kms
, &qos_params
);
518 static void _dpu_plane_set_scanout(struct drm_plane
*plane
,
519 struct dpu_plane_state
*pstate
,
520 struct dpu_hw_pipe_cfg
*pipe_cfg
,
521 struct drm_framebuffer
*fb
)
523 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
524 struct dpu_kms
*kms
= _dpu_plane_get_kms(&pdpu
->base
);
525 struct msm_gem_address_space
*aspace
= kms
->base
.aspace
;
528 ret
= dpu_format_populate_layout(aspace
, fb
, &pipe_cfg
->layout
);
530 DPU_DEBUG_PLANE(pdpu
, "not updating same src addrs\n");
532 DPU_ERROR_PLANE(pdpu
, "failed to get format layout, %d\n", ret
);
533 else if (pdpu
->pipe_hw
->ops
.setup_sourceaddress
) {
534 trace_dpu_plane_set_scanout(pdpu
->pipe_hw
->idx
,
536 pstate
->multirect_index
);
537 pdpu
->pipe_hw
->ops
.setup_sourceaddress(pdpu
->pipe_hw
, pipe_cfg
,
538 pstate
->multirect_index
);
542 static void _dpu_plane_setup_scaler3(struct dpu_plane
*pdpu
,
543 struct dpu_plane_state
*pstate
,
544 uint32_t src_w
, uint32_t src_h
, uint32_t dst_w
, uint32_t dst_h
,
545 struct dpu_hw_scaler3_cfg
*scale_cfg
,
546 const struct dpu_format
*fmt
,
547 uint32_t chroma_subsmpl_h
, uint32_t chroma_subsmpl_v
)
551 memset(scale_cfg
, 0, sizeof(*scale_cfg
));
552 memset(&pstate
->pixel_ext
, 0, sizeof(struct dpu_hw_pixel_ext
));
554 scale_cfg
->phase_step_x
[DPU_SSPP_COMP_0
] =
555 mult_frac((1 << PHASE_STEP_SHIFT
), src_w
, dst_w
);
556 scale_cfg
->phase_step_y
[DPU_SSPP_COMP_0
] =
557 mult_frac((1 << PHASE_STEP_SHIFT
), src_h
, dst_h
);
560 scale_cfg
->phase_step_y
[DPU_SSPP_COMP_1_2
] =
561 scale_cfg
->phase_step_y
[DPU_SSPP_COMP_0
] / chroma_subsmpl_v
;
562 scale_cfg
->phase_step_x
[DPU_SSPP_COMP_1_2
] =
563 scale_cfg
->phase_step_x
[DPU_SSPP_COMP_0
] / chroma_subsmpl_h
;
565 scale_cfg
->phase_step_x
[DPU_SSPP_COMP_2
] =
566 scale_cfg
->phase_step_x
[DPU_SSPP_COMP_1_2
];
567 scale_cfg
->phase_step_y
[DPU_SSPP_COMP_2
] =
568 scale_cfg
->phase_step_y
[DPU_SSPP_COMP_1_2
];
570 scale_cfg
->phase_step_x
[DPU_SSPP_COMP_3
] =
571 scale_cfg
->phase_step_x
[DPU_SSPP_COMP_0
];
572 scale_cfg
->phase_step_y
[DPU_SSPP_COMP_3
] =
573 scale_cfg
->phase_step_y
[DPU_SSPP_COMP_0
];
575 for (i
= 0; i
< DPU_MAX_PLANES
; i
++) {
576 scale_cfg
->src_width
[i
] = src_w
;
577 scale_cfg
->src_height
[i
] = src_h
;
578 if (i
== DPU_SSPP_COMP_1_2
|| i
== DPU_SSPP_COMP_2
) {
579 scale_cfg
->src_width
[i
] /= chroma_subsmpl_h
;
580 scale_cfg
->src_height
[i
] /= chroma_subsmpl_v
;
583 if (pdpu
->pipe_hw
->cap
->features
&
584 BIT(DPU_SSPP_SCALER_QSEED4
)) {
585 scale_cfg
->preload_x
[i
] = DPU_QSEED4_DEFAULT_PRELOAD_H
;
586 scale_cfg
->preload_y
[i
] = DPU_QSEED4_DEFAULT_PRELOAD_V
;
588 scale_cfg
->preload_x
[i
] = DPU_QSEED3_DEFAULT_PRELOAD_H
;
589 scale_cfg
->preload_y
[i
] = DPU_QSEED3_DEFAULT_PRELOAD_V
;
592 pstate
->pixel_ext
.num_ext_pxls_top
[i
] =
593 scale_cfg
->src_height
[i
];
594 pstate
->pixel_ext
.num_ext_pxls_left
[i
] =
595 scale_cfg
->src_width
[i
];
597 if (!(DPU_FORMAT_IS_YUV(fmt
)) && (src_h
== dst_h
)
601 scale_cfg
->dst_width
= dst_w
;
602 scale_cfg
->dst_height
= dst_h
;
603 scale_cfg
->y_rgb_filter_cfg
= DPU_SCALE_BIL
;
604 scale_cfg
->uv_filter_cfg
= DPU_SCALE_BIL
;
605 scale_cfg
->alpha_filter_cfg
= DPU_SCALE_ALPHA_BIL
;
606 scale_cfg
->lut_flag
= 0;
607 scale_cfg
->blend_cfg
= 1;
608 scale_cfg
->enable
= 1;
611 static void _dpu_plane_setup_csc(struct dpu_plane
*pdpu
)
613 static const struct dpu_csc_cfg dpu_csc_YUV2RGB_601L
= {
616 0x00012A00, 0x00000000, 0x00019880,
617 0x00012A00, 0xFFFF9B80, 0xFFFF3000,
618 0x00012A00, 0x00020480, 0x00000000,
621 { 0xfff0, 0xff80, 0xff80,},
624 { 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0,},
625 { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,},
627 static const struct dpu_csc_cfg dpu_csc10_YUV2RGB_601L
= {
630 0x00012A00, 0x00000000, 0x00019880,
631 0x00012A00, 0xFFFF9B80, 0xFFFF3000,
632 0x00012A00, 0x00020480, 0x00000000,
635 { 0xffc0, 0xfe00, 0xfe00,},
638 { 0x40, 0x3ac, 0x40, 0x3c0, 0x40, 0x3c0,},
639 { 0x00, 0x3ff, 0x00, 0x3ff, 0x00, 0x3ff,},
643 DPU_ERROR("invalid plane\n");
647 if (BIT(DPU_SSPP_CSC_10BIT
) & pdpu
->features
)
648 pdpu
->csc_ptr
= (struct dpu_csc_cfg
*)&dpu_csc10_YUV2RGB_601L
;
650 pdpu
->csc_ptr
= (struct dpu_csc_cfg
*)&dpu_csc_YUV2RGB_601L
;
652 DPU_DEBUG_PLANE(pdpu
, "using 0x%X 0x%X 0x%X...\n",
653 pdpu
->csc_ptr
->csc_mv
[0],
654 pdpu
->csc_ptr
->csc_mv
[1],
655 pdpu
->csc_ptr
->csc_mv
[2]);
658 static void _dpu_plane_setup_scaler(struct dpu_plane
*pdpu
,
659 struct dpu_plane_state
*pstate
,
660 const struct dpu_format
*fmt
, bool color_fill
)
662 const struct drm_format_info
*info
= drm_format_info(fmt
->base
.pixel_format
);
664 /* don't chroma subsample if decimating */
665 /* update scaler. calculate default config for QSEED3 */
666 _dpu_plane_setup_scaler3(pdpu
, pstate
,
667 drm_rect_width(&pdpu
->pipe_cfg
.src_rect
),
668 drm_rect_height(&pdpu
->pipe_cfg
.src_rect
),
669 drm_rect_width(&pdpu
->pipe_cfg
.dst_rect
),
670 drm_rect_height(&pdpu
->pipe_cfg
.dst_rect
),
671 &pstate
->scaler3_cfg
, fmt
,
672 info
->hsub
, info
->vsub
);
676 * _dpu_plane_color_fill - enables color fill on plane
677 * @pdpu: Pointer to DPU plane object
678 * @color: RGB fill color value, [23..16] Blue, [15..8] Green, [7..0] Red
679 * @alpha: 8-bit fill alpha value, 255 selects 100% alpha
680 * Returns: 0 on success
682 static int _dpu_plane_color_fill(struct dpu_plane
*pdpu
,
683 uint32_t color
, uint32_t alpha
)
685 const struct dpu_format
*fmt
;
686 const struct drm_plane
*plane
= &pdpu
->base
;
687 struct dpu_plane_state
*pstate
= to_dpu_plane_state(plane
->state
);
689 DPU_DEBUG_PLANE(pdpu
, "\n");
692 * select fill format to match user property expectation,
693 * h/w only supports RGB variants
695 fmt
= dpu_get_dpu_format(DRM_FORMAT_ABGR8888
);
698 if (fmt
&& pdpu
->pipe_hw
->ops
.setup_solidfill
) {
699 pdpu
->pipe_hw
->ops
.setup_solidfill(pdpu
->pipe_hw
,
700 (color
& 0xFFFFFF) | ((alpha
& 0xFF) << 24),
701 pstate
->multirect_index
);
703 /* override scaler/decimation if solid fill */
704 pdpu
->pipe_cfg
.src_rect
.x1
= 0;
705 pdpu
->pipe_cfg
.src_rect
.y1
= 0;
706 pdpu
->pipe_cfg
.src_rect
.x2
=
707 drm_rect_width(&pdpu
->pipe_cfg
.dst_rect
);
708 pdpu
->pipe_cfg
.src_rect
.y2
=
709 drm_rect_height(&pdpu
->pipe_cfg
.dst_rect
);
710 _dpu_plane_setup_scaler(pdpu
, pstate
, fmt
, true);
712 if (pdpu
->pipe_hw
->ops
.setup_format
)
713 pdpu
->pipe_hw
->ops
.setup_format(pdpu
->pipe_hw
,
714 fmt
, DPU_SSPP_SOLID_FILL
,
715 pstate
->multirect_index
);
717 if (pdpu
->pipe_hw
->ops
.setup_rects
)
718 pdpu
->pipe_hw
->ops
.setup_rects(pdpu
->pipe_hw
,
720 pstate
->multirect_index
);
722 if (pdpu
->pipe_hw
->ops
.setup_pe
)
723 pdpu
->pipe_hw
->ops
.setup_pe(pdpu
->pipe_hw
,
726 if (pdpu
->pipe_hw
->ops
.setup_scaler
&&
727 pstate
->multirect_index
!= DPU_SSPP_RECT_1
)
728 pdpu
->pipe_hw
->ops
.setup_scaler(pdpu
->pipe_hw
,
729 &pdpu
->pipe_cfg
, &pstate
->pixel_ext
,
730 &pstate
->scaler3_cfg
);
736 void dpu_plane_clear_multirect(const struct drm_plane_state
*drm_state
)
738 struct dpu_plane_state
*pstate
= to_dpu_plane_state(drm_state
);
740 pstate
->multirect_index
= DPU_SSPP_RECT_SOLO
;
741 pstate
->multirect_mode
= DPU_SSPP_MULTIRECT_NONE
;
744 int dpu_plane_validate_multirect_v2(struct dpu_multirect_plane_states
*plane
)
746 struct dpu_plane_state
*pstate
[R_MAX
];
747 const struct drm_plane_state
*drm_state
[R_MAX
];
748 struct drm_rect src
[R_MAX
], dst
[R_MAX
];
749 struct dpu_plane
*dpu_plane
[R_MAX
];
750 const struct dpu_format
*fmt
[R_MAX
];
752 unsigned int max_tile_height
= 1;
753 bool parallel_fetch_qualified
= true;
754 bool has_tiled_rect
= false;
756 for (i
= 0; i
< R_MAX
; i
++) {
757 const struct msm_format
*msm_fmt
;
759 drm_state
[i
] = i
? plane
->r1
: plane
->r0
;
760 msm_fmt
= msm_framebuffer_format(drm_state
[i
]->fb
);
761 fmt
[i
] = to_dpu_format(msm_fmt
);
763 if (DPU_FORMAT_IS_UBWC(fmt
[i
])) {
764 has_tiled_rect
= true;
765 if (fmt
[i
]->tile_height
> max_tile_height
)
766 max_tile_height
= fmt
[i
]->tile_height
;
770 for (i
= 0; i
< R_MAX
; i
++) {
773 pstate
[i
] = to_dpu_plane_state(drm_state
[i
]);
774 dpu_plane
[i
] = to_dpu_plane(drm_state
[i
]->plane
);
776 if (pstate
[i
] == NULL
) {
777 DPU_ERROR("DPU plane state of plane id %d is NULL\n",
778 drm_state
[i
]->plane
->base
.id
);
782 src
[i
].x1
= drm_state
[i
]->src_x
>> 16;
783 src
[i
].y1
= drm_state
[i
]->src_y
>> 16;
784 src
[i
].x2
= src
[i
].x1
+ (drm_state
[i
]->src_w
>> 16);
785 src
[i
].y2
= src
[i
].y1
+ (drm_state
[i
]->src_h
>> 16);
787 dst
[i
] = drm_plane_state_dest(drm_state
[i
]);
789 if (drm_rect_calc_hscale(&src
[i
], &dst
[i
], 1, 1) != 1 ||
790 drm_rect_calc_vscale(&src
[i
], &dst
[i
], 1, 1) != 1) {
791 DPU_ERROR_PLANE(dpu_plane
[i
],
792 "scaling is not supported in multirect mode\n");
796 if (DPU_FORMAT_IS_YUV(fmt
[i
])) {
797 DPU_ERROR_PLANE(dpu_plane
[i
],
798 "Unsupported format for multirect mode\n");
803 * SSPP PD_MEM is split half - one for each RECT.
804 * Tiled formats need 5 lines of buffering while fetching
805 * whereas linear formats need only 2 lines.
806 * So we cannot support more than half of the supported SSPP
807 * width for tiled formats.
809 width_threshold
= dpu_plane
[i
]->catalog
->caps
->max_linewidth
;
811 width_threshold
/= 2;
813 if (parallel_fetch_qualified
&&
814 drm_rect_width(&src
[i
]) > width_threshold
)
815 parallel_fetch_qualified
= false;
819 /* Validate RECT's and set the mode */
821 /* Prefer PARALLEL FETCH Mode over TIME_MX Mode */
822 if (parallel_fetch_qualified
) {
823 pstate
[R0
]->multirect_mode
= DPU_SSPP_MULTIRECT_PARALLEL
;
824 pstate
[R1
]->multirect_mode
= DPU_SSPP_MULTIRECT_PARALLEL
;
830 buffer_lines
= 2 * max_tile_height
;
832 if (dst
[R1
].y1
>= dst
[R0
].y2
+ buffer_lines
||
833 dst
[R0
].y1
>= dst
[R1
].y2
+ buffer_lines
) {
834 pstate
[R0
]->multirect_mode
= DPU_SSPP_MULTIRECT_TIME_MX
;
835 pstate
[R1
]->multirect_mode
= DPU_SSPP_MULTIRECT_TIME_MX
;
838 "No multirect mode possible for the planes (%d - %d)\n",
839 drm_state
[R0
]->plane
->base
.id
,
840 drm_state
[R1
]->plane
->base
.id
);
845 if (dpu_plane
[R0
]->is_virtual
) {
846 pstate
[R0
]->multirect_index
= DPU_SSPP_RECT_1
;
847 pstate
[R1
]->multirect_index
= DPU_SSPP_RECT_0
;
849 pstate
[R0
]->multirect_index
= DPU_SSPP_RECT_0
;
850 pstate
[R1
]->multirect_index
= DPU_SSPP_RECT_1
;
853 DPU_DEBUG_PLANE(dpu_plane
[R0
], "R0: %d - %d\n",
854 pstate
[R0
]->multirect_mode
, pstate
[R0
]->multirect_index
);
855 DPU_DEBUG_PLANE(dpu_plane
[R1
], "R1: %d - %d\n",
856 pstate
[R1
]->multirect_mode
, pstate
[R1
]->multirect_index
);
861 * dpu_plane_get_ctl_flush - get control flush for the given plane
862 * @plane: Pointer to drm plane structure
863 * @ctl: Pointer to hardware control driver
864 * @flush_sspp: Pointer to sspp flush control word
866 void dpu_plane_get_ctl_flush(struct drm_plane
*plane
, struct dpu_hw_ctl
*ctl
,
869 *flush_sspp
= ctl
->ops
.get_bitmask_sspp(ctl
, dpu_plane_pipe(plane
));
872 static int dpu_plane_prepare_fb(struct drm_plane
*plane
,
873 struct drm_plane_state
*new_state
)
875 struct drm_framebuffer
*fb
= new_state
->fb
;
876 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
877 struct dpu_plane_state
*pstate
= to_dpu_plane_state(new_state
);
878 struct dpu_hw_fmt_layout layout
;
879 struct dpu_kms
*kms
= _dpu_plane_get_kms(&pdpu
->base
);
885 DPU_DEBUG_PLANE(pdpu
, "FB[%u]\n", fb
->base
.id
);
888 pstate
->aspace
= kms
->base
.aspace
;
891 * TODO: Need to sort out the msm_framebuffer_prepare() call below so
892 * we can use msm_atomic_prepare_fb() instead of doing the
893 * implicit fence and fb prepare by hand here.
895 drm_gem_fb_prepare_fb(plane
, new_state
);
897 if (pstate
->aspace
) {
898 ret
= msm_framebuffer_prepare(new_state
->fb
,
901 DPU_ERROR("failed to prepare framebuffer\n");
906 /* validate framebuffer layout before commit */
907 ret
= dpu_format_populate_layout(pstate
->aspace
,
908 new_state
->fb
, &layout
);
910 DPU_ERROR_PLANE(pdpu
, "failed to get format layout, %d\n", ret
);
917 static void dpu_plane_cleanup_fb(struct drm_plane
*plane
,
918 struct drm_plane_state
*old_state
)
920 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
921 struct dpu_plane_state
*old_pstate
;
923 if (!old_state
|| !old_state
->fb
)
926 old_pstate
= to_dpu_plane_state(old_state
);
928 DPU_DEBUG_PLANE(pdpu
, "FB[%u]\n", old_state
->fb
->base
.id
);
930 msm_framebuffer_cleanup(old_state
->fb
, old_pstate
->aspace
);
933 static bool dpu_plane_validate_src(struct drm_rect
*src
,
934 struct drm_rect
*fb_rect
,
935 uint32_t min_src_size
)
937 /* Ensure fb size is supported */
938 if (drm_rect_width(fb_rect
) > MAX_IMG_WIDTH
||
939 drm_rect_height(fb_rect
) > MAX_IMG_HEIGHT
)
942 /* Ensure src rect is above the minimum size */
943 if (drm_rect_width(src
) < min_src_size
||
944 drm_rect_height(src
) < min_src_size
)
947 /* Ensure src is fully encapsulated in fb */
948 return drm_rect_intersect(fb_rect
, src
) &&
949 drm_rect_equals(fb_rect
, src
);
952 static int dpu_plane_atomic_check(struct drm_plane
*plane
,
953 struct drm_plane_state
*state
)
955 int ret
= 0, min_scale
;
956 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
957 struct dpu_plane_state
*pstate
= to_dpu_plane_state(state
);
958 const struct drm_crtc_state
*crtc_state
= NULL
;
959 const struct dpu_format
*fmt
;
960 struct drm_rect src
, dst
, fb_rect
= { 0 };
961 uint32_t min_src_size
, max_linewidth
;
964 crtc_state
= drm_atomic_get_new_crtc_state(state
->state
,
967 min_scale
= FRAC_16_16(1, pdpu
->pipe_sblk
->maxupscale
);
968 ret
= drm_atomic_helper_check_plane_state(state
, crtc_state
, min_scale
,
969 pdpu
->pipe_sblk
->maxdwnscale
<< 16,
972 DPU_DEBUG_PLANE(pdpu
, "Check plane state failed (%d)\n", ret
);
978 src
.x1
= state
->src_x
>> 16;
979 src
.y1
= state
->src_y
>> 16;
980 src
.x2
= src
.x1
+ (state
->src_w
>> 16);
981 src
.y2
= src
.y1
+ (state
->src_h
>> 16);
983 dst
= drm_plane_state_dest(state
);
985 fb_rect
.x2
= state
->fb
->width
;
986 fb_rect
.y2
= state
->fb
->height
;
988 max_linewidth
= pdpu
->catalog
->caps
->max_linewidth
;
990 fmt
= to_dpu_format(msm_framebuffer_format(state
->fb
));
992 min_src_size
= DPU_FORMAT_IS_YUV(fmt
) ? 2 : 1;
994 if (DPU_FORMAT_IS_YUV(fmt
) &&
995 (!(pdpu
->features
& DPU_SSPP_SCALER
) ||
996 !(pdpu
->features
& (BIT(DPU_SSPP_CSC
)
997 | BIT(DPU_SSPP_CSC_10BIT
))))) {
998 DPU_DEBUG_PLANE(pdpu
,
999 "plane doesn't have scaler/csc for yuv\n");
1002 /* check src bounds */
1003 } else if (!dpu_plane_validate_src(&src
, &fb_rect
, min_src_size
)) {
1004 DPU_DEBUG_PLANE(pdpu
, "invalid source " DRM_RECT_FMT
"\n",
1005 DRM_RECT_ARG(&src
));
1008 /* valid yuv image */
1009 } else if (DPU_FORMAT_IS_YUV(fmt
) &&
1010 (src
.x1
& 0x1 || src
.y1
& 0x1 ||
1011 drm_rect_width(&src
) & 0x1 ||
1012 drm_rect_height(&src
) & 0x1)) {
1013 DPU_DEBUG_PLANE(pdpu
, "invalid yuv source " DRM_RECT_FMT
"\n",
1014 DRM_RECT_ARG(&src
));
1017 /* min dst support */
1018 } else if (drm_rect_width(&dst
) < 0x1 || drm_rect_height(&dst
) < 0x1) {
1019 DPU_DEBUG_PLANE(pdpu
, "invalid dest rect " DRM_RECT_FMT
"\n",
1020 DRM_RECT_ARG(&dst
));
1023 /* check decimated source width */
1024 } else if (drm_rect_width(&src
) > max_linewidth
) {
1025 DPU_DEBUG_PLANE(pdpu
, "invalid src " DRM_RECT_FMT
" line:%u\n",
1026 DRM_RECT_ARG(&src
), max_linewidth
);
1030 pstate
->needs_qos_remap
= drm_atomic_crtc_needs_modeset(crtc_state
);
1035 void dpu_plane_flush(struct drm_plane
*plane
)
1037 struct dpu_plane
*pdpu
;
1038 struct dpu_plane_state
*pstate
;
1040 if (!plane
|| !plane
->state
) {
1041 DPU_ERROR("invalid plane\n");
1045 pdpu
= to_dpu_plane(plane
);
1046 pstate
= to_dpu_plane_state(plane
->state
);
1049 * These updates have to be done immediately before the plane flush
1050 * timing, and may not be moved to the atomic_update/mode_set functions.
1053 /* force white frame with 100% alpha pipe output on error */
1054 _dpu_plane_color_fill(pdpu
, 0xFFFFFF, 0xFF);
1055 else if (pdpu
->color_fill
& DPU_PLANE_COLOR_FILL_FLAG
)
1056 /* force 100% alpha */
1057 _dpu_plane_color_fill(pdpu
, pdpu
->color_fill
, 0xFF);
1058 else if (pdpu
->pipe_hw
&& pdpu
->csc_ptr
&& pdpu
->pipe_hw
->ops
.setup_csc
)
1059 pdpu
->pipe_hw
->ops
.setup_csc(pdpu
->pipe_hw
, pdpu
->csc_ptr
);
1061 /* flag h/w flush complete */
1063 pstate
->pending
= false;
1067 * dpu_plane_set_error: enable/disable error condition
1068 * @plane: pointer to drm_plane structure
1069 * @error: error value to set
1071 void dpu_plane_set_error(struct drm_plane
*plane
, bool error
)
1073 struct dpu_plane
*pdpu
;
1078 pdpu
= to_dpu_plane(plane
);
1079 pdpu
->is_error
= error
;
1082 static void dpu_plane_sspp_atomic_update(struct drm_plane
*plane
)
1085 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
1086 struct drm_plane_state
*state
= plane
->state
;
1087 struct dpu_plane_state
*pstate
= to_dpu_plane_state(state
);
1088 struct drm_crtc
*crtc
= state
->crtc
;
1089 struct drm_framebuffer
*fb
= state
->fb
;
1090 bool is_rt_pipe
, update_qos_remap
;
1091 const struct dpu_format
*fmt
=
1092 to_dpu_format(msm_framebuffer_format(fb
));
1094 memset(&(pdpu
->pipe_cfg
), 0, sizeof(struct dpu_hw_pipe_cfg
));
1096 _dpu_plane_set_scanout(plane
, pstate
, &pdpu
->pipe_cfg
, fb
);
1098 pstate
->pending
= true;
1100 is_rt_pipe
= (dpu_crtc_get_client_type(crtc
) != NRT_CLIENT
);
1101 _dpu_plane_set_qos_ctrl(plane
, false, DPU_PLANE_QOS_PANIC_CTRL
);
1103 DPU_DEBUG_PLANE(pdpu
, "FB[%u] " DRM_RECT_FP_FMT
"->crtc%u " DRM_RECT_FMT
1104 ", %4.4s ubwc %d\n", fb
->base
.id
, DRM_RECT_FP_ARG(&state
->src
),
1105 crtc
->base
.id
, DRM_RECT_ARG(&state
->dst
),
1106 (char *)&fmt
->base
.pixel_format
, DPU_FORMAT_IS_UBWC(fmt
));
1108 pdpu
->pipe_cfg
.src_rect
= state
->src
;
1110 /* state->src is 16.16, src_rect is not */
1111 pdpu
->pipe_cfg
.src_rect
.x1
>>= 16;
1112 pdpu
->pipe_cfg
.src_rect
.x2
>>= 16;
1113 pdpu
->pipe_cfg
.src_rect
.y1
>>= 16;
1114 pdpu
->pipe_cfg
.src_rect
.y2
>>= 16;
1116 pdpu
->pipe_cfg
.dst_rect
= state
->dst
;
1118 _dpu_plane_setup_scaler(pdpu
, pstate
, fmt
, false);
1120 /* override for color fill */
1121 if (pdpu
->color_fill
& DPU_PLANE_COLOR_FILL_FLAG
) {
1122 /* skip remaining processing on color fill */
1126 if (pdpu
->pipe_hw
->ops
.setup_rects
) {
1127 pdpu
->pipe_hw
->ops
.setup_rects(pdpu
->pipe_hw
,
1129 pstate
->multirect_index
);
1132 if (pdpu
->pipe_hw
->ops
.setup_pe
&&
1133 (pstate
->multirect_index
!= DPU_SSPP_RECT_1
))
1134 pdpu
->pipe_hw
->ops
.setup_pe(pdpu
->pipe_hw
,
1135 &pstate
->pixel_ext
);
1138 * when programmed in multirect mode, scalar block will be
1139 * bypassed. Still we need to update alpha and bitwidth
1142 if (pdpu
->pipe_hw
->ops
.setup_scaler
&&
1143 pstate
->multirect_index
!= DPU_SSPP_RECT_1
)
1144 pdpu
->pipe_hw
->ops
.setup_scaler(pdpu
->pipe_hw
,
1145 &pdpu
->pipe_cfg
, &pstate
->pixel_ext
,
1146 &pstate
->scaler3_cfg
);
1148 if (pdpu
->pipe_hw
->ops
.setup_multirect
)
1149 pdpu
->pipe_hw
->ops
.setup_multirect(
1151 pstate
->multirect_index
,
1152 pstate
->multirect_mode
);
1154 if (pdpu
->pipe_hw
->ops
.setup_format
) {
1155 unsigned int rotation
;
1159 rotation
= drm_rotation_simplify(state
->rotation
,
1161 DRM_MODE_REFLECT_X
|
1162 DRM_MODE_REFLECT_Y
);
1164 if (rotation
& DRM_MODE_REFLECT_X
)
1165 src_flags
|= DPU_SSPP_FLIP_LR
;
1167 if (rotation
& DRM_MODE_REFLECT_Y
)
1168 src_flags
|= DPU_SSPP_FLIP_UD
;
1171 pdpu
->pipe_hw
->ops
.setup_format(pdpu
->pipe_hw
, fmt
, src_flags
,
1172 pstate
->multirect_index
);
1174 if (pdpu
->pipe_hw
->ops
.setup_cdp
) {
1175 struct dpu_hw_pipe_cdp_cfg
*cdp_cfg
= &pstate
->cdp_cfg
;
1177 memset(cdp_cfg
, 0, sizeof(struct dpu_hw_pipe_cdp_cfg
));
1179 cdp_cfg
->enable
= pdpu
->catalog
->perf
.cdp_cfg
1180 [DPU_PERF_CDP_USAGE_RT
].rd_enable
;
1181 cdp_cfg
->ubwc_meta_enable
=
1182 DPU_FORMAT_IS_UBWC(fmt
);
1183 cdp_cfg
->tile_amortize_enable
=
1184 DPU_FORMAT_IS_UBWC(fmt
) ||
1185 DPU_FORMAT_IS_TILE(fmt
);
1186 cdp_cfg
->preload_ahead
= DPU_SSPP_CDP_PRELOAD_AHEAD_64
;
1188 pdpu
->pipe_hw
->ops
.setup_cdp(pdpu
->pipe_hw
, cdp_cfg
);
1192 if (DPU_FORMAT_IS_YUV(fmt
))
1193 _dpu_plane_setup_csc(pdpu
);
1198 _dpu_plane_set_qos_lut(plane
, fb
);
1199 _dpu_plane_set_danger_lut(plane
, fb
);
1201 if (plane
->type
!= DRM_PLANE_TYPE_CURSOR
) {
1202 _dpu_plane_set_qos_ctrl(plane
, true, DPU_PLANE_QOS_PANIC_CTRL
);
1203 _dpu_plane_set_ot_limit(plane
, crtc
);
1206 update_qos_remap
= (is_rt_pipe
!= pdpu
->is_rt_pipe
) ||
1207 pstate
->needs_qos_remap
;
1209 if (update_qos_remap
) {
1210 if (is_rt_pipe
!= pdpu
->is_rt_pipe
)
1211 pdpu
->is_rt_pipe
= is_rt_pipe
;
1212 else if (pstate
->needs_qos_remap
)
1213 pstate
->needs_qos_remap
= false;
1214 _dpu_plane_set_qos_remap(plane
);
1217 _dpu_plane_calc_bw(plane
, fb
);
1219 _dpu_plane_calc_clk(plane
);
1222 static void _dpu_plane_atomic_disable(struct drm_plane
*plane
)
1224 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
1225 struct drm_plane_state
*state
= plane
->state
;
1226 struct dpu_plane_state
*pstate
= to_dpu_plane_state(state
);
1228 trace_dpu_plane_disable(DRMID(plane
), is_dpu_plane_virtual(plane
),
1229 pstate
->multirect_mode
);
1231 pstate
->pending
= true;
1233 if (is_dpu_plane_virtual(plane
) &&
1234 pdpu
->pipe_hw
&& pdpu
->pipe_hw
->ops
.setup_multirect
)
1235 pdpu
->pipe_hw
->ops
.setup_multirect(pdpu
->pipe_hw
,
1236 DPU_SSPP_RECT_SOLO
, DPU_SSPP_MULTIRECT_NONE
);
1239 static void dpu_plane_atomic_update(struct drm_plane
*plane
,
1240 struct drm_plane_state
*old_state
)
1242 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
1243 struct drm_plane_state
*state
= plane
->state
;
1245 pdpu
->is_error
= false;
1247 DPU_DEBUG_PLANE(pdpu
, "\n");
1249 if (!state
->visible
) {
1250 _dpu_plane_atomic_disable(plane
);
1252 dpu_plane_sspp_atomic_update(plane
);
1256 void dpu_plane_restore(struct drm_plane
*plane
)
1258 struct dpu_plane
*pdpu
;
1260 if (!plane
|| !plane
->state
) {
1261 DPU_ERROR("invalid plane\n");
1265 pdpu
= to_dpu_plane(plane
);
1267 DPU_DEBUG_PLANE(pdpu
, "\n");
1269 /* last plane state is same as current state */
1270 dpu_plane_atomic_update(plane
, plane
->state
);
1273 static void dpu_plane_destroy(struct drm_plane
*plane
)
1275 struct dpu_plane
*pdpu
= plane
? to_dpu_plane(plane
) : NULL
;
1277 DPU_DEBUG_PLANE(pdpu
, "\n");
1280 _dpu_plane_set_qos_ctrl(plane
, false, DPU_PLANE_QOS_PANIC_CTRL
);
1282 mutex_destroy(&pdpu
->lock
);
1284 /* this will destroy the states as well */
1285 drm_plane_cleanup(plane
);
1287 dpu_hw_sspp_destroy(pdpu
->pipe_hw
);
1293 static void dpu_plane_destroy_state(struct drm_plane
*plane
,
1294 struct drm_plane_state
*state
)
1296 __drm_atomic_helper_plane_destroy_state(state
);
1297 kfree(to_dpu_plane_state(state
));
1300 static struct drm_plane_state
*
1301 dpu_plane_duplicate_state(struct drm_plane
*plane
)
1303 struct dpu_plane
*pdpu
;
1304 struct dpu_plane_state
*pstate
;
1305 struct dpu_plane_state
*old_state
;
1308 DPU_ERROR("invalid plane\n");
1310 } else if (!plane
->state
) {
1311 DPU_ERROR("invalid plane state\n");
1315 old_state
= to_dpu_plane_state(plane
->state
);
1316 pdpu
= to_dpu_plane(plane
);
1317 pstate
= kmemdup(old_state
, sizeof(*old_state
), GFP_KERNEL
);
1319 DPU_ERROR_PLANE(pdpu
, "failed to allocate state\n");
1323 DPU_DEBUG_PLANE(pdpu
, "\n");
1325 pstate
->pending
= false;
1327 __drm_atomic_helper_plane_duplicate_state(plane
, &pstate
->base
);
1329 return &pstate
->base
;
1332 static void dpu_plane_reset(struct drm_plane
*plane
)
1334 struct dpu_plane
*pdpu
;
1335 struct dpu_plane_state
*pstate
;
1338 DPU_ERROR("invalid plane\n");
1342 pdpu
= to_dpu_plane(plane
);
1343 DPU_DEBUG_PLANE(pdpu
, "\n");
1345 /* remove previous state, if present */
1347 dpu_plane_destroy_state(plane
, plane
->state
);
1351 pstate
= kzalloc(sizeof(*pstate
), GFP_KERNEL
);
1353 DPU_ERROR_PLANE(pdpu
, "failed to allocate state\n");
1357 pstate
->base
.plane
= plane
;
1359 plane
->state
= &pstate
->base
;
1362 #ifdef CONFIG_DEBUG_FS
1363 static void dpu_plane_danger_signal_ctrl(struct drm_plane
*plane
, bool enable
)
1365 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
1366 struct dpu_kms
*dpu_kms
= _dpu_plane_get_kms(plane
);
1368 if (!pdpu
->is_rt_pipe
)
1371 pm_runtime_get_sync(&dpu_kms
->pdev
->dev
);
1372 _dpu_plane_set_qos_ctrl(plane
, enable
, DPU_PLANE_QOS_PANIC_CTRL
);
1373 pm_runtime_put_sync(&dpu_kms
->pdev
->dev
);
1376 static ssize_t
_dpu_plane_danger_read(struct file
*file
,
1377 char __user
*buff
, size_t count
, loff_t
*ppos
)
1379 struct dpu_kms
*kms
= file
->private_data
;
1383 len
= scnprintf(buf
, sizeof(buf
), "%d\n", !kms
->has_danger_ctrl
);
1385 return simple_read_from_buffer(buff
, count
, ppos
, buf
, len
);
1388 static void _dpu_plane_set_danger_state(struct dpu_kms
*kms
, bool enable
)
1390 struct drm_plane
*plane
;
1392 drm_for_each_plane(plane
, kms
->dev
) {
1393 if (plane
->fb
&& plane
->state
) {
1394 dpu_plane_danger_signal_ctrl(plane
, enable
);
1395 DPU_DEBUG("plane:%d img:%dx%d ",
1396 plane
->base
.id
, plane
->fb
->width
,
1398 DPU_DEBUG("src[%d,%d,%d,%d] dst[%d,%d,%d,%d]\n",
1399 plane
->state
->src_x
>> 16,
1400 plane
->state
->src_y
>> 16,
1401 plane
->state
->src_w
>> 16,
1402 plane
->state
->src_h
>> 16,
1403 plane
->state
->crtc_x
, plane
->state
->crtc_y
,
1404 plane
->state
->crtc_w
, plane
->state
->crtc_h
);
1406 DPU_DEBUG("Inactive plane:%d\n", plane
->base
.id
);
1411 static ssize_t
_dpu_plane_danger_write(struct file
*file
,
1412 const char __user
*user_buf
, size_t count
, loff_t
*ppos
)
1414 struct dpu_kms
*kms
= file
->private_data
;
1418 ret
= kstrtouint_from_user(user_buf
, count
, 0, &disable_panic
);
1422 if (disable_panic
) {
1423 /* Disable panic signal for all active pipes */
1424 DPU_DEBUG("Disabling danger:\n");
1425 _dpu_plane_set_danger_state(kms
, false);
1426 kms
->has_danger_ctrl
= false;
1428 /* Enable panic signal for all active pipes */
1429 DPU_DEBUG("Enabling danger:\n");
1430 kms
->has_danger_ctrl
= true;
1431 _dpu_plane_set_danger_state(kms
, true);
1437 static const struct file_operations dpu_plane_danger_enable
= {
1438 .open
= simple_open
,
1439 .read
= _dpu_plane_danger_read
,
1440 .write
= _dpu_plane_danger_write
,
1443 static int _dpu_plane_init_debugfs(struct drm_plane
*plane
)
1445 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
1446 struct dpu_kms
*kms
= _dpu_plane_get_kms(plane
);
1447 const struct dpu_sspp_cfg
*cfg
= pdpu
->pipe_hw
->cap
;
1448 const struct dpu_sspp_sub_blks
*sblk
= cfg
->sblk
;
1450 /* create overall sub-directory for the pipe */
1451 pdpu
->debugfs_root
=
1452 debugfs_create_dir(pdpu
->pipe_name
,
1453 plane
->dev
->primary
->debugfs_root
);
1455 /* don't error check these */
1456 debugfs_create_x32("features", 0600,
1457 pdpu
->debugfs_root
, &pdpu
->features
);
1459 /* add register dump support */
1460 dpu_debugfs_setup_regset32(&pdpu
->debugfs_src
,
1461 sblk
->src_blk
.base
+ cfg
->base
,
1464 dpu_debugfs_create_regset32("src_blk", 0400,
1465 pdpu
->debugfs_root
, &pdpu
->debugfs_src
);
1467 if (cfg
->features
& BIT(DPU_SSPP_SCALER_QSEED3
) ||
1468 cfg
->features
& BIT(DPU_SSPP_SCALER_QSEED2
) ||
1469 cfg
->features
& BIT(DPU_SSPP_SCALER_QSEED4
)) {
1470 dpu_debugfs_setup_regset32(&pdpu
->debugfs_scaler
,
1471 sblk
->scaler_blk
.base
+ cfg
->base
,
1472 sblk
->scaler_blk
.len
,
1474 dpu_debugfs_create_regset32("scaler_blk", 0400,
1476 &pdpu
->debugfs_scaler
);
1477 debugfs_create_bool("default_scaling",
1480 &pdpu
->debugfs_default_scale
);
1483 if (cfg
->features
& BIT(DPU_SSPP_CSC
) ||
1484 cfg
->features
& BIT(DPU_SSPP_CSC_10BIT
)) {
1485 dpu_debugfs_setup_regset32(&pdpu
->debugfs_csc
,
1486 sblk
->csc_blk
.base
+ cfg
->base
,
1489 dpu_debugfs_create_regset32("csc_blk", 0400,
1490 pdpu
->debugfs_root
, &pdpu
->debugfs_csc
);
1493 debugfs_create_u32("xin_id",
1496 (u32
*) &cfg
->xin_id
);
1497 debugfs_create_u32("clk_ctrl",
1500 (u32
*) &cfg
->clk_ctrl
);
1501 debugfs_create_x32("creq_vblank",
1504 (u32
*) &sblk
->creq_vblank
);
1505 debugfs_create_x32("danger_vblank",
1508 (u32
*) &sblk
->danger_vblank
);
1510 debugfs_create_file("disable_danger",
1513 kms
, &dpu_plane_danger_enable
);
1518 static int _dpu_plane_init_debugfs(struct drm_plane
*plane
)
1524 static int dpu_plane_late_register(struct drm_plane
*plane
)
1526 return _dpu_plane_init_debugfs(plane
);
1529 static void dpu_plane_early_unregister(struct drm_plane
*plane
)
1531 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
1533 debugfs_remove_recursive(pdpu
->debugfs_root
);
1536 static bool dpu_plane_format_mod_supported(struct drm_plane
*plane
,
1537 uint32_t format
, uint64_t modifier
)
1539 if (modifier
== DRM_FORMAT_MOD_LINEAR
)
1542 if (modifier
== DRM_FORMAT_MOD_QCOM_COMPRESSED
) {
1544 for (i
= 0; i
< ARRAY_SIZE(qcom_compressed_supported_formats
); i
++) {
1545 if (format
== qcom_compressed_supported_formats
[i
])
1553 static const struct drm_plane_funcs dpu_plane_funcs
= {
1554 .update_plane
= drm_atomic_helper_update_plane
,
1555 .disable_plane
= drm_atomic_helper_disable_plane
,
1556 .destroy
= dpu_plane_destroy
,
1557 .reset
= dpu_plane_reset
,
1558 .atomic_duplicate_state
= dpu_plane_duplicate_state
,
1559 .atomic_destroy_state
= dpu_plane_destroy_state
,
1560 .late_register
= dpu_plane_late_register
,
1561 .early_unregister
= dpu_plane_early_unregister
,
1562 .format_mod_supported
= dpu_plane_format_mod_supported
,
1565 static const struct drm_plane_helper_funcs dpu_plane_helper_funcs
= {
1566 .prepare_fb
= dpu_plane_prepare_fb
,
1567 .cleanup_fb
= dpu_plane_cleanup_fb
,
1568 .atomic_check
= dpu_plane_atomic_check
,
1569 .atomic_update
= dpu_plane_atomic_update
,
1572 enum dpu_sspp
dpu_plane_pipe(struct drm_plane
*plane
)
1574 return plane
? to_dpu_plane(plane
)->pipe
: SSPP_NONE
;
1577 bool is_dpu_plane_virtual(struct drm_plane
*plane
)
1579 return plane
? to_dpu_plane(plane
)->is_virtual
: false;
1582 /* initialize plane */
1583 struct drm_plane
*dpu_plane_init(struct drm_device
*dev
,
1584 uint32_t pipe
, enum drm_plane_type type
,
1585 unsigned long possible_crtcs
, u32 master_plane_id
)
1587 struct drm_plane
*plane
= NULL
, *master_plane
= NULL
;
1588 const uint32_t *format_list
;
1589 struct dpu_plane
*pdpu
;
1590 struct msm_drm_private
*priv
= dev
->dev_private
;
1591 struct dpu_kms
*kms
= to_dpu_kms(priv
->kms
);
1592 int zpos_max
= DPU_ZPOS_MAX
;
1593 uint32_t num_formats
;
1596 /* create and zero local structure */
1597 pdpu
= kzalloc(sizeof(*pdpu
), GFP_KERNEL
);
1599 DPU_ERROR("[%u]failed to allocate local plane struct\n", pipe
);
1601 return ERR_PTR(ret
);
1604 /* cache local stuff for later */
1605 plane
= &pdpu
->base
;
1607 pdpu
->is_virtual
= (master_plane_id
!= 0);
1608 INIT_LIST_HEAD(&pdpu
->mplane_list
);
1609 master_plane
= drm_plane_find(dev
, NULL
, master_plane_id
);
1611 struct dpu_plane
*mpdpu
= to_dpu_plane(master_plane
);
1613 list_add_tail(&pdpu
->mplane_list
, &mpdpu
->mplane_list
);
1616 /* initialize underlying h/w driver */
1617 pdpu
->pipe_hw
= dpu_hw_sspp_init(pipe
, kms
->mmio
, kms
->catalog
,
1618 master_plane_id
!= 0);
1619 if (IS_ERR(pdpu
->pipe_hw
)) {
1620 DPU_ERROR("[%u]SSPP init failed\n", pipe
);
1621 ret
= PTR_ERR(pdpu
->pipe_hw
);
1623 } else if (!pdpu
->pipe_hw
->cap
|| !pdpu
->pipe_hw
->cap
->sblk
) {
1624 DPU_ERROR("[%u]SSPP init returned invalid cfg\n", pipe
);
1628 /* cache features mask for later */
1629 pdpu
->features
= pdpu
->pipe_hw
->cap
->features
;
1630 pdpu
->pipe_sblk
= pdpu
->pipe_hw
->cap
->sblk
;
1631 if (!pdpu
->pipe_sblk
) {
1632 DPU_ERROR("[%u]invalid sblk\n", pipe
);
1636 if (pdpu
->is_virtual
) {
1637 format_list
= pdpu
->pipe_sblk
->virt_format_list
;
1638 num_formats
= pdpu
->pipe_sblk
->virt_num_formats
;
1641 format_list
= pdpu
->pipe_sblk
->format_list
;
1642 num_formats
= pdpu
->pipe_sblk
->num_formats
;
1645 ret
= drm_universal_plane_init(dev
, plane
, 0xff, &dpu_plane_funcs
,
1646 format_list
, num_formats
,
1647 supported_format_modifiers
, type
, NULL
);
1651 pdpu
->catalog
= kms
->catalog
;
1653 if (kms
->catalog
->mixer_count
&&
1654 kms
->catalog
->mixer
[0].sblk
->maxblendstages
) {
1655 zpos_max
= kms
->catalog
->mixer
[0].sblk
->maxblendstages
- 1;
1656 if (zpos_max
> DPU_STAGE_MAX
- DPU_STAGE_0
- 1)
1657 zpos_max
= DPU_STAGE_MAX
- DPU_STAGE_0
- 1;
1660 ret
= drm_plane_create_zpos_property(plane
, 0, 0, zpos_max
);
1662 DPU_ERROR("failed to install zpos property, rc = %d\n", ret
);
1664 drm_plane_create_rotation_property(plane
,
1667 DRM_MODE_ROTATE_180
|
1668 DRM_MODE_REFLECT_X
|
1669 DRM_MODE_REFLECT_Y
);
1671 drm_plane_enable_fb_damage_clips(plane
);
1673 /* success! finalize initialization */
1674 drm_plane_helper_add(plane
, &dpu_plane_helper_funcs
);
1676 /* save user friendly pipe name for later */
1677 snprintf(pdpu
->pipe_name
, DPU_NAME_SIZE
, "plane%u", plane
->base
.id
);
1679 mutex_init(&pdpu
->lock
);
1681 DPU_DEBUG("%s created for pipe:%u id:%u virtual:%u\n", pdpu
->pipe_name
,
1682 pipe
, plane
->base
.id
, master_plane_id
);
1686 if (pdpu
&& pdpu
->pipe_hw
)
1687 dpu_hw_sspp_destroy(pdpu
->pipe_hw
);
1690 return ERR_PTR(ret
);