1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
6 #include "dpu_hw_catalog.h"
8 #include "dpu_hw_sspp.h"
11 #define DPU_FETCH_CONFIG_RESET_VALUE 0x00000087
14 #define SSPP_SRC_SIZE 0x00
15 #define SSPP_SRC_XY 0x08
16 #define SSPP_OUT_SIZE 0x0c
17 #define SSPP_OUT_XY 0x10
18 #define SSPP_SRC0_ADDR 0x14
19 #define SSPP_SRC1_ADDR 0x18
20 #define SSPP_SRC2_ADDR 0x1C
21 #define SSPP_SRC3_ADDR 0x20
22 #define SSPP_SRC_YSTRIDE0 0x24
23 #define SSPP_SRC_YSTRIDE1 0x28
24 #define SSPP_SRC_FORMAT 0x30
25 #define SSPP_SRC_UNPACK_PATTERN 0x34
26 #define SSPP_SRC_OP_MODE 0x38
29 #define SSPP_SRC_SIZE_REC1 0x16C
30 #define SSPP_SRC_XY_REC1 0x168
31 #define SSPP_OUT_SIZE_REC1 0x160
32 #define SSPP_OUT_XY_REC1 0x164
33 #define SSPP_SRC_FORMAT_REC1 0x174
34 #define SSPP_SRC_UNPACK_PATTERN_REC1 0x178
35 #define SSPP_SRC_OP_MODE_REC1 0x17C
36 #define SSPP_MULTIRECT_OPMODE 0x170
37 #define SSPP_SRC_CONSTANT_COLOR_REC1 0x180
38 #define SSPP_EXCL_REC_SIZE_REC1 0x184
39 #define SSPP_EXCL_REC_XY_REC1 0x188
41 #define MDSS_MDP_OP_DEINTERLACE BIT(22)
42 #define MDSS_MDP_OP_DEINTERLACE_ODD BIT(23)
43 #define MDSS_MDP_OP_IGC_ROM_1 BIT(18)
44 #define MDSS_MDP_OP_IGC_ROM_0 BIT(17)
45 #define MDSS_MDP_OP_IGC_EN BIT(16)
46 #define MDSS_MDP_OP_FLIP_UD BIT(14)
47 #define MDSS_MDP_OP_FLIP_LR BIT(13)
48 #define MDSS_MDP_OP_BWC_EN BIT(0)
49 #define MDSS_MDP_OP_PE_OVERRIDE BIT(31)
50 #define MDSS_MDP_OP_BWC_LOSSLESS (0 << 1)
51 #define MDSS_MDP_OP_BWC_Q_HIGH (1 << 1)
52 #define MDSS_MDP_OP_BWC_Q_MED (2 << 1)
54 #define SSPP_SRC_CONSTANT_COLOR 0x3c
55 #define SSPP_EXCL_REC_CTL 0x40
56 #define SSPP_UBWC_STATIC_CTRL 0x44
57 #define SSPP_FETCH_CONFIG 0x048
58 #define SSPP_DANGER_LUT 0x60
59 #define SSPP_SAFE_LUT 0x64
60 #define SSPP_CREQ_LUT 0x68
61 #define SSPP_QOS_CTRL 0x6C
62 #define SSPP_DECIMATION_CONFIG 0xB4
63 #define SSPP_SRC_ADDR_SW_STATUS 0x70
64 #define SSPP_CREQ_LUT_0 0x74
65 #define SSPP_CREQ_LUT_1 0x78
66 #define SSPP_SW_PIX_EXT_C0_LR 0x100
67 #define SSPP_SW_PIX_EXT_C0_TB 0x104
68 #define SSPP_SW_PIX_EXT_C0_REQ_PIXELS 0x108
69 #define SSPP_SW_PIX_EXT_C1C2_LR 0x110
70 #define SSPP_SW_PIX_EXT_C1C2_TB 0x114
71 #define SSPP_SW_PIX_EXT_C1C2_REQ_PIXELS 0x118
72 #define SSPP_SW_PIX_EXT_C3_LR 0x120
73 #define SSPP_SW_PIX_EXT_C3_TB 0x124
74 #define SSPP_SW_PIX_EXT_C3_REQ_PIXELS 0x128
75 #define SSPP_TRAFFIC_SHAPER 0x130
76 #define SSPP_CDP_CNTL 0x134
77 #define SSPP_UBWC_ERROR_STATUS 0x138
78 #define SSPP_TRAFFIC_SHAPER_PREFILL 0x150
79 #define SSPP_TRAFFIC_SHAPER_REC1_PREFILL 0x154
80 #define SSPP_TRAFFIC_SHAPER_REC1 0x158
81 #define SSPP_EXCL_REC_SIZE 0x1B4
82 #define SSPP_EXCL_REC_XY 0x1B8
83 #define SSPP_VIG_OP_MODE 0x0
84 #define SSPP_VIG_CSC_10_OP_MODE 0x0
85 #define SSPP_TRAFFIC_SHAPER_BPC_MAX 0xFF
88 #define SSPP_QOS_CTRL_VBLANK_EN BIT(16)
89 #define SSPP_QOS_CTRL_DANGER_SAFE_EN BIT(0)
90 #define SSPP_QOS_CTRL_DANGER_VBLANK_MASK 0x3
91 #define SSPP_QOS_CTRL_DANGER_VBLANK_OFF 4
92 #define SSPP_QOS_CTRL_CREQ_VBLANK_MASK 0x3
93 #define SSPP_QOS_CTRL_CREQ_VBLANK_OFF 20
95 /* DPU_SSPP_SCALER_QSEED2 */
96 #define SCALE_CONFIG 0x04
97 #define COMP0_3_PHASE_STEP_X 0x10
98 #define COMP0_3_PHASE_STEP_Y 0x14
99 #define COMP1_2_PHASE_STEP_X 0x18
100 #define COMP1_2_PHASE_STEP_Y 0x1c
101 #define COMP0_3_INIT_PHASE_X 0x20
102 #define COMP0_3_INIT_PHASE_Y 0x24
103 #define COMP1_2_INIT_PHASE_X 0x28
104 #define COMP1_2_INIT_PHASE_Y 0x2C
105 #define VIG_0_QSEED2_SHARP 0x30
108 * Definitions for ViG op modes
110 #define VIG_OP_CSC_DST_DATAFMT BIT(19)
111 #define VIG_OP_CSC_SRC_DATAFMT BIT(18)
112 #define VIG_OP_CSC_EN BIT(17)
113 #define VIG_OP_MEM_PROT_CONT BIT(15)
114 #define VIG_OP_MEM_PROT_VAL BIT(14)
115 #define VIG_OP_MEM_PROT_SAT BIT(13)
116 #define VIG_OP_MEM_PROT_HUE BIT(12)
117 #define VIG_OP_HIST BIT(8)
118 #define VIG_OP_SKY_COL BIT(7)
119 #define VIG_OP_FOIL BIT(6)
120 #define VIG_OP_SKIN_COL BIT(5)
121 #define VIG_OP_PA_EN BIT(4)
122 #define VIG_OP_PA_SAT_ZERO_EXP BIT(2)
123 #define VIG_OP_MEM_PROT_BLEND BIT(1)
126 * Definitions for CSC 10 op modes
128 #define VIG_CSC_10_SRC_DATAFMT BIT(1)
129 #define VIG_CSC_10_EN BIT(0)
130 #define CSC_10BIT_OFFSET 4
132 /* traffic shaper clock in Hz */
133 #define TS_CLK 19200000
136 static int _sspp_subblk_offset(struct dpu_hw_pipe
*ctx
,
141 const struct dpu_sspp_sub_blks
*sblk
= ctx
->cap
->sblk
;
148 *idx
= sblk
->src_blk
.base
;
150 case DPU_SSPP_SCALER_QSEED2
:
151 case DPU_SSPP_SCALER_QSEED3
:
152 case DPU_SSPP_SCALER_RGB
:
153 *idx
= sblk
->scaler_blk
.base
;
156 case DPU_SSPP_CSC_10BIT
:
157 *idx
= sblk
->csc_blk
.base
;
166 static void dpu_hw_sspp_setup_multirect(struct dpu_hw_pipe
*ctx
,
167 enum dpu_sspp_multirect_index index
,
168 enum dpu_sspp_multirect_mode mode
)
173 if (_sspp_subblk_offset(ctx
, DPU_SSPP_SRC
, &idx
))
176 if (index
== DPU_SSPP_RECT_SOLO
) {
178 * if rect index is RECT_SOLO, we cannot expect a
179 * virtual plane sharing the same SSPP id. So we go
180 * and disable multirect
184 mode_mask
= DPU_REG_READ(&ctx
->hw
, SSPP_MULTIRECT_OPMODE
+ idx
);
186 if (mode
== DPU_SSPP_MULTIRECT_TIME_MX
)
189 mode_mask
&= ~BIT(2);
192 DPU_REG_WRITE(&ctx
->hw
, SSPP_MULTIRECT_OPMODE
+ idx
, mode_mask
);
195 static void _sspp_setup_opmode(struct dpu_hw_pipe
*ctx
,
201 if (!test_bit(DPU_SSPP_SCALER_QSEED2
, &ctx
->cap
->features
) ||
202 _sspp_subblk_offset(ctx
, DPU_SSPP_SCALER_QSEED2
, &idx
) ||
203 !test_bit(DPU_SSPP_CSC
, &ctx
->cap
->features
))
206 opmode
= DPU_REG_READ(&ctx
->hw
, SSPP_VIG_OP_MODE
+ idx
);
213 DPU_REG_WRITE(&ctx
->hw
, SSPP_VIG_OP_MODE
+ idx
, opmode
);
216 static void _sspp_setup_csc10_opmode(struct dpu_hw_pipe
*ctx
,
222 if (_sspp_subblk_offset(ctx
, DPU_SSPP_CSC_10BIT
, &idx
))
225 opmode
= DPU_REG_READ(&ctx
->hw
, SSPP_VIG_CSC_10_OP_MODE
+ idx
);
231 DPU_REG_WRITE(&ctx
->hw
, SSPP_VIG_CSC_10_OP_MODE
+ idx
, opmode
);
235 * Setup source pixel format, flip,
237 static void dpu_hw_sspp_setup_format(struct dpu_hw_pipe
*ctx
,
238 const struct dpu_format
*fmt
, u32 flags
,
239 enum dpu_sspp_multirect_index rect_mode
)
241 struct dpu_hw_blk_reg_map
*c
;
242 u32 chroma_samp
, unpack
, src_format
;
245 u32 op_mode_off
, unpack_pat_off
, format_off
;
248 if (_sspp_subblk_offset(ctx
, DPU_SSPP_SRC
, &idx
) || !fmt
)
251 if (rect_mode
== DPU_SSPP_RECT_SOLO
|| rect_mode
== DPU_SSPP_RECT_0
) {
252 op_mode_off
= SSPP_SRC_OP_MODE
;
253 unpack_pat_off
= SSPP_SRC_UNPACK_PATTERN
;
254 format_off
= SSPP_SRC_FORMAT
;
256 op_mode_off
= SSPP_SRC_OP_MODE_REC1
;
257 unpack_pat_off
= SSPP_SRC_UNPACK_PATTERN_REC1
;
258 format_off
= SSPP_SRC_FORMAT_REC1
;
262 opmode
= DPU_REG_READ(c
, op_mode_off
+ idx
);
263 opmode
&= ~(MDSS_MDP_OP_FLIP_LR
| MDSS_MDP_OP_FLIP_UD
|
264 MDSS_MDP_OP_BWC_EN
| MDSS_MDP_OP_PE_OVERRIDE
);
266 if (flags
& DPU_SSPP_FLIP_LR
)
267 opmode
|= MDSS_MDP_OP_FLIP_LR
;
268 if (flags
& DPU_SSPP_FLIP_UD
)
269 opmode
|= MDSS_MDP_OP_FLIP_UD
;
271 chroma_samp
= fmt
->chroma_sample
;
272 if (flags
& DPU_SSPP_SOURCE_ROTATED_90
) {
273 if (chroma_samp
== DPU_CHROMA_H2V1
)
274 chroma_samp
= DPU_CHROMA_H1V2
;
275 else if (chroma_samp
== DPU_CHROMA_H1V2
)
276 chroma_samp
= DPU_CHROMA_H2V1
;
279 src_format
= (chroma_samp
<< 23) | (fmt
->fetch_planes
<< 19) |
280 (fmt
->bits
[C3_ALPHA
] << 6) | (fmt
->bits
[C2_R_Cr
] << 4) |
281 (fmt
->bits
[C1_B_Cb
] << 2) | (fmt
->bits
[C0_G_Y
] << 0);
283 if (flags
& DPU_SSPP_ROT_90
)
284 src_format
|= BIT(11); /* ROT90 */
286 if (fmt
->alpha_enable
&& fmt
->fetch_planes
== DPU_PLANE_INTERLEAVED
)
287 src_format
|= BIT(8); /* SRCC3_EN */
289 if (flags
& DPU_SSPP_SOLID_FILL
)
290 src_format
|= BIT(22);
292 unpack
= (fmt
->element
[3] << 24) | (fmt
->element
[2] << 16) |
293 (fmt
->element
[1] << 8) | (fmt
->element
[0] << 0);
294 src_format
|= ((fmt
->unpack_count
- 1) << 12) |
295 (fmt
->unpack_tight
<< 17) |
296 (fmt
->unpack_align_msb
<< 18) |
297 ((fmt
->bpp
- 1) << 9);
299 if (fmt
->fetch_mode
!= DPU_FETCH_LINEAR
) {
300 if (DPU_FORMAT_IS_UBWC(fmt
))
301 opmode
|= MDSS_MDP_OP_BWC_EN
;
302 src_format
|= (fmt
->fetch_mode
& 3) << 30; /*FRAME_FORMAT */
303 DPU_REG_WRITE(c
, SSPP_FETCH_CONFIG
,
304 DPU_FETCH_CONFIG_RESET_VALUE
|
305 ctx
->mdp
->highest_bank_bit
<< 18);
306 switch (ctx
->catalog
->caps
->ubwc_version
) {
307 case DPU_HW_UBWC_VER_10
:
308 /* TODO: UBWC v1 case */
310 case DPU_HW_UBWC_VER_20
:
311 fast_clear
= fmt
->alpha_enable
? BIT(31) : 0;
312 DPU_REG_WRITE(c
, SSPP_UBWC_STATIC_CTRL
,
313 fast_clear
| (ctx
->mdp
->ubwc_swizzle
) |
314 (ctx
->mdp
->highest_bank_bit
<< 4));
316 case DPU_HW_UBWC_VER_30
:
317 DPU_REG_WRITE(c
, SSPP_UBWC_STATIC_CTRL
,
318 BIT(30) | (ctx
->mdp
->ubwc_swizzle
) |
319 (ctx
->mdp
->highest_bank_bit
<< 4));
321 case DPU_HW_UBWC_VER_40
:
322 DPU_REG_WRITE(c
, SSPP_UBWC_STATIC_CTRL
,
323 DPU_FORMAT_IS_YUV(fmt
) ? 0 : BIT(30));
328 opmode
|= MDSS_MDP_OP_PE_OVERRIDE
;
330 /* if this is YUV pixel format, enable CSC */
331 if (DPU_FORMAT_IS_YUV(fmt
))
332 src_format
|= BIT(15);
334 if (DPU_FORMAT_IS_DX(fmt
))
335 src_format
|= BIT(14);
337 /* update scaler opmode, if appropriate */
338 if (test_bit(DPU_SSPP_CSC
, &ctx
->cap
->features
))
339 _sspp_setup_opmode(ctx
, VIG_OP_CSC_EN
| VIG_OP_CSC_SRC_DATAFMT
,
340 DPU_FORMAT_IS_YUV(fmt
));
341 else if (test_bit(DPU_SSPP_CSC_10BIT
, &ctx
->cap
->features
))
342 _sspp_setup_csc10_opmode(ctx
,
343 VIG_CSC_10_EN
| VIG_CSC_10_SRC_DATAFMT
,
344 DPU_FORMAT_IS_YUV(fmt
));
346 DPU_REG_WRITE(c
, format_off
+ idx
, src_format
);
347 DPU_REG_WRITE(c
, unpack_pat_off
+ idx
, unpack
);
348 DPU_REG_WRITE(c
, op_mode_off
+ idx
, opmode
);
350 /* clear previous UBWC error */
351 DPU_REG_WRITE(c
, SSPP_UBWC_ERROR_STATUS
+ idx
, BIT(31));
354 static void dpu_hw_sspp_setup_pe_config(struct dpu_hw_pipe
*ctx
,
355 struct dpu_hw_pixel_ext
*pe_ext
)
357 struct dpu_hw_blk_reg_map
*c
;
359 u32 lr_pe
[4], tb_pe
[4], tot_req_pixels
[4];
360 const u32 bytemask
= 0xff;
361 const u32 shortmask
= 0xffff;
364 if (_sspp_subblk_offset(ctx
, DPU_SSPP_SRC
, &idx
) || !pe_ext
)
369 /* program SW pixel extension override for all pipes*/
370 for (color
= 0; color
< DPU_MAX_PLANES
; color
++) {
371 /* color 2 has the same set of registers as color 1 */
375 lr_pe
[color
] = ((pe_ext
->right_ftch
[color
] & bytemask
) << 24)|
376 ((pe_ext
->right_rpt
[color
] & bytemask
) << 16)|
377 ((pe_ext
->left_ftch
[color
] & bytemask
) << 8)|
378 (pe_ext
->left_rpt
[color
] & bytemask
);
380 tb_pe
[color
] = ((pe_ext
->btm_ftch
[color
] & bytemask
) << 24)|
381 ((pe_ext
->btm_rpt
[color
] & bytemask
) << 16)|
382 ((pe_ext
->top_ftch
[color
] & bytemask
) << 8)|
383 (pe_ext
->top_rpt
[color
] & bytemask
);
385 tot_req_pixels
[color
] = (((pe_ext
->roi_h
[color
] +
386 pe_ext
->num_ext_pxls_top
[color
] +
387 pe_ext
->num_ext_pxls_btm
[color
]) & shortmask
) << 16) |
388 ((pe_ext
->roi_w
[color
] +
389 pe_ext
->num_ext_pxls_left
[color
] +
390 pe_ext
->num_ext_pxls_right
[color
]) & shortmask
);
394 DPU_REG_WRITE(c
, SSPP_SW_PIX_EXT_C0_LR
+ idx
, lr_pe
[0]);
395 DPU_REG_WRITE(c
, SSPP_SW_PIX_EXT_C0_TB
+ idx
, tb_pe
[0]);
396 DPU_REG_WRITE(c
, SSPP_SW_PIX_EXT_C0_REQ_PIXELS
+ idx
,
399 /* color 1 and color 2 */
400 DPU_REG_WRITE(c
, SSPP_SW_PIX_EXT_C1C2_LR
+ idx
, lr_pe
[1]);
401 DPU_REG_WRITE(c
, SSPP_SW_PIX_EXT_C1C2_TB
+ idx
, tb_pe
[1]);
402 DPU_REG_WRITE(c
, SSPP_SW_PIX_EXT_C1C2_REQ_PIXELS
+ idx
,
406 DPU_REG_WRITE(c
, SSPP_SW_PIX_EXT_C3_LR
+ idx
, lr_pe
[3]);
407 DPU_REG_WRITE(c
, SSPP_SW_PIX_EXT_C3_TB
+ idx
, lr_pe
[3]);
408 DPU_REG_WRITE(c
, SSPP_SW_PIX_EXT_C3_REQ_PIXELS
+ idx
,
412 static void _dpu_hw_sspp_setup_scaler3(struct dpu_hw_pipe
*ctx
,
413 struct dpu_hw_pipe_cfg
*sspp
,
414 struct dpu_hw_pixel_ext
*pe
,
418 struct dpu_hw_scaler3_cfg
*scaler3_cfg
= scaler_cfg
;
421 if (_sspp_subblk_offset(ctx
, DPU_SSPP_SCALER_QSEED3
, &idx
) || !sspp
422 || !scaler3_cfg
|| !ctx
|| !ctx
->cap
|| !ctx
->cap
->sblk
)
425 dpu_hw_setup_scaler3(&ctx
->hw
, scaler3_cfg
, idx
,
426 ctx
->cap
->sblk
->scaler_blk
.version
,
427 sspp
->layout
.format
);
430 static u32
_dpu_hw_sspp_get_scaler3_ver(struct dpu_hw_pipe
*ctx
)
434 if (!ctx
|| _sspp_subblk_offset(ctx
, DPU_SSPP_SCALER_QSEED3
, &idx
))
437 return dpu_hw_get_scaler3_ver(&ctx
->hw
, idx
);
441 * dpu_hw_sspp_setup_rects()
443 static void dpu_hw_sspp_setup_rects(struct dpu_hw_pipe
*ctx
,
444 struct dpu_hw_pipe_cfg
*cfg
,
445 enum dpu_sspp_multirect_index rect_index
)
447 struct dpu_hw_blk_reg_map
*c
;
448 u32 src_size
, src_xy
, dst_size
, dst_xy
, ystride0
, ystride1
;
449 u32 src_size_off
, src_xy_off
, out_size_off
, out_xy_off
;
452 if (_sspp_subblk_offset(ctx
, DPU_SSPP_SRC
, &idx
) || !cfg
)
457 if (rect_index
== DPU_SSPP_RECT_SOLO
|| rect_index
== DPU_SSPP_RECT_0
) {
458 src_size_off
= SSPP_SRC_SIZE
;
459 src_xy_off
= SSPP_SRC_XY
;
460 out_size_off
= SSPP_OUT_SIZE
;
461 out_xy_off
= SSPP_OUT_XY
;
463 src_size_off
= SSPP_SRC_SIZE_REC1
;
464 src_xy_off
= SSPP_SRC_XY_REC1
;
465 out_size_off
= SSPP_OUT_SIZE_REC1
;
466 out_xy_off
= SSPP_OUT_XY_REC1
;
470 /* src and dest rect programming */
471 src_xy
= (cfg
->src_rect
.y1
<< 16) | cfg
->src_rect
.x1
;
472 src_size
= (drm_rect_height(&cfg
->src_rect
) << 16) |
473 drm_rect_width(&cfg
->src_rect
);
474 dst_xy
= (cfg
->dst_rect
.y1
<< 16) | cfg
->dst_rect
.x1
;
475 dst_size
= (drm_rect_height(&cfg
->dst_rect
) << 16) |
476 drm_rect_width(&cfg
->dst_rect
);
478 if (rect_index
== DPU_SSPP_RECT_SOLO
) {
479 ystride0
= (cfg
->layout
.plane_pitch
[0]) |
480 (cfg
->layout
.plane_pitch
[1] << 16);
481 ystride1
= (cfg
->layout
.plane_pitch
[2]) |
482 (cfg
->layout
.plane_pitch
[3] << 16);
484 ystride0
= DPU_REG_READ(c
, SSPP_SRC_YSTRIDE0
+ idx
);
485 ystride1
= DPU_REG_READ(c
, SSPP_SRC_YSTRIDE1
+ idx
);
487 if (rect_index
== DPU_SSPP_RECT_0
) {
488 ystride0
= (ystride0
& 0xFFFF0000) |
489 (cfg
->layout
.plane_pitch
[0] & 0x0000FFFF);
490 ystride1
= (ystride1
& 0xFFFF0000)|
491 (cfg
->layout
.plane_pitch
[2] & 0x0000FFFF);
493 ystride0
= (ystride0
& 0x0000FFFF) |
494 ((cfg
->layout
.plane_pitch
[0] << 16) &
496 ystride1
= (ystride1
& 0x0000FFFF) |
497 ((cfg
->layout
.plane_pitch
[2] << 16) &
502 /* rectangle register programming */
503 DPU_REG_WRITE(c
, src_size_off
+ idx
, src_size
);
504 DPU_REG_WRITE(c
, src_xy_off
+ idx
, src_xy
);
505 DPU_REG_WRITE(c
, out_size_off
+ idx
, dst_size
);
506 DPU_REG_WRITE(c
, out_xy_off
+ idx
, dst_xy
);
508 DPU_REG_WRITE(c
, SSPP_SRC_YSTRIDE0
+ idx
, ystride0
);
509 DPU_REG_WRITE(c
, SSPP_SRC_YSTRIDE1
+ idx
, ystride1
);
512 static void dpu_hw_sspp_setup_sourceaddress(struct dpu_hw_pipe
*ctx
,
513 struct dpu_hw_pipe_cfg
*cfg
,
514 enum dpu_sspp_multirect_index rect_mode
)
519 if (_sspp_subblk_offset(ctx
, DPU_SSPP_SRC
, &idx
))
522 if (rect_mode
== DPU_SSPP_RECT_SOLO
) {
523 for (i
= 0; i
< ARRAY_SIZE(cfg
->layout
.plane_addr
); i
++)
524 DPU_REG_WRITE(&ctx
->hw
, SSPP_SRC0_ADDR
+ idx
+ i
* 0x4,
525 cfg
->layout
.plane_addr
[i
]);
526 } else if (rect_mode
== DPU_SSPP_RECT_0
) {
527 DPU_REG_WRITE(&ctx
->hw
, SSPP_SRC0_ADDR
+ idx
,
528 cfg
->layout
.plane_addr
[0]);
529 DPU_REG_WRITE(&ctx
->hw
, SSPP_SRC2_ADDR
+ idx
,
530 cfg
->layout
.plane_addr
[2]);
532 DPU_REG_WRITE(&ctx
->hw
, SSPP_SRC1_ADDR
+ idx
,
533 cfg
->layout
.plane_addr
[0]);
534 DPU_REG_WRITE(&ctx
->hw
, SSPP_SRC3_ADDR
+ idx
,
535 cfg
->layout
.plane_addr
[2]);
539 static void dpu_hw_sspp_setup_csc(struct dpu_hw_pipe
*ctx
,
540 struct dpu_csc_cfg
*data
)
545 if (_sspp_subblk_offset(ctx
, DPU_SSPP_CSC
, &idx
) || !data
)
548 if (test_bit(DPU_SSPP_CSC_10BIT
, &ctx
->cap
->features
)) {
549 idx
+= CSC_10BIT_OFFSET
;
553 dpu_hw_csc_setup(&ctx
->hw
, idx
, data
, csc10
);
556 static void dpu_hw_sspp_setup_solidfill(struct dpu_hw_pipe
*ctx
, u32 color
, enum
557 dpu_sspp_multirect_index rect_index
)
561 if (_sspp_subblk_offset(ctx
, DPU_SSPP_SRC
, &idx
))
564 if (rect_index
== DPU_SSPP_RECT_SOLO
|| rect_index
== DPU_SSPP_RECT_0
)
565 DPU_REG_WRITE(&ctx
->hw
, SSPP_SRC_CONSTANT_COLOR
+ idx
, color
);
567 DPU_REG_WRITE(&ctx
->hw
, SSPP_SRC_CONSTANT_COLOR_REC1
+ idx
,
571 static void dpu_hw_sspp_setup_danger_safe_lut(struct dpu_hw_pipe
*ctx
,
572 struct dpu_hw_pipe_qos_cfg
*cfg
)
576 if (_sspp_subblk_offset(ctx
, DPU_SSPP_SRC
, &idx
))
579 DPU_REG_WRITE(&ctx
->hw
, SSPP_DANGER_LUT
+ idx
, cfg
->danger_lut
);
580 DPU_REG_WRITE(&ctx
->hw
, SSPP_SAFE_LUT
+ idx
, cfg
->safe_lut
);
583 static void dpu_hw_sspp_setup_creq_lut(struct dpu_hw_pipe
*ctx
,
584 struct dpu_hw_pipe_qos_cfg
*cfg
)
588 if (_sspp_subblk_offset(ctx
, DPU_SSPP_SRC
, &idx
))
591 if (ctx
->cap
&& test_bit(DPU_SSPP_QOS_8LVL
, &ctx
->cap
->features
)) {
592 DPU_REG_WRITE(&ctx
->hw
, SSPP_CREQ_LUT_0
+ idx
, cfg
->creq_lut
);
593 DPU_REG_WRITE(&ctx
->hw
, SSPP_CREQ_LUT_1
+ idx
,
594 cfg
->creq_lut
>> 32);
596 DPU_REG_WRITE(&ctx
->hw
, SSPP_CREQ_LUT
+ idx
, cfg
->creq_lut
);
600 static void dpu_hw_sspp_setup_qos_ctrl(struct dpu_hw_pipe
*ctx
,
601 struct dpu_hw_pipe_qos_cfg
*cfg
)
606 if (_sspp_subblk_offset(ctx
, DPU_SSPP_SRC
, &idx
))
609 if (cfg
->vblank_en
) {
610 qos_ctrl
|= ((cfg
->creq_vblank
&
611 SSPP_QOS_CTRL_CREQ_VBLANK_MASK
) <<
612 SSPP_QOS_CTRL_CREQ_VBLANK_OFF
);
613 qos_ctrl
|= ((cfg
->danger_vblank
&
614 SSPP_QOS_CTRL_DANGER_VBLANK_MASK
) <<
615 SSPP_QOS_CTRL_DANGER_VBLANK_OFF
);
616 qos_ctrl
|= SSPP_QOS_CTRL_VBLANK_EN
;
619 if (cfg
->danger_safe_en
)
620 qos_ctrl
|= SSPP_QOS_CTRL_DANGER_SAFE_EN
;
622 DPU_REG_WRITE(&ctx
->hw
, SSPP_QOS_CTRL
+ idx
, qos_ctrl
);
625 static void dpu_hw_sspp_setup_cdp(struct dpu_hw_pipe
*ctx
,
626 struct dpu_hw_pipe_cdp_cfg
*cfg
)
634 if (_sspp_subblk_offset(ctx
, DPU_SSPP_SRC
, &idx
))
639 if (cfg
->ubwc_meta_enable
)
641 if (cfg
->tile_amortize_enable
)
643 if (cfg
->preload_ahead
== DPU_SSPP_CDP_PRELOAD_AHEAD_64
)
646 DPU_REG_WRITE(&ctx
->hw
, SSPP_CDP_CNTL
, cdp_cntl
);
649 static void _setup_layer_ops(struct dpu_hw_pipe
*c
,
650 unsigned long features
)
652 if (test_bit(DPU_SSPP_SRC
, &features
)) {
653 c
->ops
.setup_format
= dpu_hw_sspp_setup_format
;
654 c
->ops
.setup_rects
= dpu_hw_sspp_setup_rects
;
655 c
->ops
.setup_sourceaddress
= dpu_hw_sspp_setup_sourceaddress
;
656 c
->ops
.setup_solidfill
= dpu_hw_sspp_setup_solidfill
;
657 c
->ops
.setup_pe
= dpu_hw_sspp_setup_pe_config
;
660 if (test_bit(DPU_SSPP_QOS
, &features
)) {
661 c
->ops
.setup_danger_safe_lut
=
662 dpu_hw_sspp_setup_danger_safe_lut
;
663 c
->ops
.setup_creq_lut
= dpu_hw_sspp_setup_creq_lut
;
664 c
->ops
.setup_qos_ctrl
= dpu_hw_sspp_setup_qos_ctrl
;
667 if (test_bit(DPU_SSPP_CSC
, &features
) ||
668 test_bit(DPU_SSPP_CSC_10BIT
, &features
))
669 c
->ops
.setup_csc
= dpu_hw_sspp_setup_csc
;
671 if (test_bit(DPU_SSPP_SMART_DMA_V1
, &c
->cap
->features
) ||
672 test_bit(DPU_SSPP_SMART_DMA_V2
, &c
->cap
->features
))
673 c
->ops
.setup_multirect
= dpu_hw_sspp_setup_multirect
;
675 if (test_bit(DPU_SSPP_SCALER_QSEED3
, &features
) ||
676 test_bit(DPU_SSPP_SCALER_QSEED4
, &features
)) {
677 c
->ops
.setup_scaler
= _dpu_hw_sspp_setup_scaler3
;
678 c
->ops
.get_scaler_ver
= _dpu_hw_sspp_get_scaler3_ver
;
681 if (test_bit(DPU_SSPP_CDP
, &features
))
682 c
->ops
.setup_cdp
= dpu_hw_sspp_setup_cdp
;
685 static const struct dpu_sspp_cfg
*_sspp_offset(enum dpu_sspp sspp
,
687 struct dpu_mdss_cfg
*catalog
,
688 struct dpu_hw_blk_reg_map
*b
)
692 if ((sspp
< SSPP_MAX
) && catalog
&& addr
&& b
) {
693 for (i
= 0; i
< catalog
->sspp_count
; i
++) {
694 if (sspp
== catalog
->sspp
[i
].id
) {
696 b
->blk_off
= catalog
->sspp
[i
].base
;
697 b
->length
= catalog
->sspp
[i
].len
;
698 b
->hwversion
= catalog
->hwversion
;
699 b
->log_mask
= DPU_DBG_MASK_SSPP
;
700 return &catalog
->sspp
[i
];
705 return ERR_PTR(-ENOMEM
);
708 static struct dpu_hw_blk_ops dpu_hw_ops
;
710 struct dpu_hw_pipe
*dpu_hw_sspp_init(enum dpu_sspp idx
,
711 void __iomem
*addr
, struct dpu_mdss_cfg
*catalog
,
712 bool is_virtual_pipe
)
714 struct dpu_hw_pipe
*hw_pipe
;
715 const struct dpu_sspp_cfg
*cfg
;
717 if (!addr
|| !catalog
)
718 return ERR_PTR(-EINVAL
);
720 hw_pipe
= kzalloc(sizeof(*hw_pipe
), GFP_KERNEL
);
722 return ERR_PTR(-ENOMEM
);
724 cfg
= _sspp_offset(idx
, addr
, catalog
, &hw_pipe
->hw
);
725 if (IS_ERR_OR_NULL(cfg
)) {
727 return ERR_PTR(-EINVAL
);
731 hw_pipe
->catalog
= catalog
;
732 hw_pipe
->mdp
= &catalog
->mdp
[0];
735 _setup_layer_ops(hw_pipe
, hw_pipe
->cap
->features
);
737 dpu_hw_blk_init(&hw_pipe
->base
, DPU_HW_BLK_SSPP
, idx
, &dpu_hw_ops
);
742 void dpu_hw_sspp_destroy(struct dpu_hw_pipe
*ctx
)
745 dpu_hw_blk_destroy(&ctx
->base
);