cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dpu_hw_sspp.c (23586B)


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