File Index
Files and directories
Sign in
FILE

dpu_hw_sspp.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  3 */
  4
  5#include <linux/debugfs.h>
  6
  7#include "dpu_hwio.h"
  8#include "dpu_hw_catalog.h"
  9#include "dpu_hw_lm.h"
 10#include "dpu_hw_sspp.h"
 11#include "dpu_kms.h"
 12
 13#include <drm/drm_file.h>
 14#include <drm/drm_managed.h>
 15
 16#include <linux/soc/qcom/ubwc.h>
 17
 18#define DPU_FETCH_CONFIG_RESET_VALUE   0x00000087
 19
 20/* SSPP registers */
 21#define SSPP_SRC_SIZE                      0x00
 22#define SSPP_SRC_XY                        0x08
 23#define SSPP_OUT_SIZE                      0x0c
 24#define SSPP_OUT_XY                        0x10
 25#define SSPP_SRC0_ADDR                     0x14
 26#define SSPP_SRC1_ADDR                     0x18
 27#define SSPP_SRC2_ADDR                     0x1C
 28#define SSPP_SRC3_ADDR                     0x20
 29#define SSPP_SRC_YSTRIDE0                  0x24
 30#define SSPP_SRC_YSTRIDE1                  0x28
 31#define SSPP_SRC_FORMAT                    0x30
 32#define SSPP_SRC_UNPACK_PATTERN            0x34
 33#define SSPP_SRC_OP_MODE                   0x38
 34#define SSPP_SRC_CONSTANT_COLOR            0x3c
 35#define SSPP_EXCL_REC_CTL                  0x40
 36#define SSPP_UBWC_STATIC_CTRL              0x44
 37#define SSPP_FETCH_CONFIG                  0x48
 38#define SSPP_DANGER_LUT                    0x60
 39#define SSPP_SAFE_LUT                      0x64
 40#define SSPP_CREQ_LUT                      0x68
 41#define SSPP_QOS_CTRL                      0x6C
 42#define SSPP_SRC_ADDR_SW_STATUS            0x70
 43#define SSPP_CREQ_LUT_0                    0x74
 44#define SSPP_CREQ_LUT_1                    0x78
 45#define SSPP_DECIMATION_CONFIG             0xB4
 46#define SSPP_SW_PIX_EXT_C0_LR              0x100
 47#define SSPP_SW_PIX_EXT_C0_TB              0x104
 48#define SSPP_SW_PIX_EXT_C0_REQ_PIXELS      0x108
 49#define SSPP_SW_PIX_EXT_C1C2_LR            0x110
 50#define SSPP_SW_PIX_EXT_C1C2_TB            0x114
 51#define SSPP_SW_PIX_EXT_C1C2_REQ_PIXELS    0x118
 52#define SSPP_SW_PIX_EXT_C3_LR              0x120
 53#define SSPP_SW_PIX_EXT_C3_TB              0x124
 54#define SSPP_SW_PIX_EXT_C3_REQ_PIXELS      0x128
 55#define SSPP_TRAFFIC_SHAPER                0x130
 56#define SSPP_CDP_CNTL                      0x134
 57#define SSPP_UBWC_ERROR_STATUS             0x138
 58#define SSPP_CDP_CNTL_REC1                 0x13c
 59#define SSPP_TRAFFIC_SHAPER_PREFILL        0x150
 60#define SSPP_TRAFFIC_SHAPER_REC1_PREFILL   0x154
 61#define SSPP_TRAFFIC_SHAPER_REC1           0x158
 62#define SSPP_OUT_SIZE_REC1                 0x160
 63#define SSPP_OUT_XY_REC1                   0x164
 64#define SSPP_SRC_XY_REC1                   0x168
 65#define SSPP_SRC_SIZE_REC1                 0x16C
 66#define SSPP_MULTIRECT_OPMODE              0x170
 67#define SSPP_SRC_FORMAT_REC1               0x174
 68#define SSPP_SRC_UNPACK_PATTERN_REC1       0x178
 69#define SSPP_SRC_OP_MODE_REC1              0x17C
 70#define SSPP_SRC_CONSTANT_COLOR_REC1       0x180
 71#define SSPP_EXCL_REC_SIZE_REC1            0x184
 72#define SSPP_EXCL_REC_XY_REC1              0x188
 73#define SSPP_EXCL_REC_SIZE                 0x1B4
 74#define SSPP_EXCL_REC_XY                   0x1B8
 75#define SSPP_UBWC_STATIC_CTRL_REC1         0x1c0
 76#define SSPP_UBWC_ERROR_STATUS_REC1        0x1c8
 77#define SSPP_CLK_CTRL                      0x330
 78
 79/* SSPP_SRC_OP_MODE & OP_MODE_REC1 */
 80#define MDSS_MDP_OP_DEINTERLACE            BIT(22)
 81#define MDSS_MDP_OP_DEINTERLACE_ODD        BIT(23)
 82#define MDSS_MDP_OP_IGC_ROM_1              BIT(18)
 83#define MDSS_MDP_OP_IGC_ROM_0              BIT(17)
 84#define MDSS_MDP_OP_IGC_EN                 BIT(16)
 85#define MDSS_MDP_OP_FLIP_UD                BIT(14)
 86#define MDSS_MDP_OP_FLIP_LR                BIT(13)
 87#define MDSS_MDP_OP_BWC_EN                 BIT(0)
 88#define MDSS_MDP_OP_PE_OVERRIDE            BIT(31)
 89#define MDSS_MDP_OP_BWC_LOSSLESS           (0 << 1)
 90#define MDSS_MDP_OP_BWC_Q_HIGH             (1 << 1)
 91#define MDSS_MDP_OP_BWC_Q_MED              (2 << 1)
 92
 93/* SSPP_QOS_CTRL */
 94#define SSPP_QOS_CTRL_VBLANK_EN            BIT(16)
 95#define SSPP_QOS_CTRL_DANGER_SAFE_EN       BIT(0)
 96#define SSPP_QOS_CTRL_DANGER_VBLANK_MASK   0x3
 97#define SSPP_QOS_CTRL_DANGER_VBLANK_OFF    4
 98#define SSPP_QOS_CTRL_CREQ_VBLANK_MASK     0x3
 99#define SSPP_QOS_CTRL_CREQ_VBLANK_OFF      20
