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 if (IS_UBWC_20_SUPPORTED(ctx
->catalog
->caps
->ubwc_version
)) {
307 fast_clear
= fmt
->alpha_enable
? BIT(31) : 0;
308 DPU_REG_WRITE(c
, SSPP_UBWC_STATIC_CTRL
,
309 fast_clear
| (ctx
->mdp
->ubwc_swizzle
) |
310 (ctx
->mdp
->highest_bank_bit
<< 4));
314 opmode
|= MDSS_MDP_OP_PE_OVERRIDE
;
316 /* if this is YUV pixel format, enable CSC */
317 if (DPU_FORMAT_IS_YUV(fmt
))
318 src_format
|= BIT(15);
320 if (DPU_FORMAT_IS_DX(fmt
))
321 src_format
|= BIT(14);
323 /* update scaler opmode, if appropriate */
324 if (test_bit(DPU_SSPP_CSC
, &ctx
->cap
->features
))
325 _sspp_setup_opmode(ctx
, VIG_OP_CSC_EN
| VIG_OP_CSC_SRC_DATAFMT
,
326 DPU_FORMAT_IS_YUV(fmt
));
327 else if (test_bit(DPU_SSPP_CSC_10BIT
, &ctx
->cap
->features
))
328 _sspp_setup_csc10_opmode(ctx
,
329 VIG_CSC_10_EN
| VIG_CSC_10_SRC_DATAFMT
,
330 DPU_FORMAT_IS_YUV(fmt
));
332 DPU_REG_WRITE(c
, format_off
+ idx
, src_format
);
333 DPU_REG_WRITE(c
, unpack_pat_off
+ idx
, unpack
);
334 DPU_REG_WRITE(c
, op_mode_off
+ idx
, opmode
);
336 /* clear previous UBWC error */
337 DPU_REG_WRITE(c
, SSPP_UBWC_ERROR_STATUS
+ idx
, BIT(31));
340 static void dpu_hw_sspp_setup_pe_config(struct dpu_hw_pipe
*ctx
,
341 struct dpu_hw_pixel_ext
*pe_ext
)
343 struct dpu_hw_blk_reg_map
*c
;
345 u32 lr_pe
[4], tb_pe
[4], tot_req_pixels
[4];
346 const u32 bytemask
= 0xff;
347 const u32 shortmask
= 0xffff;
350 if (_sspp_subblk_offset(ctx
, DPU_SSPP_SRC
, &idx
) || !pe_ext
)
355 /* program SW pixel extension override for all pipes*/
356 for (color
= 0; color
< DPU_MAX_PLANES
; color
++) {
357 /* color 2 has the same set of registers as color 1 */
361 lr_pe
[color
] = ((pe_ext
->right_ftch
[color
] & bytemask
) << 24)|
362 ((pe_ext
->right_rpt
[color
] & bytemask
) << 16)|
363 ((pe_ext
->left_ftch
[color
] & bytemask
) << 8)|
364 (pe_ext
->left_rpt
[color
] & bytemask
);
366 tb_pe
[color
] = ((pe_ext
->btm_ftch
[color
] & bytemask
) << 24)|
367 ((pe_ext
->btm_rpt
[color
] & bytemask
) << 16)|
368 ((pe_ext
->top_ftch
[color
] & bytemask
) << 8)|
369 (pe_ext
->top_rpt
[color
] & bytemask
);
371 tot_req_pixels
[color
] = (((pe_ext
->roi_h
[color
] +
372 pe_ext
->num_ext_pxls_top
[color
] +
373 pe_ext
->num_ext_pxls_btm
[color
]) & shortmask
) << 16) |
374 ((pe_ext
->roi_w
[color
] +
375 pe_ext
->num_ext_pxls_left
[color
] +
376 pe_ext
->num_ext_pxls_right
[color
]) & shortmask
);
380 DPU_REG_WRITE(c
, SSPP_SW_PIX_EXT_C0_LR
+ idx
, lr_pe
[0]);
381 DPU_REG_WRITE(c
, SSPP_SW_PIX_EXT_C0_TB
+ idx
, tb_pe
[0]);
382 DPU_REG_WRITE(c
, SSPP_SW_PIX_EXT_C0_REQ_PIXELS
+ idx
,
385 /* color 1 and color 2 */
386 DPU_REG_WRITE(c
, SSPP_SW_PIX_EXT_C1C2_LR
+ idx
, lr_pe
[1]);
387 DPU_REG_WRITE(c
, SSPP_SW_PIX_EXT_C1C2_TB
+ idx
, tb_pe
[1]);
388 DPU_REG_WRITE(c
, SSPP_SW_PIX_EXT_C1C2_REQ_PIXELS
+ idx
,
392 DPU_REG_WRITE(c
, SSPP_SW_PIX_EXT_C3_LR
+ idx
, lr_pe
[3]);
393 DPU_REG_WRITE(c
, SSPP_SW_PIX_EXT_C3_TB
+ idx
, lr_pe
[3]);
394 DPU_REG_WRITE(c
, SSPP_SW_PIX_EXT_C3_REQ_PIXELS
+ idx
,
398 static void _dpu_hw_sspp_setup_scaler3(struct dpu_hw_pipe
*ctx
,
399 struct dpu_hw_pipe_cfg
*sspp
,
400 struct dpu_hw_pixel_ext
*pe
,
404 struct dpu_hw_scaler3_cfg
*scaler3_cfg
= scaler_cfg
;
407 if (_sspp_subblk_offset(ctx
, DPU_SSPP_SCALER_QSEED3
, &idx
) || !sspp
408 || !scaler3_cfg
|| !ctx
|| !ctx
->cap
|| !ctx
->cap
->sblk
)
411 dpu_hw_setup_scaler3(&ctx
->hw
, scaler3_cfg
, idx
,
412 ctx
->cap
->sblk
->scaler_blk
.version
,
413 sspp
->layout
.format
);
416 static u32
_dpu_hw_sspp_get_scaler3_ver(struct dpu_hw_pipe
*ctx
)
420 if (!ctx
|| _sspp_subblk_offset(ctx
, DPU_SSPP_SCALER_QSEED3
, &idx
))
423 return dpu_hw_get_scaler3_ver(&ctx
->hw
, idx
);
427 * dpu_hw_sspp_setup_rects()
429 static void dpu_hw_sspp_setup_rects(struct dpu_hw_pipe
*ctx
,
430 struct dpu_hw_pipe_cfg
*cfg
,
431 enum dpu_sspp_multirect_index rect_index
)
433 struct dpu_hw_blk_reg_map
*c
;
434 u32 src_size
, src_xy
, dst_size
, dst_xy
, ystride0
, ystride1
;
435 u32 src_size_off
, src_xy_off
, out_size_off
, out_xy_off
;
438 if (_sspp_subblk_offset(ctx
, DPU_SSPP_SRC
, &idx
) || !cfg
)
443 if (rect_index
== DPU_SSPP_RECT_SOLO
|| rect_index
== DPU_SSPP_RECT_0
) {
444 src_size_off
= SSPP_SRC_SIZE
;
445 src_xy_off
= SSPP_SRC_XY
;
446 out_size_off
= SSPP_OUT_SIZE
;
447 out_xy_off
= SSPP_OUT_XY
;
449 src_size_off
= SSPP_SRC_SIZE_REC1
;
450 src_xy_off
= SSPP_SRC_XY_REC1
;
451 out_size_off
= SSPP_OUT_SIZE_REC1
;
452 out_xy_off
= SSPP_OUT_XY_REC1
;
456 /* src and dest rect programming */
457 src_xy
= (cfg
->src_rect
.y1
<< 16) | cfg
->src_rect
.x1
;
458 src_size
= (drm_rect_height(&cfg
->src_rect
) << 16) |
459 drm_rect_width(&cfg
->src_rect
);
460 dst_xy
= (cfg
->dst_rect
.y1
<< 16) | cfg
->dst_rect
.x1
;
461 dst_size
= (drm_rect_height(&cfg
->dst_rect
) << 16) |
462 drm_rect_width(&cfg
->dst_rect
);
464 if (rect_index
== DPU_SSPP_RECT_SOLO
) {
465 ystride0
= (cfg
->layout
.plane_pitch
[0]) |
466 (cfg
->layout
.plane_pitch
[1] << 16);
467 ystride1
= (cfg
->layout
.plane_pitch
[2]) |
468 (cfg
->layout
.plane_pitch
[3] << 16);
470 ystride0
= DPU_REG_READ(c
, SSPP_SRC_YSTRIDE0
+ idx
);
471 ystride1
= DPU_REG_READ(c
, SSPP_SRC_YSTRIDE1
+ idx
);
473 if (rect_index
== DPU_SSPP_RECT_0
) {
474 ystride0
= (ystride0
& 0xFFFF0000) |
475 (cfg
->layout
.plane_pitch
[0] & 0x0000FFFF);
476 ystride1
= (ystride1
& 0xFFFF0000)|
477 (cfg
->layout
.plane_pitch
[2] & 0x0000FFFF);
479 ystride0
= (ystride0
& 0x0000FFFF) |
480 ((cfg
->layout
.plane_pitch
[0] << 16) &
482 ystride1
= (ystride1
& 0x0000FFFF) |
483 ((cfg
->layout
.plane_pitch
[2] << 16) &
488 /* rectangle register programming */
489 DPU_REG_WRITE(c
, src_size_off
+ idx
, src_size
);
490 DPU_REG_WRITE(c
, src_xy_off
+ idx
, src_xy
);
491 DPU_REG_WRITE(c
, out_size_off
+ idx
, dst_size
);
492 DPU_REG_WRITE(c
, out_xy_off
+ idx
, dst_xy
);
494 DPU_REG_WRITE(c
, SSPP_SRC_YSTRIDE0
+ idx
, ystride0
);
495 DPU_REG_WRITE(c
, SSPP_SRC_YSTRIDE1
+ idx
, ystride1
);
498 static void dpu_hw_sspp_setup_sourceaddress(struct dpu_hw_pipe
*ctx
,
499 struct dpu_hw_pipe_cfg
*cfg
,
500 enum dpu_sspp_multirect_index rect_mode
)
505 if (_sspp_subblk_offset(ctx
, DPU_SSPP_SRC
, &idx
))
508 if (rect_mode
== DPU_SSPP_RECT_SOLO
) {
509 for (i
= 0; i
< ARRAY_SIZE(cfg
->layout
.plane_addr
); i
++)
510 DPU_REG_WRITE(&ctx
->hw
, SSPP_SRC0_ADDR
+ idx
+ i
* 0x4,
511 cfg
->layout
.plane_addr
[i
]);
512 } else if (rect_mode
== DPU_SSPP_RECT_0
) {
513 DPU_REG_WRITE(&ctx
->hw
, SSPP_SRC0_ADDR
+ idx
,
514 cfg
->layout
.plane_addr
[0]);
515 DPU_REG_WRITE(&ctx
->hw
, SSPP_SRC2_ADDR
+ idx
,
516 cfg
->layout
.plane_addr
[2]);
518 DPU_REG_WRITE(&ctx
->hw
, SSPP_SRC1_ADDR
+ idx
,
519 cfg
->layout
.plane_addr
[0]);
520 DPU_REG_WRITE(&ctx
->hw
, SSPP_SRC3_ADDR
+ idx
,
521 cfg
->layout
.plane_addr
[2]);
525 static void dpu_hw_sspp_setup_csc(struct dpu_hw_pipe
*ctx
,
526 struct dpu_csc_cfg
*data
)
531 if (_sspp_subblk_offset(ctx
, DPU_SSPP_CSC
, &idx
) || !data
)
534 if (test_bit(DPU_SSPP_CSC_10BIT
, &ctx
->cap
->features
)) {
535 idx
+= CSC_10BIT_OFFSET
;
539 dpu_hw_csc_setup(&ctx
->hw
, idx
, data
, csc10
);
542 static void dpu_hw_sspp_setup_solidfill(struct dpu_hw_pipe
*ctx
, u32 color
, enum
543 dpu_sspp_multirect_index rect_index
)
547 if (_sspp_subblk_offset(ctx
, DPU_SSPP_SRC
, &idx
))
550 if (rect_index
== DPU_SSPP_RECT_SOLO
|| rect_index
== DPU_SSPP_RECT_0
)
551 DPU_REG_WRITE(&ctx
->hw
, SSPP_SRC_CONSTANT_COLOR
+ idx
, color
);
553 DPU_REG_WRITE(&ctx
->hw
, SSPP_SRC_CONSTANT_COLOR_REC1
+ idx
,
557 static void dpu_hw_sspp_setup_danger_safe_lut(struct dpu_hw_pipe
*ctx
,
558 struct dpu_hw_pipe_qos_cfg
*cfg
)
562 if (_sspp_subblk_offset(ctx
, DPU_SSPP_SRC
, &idx
))
565 DPU_REG_WRITE(&ctx
->hw
, SSPP_DANGER_LUT
+ idx
, cfg
->danger_lut
);
566 DPU_REG_WRITE(&ctx
->hw
, SSPP_SAFE_LUT
+ idx
, cfg
->safe_lut
);
569 static void dpu_hw_sspp_setup_creq_lut(struct dpu_hw_pipe
*ctx
,
570 struct dpu_hw_pipe_qos_cfg
*cfg
)
574 if (_sspp_subblk_offset(ctx
, DPU_SSPP_SRC
, &idx
))
577 if (ctx
->cap
&& test_bit(DPU_SSPP_QOS_8LVL
, &ctx
->cap
->features
)) {
578 DPU_REG_WRITE(&ctx
->hw
, SSPP_CREQ_LUT_0
+ idx
, cfg
->creq_lut
);
579 DPU_REG_WRITE(&ctx
->hw
, SSPP_CREQ_LUT_1
+ idx
,
580 cfg
->creq_lut
>> 32);
582 DPU_REG_WRITE(&ctx
->hw
, SSPP_CREQ_LUT
+ idx
, cfg
->creq_lut
);
586 static void dpu_hw_sspp_setup_qos_ctrl(struct dpu_hw_pipe
*ctx
,
587 struct dpu_hw_pipe_qos_cfg
*cfg
)
592 if (_sspp_subblk_offset(ctx
, DPU_SSPP_SRC
, &idx
))
595 if (cfg
->vblank_en
) {
596 qos_ctrl
|= ((cfg
->creq_vblank
&
597 SSPP_QOS_CTRL_CREQ_VBLANK_MASK
) <<
598 SSPP_QOS_CTRL_CREQ_VBLANK_OFF
);
599 qos_ctrl
|= ((cfg
->danger_vblank
&
600 SSPP_QOS_CTRL_DANGER_VBLANK_MASK
) <<
601 SSPP_QOS_CTRL_DANGER_VBLANK_OFF
);
602 qos_ctrl
|= SSPP_QOS_CTRL_VBLANK_EN
;
605 if (cfg
->danger_safe_en
)
606 qos_ctrl
|= SSPP_QOS_CTRL_DANGER_SAFE_EN
;
608 DPU_REG_WRITE(&ctx
->hw
, SSPP_QOS_CTRL
+ idx
, qos_ctrl
);
611 static void dpu_hw_sspp_setup_cdp(struct dpu_hw_pipe
*ctx
,
612 struct dpu_hw_pipe_cdp_cfg
*cfg
)
620 if (_sspp_subblk_offset(ctx
, DPU_SSPP_SRC
, &idx
))
625 if (cfg
->ubwc_meta_enable
)
627 if (cfg
->tile_amortize_enable
)
629 if (cfg
->preload_ahead
== DPU_SSPP_CDP_PRELOAD_AHEAD_64
)
632 DPU_REG_WRITE(&ctx
->hw
, SSPP_CDP_CNTL
, cdp_cntl
);
635 static void _setup_layer_ops(struct dpu_hw_pipe
*c
,
636 unsigned long features
)
638 if (test_bit(DPU_SSPP_SRC
, &features
)) {
639 c
->ops
.setup_format
= dpu_hw_sspp_setup_format
;
640 c
->ops
.setup_rects
= dpu_hw_sspp_setup_rects
;
641 c
->ops
.setup_sourceaddress
= dpu_hw_sspp_setup_sourceaddress
;
642 c
->ops
.setup_solidfill
= dpu_hw_sspp_setup_solidfill
;
643 c
->ops
.setup_pe
= dpu_hw_sspp_setup_pe_config
;
646 if (test_bit(DPU_SSPP_QOS
, &features
)) {
647 c
->ops
.setup_danger_safe_lut
=
648 dpu_hw_sspp_setup_danger_safe_lut
;
649 c
->ops
.setup_creq_lut
= dpu_hw_sspp_setup_creq_lut
;
650 c
->ops
.setup_qos_ctrl
= dpu_hw_sspp_setup_qos_ctrl
;
653 if (test_bit(DPU_SSPP_CSC
, &features
) ||
654 test_bit(DPU_SSPP_CSC_10BIT
, &features
))
655 c
->ops
.setup_csc
= dpu_hw_sspp_setup_csc
;
657 if (test_bit(DPU_SSPP_SMART_DMA_V1
, &c
->cap
->features
) ||
658 test_bit(DPU_SSPP_SMART_DMA_V2
, &c
->cap
->features
))
659 c
->ops
.setup_multirect
= dpu_hw_sspp_setup_multirect
;
661 if (test_bit(DPU_SSPP_SCALER_QSEED3
, &features
) ||
662 test_bit(DPU_SSPP_SCALER_QSEED4
, &features
)) {
663 c
->ops
.setup_scaler
= _dpu_hw_sspp_setup_scaler3
;
664 c
->ops
.get_scaler_ver
= _dpu_hw_sspp_get_scaler3_ver
;
667 if (test_bit(DPU_SSPP_CDP
, &features
))
668 c
->ops
.setup_cdp
= dpu_hw_sspp_setup_cdp
;
671 static const struct dpu_sspp_cfg
*_sspp_offset(enum dpu_sspp sspp
,
673 struct dpu_mdss_cfg
*catalog
,
674 struct dpu_hw_blk_reg_map
*b
)
678 if ((sspp
< SSPP_MAX
) && catalog
&& addr
&& b
) {
679 for (i
= 0; i
< catalog
->sspp_count
; i
++) {
680 if (sspp
== catalog
->sspp
[i
].id
) {
682 b
->blk_off
= catalog
->sspp
[i
].base
;
683 b
->length
= catalog
->sspp
[i
].len
;
684 b
->hwversion
= catalog
->hwversion
;
685 b
->log_mask
= DPU_DBG_MASK_SSPP
;
686 return &catalog
->sspp
[i
];
691 return ERR_PTR(-ENOMEM
);
694 static struct dpu_hw_blk_ops dpu_hw_ops
;
696 struct dpu_hw_pipe
*dpu_hw_sspp_init(enum dpu_sspp idx
,
697 void __iomem
*addr
, struct dpu_mdss_cfg
*catalog
,
698 bool is_virtual_pipe
)
700 struct dpu_hw_pipe
*hw_pipe
;
701 const struct dpu_sspp_cfg
*cfg
;
703 if (!addr
|| !catalog
)
704 return ERR_PTR(-EINVAL
);
706 hw_pipe
= kzalloc(sizeof(*hw_pipe
), GFP_KERNEL
);
708 return ERR_PTR(-ENOMEM
);
710 cfg
= _sspp_offset(idx
, addr
, catalog
, &hw_pipe
->hw
);
711 if (IS_ERR_OR_NULL(cfg
)) {
713 return ERR_PTR(-EINVAL
);
717 hw_pipe
->catalog
= catalog
;
718 hw_pipe
->mdp
= &catalog
->mdp
[0];
721 _setup_layer_ops(hw_pipe
, hw_pipe
->cap
->features
);
723 dpu_hw_blk_init(&hw_pipe
->base
, DPU_HW_BLK_SSPP
, idx
, &dpu_hw_ops
);
728 void dpu_hw_sspp_destroy(struct dpu_hw_pipe
*ctx
)
731 dpu_hw_blk_destroy(&ctx
->base
);