GNU Linux-libre 4.19.264-gnu1
[releases.git] / drivers / gpu / drm / msm / disp / dpu1 / dpu_hw_sspp.c
1 /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
2  *
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License version 2 and
5  * only version 2 as published by the Free Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  */
12
13 #include "dpu_hwio.h"
14 #include "dpu_hw_catalog.h"
15 #include "dpu_hw_lm.h"
16 #include "dpu_hw_sspp.h"
17 #include "dpu_dbg.h"
18 #include "dpu_kms.h"
19
20 #define DPU_FETCH_CONFIG_RESET_VALUE   0x00000087
21
22 /* DPU_SSPP_SRC */
23 #define SSPP_SRC_SIZE                      0x00
24 #define SSPP_SRC_XY                        0x08
25 #define SSPP_OUT_SIZE                      0x0c
26 #define SSPP_OUT_XY                        0x10
27 #define SSPP_SRC0_ADDR                     0x14
28 #define SSPP_SRC1_ADDR                     0x18
29 #define SSPP_SRC2_ADDR                     0x1C
30 #define SSPP_SRC3_ADDR                     0x20
31 #define SSPP_SRC_YSTRIDE0                  0x24
32 #define SSPP_SRC_YSTRIDE1                  0x28
33 #define SSPP_SRC_FORMAT                    0x30
34 #define SSPP_SRC_UNPACK_PATTERN            0x34
35 #define SSPP_SRC_OP_MODE                   0x38
36
37 /* SSPP_MULTIRECT*/
38 #define SSPP_SRC_SIZE_REC1                 0x16C
39 #define SSPP_SRC_XY_REC1                   0x168
40 #define SSPP_OUT_SIZE_REC1                 0x160
41 #define SSPP_OUT_XY_REC1                   0x164
42 #define SSPP_SRC_FORMAT_REC1               0x174
43 #define SSPP_SRC_UNPACK_PATTERN_REC1       0x178
44 #define SSPP_SRC_OP_MODE_REC1              0x17C
45 #define SSPP_MULTIRECT_OPMODE              0x170
46 #define SSPP_SRC_CONSTANT_COLOR_REC1       0x180
47 #define SSPP_EXCL_REC_SIZE_REC1            0x184
48 #define SSPP_EXCL_REC_XY_REC1              0x188
49
50 #define MDSS_MDP_OP_DEINTERLACE            BIT(22)
51 #define MDSS_MDP_OP_DEINTERLACE_ODD        BIT(23)
52 #define MDSS_MDP_OP_IGC_ROM_1              BIT(18)
53 #define MDSS_MDP_OP_IGC_ROM_0              BIT(17)
54 #define MDSS_MDP_OP_IGC_EN                 BIT(16)
55 #define MDSS_MDP_OP_FLIP_UD                BIT(14)
56 #define MDSS_MDP_OP_FLIP_LR                BIT(13)
57 #define MDSS_MDP_OP_BWC_EN                 BIT(0)
58 #define MDSS_MDP_OP_PE_OVERRIDE            BIT(31)
59 #define MDSS_MDP_OP_BWC_LOSSLESS           (0 << 1)
60 #define MDSS_MDP_OP_BWC_Q_HIGH             (1 << 1)
61 #define MDSS_MDP_OP_BWC_Q_MED              (2 << 1)
62
63 #define SSPP_SRC_CONSTANT_COLOR            0x3c
64 #define SSPP_EXCL_REC_CTL                  0x40
65 #define SSPP_UBWC_STATIC_CTRL              0x44
66 #define SSPP_FETCH_CONFIG                  0x048
67 #define SSPP_DANGER_LUT                    0x60
68 #define SSPP_SAFE_LUT                      0x64
69 #define SSPP_CREQ_LUT                      0x68
70 #define SSPP_QOS_CTRL                      0x6C
71 #define SSPP_DECIMATION_CONFIG             0xB4
72 #define SSPP_SRC_ADDR_SW_STATUS            0x70
73 #define SSPP_CREQ_LUT_0                    0x74
74 #define SSPP_CREQ_LUT_1                    0x78
75 #define SSPP_SW_PIX_EXT_C0_LR              0x100
76 #define SSPP_SW_PIX_EXT_C0_TB              0x104
77 #define SSPP_SW_PIX_EXT_C0_REQ_PIXELS      0x108
78 #define SSPP_SW_PIX_EXT_C1C2_LR            0x110
79 #define SSPP_SW_PIX_EXT_C1C2_TB            0x114
80 #define SSPP_SW_PIX_EXT_C1C2_REQ_PIXELS    0x118
81 #define SSPP_SW_PIX_EXT_C3_LR              0x120
82 #define SSPP_SW_PIX_EXT_C3_TB              0x124
83 #define SSPP_SW_PIX_EXT_C3_REQ_PIXELS      0x128
84 #define SSPP_TRAFFIC_SHAPER                0x130
85 #define SSPP_CDP_CNTL                      0x134
86 #define SSPP_UBWC_ERROR_STATUS             0x138
87 #define SSPP_TRAFFIC_SHAPER_PREFILL        0x150
88 #define SSPP_TRAFFIC_SHAPER_REC1_PREFILL   0x154
89 #define SSPP_TRAFFIC_SHAPER_REC1           0x158
90 #define SSPP_EXCL_REC_SIZE                 0x1B4
91 #define SSPP_EXCL_REC_XY                   0x1B8
92 #define SSPP_VIG_OP_MODE                   0x0
93 #define SSPP_VIG_CSC_10_OP_MODE            0x0
94 #define SSPP_TRAFFIC_SHAPER_BPC_MAX        0xFF
95
96 /* SSPP_QOS_CTRL */
97 #define SSPP_QOS_CTRL_VBLANK_EN            BIT(16)
98 #define SSPP_QOS_CTRL_DANGER_SAFE_EN       BIT(0)
99 #define SSPP_QOS_CTRL_DANGER_VBLANK_MASK   0x3
100 #define SSPP_QOS_CTRL_DANGER_VBLANK_OFF    4
101 #define SSPP_QOS_CTRL_CREQ_VBLANK_MASK     0x3
102 #define SSPP_QOS_CTRL_CREQ_VBLANK_OFF      20
103
104 /* DPU_SSPP_SCALER_QSEED2 */
105 #define SCALE_CONFIG                       0x04
106 #define COMP0_3_PHASE_STEP_X               0x10
107 #define COMP0_3_PHASE_STEP_Y               0x14
108 #define COMP1_2_PHASE_STEP_X               0x18
109 #define COMP1_2_PHASE_STEP_Y               0x1c
110 #define COMP0_3_INIT_PHASE_X               0x20
111 #define COMP0_3_INIT_PHASE_Y               0x24
112 #define COMP1_2_INIT_PHASE_X               0x28
113 #define COMP1_2_INIT_PHASE_Y               0x2C
114 #define VIG_0_QSEED2_SHARP                 0x30
115
116 /*
117  * Definitions for ViG op modes
118  */
119 #define VIG_OP_CSC_DST_DATAFMT BIT(19)
120 #define VIG_OP_CSC_SRC_DATAFMT BIT(18)
121 #define VIG_OP_CSC_EN          BIT(17)
122 #define VIG_OP_MEM_PROT_CONT   BIT(15)
123 #define VIG_OP_MEM_PROT_VAL    BIT(14)
124 #define VIG_OP_MEM_PROT_SAT    BIT(13)
125 #define VIG_OP_MEM_PROT_HUE    BIT(12)
126 #define VIG_OP_HIST            BIT(8)
127 #define VIG_OP_SKY_COL         BIT(7)
128 #define VIG_OP_FOIL            BIT(6)
129 #define VIG_OP_SKIN_COL        BIT(5)
130 #define VIG_OP_PA_EN           BIT(4)
131 #define VIG_OP_PA_SAT_ZERO_EXP BIT(2)
132 #define VIG_OP_MEM_PROT_BLEND  BIT(1)
133
134 /*
135  * Definitions for CSC 10 op modes
136  */
137 #define VIG_CSC_10_SRC_DATAFMT BIT(1)
138 #define VIG_CSC_10_EN          BIT(0)
139 #define CSC_10BIT_OFFSET       4
140
141 /* traffic shaper clock in Hz */
142 #define TS_CLK                  19200000
143
144 static inline int _sspp_subblk_offset(struct dpu_hw_pipe *ctx,
145                 int s_id,
146                 u32 *idx)
147 {
148         int rc = 0;
149         const struct dpu_sspp_sub_blks *sblk;
150
151         if (!ctx || !ctx->cap || !ctx->cap->sblk)
152                 return -EINVAL;
153
154         sblk = ctx->cap->sblk;
155
156         switch (s_id) {
157         case DPU_SSPP_SRC:
158                 *idx = sblk->src_blk.base;
159                 break;
160         case DPU_SSPP_SCALER_QSEED2:
161         case DPU_SSPP_SCALER_QSEED3:
162         case DPU_SSPP_SCALER_RGB:
163                 *idx = sblk->scaler_blk.base;
164                 break;
165         case DPU_SSPP_CSC:
166         case DPU_SSPP_CSC_10BIT:
167                 *idx = sblk->csc_blk.base;
168                 break;
169         default:
170                 rc = -EINVAL;
171         }
172
173         return rc;
174 }
175
176 static void dpu_hw_sspp_setup_multirect(struct dpu_hw_pipe *ctx,
177                 enum dpu_sspp_multirect_index index,
178                 enum dpu_sspp_multirect_mode mode)
179 {
180         u32 mode_mask;
181         u32 idx;
182
183         if (_sspp_subblk_offset(ctx, DPU_SSPP_SRC, &idx))
184                 return;
185
186         if (index == DPU_SSPP_RECT_SOLO) {
187                 /**
188                  * if rect index is RECT_SOLO, we cannot expect a
189                  * virtual plane sharing the same SSPP id. So we go
190                  * and disable multirect
191                  */
192                 mode_mask = 0;
193         } else {
194                 mode_mask = DPU_REG_READ(&ctx->hw, SSPP_MULTIRECT_OPMODE + idx);
195                 mode_mask |= index;
196                 if (mode == DPU_SSPP_MULTIRECT_TIME_MX)
197                         mode_mask |= BIT(2);
198                 else
199                         mode_mask &= ~BIT(2);
200         }
201
202         DPU_REG_WRITE(&ctx->hw, SSPP_MULTIRECT_OPMODE + idx, mode_mask);
203 }
204
205 static void _sspp_setup_opmode(struct dpu_hw_pipe *ctx,
206                 u32 mask, u8 en)
207 {
208         u32 idx;
209         u32 opmode;
210
211         if (!test_bit(DPU_SSPP_SCALER_QSEED2, &ctx->cap->features) ||
212                 _sspp_subblk_offset(ctx, DPU_SSPP_SCALER_QSEED2, &idx) ||
213                 !test_bit(DPU_SSPP_CSC, &ctx->cap->features))
214                 return;
215
216         opmode = DPU_REG_READ(&ctx->hw, SSPP_VIG_OP_MODE + idx);
217
218         if (en)
219                 opmode |= mask;
220         else
221                 opmode &= ~mask;
222
223         DPU_REG_WRITE(&ctx->hw, SSPP_VIG_OP_MODE + idx, opmode);
224 }
225
226 static void _sspp_setup_csc10_opmode(struct dpu_hw_pipe *ctx,
227                 u32 mask, u8 en)
228 {
229         u32 idx;
230         u32 opmode;
231
232         if (_sspp_subblk_offset(ctx, DPU_SSPP_CSC_10BIT, &idx))
233                 return;
234
235         opmode = DPU_REG_READ(&ctx->hw, SSPP_VIG_CSC_10_OP_MODE + idx);
236         if (en)
237                 opmode |= mask;
238         else
239                 opmode &= ~mask;
240
241         DPU_REG_WRITE(&ctx->hw, SSPP_VIG_CSC_10_OP_MODE + idx, opmode);
242 }
243
244 /**
245  * Setup source pixel format, flip,
246  */
247 static void dpu_hw_sspp_setup_format(struct dpu_hw_pipe *ctx,
248                 const struct dpu_format *fmt, u32 flags,
249                 enum dpu_sspp_multirect_index rect_mode)
250 {
251         struct dpu_hw_blk_reg_map *c;
252         u32 chroma_samp, unpack, src_format;
253         u32 opmode = 0;
254         u32 fast_clear = 0;
255         u32 op_mode_off, unpack_pat_off, format_off;
256         u32 idx;
257
258         if (_sspp_subblk_offset(ctx, DPU_SSPP_SRC, &idx) || !fmt)
259                 return;
260
261         if (rect_mode == DPU_SSPP_RECT_SOLO || rect_mode == DPU_SSPP_RECT_0) {
262                 op_mode_off = SSPP_SRC_OP_MODE;
263                 unpack_pat_off = SSPP_SRC_UNPACK_PATTERN;
264                 format_off = SSPP_SRC_FORMAT;
265         } else {
266                 op_mode_off = SSPP_SRC_OP_MODE_REC1;
267                 unpack_pat_off = SSPP_SRC_UNPACK_PATTERN_REC1;
268                 format_off = SSPP_SRC_FORMAT_REC1;
269         }
270
271         c = &ctx->hw;
272         opmode = DPU_REG_READ(c, op_mode_off + idx);
273         opmode &= ~(MDSS_MDP_OP_FLIP_LR | MDSS_MDP_OP_FLIP_UD |
274                         MDSS_MDP_OP_BWC_EN | MDSS_MDP_OP_PE_OVERRIDE);
275
276         if (flags & DPU_SSPP_FLIP_LR)
277                 opmode |= MDSS_MDP_OP_FLIP_LR;
278         if (flags & DPU_SSPP_FLIP_UD)
279                 opmode |= MDSS_MDP_OP_FLIP_UD;
280
281         chroma_samp = fmt->chroma_sample;
282         if (flags & DPU_SSPP_SOURCE_ROTATED_90) {
283                 if (chroma_samp == DPU_CHROMA_H2V1)
284                         chroma_samp = DPU_CHROMA_H1V2;
285                 else if (chroma_samp == DPU_CHROMA_H1V2)
286                         chroma_samp = DPU_CHROMA_H2V1;
287         }
288
289         src_format = (chroma_samp << 23) | (fmt->fetch_planes << 19) |
290                 (fmt->bits[C3_ALPHA] << 6) | (fmt->bits[C2_R_Cr] << 4) |
291                 (fmt->bits[C1_B_Cb] << 2) | (fmt->bits[C0_G_Y] << 0);
292
293         if (flags & DPU_SSPP_ROT_90)
294                 src_format |= BIT(11); /* ROT90 */
295
296         if (fmt->alpha_enable && fmt->fetch_planes == DPU_PLANE_INTERLEAVED)
297                 src_format |= BIT(8); /* SRCC3_EN */
298
299         if (flags & DPU_SSPP_SOLID_FILL)
300                 src_format |= BIT(22);
301
302         unpack = (fmt->element[3] << 24) | (fmt->element[2] << 16) |
303                 (fmt->element[1] << 8) | (fmt->element[0] << 0);
304         src_format |= ((fmt->unpack_count - 1) << 12) |
305                 (fmt->unpack_tight << 17) |
306                 (fmt->unpack_align_msb << 18) |
307                 ((fmt->bpp - 1) << 9);
308
309         if (fmt->fetch_mode != DPU_FETCH_LINEAR) {
310                 if (DPU_FORMAT_IS_UBWC(fmt))
311                         opmode |= MDSS_MDP_OP_BWC_EN;
312                 src_format |= (fmt->fetch_mode & 3) << 30; /*FRAME_FORMAT */
313                 DPU_REG_WRITE(c, SSPP_FETCH_CONFIG,
314                         DPU_FETCH_CONFIG_RESET_VALUE |
315                         ctx->mdp->highest_bank_bit << 18);
316                 if (IS_UBWC_20_SUPPORTED(ctx->catalog->caps->ubwc_version)) {
317                         fast_clear = fmt->alpha_enable ? BIT(31) : 0;
318                         DPU_REG_WRITE(c, SSPP_UBWC_STATIC_CTRL,
319                                         fast_clear | (ctx->mdp->ubwc_swizzle) |
320                                         (ctx->mdp->highest_bank_bit << 4));
321                 }
322         }
323
324         opmode |= MDSS_MDP_OP_PE_OVERRIDE;
325
326         /* if this is YUV pixel format, enable CSC */
327         if (DPU_FORMAT_IS_YUV(fmt))
328                 src_format |= BIT(15);
329
330         if (DPU_FORMAT_IS_DX(fmt))
331                 src_format |= BIT(14);
332
333         /* update scaler opmode, if appropriate */
334         if (test_bit(DPU_SSPP_CSC, &ctx->cap->features))
335                 _sspp_setup_opmode(ctx, VIG_OP_CSC_EN | VIG_OP_CSC_SRC_DATAFMT,
336                         DPU_FORMAT_IS_YUV(fmt));
337         else if (test_bit(DPU_SSPP_CSC_10BIT, &ctx->cap->features))
338                 _sspp_setup_csc10_opmode(ctx,
339                         VIG_CSC_10_EN | VIG_CSC_10_SRC_DATAFMT,
340                         DPU_FORMAT_IS_YUV(fmt));
341
342         DPU_REG_WRITE(c, format_off + idx, src_format);
343         DPU_REG_WRITE(c, unpack_pat_off + idx, unpack);
344         DPU_REG_WRITE(c, op_mode_off + idx, opmode);
345
346         /* clear previous UBWC error */
347         DPU_REG_WRITE(c, SSPP_UBWC_ERROR_STATUS + idx, BIT(31));
348 }
349
350 static void dpu_hw_sspp_setup_pe_config(struct dpu_hw_pipe *ctx,
351                 struct dpu_hw_pixel_ext *pe_ext)
352 {
353         struct dpu_hw_blk_reg_map *c;
354         u8 color;
355         u32 lr_pe[4], tb_pe[4], tot_req_pixels[4];
356         const u32 bytemask = 0xff;
357         const u32 shortmask = 0xffff;
358         u32 idx;
359
360         if (_sspp_subblk_offset(ctx, DPU_SSPP_SRC, &idx) || !pe_ext)
361                 return;
362
363         c = &ctx->hw;
364
365         /* program SW pixel extension override for all pipes*/
366         for (color = 0; color < DPU_MAX_PLANES; color++) {
367                 /* color 2 has the same set of registers as color 1 */
368                 if (color == 2)
369                         continue;
370
371                 lr_pe[color] = ((pe_ext->right_ftch[color] & bytemask) << 24)|
372                         ((pe_ext->right_rpt[color] & bytemask) << 16)|
373                         ((pe_ext->left_ftch[color] & bytemask) << 8)|
374                         (pe_ext->left_rpt[color] & bytemask);
375
376                 tb_pe[color] = ((pe_ext->btm_ftch[color] & bytemask) << 24)|
377                         ((pe_ext->btm_rpt[color] & bytemask) << 16)|
378                         ((pe_ext->top_ftch[color] & bytemask) << 8)|
379                         (pe_ext->top_rpt[color] & bytemask);
380
381                 tot_req_pixels[color] = (((pe_ext->roi_h[color] +
382                         pe_ext->num_ext_pxls_top[color] +
383                         pe_ext->num_ext_pxls_btm[color]) & shortmask) << 16) |
384                         ((pe_ext->roi_w[color] +
385                         pe_ext->num_ext_pxls_left[color] +
386                         pe_ext->num_ext_pxls_right[color]) & shortmask);
387         }
388
389         /* color 0 */
390         DPU_REG_WRITE(c, SSPP_SW_PIX_EXT_C0_LR + idx, lr_pe[0]);
391         DPU_REG_WRITE(c, SSPP_SW_PIX_EXT_C0_TB + idx, tb_pe[0]);
392         DPU_REG_WRITE(c, SSPP_SW_PIX_EXT_C0_REQ_PIXELS + idx,
393                         tot_req_pixels[0]);
394
395         /* color 1 and color 2 */
396         DPU_REG_WRITE(c, SSPP_SW_PIX_EXT_C1C2_LR + idx, lr_pe[1]);
397         DPU_REG_WRITE(c, SSPP_SW_PIX_EXT_C1C2_TB + idx, tb_pe[1]);
398         DPU_REG_WRITE(c, SSPP_SW_PIX_EXT_C1C2_REQ_PIXELS + idx,
399                         tot_req_pixels[1]);
400
401         /* color 3 */
402         DPU_REG_WRITE(c, SSPP_SW_PIX_EXT_C3_LR + idx, lr_pe[3]);
403         DPU_REG_WRITE(c, SSPP_SW_PIX_EXT_C3_TB + idx, lr_pe[3]);
404         DPU_REG_WRITE(c, SSPP_SW_PIX_EXT_C3_REQ_PIXELS + idx,
405                         tot_req_pixels[3]);
406 }
407
408 static void _dpu_hw_sspp_setup_scaler3(struct dpu_hw_pipe *ctx,
409                 struct dpu_hw_pipe_cfg *sspp,
410                 struct dpu_hw_pixel_ext *pe,
411                 void *scaler_cfg)
412 {
413         u32 idx;
414         struct dpu_hw_scaler3_cfg *scaler3_cfg = scaler_cfg;
415
416         (void)pe;
417         if (_sspp_subblk_offset(ctx, DPU_SSPP_SCALER_QSEED3, &idx) || !sspp
418                 || !scaler3_cfg)
419                 return;
420
421         dpu_hw_setup_scaler3(&ctx->hw, scaler3_cfg, idx,
422                         ctx->cap->sblk->scaler_blk.version,
423                         sspp->layout.format);
424 }
425
426 static u32 _dpu_hw_sspp_get_scaler3_ver(struct dpu_hw_pipe *ctx)
427 {
428         u32 idx;
429
430         if (!ctx || _sspp_subblk_offset(ctx, DPU_SSPP_SCALER_QSEED3, &idx))
431                 return 0;
432
433         return dpu_hw_get_scaler3_ver(&ctx->hw, idx);
434 }
435
436 /**
437  * dpu_hw_sspp_setup_rects()
438  */
439 static void dpu_hw_sspp_setup_rects(struct dpu_hw_pipe *ctx,
440                 struct dpu_hw_pipe_cfg *cfg,
441                 enum dpu_sspp_multirect_index rect_index)
442 {
443         struct dpu_hw_blk_reg_map *c;
444         u32 src_size, src_xy, dst_size, dst_xy, ystride0, ystride1;
445         u32 src_size_off, src_xy_off, out_size_off, out_xy_off;
446         u32 idx;
447
448         if (_sspp_subblk_offset(ctx, DPU_SSPP_SRC, &idx) || !cfg)
449                 return;
450
451         c = &ctx->hw;
452
453         if (rect_index == DPU_SSPP_RECT_SOLO || rect_index == DPU_SSPP_RECT_0) {
454                 src_size_off = SSPP_SRC_SIZE;
455                 src_xy_off = SSPP_SRC_XY;
456                 out_size_off = SSPP_OUT_SIZE;
457                 out_xy_off = SSPP_OUT_XY;
458         } else {
459                 src_size_off = SSPP_SRC_SIZE_REC1;
460                 src_xy_off = SSPP_SRC_XY_REC1;
461                 out_size_off = SSPP_OUT_SIZE_REC1;
462                 out_xy_off = SSPP_OUT_XY_REC1;
463         }
464
465
466         /* src and dest rect programming */
467         src_xy = (cfg->src_rect.y1 << 16) | cfg->src_rect.x1;
468         src_size = (drm_rect_height(&cfg->src_rect) << 16) |
469                    drm_rect_width(&cfg->src_rect);
470         dst_xy = (cfg->dst_rect.y1 << 16) | cfg->dst_rect.x1;
471         dst_size = (drm_rect_height(&cfg->dst_rect) << 16) |
472                 drm_rect_width(&cfg->dst_rect);
473
474         if (rect_index == DPU_SSPP_RECT_SOLO) {
475                 ystride0 = (cfg->layout.plane_pitch[0]) |
476                         (cfg->layout.plane_pitch[1] << 16);
477                 ystride1 = (cfg->layout.plane_pitch[2]) |
478                         (cfg->layout.plane_pitch[3] << 16);
479         } else {
480                 ystride0 = DPU_REG_READ(c, SSPP_SRC_YSTRIDE0 + idx);
481                 ystride1 = DPU_REG_READ(c, SSPP_SRC_YSTRIDE1 + idx);
482
483                 if (rect_index == DPU_SSPP_RECT_0) {
484                         ystride0 = (ystride0 & 0xFFFF0000) |
485                                 (cfg->layout.plane_pitch[0] & 0x0000FFFF);
486                         ystride1 = (ystride1 & 0xFFFF0000)|
487                                 (cfg->layout.plane_pitch[2] & 0x0000FFFF);
488                 } else {
489                         ystride0 = (ystride0 & 0x0000FFFF) |
490                                 ((cfg->layout.plane_pitch[0] << 16) &
491                                  0xFFFF0000);
492                         ystride1 = (ystride1 & 0x0000FFFF) |
493                                 ((cfg->layout.plane_pitch[2] << 16) &
494                                  0xFFFF0000);
495                 }
496         }
497
498         /* rectangle register programming */
499         DPU_REG_WRITE(c, src_size_off + idx, src_size);
500         DPU_REG_WRITE(c, src_xy_off + idx, src_xy);
501         DPU_REG_WRITE(c, out_size_off + idx, dst_size);
502         DPU_REG_WRITE(c, out_xy_off + idx, dst_xy);
503
504         DPU_REG_WRITE(c, SSPP_SRC_YSTRIDE0 + idx, ystride0);
505         DPU_REG_WRITE(c, SSPP_SRC_YSTRIDE1 + idx, ystride1);
506 }
507
508 static void dpu_hw_sspp_setup_sourceaddress(struct dpu_hw_pipe *ctx,
509                 struct dpu_hw_pipe_cfg *cfg,
510                 enum dpu_sspp_multirect_index rect_mode)
511 {
512         int i;
513         u32 idx;
514
515         if (_sspp_subblk_offset(ctx, DPU_SSPP_SRC, &idx))
516                 return;
517
518         if (rect_mode == DPU_SSPP_RECT_SOLO) {
519                 for (i = 0; i < ARRAY_SIZE(cfg->layout.plane_addr); i++)
520                         DPU_REG_WRITE(&ctx->hw, SSPP_SRC0_ADDR + idx + i * 0x4,
521                                         cfg->layout.plane_addr[i]);
522         } else if (rect_mode == DPU_SSPP_RECT_0) {
523                 DPU_REG_WRITE(&ctx->hw, SSPP_SRC0_ADDR + idx,
524                                 cfg->layout.plane_addr[0]);
525                 DPU_REG_WRITE(&ctx->hw, SSPP_SRC2_ADDR + idx,
526                                 cfg->layout.plane_addr[2]);
527         } else {
528                 DPU_REG_WRITE(&ctx->hw, SSPP_SRC1_ADDR + idx,
529                                 cfg->layout.plane_addr[0]);
530                 DPU_REG_WRITE(&ctx->hw, SSPP_SRC3_ADDR + idx,
531                                 cfg->layout.plane_addr[2]);
532         }
533 }
534
535 static void dpu_hw_sspp_setup_csc(struct dpu_hw_pipe *ctx,
536                 struct dpu_csc_cfg *data)
537 {
538         u32 idx;
539         bool csc10 = false;
540
541         if (_sspp_subblk_offset(ctx, DPU_SSPP_CSC, &idx) || !data)
542                 return;
543
544         if (test_bit(DPU_SSPP_CSC_10BIT, &ctx->cap->features)) {
545                 idx += CSC_10BIT_OFFSET;
546                 csc10 = true;
547         }
548
549         dpu_hw_csc_setup(&ctx->hw, idx, data, csc10);
550 }
551
552 static void dpu_hw_sspp_setup_solidfill(struct dpu_hw_pipe *ctx, u32 color, enum
553                 dpu_sspp_multirect_index rect_index)
554 {
555         u32 idx;
556
557         if (_sspp_subblk_offset(ctx, DPU_SSPP_SRC, &idx))
558                 return;
559
560         if (rect_index == DPU_SSPP_RECT_SOLO || rect_index == DPU_SSPP_RECT_0)
561                 DPU_REG_WRITE(&ctx->hw, SSPP_SRC_CONSTANT_COLOR + idx, color);
562         else
563                 DPU_REG_WRITE(&ctx->hw, SSPP_SRC_CONSTANT_COLOR_REC1 + idx,
564                                 color);
565 }
566
567 static void dpu_hw_sspp_setup_danger_safe_lut(struct dpu_hw_pipe *ctx,
568                 struct dpu_hw_pipe_qos_cfg *cfg)
569 {
570         u32 idx;
571
572         if (_sspp_subblk_offset(ctx, DPU_SSPP_SRC, &idx))
573                 return;
574
575         DPU_REG_WRITE(&ctx->hw, SSPP_DANGER_LUT + idx, cfg->danger_lut);
576         DPU_REG_WRITE(&ctx->hw, SSPP_SAFE_LUT + idx, cfg->safe_lut);
577 }
578
579 static void dpu_hw_sspp_setup_creq_lut(struct dpu_hw_pipe *ctx,
580                 struct dpu_hw_pipe_qos_cfg *cfg)
581 {
582         u32 idx;
583
584         if (_sspp_subblk_offset(ctx, DPU_SSPP_SRC, &idx))
585                 return;
586
587         if (ctx->cap && test_bit(DPU_SSPP_QOS_8LVL, &ctx->cap->features)) {
588                 DPU_REG_WRITE(&ctx->hw, SSPP_CREQ_LUT_0 + idx, cfg->creq_lut);
589                 DPU_REG_WRITE(&ctx->hw, SSPP_CREQ_LUT_1 + idx,
590                                 cfg->creq_lut >> 32);
591         } else {
592                 DPU_REG_WRITE(&ctx->hw, SSPP_CREQ_LUT + idx, cfg->creq_lut);
593         }
594 }
595
596 static void dpu_hw_sspp_setup_qos_ctrl(struct dpu_hw_pipe *ctx,
597                 struct dpu_hw_pipe_qos_cfg *cfg)
598 {
599         u32 idx;
600         u32 qos_ctrl = 0;
601
602         if (_sspp_subblk_offset(ctx, DPU_SSPP_SRC, &idx))
603                 return;
604
605         if (cfg->vblank_en) {
606                 qos_ctrl |= ((cfg->creq_vblank &
607                                 SSPP_QOS_CTRL_CREQ_VBLANK_MASK) <<
608                                 SSPP_QOS_CTRL_CREQ_VBLANK_OFF);
609                 qos_ctrl |= ((cfg->danger_vblank &
610                                 SSPP_QOS_CTRL_DANGER_VBLANK_MASK) <<
611                                 SSPP_QOS_CTRL_DANGER_VBLANK_OFF);
612                 qos_ctrl |= SSPP_QOS_CTRL_VBLANK_EN;
613         }
614
615         if (cfg->danger_safe_en)
616                 qos_ctrl |= SSPP_QOS_CTRL_DANGER_SAFE_EN;
617
618         DPU_REG_WRITE(&ctx->hw, SSPP_QOS_CTRL + idx, qos_ctrl);
619 }
620
621 static void dpu_hw_sspp_setup_cdp(struct dpu_hw_pipe *ctx,
622                 struct dpu_hw_pipe_cdp_cfg *cfg)
623 {
624         u32 idx;
625         u32 cdp_cntl = 0;
626
627         if (!ctx || !cfg)
628                 return;
629
630         if (_sspp_subblk_offset(ctx, DPU_SSPP_SRC, &idx))
631                 return;
632
633         if (cfg->enable)
634                 cdp_cntl |= BIT(0);
635         if (cfg->ubwc_meta_enable)
636                 cdp_cntl |= BIT(1);
637         if (cfg->tile_amortize_enable)
638                 cdp_cntl |= BIT(2);
639         if (cfg->preload_ahead == DPU_SSPP_CDP_PRELOAD_AHEAD_64)
640                 cdp_cntl |= BIT(3);
641
642         DPU_REG_WRITE(&ctx->hw, SSPP_CDP_CNTL, cdp_cntl);
643 }
644
645 static void _setup_layer_ops(struct dpu_hw_pipe *c,
646                 unsigned long features)
647 {
648         if (test_bit(DPU_SSPP_SRC, &features)) {
649                 c->ops.setup_format = dpu_hw_sspp_setup_format;
650                 c->ops.setup_rects = dpu_hw_sspp_setup_rects;
651                 c->ops.setup_sourceaddress = dpu_hw_sspp_setup_sourceaddress;
652                 c->ops.setup_solidfill = dpu_hw_sspp_setup_solidfill;
653                 c->ops.setup_pe = dpu_hw_sspp_setup_pe_config;
654         }
655
656         if (test_bit(DPU_SSPP_QOS, &features)) {
657                 c->ops.setup_danger_safe_lut =
658                         dpu_hw_sspp_setup_danger_safe_lut;
659                 c->ops.setup_creq_lut = dpu_hw_sspp_setup_creq_lut;
660                 c->ops.setup_qos_ctrl = dpu_hw_sspp_setup_qos_ctrl;
661         }
662
663         if (test_bit(DPU_SSPP_CSC, &features) ||
664                 test_bit(DPU_SSPP_CSC_10BIT, &features))
665                 c->ops.setup_csc = dpu_hw_sspp_setup_csc;
666
667         if (dpu_hw_sspp_multirect_enabled(c->cap))
668                 c->ops.setup_multirect = dpu_hw_sspp_setup_multirect;
669
670         if (test_bit(DPU_SSPP_SCALER_QSEED3, &features)) {
671                 c->ops.setup_scaler = _dpu_hw_sspp_setup_scaler3;
672                 c->ops.get_scaler_ver = _dpu_hw_sspp_get_scaler3_ver;
673         }
674
675         if (test_bit(DPU_SSPP_CDP, &features))
676                 c->ops.setup_cdp = dpu_hw_sspp_setup_cdp;
677 }
678
679 static struct dpu_sspp_cfg *_sspp_offset(enum dpu_sspp sspp,
680                 void __iomem *addr,
681                 struct dpu_mdss_cfg *catalog,
682                 struct dpu_hw_blk_reg_map *b)
683 {
684         int i;
685
686         if ((sspp < SSPP_MAX) && catalog && addr && b) {
687                 for (i = 0; i < catalog->sspp_count; i++) {
688                         if (sspp == catalog->sspp[i].id) {
689                                 b->base_off = addr;
690                                 b->blk_off = catalog->sspp[i].base;
691                                 b->length = catalog->sspp[i].len;
692                                 b->hwversion = catalog->hwversion;
693                                 b->log_mask = DPU_DBG_MASK_SSPP;
694                                 return &catalog->sspp[i];
695                         }
696                 }
697         }
698
699         return ERR_PTR(-ENOMEM);
700 }
701
702 static struct dpu_hw_blk_ops dpu_hw_ops = {
703         .start = NULL,
704         .stop = NULL,
705 };
706
707 struct dpu_hw_pipe *dpu_hw_sspp_init(enum dpu_sspp idx,
708                 void __iomem *addr, struct dpu_mdss_cfg *catalog,
709                 bool is_virtual_pipe)
710 {
711         struct dpu_hw_pipe *hw_pipe;
712         struct dpu_sspp_cfg *cfg;
713         int rc;
714
715         if (!addr || !catalog)
716                 return ERR_PTR(-EINVAL);
717
718         hw_pipe = kzalloc(sizeof(*hw_pipe), GFP_KERNEL);
719         if (!hw_pipe)
720                 return ERR_PTR(-ENOMEM);
721
722         cfg = _sspp_offset(idx, addr, catalog, &hw_pipe->hw);
723         if (IS_ERR_OR_NULL(cfg)) {
724                 kfree(hw_pipe);
725                 return ERR_PTR(-EINVAL);
726         }
727
728         /* Assign ops */
729         hw_pipe->catalog = catalog;
730         hw_pipe->mdp = &catalog->mdp[0];
731         hw_pipe->idx = idx;
732         hw_pipe->cap = cfg;
733         _setup_layer_ops(hw_pipe, hw_pipe->cap->features);
734
735         rc = dpu_hw_blk_init(&hw_pipe->base, DPU_HW_BLK_SSPP, idx, &dpu_hw_ops);
736         if (rc) {
737                 DPU_ERROR("failed to init hw blk %d\n", rc);
738                 goto blk_init_error;
739         }
740
741         return hw_pipe;
742
743 blk_init_error:
744         kzfree(hw_pipe);
745
746         return ERR_PTR(rc);
747 }
748
749 void dpu_hw_sspp_destroy(struct dpu_hw_pipe *ctx)
750 {
751         if (ctx)
752                 dpu_hw_blk_destroy(&ctx->base);
753         kfree(ctx);
754 }
755