100
101/* DPU_SSPP_SCALER_QSEED2 */
102#define SSPP_VIG_OP_MODE                   0x0
103#define SCALE_CONFIG                       0x04
104#define COMP0_3_PHASE_STEP_X               0x10
105#define COMP0_3_PHASE_STEP_Y               0x14
106#define COMP1_2_PHASE_STEP_X               0x18
107#define COMP1_2_PHASE_STEP_Y               0x1c
108#define COMP0_3_INIT_PHASE_X               0x20
109#define COMP0_3_INIT_PHASE_Y               0x24
110#define COMP1_2_INIT_PHASE_X               0x28
111#define COMP1_2_INIT_PHASE_Y               0x2C
112#define VIG_0_QSEED2_SHARP                 0x30
113
114/* SSPP_TRAFFIC_SHAPER and _REC1 */
115#define SSPP_TRAFFIC_SHAPER_BPC_MAX        0xFF
116
117/*
118 * Definitions for ViG op modes
119 */
120#define VIG_OP_CSC_DST_DATAFMT BIT(19)
121#define VIG_OP_CSC_SRC_DATAFMT BIT(18)
122#define VIG_OP_CSC_EN          BIT(17)
123#define VIG_OP_MEM_PROT_CONT   BIT(15)
124#define VIG_OP_MEM_PROT_VAL    BIT(14)
125#define VIG_OP_MEM_PROT_SAT    BIT(13)
126#define VIG_OP_MEM_PROT_HUE    BIT(12)
127#define VIG_OP_HIST            BIT(8)
128#define VIG_OP_SKY_COL         BIT(7)
129#define VIG_OP_FOIL            BIT(6)
130#define VIG_OP_SKIN_COL        BIT(5)
131#define VIG_OP_PA_EN           BIT(4)
132#define VIG_OP_PA_SAT_ZERO_EXP BIT(2)
133#define VIG_OP_MEM_PROT_BLEND  BIT(1)
134
135/*
136 * Definitions for CSC 10 op modes
137 */
138#define SSPP_VIG_CSC_10_OP_MODE            0x0
139#define VIG_CSC_10_SRC_DATAFMT BIT(1)
140#define VIG_CSC_10_EN          BIT(0)
141#define CSC_10BIT_OFFSET       4
142
143/* traffic shaper clock in Hz */
144#define TS_CLK			19200000
145
146
147static void dpu_hw_sspp_setup_multirect(struct dpu_sw_pipe *pipe)
148{
149	struct dpu_hw_sspp *ctx = pipe->sspp;
150	u32 mode_mask;
151
152	if (!ctx)
153		return;
154
155	if (pipe->multirect_index == DPU_SSPP_RECT_SOLO) {
156		/**
157		 * if rect index is RECT_SOLO, we cannot expect a
158		 * virtual plane sharing the same SSPP id. So we go
159		 * and disable multirect
160		 */
161		mode_mask = 0;
162	} else {
163		mode_mask = DPU_REG_READ(&ctx->hw, SSPP_MULTIRECT_OPMODE);
164		mode_mask |= pipe->multirect_index;
165		if (pipe->multirect_mode == DPU_SSPP_MULTIRECT_TIME_MX)
166			mode_mask |= BIT(2);
167		else
168			mode_mask &= ~BIT(2);
169	}
170
171	DPU_REG_WRITE(&ctx->hw, SSPP_MULTIRECT_OPMODE, mode_mask);
172}
173
174static void _sspp_setup_opmode(struct dpu_hw_sspp *ctx,
175		u32 mask, u8 en)
176{
177	const struct dpu_sspp_sub_blks *sblk = ctx->cap->sblk;
178	u32 opmode;
179
180	if (!test_bit(DPU_SSPP_SCALER_QSEED2, &ctx->cap->features) ||
181		!test_bit(DPU_SSPP_CSC, &ctx->cap->features))
182		return;
183
184	opmode = DPU_REG_READ(&ctx->hw, sblk->scaler_blk.base + SSPP_VIG_OP_MODE);
185
186	if (en)
187		opmode |= mask;
188	else
189		opmode &= ~mask;
190
191	DPU_REG_WRITE(&ctx->hw, sblk->scaler_blk.base + SSPP_VIG_OP_MODE, opmode);
192}
193
194static void _sspp_setup_csc10_opmode(struct dpu_hw_sspp *ctx,
195		u32 mask, u8 en)
196{
197	const struct dpu_sspp_sub_blks *sblk = ctx->cap->sblk;
198	u32 opmode;
199
200	opmode = DPU_REG_READ(&ctx->hw, sblk->csc_blk.base + SSPP_VIG_CSC_10_OP_MODE);
201	if (en)
202		opmode |= mask;
203	else
204		opmode &= ~mask;
205
206	DPU_REG_WRITE(&ctx->hw, sblk->csc_blk.base + SSPP_VIG_CSC_10_OP_MODE, opmode);
207}
208
209/*
210 * Setup source pixel format, flip,
211 */
212static void dpu_hw_sspp_setup_format(struct dpu_sw_pipe *pipe,
213		const struct msm_format *fmt, u32 flags)
214{
215	struct dpu_hw_sspp *ctx = pipe->sspp;
216	struct dpu_hw_blk_reg_map *c;
217	u32 chroma_samp, unpack, src_format;
218	u32 opmode = 0;
219	u32 fast_clear = 0;
220	u32 op_mode_off, unpack_pat_off, format_off, ubwc_ctrl_off, ubwc_error_off;
221
222	if (!ctx || !fmt)
223		return;
224
225	if (pipe->multirect_index == DPU_SSPP_RECT_SOLO ||
226	    pipe->multirect_index == DPU_SSPP_RECT_0) {
227		op_mode_off = SSPP_SRC_OP_MODE;
228		unpack_pat_off = SSPP_SRC_UNPACK_PATTERN;
229		format_off = SSPP_SRC_FORMAT;
230		ubwc_ctrl_off = SSPP_UBWC_STATIC_CTRL;
231		ubwc_error_off = SSPP_UBWC_ERROR_STATUS;
232	} else {
233		op_mode_off = SSPP_SRC_OP_MODE_REC1;
234		unpack_pat_off = SSPP_SRC_UNPACK_PATTERN_REC1;
235		format_off = SSPP_SRC_FORMAT_REC1;
236
237		/* reg wasn't present before DPU 8.0 */
238		if (ctx->mdss_ver->core_major_ver >= 8) {
239			ubwc_ctrl_off = SSPP_UBWC_STATIC_CTRL_REC1;
240			ubwc_error_off = SSPP_UBWC_ERROR_STATUS_REC1;
241		} else {
242			ubwc_ctrl_off = SSPP_UBWC_STATIC_CTRL;
243			ubwc_error_off = SSPP_UBWC_ERROR_STATUS;
244		}
245	}
246
247	c = &ctx->hw;
248	opmode = DPU_REG_READ(c, op_mode_off);
249	opmode &= ~(MDSS_MDP_OP_FLIP_LR | MDSS_MDP_OP_FLIP_UD |
250			MDSS_MDP_OP_BWC_EN | MDSS_MDP_OP_PE_OVERRIDE);
251
252	if (flags & DPU_SSPP_FLIP_LR)
253		opmode |= MDSS_MDP_OP_FLIP_LR;
254	if (flags & DPU_SSPP_FLIP_UD)
255		opmode |= MDSS_MDP_OP_FLIP_UD;
256
257	chroma_samp = fmt->chroma_sample;
258	if (flags & DPU_SSPP_SOURCE_ROTATED_90) {
259		if (chroma_samp == CHROMA_H2V1)
260			chroma_samp = CHROMA_H1V2;
261		else if (chroma_samp == CHROMA_H1V2)
262			chroma_samp = CHROMA_H2V1;
263	}
264
265	src_format = (chroma_samp << 23) | (fmt->fetch_type << 19) |
266		(fmt->bpc_a << 6) | (fmt->bpc_r_cr << 4) |
267		(fmt->bpc_b_cb << 2) | (fmt->bpc_g_y << 0);
268
269	if (flags & DPU_SSPP_ROT_90)
270		src_format |= BIT(11); /* ROT90 */
271
272	if (fmt->alpha_enable && fmt->fetch_type == MDP_PLANE_INTERLEAVED)
273		src_format |= BIT(8); /* SRCC3_EN */
274
275	if (flags & DPU_SSPP_SOLID_FILL)
276		src_format |= BIT(22);
277
278	unpack = (fmt->element[3] << 24) | (fmt->element[2] << 16) |
279		(fmt->element[1] << 8) | (fmt->element[0] << 0);
280	src_format |= ((fmt->unpack_count - 1) << 12) |
281		((fmt->flags & MSM_FORMAT_FLAG_UNPACK_TIGHT ? 1 : 0) << 17) |
282		((fmt->flags & MSM_FORMAT_FLAG_UNPACK_ALIGN_MSB ? 1 : 0) << 18) |
283		((fmt->bpp - 1) << 9);
284
285	if (fmt->fetch_mode != MDP_FETCH_LINEAR) {
286		u32 hbb = ctx->ubwc->highest_bank_bit - 13;
287		u32 ctrl_val;
288
289		if (MSM_FORMAT_IS_UBWC(fmt))
290			opmode |= MDSS_MDP_OP_BWC_EN;
291		src_format |= (fmt->fetch_mode & 3) << 30; /*FRAME_FORMAT */
292		DPU_REG_WRITE(c, SSPP_FETCH_CONFIG,
293			DPU_FETCH_CONFIG_RESET_VALUE |
294			hbb << 18);
295
296		if (ctx->ubwc->ubwc_enc_version == UBWC_1_0) {
297			fast_clear = fmt->alpha_enable ? BIT(31) : 0;
298			ctrl_val = fast_clear | (ctx->ubwc->ubwc_swizzle & 0x1) |
299				BIT(8) | (hbb << 4);
300		} else if (ctx->ubwc->ubwc_enc_version == UBWC_2_0) {
301			fast_clear = fmt->alpha_enable ? BIT(31) : 0;
302			ctrl_val = fast_clear | ctx->ubwc->ubwc_swizzle | (hbb << 4);
303		} else if (ctx->ubwc->ubwc_enc_version == UBWC_3_0) {
304			ctrl_val = BIT(30) | (ctx->ubwc->ubwc_swizzle) | (hbb << 4);
305		} else if (ctx->ubwc->ubwc_enc_version == UBWC_4_0) {
306			ctrl_val = MSM_FORMAT_IS_YUV(fmt) ? 0 : BIT(30);
307		} else if (ctx->ubwc->ubwc_enc_version <= UBWC_6_0) {
308			if (MSM_FORMAT_IS_YUV(fmt))
309				ctrl_val = 0;
310			else if (MSM_FORMAT_IS_DX(fmt)) /* or FP16, but it's unsupported */
311				ctrl_val = BIT(30);
312			else
313				ctrl_val = BIT(30) | BIT(31);
314			/* SDE also sets bits for lossy formats, but we don't support them yet */
315		} else {
316			DRM_WARN_ONCE("Unsupported UBWC version %x\n", ctx->ubwc->ubwc_enc_version);
317			ctrl_val = 0;
318		}
319
320		DPU_REG_WRITE(c, ubwc_ctrl_off, ctrl_val);
321	}
322
323	opmode |= MDSS_MDP_OP_PE_OVERRIDE;
324
325	/* if this is YUV pixel format, enable CSC */
326	if (MSM_FORMAT_IS_YUV(fmt))
327		src_format |= BIT(15);
328
329	if (MSM_FORMAT_IS_DX(fmt))
330		src_format |= BIT(14);
331
332	/* update scaler opmode, if appropriate */
333	if (test_bit(DPU_SSPP_CSC, &ctx->cap->features))
334		_sspp_setup_opmode(ctx, VIG_OP_CSC_EN | VIG_OP_CSC_SRC_DATAFMT,
335			MSM_FORMAT_IS_YUV(fmt));
336	else if (test_bit(DPU_SSPP_CSC_10BIT, &ctx->cap->features))
337		_sspp_setup_csc10_opmode(ctx,
338			VIG_CSC_10_EN | VIG_CSC_10_SRC_DATAFMT,
339			MSM_FORMAT_IS_YUV(fmt));
340
341	DPU_REG_WRITE(c, format_off, src_format);
342	DPU_REG_WRITE(c, unpack_pat_off, unpack);
343	DPU_REG_WRITE(c, op_mode_off, opmode);
344
345	/* clear previous UBWC error */
346	DPU_REG_WRITE(c, ubwc_error_off, BIT(31));
347}
348
349static void dpu_hw_sspp_setup_pe_config(struct dpu_hw_sspp *ctx,
350		struct dpu_hw_pixel_ext *pe_ext)
351{
352	struct dpu_hw_blk_reg_map *c;
353	u8 color;
354	u32 lr_pe[4], tb_pe[4], tot_req_pixels[4];
355	const u32 bytemask = 0xff;
356	const u32 shortmask = 0xffff;
357
358	if (!ctx || !pe_ext)
359		return;
360
361	c = &ctx->hw;
362
363	/* program SW pixel extension override for all pipes*/
364	for (color = 0; color < DPU_MAX_PLANES; color++) {
365		/* color 2 has the same set of registers as color 1 */
366		if (color == 2)
367			continue;
368
369		lr_pe[color] = ((pe_ext->right_ftch[color] & bytemask) << 24)|
370			((pe_ext->right_rpt[color] & bytemask) << 16)|
371			((pe_ext->left_ftch[color] & bytemask) << 8)|
372			(pe_ext->left_rpt[color] & bytemask);
373
374		tb_pe[color] = ((pe_ext->btm_ftch[color] & bytemask) << 24)|
375			((pe_ext->btm_rpt[color] & bytemask) << 16)|
376			((pe_ext->top_ftch[color] & bytemask) << 8)|
377			(pe_ext->top_rpt[color] & bytemask);
378
379		tot_req_pixels[color] = (((pe_ext->roi_h[color] +
380			pe_ext->num_ext_pxls_top[color] +
381			pe_ext->num_ext_pxls_btm[color]) & shortmask) << 16) |
382			((pe_ext->roi_w[color] +
383			pe_ext->num_ext_pxls_left[color] +
384			pe_ext->num_ext_pxls_right[color]) & shortmask);
385	}
386
387	/* color 0 */
388	DPU_REG_WRITE(c, SSPP_SW_PIX_EXT_C0_LR, lr_pe[0]);
389	DPU_REG_WRITE(c, SSPP_SW_PIX_EXT_C0_TB, tb_pe[0]);
390	DPU_REG_WRITE(c, SSPP_SW_PIX_EXT_C0_REQ_PIXELS,
391			tot_req_pixels[0]);
392
393	/* color 1 and color 2 */
394	DPU_REG_WRITE(c, SSPP_SW_PIX_EXT_C1C2_LR, lr_pe[1]);
395	DPU_REG_WRITE(c, SSPP_SW_PIX_EXT_C1C2_TB, tb_pe[1]);
396	DPU_REG_WRITE(c, SSPP_SW_PIX_EXT_C1C2_REQ_PIXELS,
397			tot_req_pixels[1]);
398
399	/* color 3 */
400	DPU_REG_WRITE(c, SSPP_SW_PIX_EXT_C3_LR, lr_pe[3]);
401	DPU_REG_WRITE(c, SSPP_SW_PIX_EXT_C3_TB, lr_pe[3]);
402	DPU_REG_WRITE(c, SSPP_SW_PIX_EXT_C3_REQ_PIXELS,
403			tot_req_pixels[3]);
404}
405
406static void _dpu_hw_sspp_setup_scaler3(struct dpu_hw_sspp *ctx,
407		struct dpu_hw_scaler3_cfg *scaler3_cfg,
408		const struct msm_format *format)
409{
410	if (!ctx || !scaler3_cfg)
411		return;
412
413	dpu_hw_setup_scaler3(&ctx->hw, scaler3_cfg,
414			ctx->cap->sblk->scaler_blk.base,
415			ctx->cap->sblk->scaler_blk.version,
416			format);
417}
418
419/*
420 * dpu_hw_sspp_setup_rects()
421 */
422static void dpu_hw_sspp_setup_rects(struct dpu_sw_pipe *pipe,
423		struct dpu_sw_pipe_cfg *cfg)
424{
425	struct dpu_hw_sspp *ctx = pipe->sspp;
426	struct dpu_hw_blk_reg_map *c;
427	u32 src_size, src_xy, dst_size, dst_xy;
428	u32 src_size_off, src_xy_off, out_size_off, out_xy_off;
429
430	if (!ctx || !cfg)
431		return;
432
433	c = &ctx->hw;
434
435	if (pipe->multirect_index == DPU_SSPP_RECT_SOLO ||
436	    pipe->multirect_index == DPU_SSPP_RECT_0) {
437		src_size_off = SSPP_SRC_SIZE;
438		src_xy_off = SSPP_SRC_XY;
439		out_size_off = SSPP_OUT_SIZE;
440		out_xy_off = SSPP_OUT_XY;
441	} else {
442		src_size_off = SSPP_SRC_SIZE_REC1;
443		src_xy_off = SSPP_SRC_XY_REC1;
444		out_size_off = SSPP_OUT_SIZE_REC1;
445		out_xy_off = SSPP_OUT_XY_REC1;
446	}
447
448
449	/* src and dest rect programming */
450	src_xy = (cfg->src_rect.y1 << 16) | cfg->src_rect.x1;
451	src_size = (drm_rect_height(&cfg->src_rect) << 16) |
452		   drm_rect_width(&cfg->src_rect);
453	dst_xy = (cfg->dst_rect.y1 << 16) | cfg->dst_rect.x1;
454	dst_size = (drm_rect_height(&cfg->dst_rect) << 16) |
455		drm_rect_width(&cfg->dst_rect);
456
457	/* rectangle register programming */
458	DPU_REG_WRITE(c, src_size_off, src_size);
459	DPU_REG_WRITE(c, src_xy_off, src_xy);
460	DPU_REG_WRITE(c, out_size_off, dst_size);
461	DPU_REG_WRITE(c, out_xy_off, dst_xy);
462}
463
464static void dpu_hw_sspp_setup_sourceaddress(struct dpu_sw_pipe *pipe,
465		struct dpu_hw_fmt_layout *layout)
466{
467	struct dpu_hw_sspp *ctx = pipe->sspp;
468	u32 ystride0, ystride1;
469	int i;
470
471	if (!ctx)
472		return;
473
474	if (pipe->multirect_index == DPU_SSPP_RECT_SOLO) {
475		for (i = 0; i < ARRAY_SIZE(layout->plane_addr); i++)
476			DPU_REG_WRITE(&ctx->hw, SSPP_SRC0_ADDR + i * 0x4,
477					layout->plane_addr[i]);
478	} else if (pipe->multirect_index == DPU_SSPP_RECT_0) {
479		DPU_REG_WRITE(&ctx->hw, SSPP_SRC0_ADDR,
480				layout->plane_addr[0]);
481		DPU_REG_WRITE(&ctx->hw, SSPP_SRC2_ADDR,
482				layout->plane_addr[2]);
483	} else {
484		DPU_REG_WRITE(&ctx->hw, SSPP_SRC1_ADDR,
485				layout->plane_addr[0]);
486		DPU_REG_WRITE(&ctx->hw, SSPP_SRC3_ADDR,
487				layout->plane_addr[2]);
488	}
489
490	if (pipe->multirect_index == DPU_SSPP_RECT_SOLO) {
491		ystride0 = (layout->plane_pitch[0]) |
492			(layout->plane_pitch[1] << 16);
493		ystride1 = (layout->plane_pitch[2]) |
494			(layout->plane_pitch[3] << 16);
495	} else {
496		ystride0 = DPU_REG_READ(&ctx->hw, SSPP_SRC_YSTRIDE0);
497		ystride1 = DPU_REG_READ(&ctx->hw, SSPP_SRC_YSTRIDE1);
498
499		if (pipe->multirect_index == DPU_SSPP_RECT_0) {
500			ystride0 = (ystride0 & 0xFFFF0000) |
501				(layout->plane_pitch[0] & 0x0000FFFF);
502			ystride1 = (ystride1 & 0xFFFF0000)|
503				(layout->plane_pitch[2] & 0x0000FFFF);
504		} else {
505			ystride0 = (ystride0 & 0x0000FFFF) |
506				((layout->plane_pitch[0] << 16) &
507				 0xFFFF0000);
508			ystride1 = (ystride1 & 0x0000FFFF) |
509				((layout->plane_pitch[2] << 16) &
510				 0xFFFF0000);
511		}
512	}
513
514	DPU_REG_WRITE(&ctx->hw, SSPP_SRC_YSTRIDE0, ystride0);
515	DPU_REG_WRITE(&ctx->hw, SSPP_SRC_YSTRIDE1, ystride1);
516}
517
518static void dpu_hw_sspp_setup_csc(struct dpu_hw_sspp *ctx,
519		const struct dpu_csc_cfg *data)
520{
521	u32 offset;
522	bool csc10 = false;
523
524	if (!ctx || !data)
525		return;
526
527	offset = ctx->cap->sblk->csc_blk.base;
528
529	if (test_bit(DPU_SSPP_CSC_10BIT, &ctx->cap->features)) {
530		offset += CSC_10BIT_OFFSET;
531		csc10 = true;
532	}
533
534	dpu_hw_csc_setup(&ctx->hw, offset, data, csc10);
535}
536
537static void dpu_hw_sspp_setup_solidfill(struct dpu_sw_pipe *pipe, u32 color)
538{
539	struct dpu_hw_sspp *ctx = pipe->sspp;
540	struct dpu_hw_fmt_layout cfg;
541
542	if (!ctx)
543		return;
544
545	/* cleanup source addresses */
546	memset(&cfg, 0, sizeof(cfg));
547	ctx->ops.setup_sourceaddress(pipe, &cfg);
548
549	if (pipe->multirect_index == DPU_SSPP_RECT_SOLO ||
550	    pipe->multirect_index == DPU_SSPP_RECT_0)
551		DPU_REG_WRITE(&ctx->hw, SSPP_SRC_CONSTANT_COLOR, color);
552	else
553		DPU_REG_WRITE(&ctx->hw, SSPP_SRC_CONSTANT_COLOR_REC1,
554				color);
555}
556
557static void dpu_hw_sspp_setup_qos_lut(struct dpu_hw_sspp *ctx,
558				      struct dpu_hw_qos_cfg *cfg)
559{
560	if (!ctx || !cfg)
561		return;
562
563	_dpu_hw_setup_qos_lut(&ctx->hw, SSPP_DANGER_LUT,
564			      ctx->mdss_ver->core_major_ver >= 4,
565			      cfg);
566}
567
568static void dpu_hw_sspp_setup_qos_ctrl(struct dpu_hw_sspp *ctx,
569				       bool danger_safe_en)
570{
571	if (!ctx)
572		return;
573
574	DPU_REG_WRITE(&ctx->hw, SSPP_QOS_CTRL,
575		      danger_safe_en ? SSPP_QOS_CTRL_DANGER_SAFE_EN : 0);
576}
577
578static void dpu_hw_sspp_setup_cdp(struct dpu_sw_pipe *pipe,
579				  const struct msm_format *fmt,
580				  bool enable)
581{
582	struct dpu_hw_sspp *ctx = pipe->sspp;
583	u32 cdp_cntl_offset = 0;
584
585	if (!ctx)
586		return;
587
588	if (pipe->multirect_index == DPU_SSPP_RECT_SOLO ||
589	    pipe->multirect_index == DPU_SSPP_RECT_0)
590		cdp_cntl_offset = SSPP_CDP_CNTL;
591	else
592		cdp_cntl_offset = SSPP_CDP_CNTL_REC1;
593
594	dpu_setup_cdp(&ctx->hw, cdp_cntl_offset, fmt, enable);
595}
596
597static bool dpu_hw_sspp_setup_clk_force_ctrl(struct dpu_hw_sspp *ctx, bool enable)
598{
599	static const struct dpu_clk_ctrl_reg sspp_clk_ctrl = {
600		.reg_off = SSPP_CLK_CTRL,
601		.bit_off = 0
602	};
603
604	return dpu_hw_clk_force_ctrl(&ctx->hw, &sspp_clk_ctrl, enable);
605}
606
607static void _setup_layer_ops(struct dpu_hw_sspp *c,
608		unsigned long features, const struct dpu_mdss_version *mdss_rev)
609{
610	c->ops.setup_format = dpu_hw_sspp_setup_format;
611	c->ops.setup_rects = dpu_hw_sspp_setup_rects;
612	c->ops.setup_sourceaddress = dpu_hw_sspp_setup_sourceaddress;
613	c->ops.setup_solidfill = dpu_hw_sspp_setup_solidfill;
614	c->ops.setup_pe = dpu_hw_sspp_setup_pe_config;
615
616	if (test_bit(DPU_SSPP_QOS, &features)) {
617		c->ops.setup_qos_lut = dpu_hw_sspp_setup_qos_lut;
618		c->ops.setup_qos_ctrl = dpu_hw_sspp_setup_qos_ctrl;
619	}
620
621	if (test_bit(DPU_SSPP_CSC, &features) ||
622		test_bit(DPU_SSPP_CSC_10BIT, &features))
623		c->ops.setup_csc = dpu_hw_sspp_setup_csc;
624
625	if (test_bit(DPU_SSPP_SMART_DMA_V1, &c->cap->features) ||
626		test_bit(DPU_SSPP_SMART_DMA_V2, &c->cap->features))
627		c->ops.setup_multirect = dpu_hw_sspp_setup_multirect;
628
629	if (test_bit(DPU_SSPP_SCALER_QSEED3_COMPATIBLE, &features))
630		c->ops.setup_scaler = _dpu_hw_sspp_setup_scaler3;
631
632	if (test_bit(DPU_SSPP_CDP, &features))
633		c->ops.setup_cdp = dpu_hw_sspp_setup_cdp;
634
635	if (mdss_rev->core_major_ver >= 9)
636		c->ops.setup_clk_force_ctrl = dpu_hw_sspp_setup_clk_force_ctrl;
637}
638
639#ifdef CONFIG_DEBUG_FS
640int _dpu_hw_sspp_init_debugfs(struct dpu_hw_sspp *hw_pipe, struct dpu_kms *kms,
641			      struct dentry *entry)
642{
643	const struct dpu_sspp_cfg *cfg = hw_pipe->cap;
644	const struct dpu_sspp_sub_blks *sblk = cfg->sblk;
645	struct dentry *debugfs_root;
646	char sspp_name[32];
647
648	snprintf(sspp_name, sizeof(sspp_name), "%d", hw_pipe->idx);
649
650	/* create overall sub-directory for the pipe */
651	debugfs_root =
652		debugfs_create_dir(sspp_name, entry);
653
654	/* don't error check these */
655	debugfs_create_xul("features", 0600,
656			debugfs_root, (unsigned long *)&hw_pipe->cap->features);
657
658	/* add register dump support */
659	dpu_debugfs_create_regset32("src_blk", 0400,
660			debugfs_root,
661			cfg->base,
662			cfg->len,
663			kms);
664
665	if (sblk->scaler_blk.len)
666		dpu_debugfs_create_regset32("scaler_blk", 0400,
667				debugfs_root,
668				sblk->scaler_blk.base + cfg->base,
669				sblk->scaler_blk.len,
670				kms);
671
672	if (cfg->features & BIT(DPU_SSPP_CSC) ||
673			cfg->features & BIT(DPU_SSPP_CSC_10BIT))
674		dpu_debugfs_create_regset32("csc_blk", 0400,
675				debugfs_root,
676				sblk->csc_blk.base + cfg->base,
677				sblk->csc_blk.len,
678				kms);
679
680	debugfs_create_u32("xin_id",
681			0400,
682			debugfs_root,
683			(u32 *) &cfg->xin_id);
684	debugfs_create_u32("clk_ctrl",
685			0400,
686			debugfs_root,
687			(u32 *) &cfg->clk_ctrl);
688
689	return 0;
690}
691#endif
692
693/**
694 * dpu_hw_sspp_init() - Initializes the sspp hw driver object.
695 * Should be called once before accessing every pipe.
696 * @dev:  Corresponding device for devres management
697 * @cfg:  Pipe catalog entry for which driver object is required
698 * @addr: Mapped register io address of MDP
699 * @mdss_data: UBWC / MDSS configuration data
700 * @mdss_rev: dpu core's major and minor versions
701 */
702struct dpu_hw_sspp *dpu_hw_sspp_init(struct drm_device *dev,
703				     const struct dpu_sspp_cfg *cfg,
704				     void __iomem *addr,
705				     const struct qcom_ubwc_cfg_data *mdss_data,
706				     const struct dpu_mdss_version *mdss_rev)
707{
708	struct dpu_hw_sspp *hw_pipe;
709
710	if (!addr)
711		return ERR_PTR(-EINVAL);
712
713	hw_pipe = drmm_kzalloc(dev, sizeof(*hw_pipe), GFP_KERNEL);
714	if (!hw_pipe)
715		return ERR_PTR(-ENOMEM);
716
717	hw_pipe->hw.blk_addr = addr + cfg->base;
718	hw_pipe->hw.log_mask = DPU_DBG_MASK_SSPP;
719
720	/* Assign ops */
721	hw_pipe->ubwc = mdss_data;
722	hw_pipe->idx = cfg->id;
723	hw_pipe->cap = cfg;
724
725	hw_pipe->mdss_ver = mdss_rev;
726
727	_setup_layer_ops(hw_pipe, hw_pipe->cap->features, mdss_rev);
728
729	return hw_pipe;
730}
~/ Read-only file preview.