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.h>
14 #include <drm/drm_atomic_uapi.h>
15 #include <drm/drm_blend.h>
16 #include <drm/drm_damage_helper.h>
17 #include <drm/drm_framebuffer.h>
18 #include <drm/drm_gem_atomic_helper.h>
22 #include "dpu_formats.h"
23 #include "dpu_hw_sspp.h"
24 #include "dpu_trace.h"
27 #include "dpu_plane.h"
29 #define DPU_DEBUG_PLANE(pl, fmt, ...) DRM_DEBUG_ATOMIC("plane%d " fmt,\
30 (pl) ? (pl)->base.base.id : -1, ##__VA_ARGS__)
32 #define DPU_ERROR_PLANE(pl, fmt, ...) DPU_ERROR("plane%d " fmt,\
33 (pl) ? (pl)->base.base.id : -1, ##__VA_ARGS__)
35 #define DECIMATED_DIMENSION(dim, deci) (((dim) + ((1 << (deci)) - 1)) >> (deci))
36 #define PHASE_STEP_SHIFT 21
37 #define PHASE_STEP_UNIT_SCALE ((int) (1 << PHASE_STEP_SHIFT))
38 #define PHASE_RESIDUAL 15
40 #define SHARP_STRENGTH_DEFAULT 32
41 #define SHARP_EDGE_THR_DEFAULT 112
42 #define SHARP_SMOOTH_THR_DEFAULT 8
43 #define SHARP_NOISE_THR_DEFAULT 2
45 #define DPU_PLANE_COLOR_FILL_FLAG BIT(31)
46 #define DPU_ZPOS_MAX 255
49 * Default Preload Values
51 #define DPU_QSEED3_DEFAULT_PRELOAD_H 0x4
52 #define DPU_QSEED3_DEFAULT_PRELOAD_V 0x3
53 #define DPU_QSEED4_DEFAULT_PRELOAD_V 0x2
54 #define DPU_QSEED4_DEFAULT_PRELOAD_H 0x4
56 #define DEFAULT_REFRESH_RATE 60
58 static const uint32_t qcom_compressed_supported_formats
[] = {
63 DRM_FORMAT_ARGB2101010
,
64 DRM_FORMAT_XRGB2101010
,
72 * struct dpu_plane - local dpu plane structure
73 * @aspace: address space pointer
74 * @csc_ptr: Points to dpu_csc_cfg structure to use for current
75 * @catalog: Points to dpu catalog structure
76 * @revalidate: force revalidation of all the plane properties
79 struct drm_plane base
;
88 const struct dpu_mdss_cfg
*catalog
;
91 static const uint64_t supported_format_modifiers
[] = {
92 DRM_FORMAT_MOD_QCOM_COMPRESSED
,
93 DRM_FORMAT_MOD_LINEAR
,
94 DRM_FORMAT_MOD_INVALID
97 #define to_dpu_plane(x) container_of(x, struct dpu_plane, base)
99 static struct dpu_kms
*_dpu_plane_get_kms(struct drm_plane
*plane
)
101 struct msm_drm_private
*priv
= plane
->dev
->dev_private
;
103 return to_dpu_kms(priv
->kms
);
107 * _dpu_plane_calc_bw - calculate bandwidth required for a plane
108 * @catalog: Points to dpu catalog structure
109 * @fmt: Pointer to source buffer format
110 * @mode: Pointer to drm display mode
111 * @pipe_cfg: Pointer to pipe configuration
112 * Result: Updates calculated bandwidth in the plane state.
113 * BW Equation: src_w * src_h * bpp * fps * (v_total / v_dest)
114 * Prefill BW Equation: line src bytes * line_time
116 static u64
_dpu_plane_calc_bw(const struct dpu_mdss_cfg
*catalog
,
117 const struct dpu_format
*fmt
,
118 const struct drm_display_mode
*mode
,
119 struct dpu_sw_pipe_cfg
*pipe_cfg
)
121 int src_width
, src_height
, dst_height
, fps
;
122 u64 plane_pixel_rate
, plane_bit_rate
;
123 u64 plane_prefill_bw
;
125 u32 hw_latency_lines
;
129 src_width
= drm_rect_width(&pipe_cfg
->src_rect
);
130 src_height
= drm_rect_height(&pipe_cfg
->src_rect
);
131 dst_height
= drm_rect_height(&pipe_cfg
->dst_rect
);
132 fps
= drm_mode_vrefresh(mode
);
133 vbp
= mode
->vtotal
- mode
->vsync_end
;
134 vpw
= mode
->vsync_end
- mode
->vsync_start
;
135 vfp
= mode
->vsync_start
- mode
->vdisplay
;
136 hw_latency_lines
= catalog
->perf
->min_prefill_lines
;
137 scale_factor
= src_height
> dst_height
?
138 mult_frac(src_height
, 1, dst_height
) : 1;
140 plane_pixel_rate
= src_width
* mode
->vtotal
* fps
;
141 plane_bit_rate
= plane_pixel_rate
* fmt
->bpp
;
143 plane_bw
= plane_bit_rate
* scale_factor
;
145 plane_prefill_bw
= plane_bw
* hw_latency_lines
;
147 if ((vbp
+vpw
) > hw_latency_lines
)
148 do_div(plane_prefill_bw
, (vbp
+vpw
));
149 else if ((vbp
+vpw
+vfp
) < hw_latency_lines
)
150 do_div(plane_prefill_bw
, (vbp
+vpw
+vfp
));
152 do_div(plane_prefill_bw
, hw_latency_lines
);
155 return max(plane_bw
, plane_prefill_bw
);
159 * _dpu_plane_calc_clk - calculate clock required for a plane
160 * @mode: Pointer to drm display mode
161 * @pipe_cfg: Pointer to pipe configuration
162 * Result: Updates calculated clock in the plane state.
163 * Clock equation: dst_w * v_total * fps * (src_h / dst_h)
165 static u64
_dpu_plane_calc_clk(const struct drm_display_mode
*mode
,
166 struct dpu_sw_pipe_cfg
*pipe_cfg
)
168 int dst_width
, src_height
, dst_height
, fps
;
171 src_height
= drm_rect_height(&pipe_cfg
->src_rect
);
172 dst_width
= drm_rect_width(&pipe_cfg
->dst_rect
);
173 dst_height
= drm_rect_height(&pipe_cfg
->dst_rect
);
174 fps
= drm_mode_vrefresh(mode
);
177 dst_width
* mode
->vtotal
* fps
;
179 if (src_height
> dst_height
) {
180 plane_clk
*= src_height
;
181 do_div(plane_clk
, dst_height
);
188 * _dpu_plane_calc_fill_level - calculate fill level of the given source format
189 * @plane: Pointer to drm plane
190 * @pipe: Pointer to software pipe
191 * @lut_usage: LUT usecase
192 * @fmt: Pointer to source buffer format
193 * @src_width: width of source buffer
194 * Return: fill level corresponding to the source buffer/format or 0 if error
196 static int _dpu_plane_calc_fill_level(struct drm_plane
*plane
,
197 struct dpu_sw_pipe
*pipe
,
198 enum dpu_qos_lut_usage lut_usage
,
199 const struct dpu_format
*fmt
, u32 src_width
)
201 struct dpu_plane
*pdpu
;
205 if (!fmt
|| !pipe
|| !src_width
|| !fmt
->bpp
) {
206 DPU_ERROR("invalid arguments\n");
210 if (lut_usage
== DPU_QOS_LUT_USAGE_NRT
)
213 pdpu
= to_dpu_plane(plane
);
214 fixed_buff_size
= pdpu
->catalog
->caps
->pixel_ram_size
;
216 /* FIXME: in multirect case account for the src_width of all the planes */
218 if (fmt
->fetch_planes
== DPU_PLANE_PSEUDO_PLANAR
) {
219 if (fmt
->chroma_sample
== DPU_CHROMA_420
) {
221 total_fl
= (fixed_buff_size
/ 2) /
222 ((src_width
+ 32) * fmt
->bpp
);
225 total_fl
= (fixed_buff_size
/ 2) * 2 /
226 ((src_width
+ 32) * fmt
->bpp
);
229 if (pipe
->multirect_mode
== DPU_SSPP_MULTIRECT_PARALLEL
) {
230 total_fl
= (fixed_buff_size
/ 2) * 2 /
231 ((src_width
+ 32) * fmt
->bpp
);
233 total_fl
= (fixed_buff_size
) * 2 /
234 ((src_width
+ 32) * fmt
->bpp
);
238 DPU_DEBUG_PLANE(pdpu
, "pnum:%d fmt: %4.4s w:%u fl:%u\n",
239 pipe
->sspp
->idx
- SSPP_VIG0
,
240 (char *)&fmt
->base
.pixel_format
,
241 src_width
, total_fl
);
247 * _dpu_plane_set_qos_lut - set QoS LUT of the given plane
248 * @plane: Pointer to drm plane
249 * @pipe: Pointer to software pipe
250 * @fmt: Pointer to source buffer format
251 * @pipe_cfg: Pointer to pipe configuration
253 static void _dpu_plane_set_qos_lut(struct drm_plane
*plane
,
254 struct dpu_sw_pipe
*pipe
,
255 const struct dpu_format
*fmt
, struct dpu_sw_pipe_cfg
*pipe_cfg
)
257 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
258 struct dpu_hw_qos_cfg cfg
;
259 u32 total_fl
, lut_usage
;
261 if (!pdpu
->is_rt_pipe
) {
262 lut_usage
= DPU_QOS_LUT_USAGE_NRT
;
264 if (fmt
&& DPU_FORMAT_IS_LINEAR(fmt
))
265 lut_usage
= DPU_QOS_LUT_USAGE_LINEAR
;
267 lut_usage
= DPU_QOS_LUT_USAGE_MACROTILE
;
270 total_fl
= _dpu_plane_calc_fill_level(plane
, pipe
, lut_usage
, fmt
,
271 drm_rect_width(&pipe_cfg
->src_rect
));
273 cfg
.creq_lut
= _dpu_hw_get_qos_lut(&pdpu
->catalog
->perf
->qos_lut_tbl
[lut_usage
], total_fl
);
274 cfg
.danger_lut
= pdpu
->catalog
->perf
->danger_lut_tbl
[lut_usage
];
275 cfg
.safe_lut
= pdpu
->catalog
->perf
->safe_lut_tbl
[lut_usage
];
277 if (pipe
->sspp
->idx
!= SSPP_CURSOR0
&&
278 pipe
->sspp
->idx
!= SSPP_CURSOR1
&&
280 cfg
.danger_safe_en
= true;
282 DPU_DEBUG_PLANE(pdpu
, "pnum:%d ds:%d is_rt:%d\n",
283 pdpu
->pipe
- SSPP_VIG0
,
287 trace_dpu_perf_set_qos_luts(pipe
->sspp
->idx
- SSPP_VIG0
,
288 (fmt
) ? fmt
->base
.pixel_format
: 0,
289 pdpu
->is_rt_pipe
, total_fl
, cfg
.creq_lut
, lut_usage
);
291 DPU_DEBUG_PLANE(pdpu
, "pnum:%d fmt: %4.4s rt:%d fl:%u lut:0x%llx\n",
292 pdpu
->pipe
- SSPP_VIG0
,
293 fmt
? (char *)&fmt
->base
.pixel_format
: NULL
,
294 pdpu
->is_rt_pipe
, total_fl
, cfg
.creq_lut
);
296 trace_dpu_perf_set_danger_luts(pdpu
->pipe
- SSPP_VIG0
,
297 (fmt
) ? fmt
->base
.pixel_format
: 0,
298 (fmt
) ? fmt
->fetch_mode
: 0,
302 DPU_DEBUG_PLANE(pdpu
, "pnum:%d fmt: %4.4s mode:%d luts[0x%x, 0x%x]\n",
303 pdpu
->pipe
- SSPP_VIG0
,
304 fmt
? (char *)&fmt
->base
.pixel_format
: NULL
,
305 fmt
? fmt
->fetch_mode
: -1,
309 pipe
->sspp
->ops
.setup_qos_lut(pipe
->sspp
, &cfg
);
313 * _dpu_plane_set_qos_ctrl - set QoS control of the given plane
314 * @plane: Pointer to drm plane
315 * @pipe: Pointer to software pipe
316 * @enable: true to enable QoS control
318 static void _dpu_plane_set_qos_ctrl(struct drm_plane
*plane
,
319 struct dpu_sw_pipe
*pipe
,
322 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
324 if (!pdpu
->is_rt_pipe
)
327 DPU_DEBUG_PLANE(pdpu
, "pnum:%d ds:%d is_rt:%d\n",
328 pdpu
->pipe
- SSPP_VIG0
,
332 pipe
->sspp
->ops
.setup_qos_ctrl(pipe
->sspp
,
337 * _dpu_plane_set_ot_limit - set OT limit for the given plane
338 * @plane: Pointer to drm plane
339 * @pipe: Pointer to software pipe
340 * @pipe_cfg: Pointer to pipe configuration
341 * @frame_rate: CRTC's frame rate
343 static void _dpu_plane_set_ot_limit(struct drm_plane
*plane
,
344 struct dpu_sw_pipe
*pipe
,
345 struct dpu_sw_pipe_cfg
*pipe_cfg
,
348 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
349 struct dpu_vbif_set_ot_params ot_params
;
350 struct dpu_kms
*dpu_kms
= _dpu_plane_get_kms(plane
);
352 memset(&ot_params
, 0, sizeof(ot_params
));
353 ot_params
.xin_id
= pipe
->sspp
->cap
->xin_id
;
354 ot_params
.num
= pipe
->sspp
->idx
- SSPP_NONE
;
355 ot_params
.width
= drm_rect_width(&pipe_cfg
->src_rect
);
356 ot_params
.height
= drm_rect_height(&pipe_cfg
->src_rect
);
357 ot_params
.is_wfd
= !pdpu
->is_rt_pipe
;
358 ot_params
.frame_rate
= frame_rate
;
359 ot_params
.vbif_idx
= VBIF_RT
;
360 ot_params
.clk_ctrl
= pipe
->sspp
->cap
->clk_ctrl
;
363 dpu_vbif_set_ot_limit(dpu_kms
, &ot_params
);
367 * _dpu_plane_set_qos_remap - set vbif QoS for the given plane
368 * @plane: Pointer to drm plane
369 * @pipe: Pointer to software pipe
371 static void _dpu_plane_set_qos_remap(struct drm_plane
*plane
,
372 struct dpu_sw_pipe
*pipe
)
374 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
375 struct dpu_vbif_set_qos_params qos_params
;
376 struct dpu_kms
*dpu_kms
= _dpu_plane_get_kms(plane
);
378 memset(&qos_params
, 0, sizeof(qos_params
));
379 qos_params
.vbif_idx
= VBIF_RT
;
380 qos_params
.clk_ctrl
= pipe
->sspp
->cap
->clk_ctrl
;
381 qos_params
.xin_id
= pipe
->sspp
->cap
->xin_id
;
382 qos_params
.num
= pipe
->sspp
->idx
- SSPP_VIG0
;
383 qos_params
.is_rt
= pdpu
->is_rt_pipe
;
385 DPU_DEBUG_PLANE(pdpu
, "pipe:%d vbif:%d xin:%d rt:%d, clk_ctrl:%d\n",
388 qos_params
.xin_id
, qos_params
.is_rt
,
389 qos_params
.clk_ctrl
);
391 dpu_vbif_set_qos_remap(dpu_kms
, &qos_params
);
394 static void _dpu_plane_setup_scaler3(struct dpu_hw_sspp
*pipe_hw
,
395 uint32_t src_w
, uint32_t src_h
, uint32_t dst_w
, uint32_t dst_h
,
396 struct dpu_hw_scaler3_cfg
*scale_cfg
,
397 const struct dpu_format
*fmt
,
398 uint32_t chroma_subsmpl_h
, uint32_t chroma_subsmpl_v
,
399 unsigned int rotation
)
402 bool inline_rotation
= rotation
& DRM_MODE_ROTATE_90
;
405 * For inline rotation cases, scaler config is post-rotation,
406 * so swap the dimensions here. However, pixel extension will
407 * need pre-rotation settings.
412 scale_cfg
->phase_step_x
[DPU_SSPP_COMP_0
] =
413 mult_frac((1 << PHASE_STEP_SHIFT
), src_w
, dst_w
);
414 scale_cfg
->phase_step_y
[DPU_SSPP_COMP_0
] =
415 mult_frac((1 << PHASE_STEP_SHIFT
), src_h
, dst_h
);
418 scale_cfg
->phase_step_y
[DPU_SSPP_COMP_1_2
] =
419 scale_cfg
->phase_step_y
[DPU_SSPP_COMP_0
] / chroma_subsmpl_v
;
420 scale_cfg
->phase_step_x
[DPU_SSPP_COMP_1_2
] =
421 scale_cfg
->phase_step_x
[DPU_SSPP_COMP_0
] / chroma_subsmpl_h
;
423 scale_cfg
->phase_step_x
[DPU_SSPP_COMP_2
] =
424 scale_cfg
->phase_step_x
[DPU_SSPP_COMP_1_2
];
425 scale_cfg
->phase_step_y
[DPU_SSPP_COMP_2
] =
426 scale_cfg
->phase_step_y
[DPU_SSPP_COMP_1_2
];
428 scale_cfg
->phase_step_x
[DPU_SSPP_COMP_3
] =
429 scale_cfg
->phase_step_x
[DPU_SSPP_COMP_0
];
430 scale_cfg
->phase_step_y
[DPU_SSPP_COMP_3
] =
431 scale_cfg
->phase_step_y
[DPU_SSPP_COMP_0
];
433 for (i
= 0; i
< DPU_MAX_PLANES
; i
++) {
434 scale_cfg
->src_width
[i
] = src_w
;
435 scale_cfg
->src_height
[i
] = src_h
;
436 if (i
== DPU_SSPP_COMP_1_2
|| i
== DPU_SSPP_COMP_2
) {
437 scale_cfg
->src_width
[i
] /= chroma_subsmpl_h
;
438 scale_cfg
->src_height
[i
] /= chroma_subsmpl_v
;
441 if (pipe_hw
->cap
->features
&
442 BIT(DPU_SSPP_SCALER_QSEED4
)) {
443 scale_cfg
->preload_x
[i
] = DPU_QSEED4_DEFAULT_PRELOAD_H
;
444 scale_cfg
->preload_y
[i
] = DPU_QSEED4_DEFAULT_PRELOAD_V
;
446 scale_cfg
->preload_x
[i
] = DPU_QSEED3_DEFAULT_PRELOAD_H
;
447 scale_cfg
->preload_y
[i
] = DPU_QSEED3_DEFAULT_PRELOAD_V
;
450 if (!(DPU_FORMAT_IS_YUV(fmt
)) && (src_h
== dst_h
)
454 scale_cfg
->dst_width
= dst_w
;
455 scale_cfg
->dst_height
= dst_h
;
456 scale_cfg
->y_rgb_filter_cfg
= DPU_SCALE_BIL
;
457 scale_cfg
->uv_filter_cfg
= DPU_SCALE_BIL
;
458 scale_cfg
->alpha_filter_cfg
= DPU_SCALE_ALPHA_BIL
;
459 scale_cfg
->lut_flag
= 0;
460 scale_cfg
->blend_cfg
= 1;
461 scale_cfg
->enable
= 1;
464 static void _dpu_plane_setup_pixel_ext(struct dpu_hw_scaler3_cfg
*scale_cfg
,
465 struct dpu_hw_pixel_ext
*pixel_ext
,
466 uint32_t src_w
, uint32_t src_h
,
467 uint32_t chroma_subsmpl_h
, uint32_t chroma_subsmpl_v
)
471 for (i
= 0; i
< DPU_MAX_PLANES
; i
++) {
472 if (i
== DPU_SSPP_COMP_1_2
|| i
== DPU_SSPP_COMP_2
) {
473 src_w
/= chroma_subsmpl_h
;
474 src_h
/= chroma_subsmpl_v
;
477 pixel_ext
->num_ext_pxls_top
[i
] = src_h
;
478 pixel_ext
->num_ext_pxls_left
[i
] = src_w
;
482 static const struct dpu_csc_cfg dpu_csc_YUV2RGB_601L
= {
485 0x00012A00, 0x00000000, 0x00019880,
486 0x00012A00, 0xFFFF9B80, 0xFFFF3000,
487 0x00012A00, 0x00020480, 0x00000000,
490 { 0xfff0, 0xff80, 0xff80,},
493 { 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0,},
494 { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,},
497 static const struct dpu_csc_cfg dpu_csc10_YUV2RGB_601L
= {
500 0x00012A00, 0x00000000, 0x00019880,
501 0x00012A00, 0xFFFF9B80, 0xFFFF3000,
502 0x00012A00, 0x00020480, 0x00000000,
505 { 0xffc0, 0xfe00, 0xfe00,},
508 { 0x40, 0x3ac, 0x40, 0x3c0, 0x40, 0x3c0,},
509 { 0x00, 0x3ff, 0x00, 0x3ff, 0x00, 0x3ff,},
512 static const struct dpu_csc_cfg
*_dpu_plane_get_csc(struct dpu_sw_pipe
*pipe
,
513 const struct dpu_format
*fmt
)
515 const struct dpu_csc_cfg
*csc_ptr
;
517 if (!DPU_FORMAT_IS_YUV(fmt
))
520 if (BIT(DPU_SSPP_CSC_10BIT
) & pipe
->sspp
->cap
->features
)
521 csc_ptr
= &dpu_csc10_YUV2RGB_601L
;
523 csc_ptr
= &dpu_csc_YUV2RGB_601L
;
528 static void _dpu_plane_setup_scaler(struct dpu_sw_pipe
*pipe
,
529 const struct dpu_format
*fmt
, bool color_fill
,
530 struct dpu_sw_pipe_cfg
*pipe_cfg
,
531 unsigned int rotation
)
533 struct dpu_hw_sspp
*pipe_hw
= pipe
->sspp
;
534 const struct drm_format_info
*info
= drm_format_info(fmt
->base
.pixel_format
);
535 struct dpu_hw_scaler3_cfg scaler3_cfg
;
536 struct dpu_hw_pixel_ext pixel_ext
;
537 u32 src_width
= drm_rect_width(&pipe_cfg
->src_rect
);
538 u32 src_height
= drm_rect_height(&pipe_cfg
->src_rect
);
539 u32 dst_width
= drm_rect_width(&pipe_cfg
->dst_rect
);
540 u32 dst_height
= drm_rect_height(&pipe_cfg
->dst_rect
);
542 memset(&scaler3_cfg
, 0, sizeof(scaler3_cfg
));
543 memset(&pixel_ext
, 0, sizeof(pixel_ext
));
545 /* don't chroma subsample if decimating */
546 /* update scaler. calculate default config for QSEED3 */
547 _dpu_plane_setup_scaler3(pipe_hw
,
553 info
->hsub
, info
->vsub
,
556 /* configure pixel extension based on scalar config */
557 _dpu_plane_setup_pixel_ext(&scaler3_cfg
, &pixel_ext
,
558 src_width
, src_height
, info
->hsub
, info
->vsub
);
560 if (pipe_hw
->ops
.setup_pe
)
561 pipe_hw
->ops
.setup_pe(pipe_hw
,
565 * when programmed in multirect mode, scalar block will be
566 * bypassed. Still we need to update alpha and bitwidth
569 if (pipe_hw
->ops
.setup_scaler
&&
570 pipe
->multirect_index
!= DPU_SSPP_RECT_1
)
571 pipe_hw
->ops
.setup_scaler(pipe_hw
,
576 static void _dpu_plane_color_fill_pipe(struct dpu_plane_state
*pstate
,
577 struct dpu_sw_pipe
*pipe
,
578 struct drm_rect
*dst_rect
,
580 const struct dpu_format
*fmt
)
582 struct dpu_sw_pipe_cfg pipe_cfg
;
585 if (!pipe
->sspp
->ops
.setup_solidfill
)
588 pipe
->sspp
->ops
.setup_solidfill(pipe
, fill_color
);
590 /* override scaler/decimation if solid fill */
591 pipe_cfg
.dst_rect
= *dst_rect
;
593 pipe_cfg
.src_rect
.x1
= 0;
594 pipe_cfg
.src_rect
.y1
= 0;
595 pipe_cfg
.src_rect
.x2
=
596 drm_rect_width(&pipe_cfg
.dst_rect
);
597 pipe_cfg
.src_rect
.y2
=
598 drm_rect_height(&pipe_cfg
.dst_rect
);
600 if (pipe
->sspp
->ops
.setup_format
)
601 pipe
->sspp
->ops
.setup_format(pipe
, fmt
, DPU_SSPP_SOLID_FILL
);
603 if (pipe
->sspp
->ops
.setup_rects
)
604 pipe
->sspp
->ops
.setup_rects(pipe
, &pipe_cfg
);
606 _dpu_plane_setup_scaler(pipe
, fmt
, true, &pipe_cfg
, pstate
->rotation
);
610 * _dpu_plane_color_fill - enables color fill on plane
611 * @pdpu: Pointer to DPU plane object
612 * @color: RGB fill color value, [23..16] Blue, [15..8] Green, [7..0] Red
613 * @alpha: 8-bit fill alpha value, 255 selects 100% alpha
615 static void _dpu_plane_color_fill(struct dpu_plane
*pdpu
,
616 uint32_t color
, uint32_t alpha
)
618 const struct dpu_format
*fmt
;
619 const struct drm_plane
*plane
= &pdpu
->base
;
620 struct dpu_plane_state
*pstate
= to_dpu_plane_state(plane
->state
);
621 u32 fill_color
= (color
& 0xFFFFFF) | ((alpha
& 0xFF) << 24);
623 DPU_DEBUG_PLANE(pdpu
, "\n");
626 * select fill format to match user property expectation,
627 * h/w only supports RGB variants
629 fmt
= dpu_get_dpu_format(DRM_FORMAT_ABGR8888
);
630 /* should not happen ever */
635 _dpu_plane_color_fill_pipe(pstate
, &pstate
->pipe
, &pstate
->pipe_cfg
.dst_rect
,
638 if (pstate
->r_pipe
.sspp
)
639 _dpu_plane_color_fill_pipe(pstate
, &pstate
->r_pipe
, &pstate
->r_pipe_cfg
.dst_rect
,
643 static int dpu_plane_prepare_fb(struct drm_plane
*plane
,
644 struct drm_plane_state
*new_state
)
646 struct drm_framebuffer
*fb
= new_state
->fb
;
647 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
648 struct dpu_plane_state
*pstate
= to_dpu_plane_state(new_state
);
649 struct dpu_hw_fmt_layout layout
;
650 struct dpu_kms
*kms
= _dpu_plane_get_kms(&pdpu
->base
);
656 DPU_DEBUG_PLANE(pdpu
, "FB[%u]\n", fb
->base
.id
);
659 pstate
->aspace
= kms
->base
.aspace
;
662 * TODO: Need to sort out the msm_framebuffer_prepare() call below so
663 * we can use msm_atomic_prepare_fb() instead of doing the
664 * implicit fence and fb prepare by hand here.
666 drm_gem_plane_helper_prepare_fb(plane
, new_state
);
668 if (pstate
->aspace
) {
669 ret
= msm_framebuffer_prepare(new_state
->fb
,
670 pstate
->aspace
, pstate
->needs_dirtyfb
);
672 DPU_ERROR("failed to prepare framebuffer\n");
677 /* validate framebuffer layout before commit */
678 ret
= dpu_format_populate_layout(pstate
->aspace
,
679 new_state
->fb
, &layout
);
681 DPU_ERROR_PLANE(pdpu
, "failed to get format layout, %d\n", ret
);
688 static void dpu_plane_cleanup_fb(struct drm_plane
*plane
,
689 struct drm_plane_state
*old_state
)
691 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
692 struct dpu_plane_state
*old_pstate
;
694 if (!old_state
|| !old_state
->fb
)
697 old_pstate
= to_dpu_plane_state(old_state
);
699 DPU_DEBUG_PLANE(pdpu
, "FB[%u]\n", old_state
->fb
->base
.id
);
701 msm_framebuffer_cleanup(old_state
->fb
, old_pstate
->aspace
,
702 old_pstate
->needs_dirtyfb
);
705 static int dpu_plane_check_inline_rotation(struct dpu_plane
*pdpu
,
706 const struct dpu_sspp_sub_blks
*sblk
,
707 struct drm_rect src
, const struct dpu_format
*fmt
)
710 const u32
*supported_formats
;
712 if (!sblk
->rotation_cfg
) {
713 DPU_ERROR("invalid rotation cfg\n");
717 if (drm_rect_width(&src
) > sblk
->rotation_cfg
->rot_maxheight
) {
718 DPU_DEBUG_PLANE(pdpu
, "invalid height for inline rot:%d max:%d\n",
719 src
.y2
, sblk
->rotation_cfg
->rot_maxheight
);
723 supported_formats
= sblk
->rotation_cfg
->rot_format_list
;
724 num_formats
= sblk
->rotation_cfg
->rot_num_formats
;
726 if (!DPU_FORMAT_IS_UBWC(fmt
) ||
727 !dpu_find_format(fmt
->base
.pixel_format
, supported_formats
, num_formats
))
733 static int dpu_plane_atomic_check_pipe(struct dpu_plane
*pdpu
,
734 struct dpu_sw_pipe
*pipe
,
735 struct dpu_sw_pipe_cfg
*pipe_cfg
,
736 const struct dpu_format
*fmt
,
737 const struct drm_display_mode
*mode
)
739 uint32_t min_src_size
;
740 struct dpu_kms
*kms
= _dpu_plane_get_kms(&pdpu
->base
);
742 min_src_size
= DPU_FORMAT_IS_YUV(fmt
) ? 2 : 1;
744 if (DPU_FORMAT_IS_YUV(fmt
) &&
745 (!(pipe
->sspp
->cap
->features
& DPU_SSPP_SCALER
) ||
746 !(pipe
->sspp
->cap
->features
& DPU_SSPP_CSC_ANY
))) {
747 DPU_DEBUG_PLANE(pdpu
,
748 "plane doesn't have scaler/csc for yuv\n");
752 /* check src bounds */
753 if (drm_rect_width(&pipe_cfg
->src_rect
) < min_src_size
||
754 drm_rect_height(&pipe_cfg
->src_rect
) < min_src_size
) {
755 DPU_DEBUG_PLANE(pdpu
, "invalid source " DRM_RECT_FMT
"\n",
756 DRM_RECT_ARG(&pipe_cfg
->src_rect
));
760 /* valid yuv image */
761 if (DPU_FORMAT_IS_YUV(fmt
) &&
762 (pipe_cfg
->src_rect
.x1
& 0x1 ||
763 pipe_cfg
->src_rect
.y1
& 0x1 ||
764 drm_rect_width(&pipe_cfg
->src_rect
) & 0x1 ||
765 drm_rect_height(&pipe_cfg
->src_rect
) & 0x1)) {
766 DPU_DEBUG_PLANE(pdpu
, "invalid yuv source " DRM_RECT_FMT
"\n",
767 DRM_RECT_ARG(&pipe_cfg
->src_rect
));
771 /* min dst support */
772 if (drm_rect_width(&pipe_cfg
->dst_rect
) < 0x1 ||
773 drm_rect_height(&pipe_cfg
->dst_rect
) < 0x1) {
774 DPU_DEBUG_PLANE(pdpu
, "invalid dest rect " DRM_RECT_FMT
"\n",
775 DRM_RECT_ARG(&pipe_cfg
->dst_rect
));
780 if (_dpu_plane_calc_clk(mode
, pipe_cfg
) > kms
->perf
.max_core_clk_rate
) {
781 DPU_DEBUG_PLANE(pdpu
, "plane exceeds max mdp core clk limits\n");
788 static int dpu_plane_atomic_check(struct drm_plane
*plane
,
789 struct drm_atomic_state
*state
)
791 struct drm_plane_state
*new_plane_state
= drm_atomic_get_new_plane_state(state
,
793 int ret
= 0, min_scale
;
794 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
795 struct dpu_plane_state
*pstate
= to_dpu_plane_state(new_plane_state
);
796 struct dpu_sw_pipe
*pipe
= &pstate
->pipe
;
797 struct dpu_sw_pipe
*r_pipe
= &pstate
->r_pipe
;
798 const struct drm_crtc_state
*crtc_state
= NULL
;
799 const struct dpu_format
*fmt
;
800 struct dpu_sw_pipe_cfg
*pipe_cfg
= &pstate
->pipe_cfg
;
801 struct dpu_sw_pipe_cfg
*r_pipe_cfg
= &pstate
->r_pipe_cfg
;
802 struct drm_rect fb_rect
= { 0 };
803 uint32_t max_linewidth
;
804 unsigned int rotation
;
805 uint32_t supported_rotations
;
806 const struct dpu_sspp_cfg
*pipe_hw_caps
= pstate
->pipe
.sspp
->cap
;
807 const struct dpu_sspp_sub_blks
*sblk
= pstate
->pipe
.sspp
->cap
->sblk
;
809 if (new_plane_state
->crtc
)
810 crtc_state
= drm_atomic_get_new_crtc_state(state
,
811 new_plane_state
->crtc
);
813 min_scale
= FRAC_16_16(1, sblk
->maxupscale
);
814 ret
= drm_atomic_helper_check_plane_state(new_plane_state
, crtc_state
,
816 sblk
->maxdwnscale
<< 16,
819 DPU_DEBUG_PLANE(pdpu
, "Check plane state failed (%d)\n", ret
);
822 if (!new_plane_state
->visible
)
825 pipe
->multirect_index
= DPU_SSPP_RECT_SOLO
;
826 pipe
->multirect_mode
= DPU_SSPP_MULTIRECT_NONE
;
827 r_pipe
->multirect_index
= DPU_SSPP_RECT_SOLO
;
828 r_pipe
->multirect_mode
= DPU_SSPP_MULTIRECT_NONE
;
831 pstate
->stage
= DPU_STAGE_0
+ pstate
->base
.normalized_zpos
;
832 if (pstate
->stage
>= pdpu
->catalog
->caps
->max_mixer_blendstages
) {
833 DPU_ERROR("> %d plane stages assigned\n",
834 pdpu
->catalog
->caps
->max_mixer_blendstages
- DPU_STAGE_0
);
838 pipe_cfg
->src_rect
= new_plane_state
->src
;
840 /* state->src is 16.16, src_rect is not */
841 pipe_cfg
->src_rect
.x1
>>= 16;
842 pipe_cfg
->src_rect
.x2
>>= 16;
843 pipe_cfg
->src_rect
.y1
>>= 16;
844 pipe_cfg
->src_rect
.y2
>>= 16;
846 pipe_cfg
->dst_rect
= new_plane_state
->dst
;
848 fb_rect
.x2
= new_plane_state
->fb
->width
;
849 fb_rect
.y2
= new_plane_state
->fb
->height
;
851 /* Ensure fb size is supported */
852 if (drm_rect_width(&fb_rect
) > MAX_IMG_WIDTH
||
853 drm_rect_height(&fb_rect
) > MAX_IMG_HEIGHT
) {
854 DPU_DEBUG_PLANE(pdpu
, "invalid framebuffer " DRM_RECT_FMT
"\n",
855 DRM_RECT_ARG(&fb_rect
));
859 fmt
= to_dpu_format(msm_framebuffer_format(new_plane_state
->fb
));
861 max_linewidth
= pdpu
->catalog
->caps
->max_linewidth
;
863 if (drm_rect_width(&pipe_cfg
->src_rect
) > max_linewidth
) {
865 * In parallel multirect case only the half of the usual width
866 * is supported for tiled formats. If we are here, we know that
867 * full width is more than max_linewidth, thus each rect is
868 * wider than allowed.
870 if (DPU_FORMAT_IS_UBWC(fmt
)) {
871 DPU_DEBUG_PLANE(pdpu
, "invalid src " DRM_RECT_FMT
" line:%u, tiled format\n",
872 DRM_RECT_ARG(&pipe_cfg
->src_rect
), max_linewidth
);
876 if (drm_rect_width(&pipe_cfg
->src_rect
) > 2 * max_linewidth
) {
877 DPU_DEBUG_PLANE(pdpu
, "invalid src " DRM_RECT_FMT
" line:%u\n",
878 DRM_RECT_ARG(&pipe_cfg
->src_rect
), max_linewidth
);
882 if (drm_rect_width(&pipe_cfg
->src_rect
) != drm_rect_width(&pipe_cfg
->dst_rect
) ||
883 drm_rect_height(&pipe_cfg
->src_rect
) != drm_rect_height(&pipe_cfg
->dst_rect
) ||
884 (!test_bit(DPU_SSPP_SMART_DMA_V1
, &pipe
->sspp
->cap
->features
) &&
885 !test_bit(DPU_SSPP_SMART_DMA_V2
, &pipe
->sspp
->cap
->features
)) ||
886 DPU_FORMAT_IS_YUV(fmt
)) {
887 DPU_DEBUG_PLANE(pdpu
, "invalid src " DRM_RECT_FMT
" line:%u, can't use split source\n",
888 DRM_RECT_ARG(&pipe_cfg
->src_rect
), max_linewidth
);
893 * Use multirect for wide plane. We do not support dynamic
894 * assignment of SSPPs, so we know the configuration.
896 pipe
->multirect_index
= DPU_SSPP_RECT_0
;
897 pipe
->multirect_mode
= DPU_SSPP_MULTIRECT_PARALLEL
;
899 r_pipe
->sspp
= pipe
->sspp
;
900 r_pipe
->multirect_index
= DPU_SSPP_RECT_1
;
901 r_pipe
->multirect_mode
= DPU_SSPP_MULTIRECT_PARALLEL
;
903 *r_pipe_cfg
= *pipe_cfg
;
904 pipe_cfg
->src_rect
.x2
= (pipe_cfg
->src_rect
.x1
+ pipe_cfg
->src_rect
.x2
) >> 1;
905 pipe_cfg
->dst_rect
.x2
= (pipe_cfg
->dst_rect
.x1
+ pipe_cfg
->dst_rect
.x2
) >> 1;
906 r_pipe_cfg
->src_rect
.x1
= pipe_cfg
->src_rect
.x2
;
907 r_pipe_cfg
->dst_rect
.x1
= pipe_cfg
->dst_rect
.x2
;
910 ret
= dpu_plane_atomic_check_pipe(pdpu
, pipe
, pipe_cfg
, fmt
, &crtc_state
->adjusted_mode
);
915 ret
= dpu_plane_atomic_check_pipe(pdpu
, r_pipe
, r_pipe_cfg
, fmt
,
916 &crtc_state
->adjusted_mode
);
921 supported_rotations
= DRM_MODE_REFLECT_MASK
| DRM_MODE_ROTATE_0
;
923 if (pipe_hw_caps
->features
& BIT(DPU_SSPP_INLINE_ROTATION
))
924 supported_rotations
|= DRM_MODE_ROTATE_90
;
926 rotation
= drm_rotation_simplify(new_plane_state
->rotation
,
927 supported_rotations
);
929 if ((pipe_hw_caps
->features
& BIT(DPU_SSPP_INLINE_ROTATION
)) &&
930 (rotation
& DRM_MODE_ROTATE_90
)) {
931 ret
= dpu_plane_check_inline_rotation(pdpu
, sblk
, pipe_cfg
->src_rect
, fmt
);
936 pstate
->rotation
= rotation
;
937 pstate
->needs_qos_remap
= drm_atomic_crtc_needs_modeset(crtc_state
);
942 static void dpu_plane_flush_csc(struct dpu_plane
*pdpu
, struct dpu_sw_pipe
*pipe
)
944 const struct dpu_format
*format
=
945 to_dpu_format(msm_framebuffer_format(pdpu
->base
.state
->fb
));
946 const struct dpu_csc_cfg
*csc_ptr
;
948 if (!pipe
->sspp
|| !pipe
->sspp
->ops
.setup_csc
)
951 csc_ptr
= _dpu_plane_get_csc(pipe
, format
);
955 DPU_DEBUG_PLANE(pdpu
, "using 0x%X 0x%X 0x%X...\n",
960 pipe
->sspp
->ops
.setup_csc(pipe
->sspp
, csc_ptr
);
964 void dpu_plane_flush(struct drm_plane
*plane
)
966 struct dpu_plane
*pdpu
;
967 struct dpu_plane_state
*pstate
;
969 if (!plane
|| !plane
->state
) {
970 DPU_ERROR("invalid plane\n");
974 pdpu
= to_dpu_plane(plane
);
975 pstate
= to_dpu_plane_state(plane
->state
);
978 * These updates have to be done immediately before the plane flush
979 * timing, and may not be moved to the atomic_update/mode_set functions.
982 /* force white frame with 100% alpha pipe output on error */
983 _dpu_plane_color_fill(pdpu
, 0xFFFFFF, 0xFF);
984 else if (pdpu
->color_fill
& DPU_PLANE_COLOR_FILL_FLAG
)
985 /* force 100% alpha */
986 _dpu_plane_color_fill(pdpu
, pdpu
->color_fill
, 0xFF);
988 dpu_plane_flush_csc(pdpu
, &pstate
->pipe
);
989 dpu_plane_flush_csc(pdpu
, &pstate
->r_pipe
);
992 /* flag h/w flush complete */
994 pstate
->pending
= false;
998 * dpu_plane_set_error: enable/disable error condition
999 * @plane: pointer to drm_plane structure
1000 * @error: error value to set
1002 void dpu_plane_set_error(struct drm_plane
*plane
, bool error
)
1004 struct dpu_plane
*pdpu
;
1009 pdpu
= to_dpu_plane(plane
);
1010 pdpu
->is_error
= error
;
1013 static void dpu_plane_sspp_update_pipe(struct drm_plane
*plane
,
1014 struct dpu_sw_pipe
*pipe
,
1015 struct dpu_sw_pipe_cfg
*pipe_cfg
,
1016 const struct dpu_format
*fmt
,
1018 struct dpu_hw_fmt_layout
*layout
)
1021 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
1022 struct drm_plane_state
*state
= plane
->state
;
1023 struct dpu_plane_state
*pstate
= to_dpu_plane_state(state
);
1025 if (layout
&& pipe
->sspp
->ops
.setup_sourceaddress
) {
1026 trace_dpu_plane_set_scanout(pipe
, layout
);
1027 pipe
->sspp
->ops
.setup_sourceaddress(pipe
, layout
);
1030 /* override for color fill */
1031 if (pdpu
->color_fill
& DPU_PLANE_COLOR_FILL_FLAG
) {
1032 _dpu_plane_set_qos_ctrl(plane
, pipe
, false);
1034 /* skip remaining processing on color fill */
1038 if (pipe
->sspp
->ops
.setup_rects
) {
1039 pipe
->sspp
->ops
.setup_rects(pipe
,
1043 _dpu_plane_setup_scaler(pipe
, fmt
, false, pipe_cfg
, pstate
->rotation
);
1045 if (pipe
->sspp
->ops
.setup_multirect
)
1046 pipe
->sspp
->ops
.setup_multirect(
1049 if (pipe
->sspp
->ops
.setup_format
) {
1050 unsigned int rotation
= pstate
->rotation
;
1054 if (rotation
& DRM_MODE_REFLECT_X
)
1055 src_flags
|= DPU_SSPP_FLIP_LR
;
1057 if (rotation
& DRM_MODE_REFLECT_Y
)
1058 src_flags
|= DPU_SSPP_FLIP_UD
;
1060 if (rotation
& DRM_MODE_ROTATE_90
)
1061 src_flags
|= DPU_SSPP_ROT_90
;
1064 pipe
->sspp
->ops
.setup_format(pipe
, fmt
, src_flags
);
1066 if (pipe
->sspp
->ops
.setup_cdp
) {
1067 const struct dpu_perf_cfg
*perf
= pdpu
->catalog
->perf
;
1069 pipe
->sspp
->ops
.setup_cdp(pipe
, fmt
,
1070 perf
->cdp_cfg
[DPU_PERF_CDP_USAGE_RT
].rd_enable
);
1074 _dpu_plane_set_qos_lut(plane
, pipe
, fmt
, pipe_cfg
);
1076 if (pipe
->sspp
->idx
!= SSPP_CURSOR0
&&
1077 pipe
->sspp
->idx
!= SSPP_CURSOR1
)
1078 _dpu_plane_set_ot_limit(plane
, pipe
, pipe_cfg
, frame_rate
);
1080 if (pstate
->needs_qos_remap
)
1081 _dpu_plane_set_qos_remap(plane
, pipe
);
1084 static void dpu_plane_sspp_atomic_update(struct drm_plane
*plane
)
1086 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
1087 struct drm_plane_state
*state
= plane
->state
;
1088 struct dpu_plane_state
*pstate
= to_dpu_plane_state(state
);
1089 struct dpu_sw_pipe
*pipe
= &pstate
->pipe
;
1090 struct dpu_sw_pipe
*r_pipe
= &pstate
->r_pipe
;
1091 struct drm_crtc
*crtc
= state
->crtc
;
1092 struct drm_framebuffer
*fb
= state
->fb
;
1094 const struct dpu_format
*fmt
=
1095 to_dpu_format(msm_framebuffer_format(fb
));
1096 struct dpu_sw_pipe_cfg
*pipe_cfg
= &pstate
->pipe_cfg
;
1097 struct dpu_sw_pipe_cfg
*r_pipe_cfg
= &pstate
->r_pipe_cfg
;
1098 struct dpu_kms
*kms
= _dpu_plane_get_kms(&pdpu
->base
);
1099 struct msm_gem_address_space
*aspace
= kms
->base
.aspace
;
1100 struct dpu_hw_fmt_layout layout
;
1101 bool layout_valid
= false;
1104 ret
= dpu_format_populate_layout(aspace
, fb
, &layout
);
1106 DPU_ERROR_PLANE(pdpu
, "failed to get format layout, %d\n", ret
);
1108 layout_valid
= true;
1110 pstate
->pending
= true;
1112 is_rt_pipe
= (dpu_crtc_get_client_type(crtc
) != NRT_CLIENT
);
1113 pstate
->needs_qos_remap
|= (is_rt_pipe
!= pdpu
->is_rt_pipe
);
1114 pdpu
->is_rt_pipe
= is_rt_pipe
;
1116 DPU_DEBUG_PLANE(pdpu
, "FB[%u] " DRM_RECT_FP_FMT
"->crtc%u " DRM_RECT_FMT
1117 ", %4.4s ubwc %d\n", fb
->base
.id
, DRM_RECT_FP_ARG(&state
->src
),
1118 crtc
->base
.id
, DRM_RECT_ARG(&state
->dst
),
1119 (char *)&fmt
->base
.pixel_format
, DPU_FORMAT_IS_UBWC(fmt
));
1121 dpu_plane_sspp_update_pipe(plane
, pipe
, pipe_cfg
, fmt
,
1122 drm_mode_vrefresh(&crtc
->mode
),
1123 layout_valid
? &layout
: NULL
);
1126 dpu_plane_sspp_update_pipe(plane
, r_pipe
, r_pipe_cfg
, fmt
,
1127 drm_mode_vrefresh(&crtc
->mode
),
1128 layout_valid
? &layout
: NULL
);
1131 if (pstate
->needs_qos_remap
)
1132 pstate
->needs_qos_remap
= false;
1134 pstate
->plane_fetch_bw
= _dpu_plane_calc_bw(pdpu
->catalog
, fmt
,
1135 &crtc
->mode
, pipe_cfg
);
1137 pstate
->plane_clk
= _dpu_plane_calc_clk(&crtc
->mode
, pipe_cfg
);
1140 pstate
->plane_fetch_bw
+= _dpu_plane_calc_bw(pdpu
->catalog
, fmt
, &crtc
->mode
, r_pipe_cfg
);
1142 pstate
->plane_clk
= max(pstate
->plane_clk
, _dpu_plane_calc_clk(&crtc
->mode
, r_pipe_cfg
));
1146 static void _dpu_plane_atomic_disable(struct drm_plane
*plane
)
1148 struct drm_plane_state
*state
= plane
->state
;
1149 struct dpu_plane_state
*pstate
= to_dpu_plane_state(state
);
1150 struct dpu_sw_pipe
*r_pipe
= &pstate
->r_pipe
;
1152 trace_dpu_plane_disable(DRMID(plane
), false,
1153 pstate
->pipe
.multirect_mode
);
1156 r_pipe
->multirect_index
= DPU_SSPP_RECT_SOLO
;
1157 r_pipe
->multirect_mode
= DPU_SSPP_MULTIRECT_NONE
;
1159 if (r_pipe
->sspp
->ops
.setup_multirect
)
1160 r_pipe
->sspp
->ops
.setup_multirect(r_pipe
);
1163 pstate
->pending
= true;
1166 static void dpu_plane_atomic_update(struct drm_plane
*plane
,
1167 struct drm_atomic_state
*state
)
1169 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
1170 struct drm_plane_state
*new_state
= drm_atomic_get_new_plane_state(state
,
1173 pdpu
->is_error
= false;
1175 DPU_DEBUG_PLANE(pdpu
, "\n");
1177 if (!new_state
->visible
) {
1178 _dpu_plane_atomic_disable(plane
);
1180 dpu_plane_sspp_atomic_update(plane
);
1184 static void dpu_plane_destroy(struct drm_plane
*plane
)
1186 struct dpu_plane
*pdpu
= plane
? to_dpu_plane(plane
) : NULL
;
1187 struct dpu_plane_state
*pstate
;
1189 DPU_DEBUG_PLANE(pdpu
, "\n");
1192 pstate
= to_dpu_plane_state(plane
->state
);
1193 _dpu_plane_set_qos_ctrl(plane
, &pstate
->pipe
, false);
1195 if (pstate
->r_pipe
.sspp
)
1196 _dpu_plane_set_qos_ctrl(plane
, &pstate
->r_pipe
, false);
1198 mutex_destroy(&pdpu
->lock
);
1200 /* this will destroy the states as well */
1201 drm_plane_cleanup(plane
);
1207 static void dpu_plane_destroy_state(struct drm_plane
*plane
,
1208 struct drm_plane_state
*state
)
1210 __drm_atomic_helper_plane_destroy_state(state
);
1211 kfree(to_dpu_plane_state(state
));
1214 static struct drm_plane_state
*
1215 dpu_plane_duplicate_state(struct drm_plane
*plane
)
1217 struct dpu_plane
*pdpu
;
1218 struct dpu_plane_state
*pstate
;
1219 struct dpu_plane_state
*old_state
;
1222 DPU_ERROR("invalid plane\n");
1224 } else if (!plane
->state
) {
1225 DPU_ERROR("invalid plane state\n");
1229 old_state
= to_dpu_plane_state(plane
->state
);
1230 pdpu
= to_dpu_plane(plane
);
1231 pstate
= kmemdup(old_state
, sizeof(*old_state
), GFP_KERNEL
);
1233 DPU_ERROR_PLANE(pdpu
, "failed to allocate state\n");
1237 DPU_DEBUG_PLANE(pdpu
, "\n");
1239 pstate
->pending
= false;
1241 __drm_atomic_helper_plane_duplicate_state(plane
, &pstate
->base
);
1243 return &pstate
->base
;
1246 static const char * const multirect_mode_name
[] = {
1247 [DPU_SSPP_MULTIRECT_NONE
] = "none",
1248 [DPU_SSPP_MULTIRECT_PARALLEL
] = "parallel",
1249 [DPU_SSPP_MULTIRECT_TIME_MX
] = "time_mx",
1252 static const char * const multirect_index_name
[] = {
1253 [DPU_SSPP_RECT_SOLO
] = "solo",
1254 [DPU_SSPP_RECT_0
] = "rect_0",
1255 [DPU_SSPP_RECT_1
] = "rect_1",
1258 static const char *dpu_get_multirect_mode(enum dpu_sspp_multirect_mode mode
)
1260 if (WARN_ON(mode
>= ARRAY_SIZE(multirect_mode_name
)))
1263 return multirect_mode_name
[mode
];
1266 static const char *dpu_get_multirect_index(enum dpu_sspp_multirect_index index
)
1268 if (WARN_ON(index
>= ARRAY_SIZE(multirect_index_name
)))
1271 return multirect_index_name
[index
];
1274 static void dpu_plane_atomic_print_state(struct drm_printer
*p
,
1275 const struct drm_plane_state
*state
)
1277 const struct dpu_plane_state
*pstate
= to_dpu_plane_state(state
);
1278 const struct dpu_sw_pipe
*pipe
= &pstate
->pipe
;
1279 const struct dpu_sw_pipe_cfg
*pipe_cfg
= &pstate
->pipe_cfg
;
1280 const struct dpu_sw_pipe
*r_pipe
= &pstate
->r_pipe
;
1281 const struct dpu_sw_pipe_cfg
*r_pipe_cfg
= &pstate
->r_pipe_cfg
;
1283 drm_printf(p
, "\tstage=%d\n", pstate
->stage
);
1285 drm_printf(p
, "\tsspp[0]=%s\n", pipe
->sspp
->cap
->name
);
1286 drm_printf(p
, "\tmultirect_mode[0]=%s\n", dpu_get_multirect_mode(pipe
->multirect_mode
));
1287 drm_printf(p
, "\tmultirect_index[0]=%s\n",
1288 dpu_get_multirect_index(pipe
->multirect_index
));
1289 drm_printf(p
, "\tsrc[0]=" DRM_RECT_FMT
"\n", DRM_RECT_ARG(&pipe_cfg
->src_rect
));
1290 drm_printf(p
, "\tdst[0]=" DRM_RECT_FMT
"\n", DRM_RECT_ARG(&pipe_cfg
->dst_rect
));
1293 drm_printf(p
, "\tsspp[1]=%s\n", r_pipe
->sspp
->cap
->name
);
1294 drm_printf(p
, "\tmultirect_mode[1]=%s\n",
1295 dpu_get_multirect_mode(r_pipe
->multirect_mode
));
1296 drm_printf(p
, "\tmultirect_index[1]=%s\n",
1297 dpu_get_multirect_index(r_pipe
->multirect_index
));
1298 drm_printf(p
, "\tsrc[1]=" DRM_RECT_FMT
"\n", DRM_RECT_ARG(&r_pipe_cfg
->src_rect
));
1299 drm_printf(p
, "\tdst[1]=" DRM_RECT_FMT
"\n", DRM_RECT_ARG(&r_pipe_cfg
->dst_rect
));
1303 static void dpu_plane_reset(struct drm_plane
*plane
)
1305 struct dpu_plane
*pdpu
;
1306 struct dpu_plane_state
*pstate
;
1307 struct dpu_kms
*dpu_kms
= _dpu_plane_get_kms(plane
);
1310 DPU_ERROR("invalid plane\n");
1314 pdpu
= to_dpu_plane(plane
);
1315 DPU_DEBUG_PLANE(pdpu
, "\n");
1317 /* remove previous state, if present */
1319 dpu_plane_destroy_state(plane
, plane
->state
);
1320 plane
->state
= NULL
;
1323 pstate
= kzalloc(sizeof(*pstate
), GFP_KERNEL
);
1325 DPU_ERROR_PLANE(pdpu
, "failed to allocate state\n");
1330 * Set the SSPP here until we have proper virtualized DPU planes.
1331 * This is the place where the state is allocated, so fill it fully.
1333 pstate
->pipe
.sspp
= dpu_rm_get_sspp(&dpu_kms
->rm
, pdpu
->pipe
);
1334 pstate
->pipe
.multirect_index
= DPU_SSPP_RECT_SOLO
;
1335 pstate
->pipe
.multirect_mode
= DPU_SSPP_MULTIRECT_NONE
;
1337 pstate
->r_pipe
.sspp
= NULL
;
1339 __drm_atomic_helper_plane_reset(plane
, &pstate
->base
);
1342 #ifdef CONFIG_DEBUG_FS
1343 void dpu_plane_danger_signal_ctrl(struct drm_plane
*plane
, bool enable
)
1345 struct dpu_plane
*pdpu
= to_dpu_plane(plane
);
1346 struct dpu_plane_state
*pstate
= to_dpu_plane_state(plane
->state
);
1347 struct dpu_kms
*dpu_kms
= _dpu_plane_get_kms(plane
);
1349 if (!pdpu
->is_rt_pipe
)
1352 pm_runtime_get_sync(&dpu_kms
->pdev
->dev
);
1353 _dpu_plane_set_qos_ctrl(plane
, &pstate
->pipe
, enable
);
1354 if (pstate
->r_pipe
.sspp
)
1355 _dpu_plane_set_qos_ctrl(plane
, &pstate
->r_pipe
, enable
);
1356 pm_runtime_put_sync(&dpu_kms
->pdev
->dev
);
1360 static bool dpu_plane_format_mod_supported(struct drm_plane
*plane
,
1361 uint32_t format
, uint64_t modifier
)
1363 if (modifier
== DRM_FORMAT_MOD_LINEAR
)
1366 if (modifier
== DRM_FORMAT_MOD_QCOM_COMPRESSED
)
1367 return dpu_find_format(format
, qcom_compressed_supported_formats
,
1368 ARRAY_SIZE(qcom_compressed_supported_formats
));
1373 static const struct drm_plane_funcs dpu_plane_funcs
= {
1374 .update_plane
= drm_atomic_helper_update_plane
,
1375 .disable_plane
= drm_atomic_helper_disable_plane
,
1376 .destroy
= dpu_plane_destroy
,
1377 .reset
= dpu_plane_reset
,
1378 .atomic_duplicate_state
= dpu_plane_duplicate_state
,
1379 .atomic_destroy_state
= dpu_plane_destroy_state
,
1380 .atomic_print_state
= dpu_plane_atomic_print_state
,
1381 .format_mod_supported
= dpu_plane_format_mod_supported
,
1384 static const struct drm_plane_helper_funcs dpu_plane_helper_funcs
= {
1385 .prepare_fb
= dpu_plane_prepare_fb
,
1386 .cleanup_fb
= dpu_plane_cleanup_fb
,
1387 .atomic_check
= dpu_plane_atomic_check
,
1388 .atomic_update
= dpu_plane_atomic_update
,
1391 /* initialize plane */
1392 struct drm_plane
*dpu_plane_init(struct drm_device
*dev
,
1393 uint32_t pipe
, enum drm_plane_type type
,
1394 unsigned long possible_crtcs
)
1396 struct drm_plane
*plane
= NULL
;
1397 const uint32_t *format_list
;
1398 struct dpu_plane
*pdpu
;
1399 struct msm_drm_private
*priv
= dev
->dev_private
;
1400 struct dpu_kms
*kms
= to_dpu_kms(priv
->kms
);
1401 struct dpu_hw_sspp
*pipe_hw
;
1402 uint32_t num_formats
;
1403 uint32_t supported_rotations
;
1406 /* create and zero local structure */
1407 pdpu
= kzalloc(sizeof(*pdpu
), GFP_KERNEL
);
1409 DPU_ERROR("[%u]failed to allocate local plane struct\n", pipe
);
1411 return ERR_PTR(ret
);
1414 /* cache local stuff for later */
1415 plane
= &pdpu
->base
;
1418 /* initialize underlying h/w driver */
1419 pipe_hw
= dpu_rm_get_sspp(&kms
->rm
, pipe
);
1420 if (!pipe_hw
|| !pipe_hw
->cap
|| !pipe_hw
->cap
->sblk
) {
1421 DPU_ERROR("[%u]SSPP is invalid\n", pipe
);
1425 format_list
= pipe_hw
->cap
->sblk
->format_list
;
1426 num_formats
= pipe_hw
->cap
->sblk
->num_formats
;
1428 ret
= drm_universal_plane_init(dev
, plane
, 0xff, &dpu_plane_funcs
,
1429 format_list
, num_formats
,
1430 supported_format_modifiers
, type
, NULL
);
1434 pdpu
->catalog
= kms
->catalog
;
1436 ret
= drm_plane_create_zpos_property(plane
, 0, 0, DPU_ZPOS_MAX
);
1438 DPU_ERROR("failed to install zpos property, rc = %d\n", ret
);
1440 drm_plane_create_alpha_property(plane
);
1441 drm_plane_create_blend_mode_property(plane
,
1442 BIT(DRM_MODE_BLEND_PIXEL_NONE
) |
1443 BIT(DRM_MODE_BLEND_PREMULTI
) |
1444 BIT(DRM_MODE_BLEND_COVERAGE
));
1446 supported_rotations
= DRM_MODE_REFLECT_MASK
| DRM_MODE_ROTATE_0
| DRM_MODE_ROTATE_180
;
1448 if (pipe_hw
->cap
->features
& BIT(DPU_SSPP_INLINE_ROTATION
))
1449 supported_rotations
|= DRM_MODE_ROTATE_MASK
;
1451 drm_plane_create_rotation_property(plane
,
1452 DRM_MODE_ROTATE_0
, supported_rotations
);
1454 drm_plane_enable_fb_damage_clips(plane
);
1456 /* success! finalize initialization */
1457 drm_plane_helper_add(plane
, &dpu_plane_helper_funcs
);
1459 mutex_init(&pdpu
->lock
);
1461 DPU_DEBUG("%s created for pipe:%u id:%u\n", plane
->name
,
1462 pipe
, plane
->base
.id
);
1467 return ERR_PTR(ret
);