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_ctl.c (18049B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
      3 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
      4 */
      5
      6#include <linux/delay.h>
      7#include "dpu_hwio.h"
      8#include "dpu_hw_ctl.h"
      9#include "dpu_kms.h"
     10#include "dpu_trace.h"
     11
     12#define   CTL_LAYER(lm)                 \
     13	(((lm) == LM_5) ? (0x024) : (((lm) - LM_0) * 0x004))
     14#define   CTL_LAYER_EXT(lm)             \
     15	(0x40 + (((lm) - LM_0) * 0x004))
     16#define   CTL_LAYER_EXT2(lm)             \
     17	(0x70 + (((lm) - LM_0) * 0x004))
     18#define   CTL_LAYER_EXT3(lm)             \
     19	(0xA0 + (((lm) - LM_0) * 0x004))
     20#define   CTL_TOP                       0x014
     21#define   CTL_FLUSH                     0x018
     22#define   CTL_START                     0x01C
     23#define   CTL_PREPARE                   0x0d0
     24#define   CTL_SW_RESET                  0x030
     25#define   CTL_LAYER_EXTN_OFFSET         0x40
     26#define   CTL_MERGE_3D_ACTIVE           0x0E4
     27#define   CTL_WB_ACTIVE                 0x0EC
     28#define   CTL_INTF_ACTIVE               0x0F4
     29#define   CTL_MERGE_3D_FLUSH            0x100
     30#define   CTL_DSC_ACTIVE                0x0E8
     31#define   CTL_DSC_FLUSH                0x104
     32#define   CTL_WB_FLUSH                  0x108
     33#define   CTL_INTF_FLUSH                0x110
     34#define   CTL_INTF_MASTER               0x134
     35#define   CTL_FETCH_PIPE_ACTIVE         0x0FC
     36
     37#define CTL_MIXER_BORDER_OUT            BIT(24)
     38#define CTL_FLUSH_MASK_CTL              BIT(17)
     39
     40#define DPU_REG_RESET_TIMEOUT_US        2000
     41#define  MERGE_3D_IDX   23
     42#define  DSC_IDX        22
     43#define  INTF_IDX       31
     44#define WB_IDX          16
     45#define CTL_INVALID_BIT                 0xffff
     46#define CTL_DEFAULT_GROUP_ID		0xf
     47
     48static const u32 fetch_tbl[SSPP_MAX] = {CTL_INVALID_BIT, 16, 17, 18, 19,
     49	CTL_INVALID_BIT, CTL_INVALID_BIT, CTL_INVALID_BIT, CTL_INVALID_BIT, 0,
     50	1, 2, 3, CTL_INVALID_BIT, CTL_INVALID_BIT};
     51
     52static const struct dpu_ctl_cfg *_ctl_offset(enum dpu_ctl ctl,
     53		const struct dpu_mdss_cfg *m,
     54		void __iomem *addr,
     55		struct dpu_hw_blk_reg_map *b)
     56{
     57	int i;
     58
     59	for (i = 0; i < m->ctl_count; i++) {
     60		if (ctl == m->ctl[i].id) {
     61			b->base_off = addr;
     62			b->blk_off = m->ctl[i].base;
     63			b->length = m->ctl[i].len;
     64			b->hwversion = m->hwversion;
     65			b->log_mask = DPU_DBG_MASK_CTL;
     66			return &m->ctl[i];
     67		}
     68	}
     69	return ERR_PTR(-ENOMEM);
     70}
     71
     72static int _mixer_stages(const struct dpu_lm_cfg *mixer, int count,
     73		enum dpu_lm lm)
     74{
     75	int i;
     76	int stages = -EINVAL;
     77
     78	for (i = 0; i < count; i++) {
     79		if (lm == mixer[i].id) {
     80			stages = mixer[i].sblk->maxblendstages;
     81			break;
     82		}
     83	}
     84
     85	return stages;
     86}
     87
     88static inline u32 dpu_hw_ctl_get_flush_register(struct dpu_hw_ctl *ctx)
     89{
     90	struct dpu_hw_blk_reg_map *c = &ctx->hw;
     91
     92	return DPU_REG_READ(c, CTL_FLUSH);
     93}
     94
     95static inline void dpu_hw_ctl_trigger_start(struct dpu_hw_ctl *ctx)
     96{
     97	trace_dpu_hw_ctl_trigger_start(ctx->pending_flush_mask,
     98				       dpu_hw_ctl_get_flush_register(ctx));
     99	DPU_REG_WRITE(&ctx->hw, CTL_START, 0x1);
    100}
    101
    102static inline bool dpu_hw_ctl_is_started(struct dpu_hw_ctl *ctx)
    103{
    104	return !!(DPU_REG_READ(&ctx->hw, CTL_START) & BIT(0));
    105}
    106
    107static inline void dpu_hw_ctl_trigger_pending(struct dpu_hw_ctl *ctx)
    108{
    109	trace_dpu_hw_ctl_trigger_prepare(ctx->pending_flush_mask,
    110					 dpu_hw_ctl_get_flush_register(ctx));
    111	DPU_REG_WRITE(&ctx->hw, CTL_PREPARE, 0x1);
    112}
    113
    114static inline void dpu_hw_ctl_clear_pending_flush(struct dpu_hw_ctl *ctx)
    115{
    116	trace_dpu_hw_ctl_clear_pending_flush(ctx->pending_flush_mask,
    117				     dpu_hw_ctl_get_flush_register(ctx));
    118	ctx->pending_flush_mask = 0x0;
    119}
    120
    121static inline void dpu_hw_ctl_update_pending_flush(struct dpu_hw_ctl *ctx,
    122		u32 flushbits)
    123{
    124	trace_dpu_hw_ctl_update_pending_flush(flushbits,
    125					      ctx->pending_flush_mask);
    126	ctx->pending_flush_mask |= flushbits;
    127}
    128
    129static u32 dpu_hw_ctl_get_pending_flush(struct dpu_hw_ctl *ctx)
    130{
    131	return ctx->pending_flush_mask;
    132}
    133
    134static inline void dpu_hw_ctl_trigger_flush_v1(struct dpu_hw_ctl *ctx)
    135{
    136	if (ctx->pending_flush_mask & BIT(MERGE_3D_IDX))
    137		DPU_REG_WRITE(&ctx->hw, CTL_MERGE_3D_FLUSH,
    138				ctx->pending_merge_3d_flush_mask);
    139	if (ctx->pending_flush_mask & BIT(INTF_IDX))
    140		DPU_REG_WRITE(&ctx->hw, CTL_INTF_FLUSH,
    141				ctx->pending_intf_flush_mask);
    142	if (ctx->pending_flush_mask & BIT(WB_IDX))
    143		DPU_REG_WRITE(&ctx->hw, CTL_WB_FLUSH,
    144				ctx->pending_wb_flush_mask);
    145
    146	DPU_REG_WRITE(&ctx->hw, CTL_FLUSH, ctx->pending_flush_mask);
    147}
    148
    149static inline void dpu_hw_ctl_trigger_flush(struct dpu_hw_ctl *ctx)
    150{
    151	trace_dpu_hw_ctl_trigger_pending_flush(ctx->pending_flush_mask,
    152				     dpu_hw_ctl_get_flush_register(ctx));
    153	DPU_REG_WRITE(&ctx->hw, CTL_FLUSH, ctx->pending_flush_mask);
    154}
    155
    156static uint32_t dpu_hw_ctl_get_bitmask_sspp(struct dpu_hw_ctl *ctx,
    157	enum dpu_sspp sspp)
    158{
    159	uint32_t flushbits = 0;
    160
    161	switch (sspp) {
    162	case SSPP_VIG0:
    163		flushbits =  BIT(0);
    164		break;
    165	case SSPP_VIG1:
    166		flushbits = BIT(1);
    167		break;
    168	case SSPP_VIG2:
    169		flushbits = BIT(2);
    170		break;
    171	case SSPP_VIG3:
    172		flushbits = BIT(18);
    173		break;
    174	case SSPP_RGB0:
    175		flushbits = BIT(3);
    176		break;
    177	case SSPP_RGB1:
    178		flushbits = BIT(4);
    179		break;
    180	case SSPP_RGB2:
    181		flushbits = BIT(5);
    182		break;
    183	case SSPP_RGB3:
    184		flushbits = BIT(19);
    185		break;
    186	case SSPP_DMA0:
    187		flushbits = BIT(11);
    188		break;
    189	case SSPP_DMA1:
    190		flushbits = BIT(12);
    191		break;
    192	case SSPP_DMA2:
    193		flushbits = BIT(24);
    194		break;
    195	case SSPP_DMA3:
    196		flushbits = BIT(25);
    197		break;
    198	case SSPP_CURSOR0:
    199		flushbits = BIT(22);
    200		break;
    201	case SSPP_CURSOR1:
    202		flushbits = BIT(23);
    203		break;
    204	default:
    205		break;
    206	}
    207
    208	return flushbits;
    209}
    210
    211static uint32_t dpu_hw_ctl_get_bitmask_mixer(struct dpu_hw_ctl *ctx,
    212	enum dpu_lm lm)
    213{
    214	uint32_t flushbits = 0;
    215
    216	switch (lm) {
    217	case LM_0:
    218		flushbits = BIT(6);
    219		break;
    220	case LM_1:
    221		flushbits = BIT(7);
    222		break;
    223	case LM_2:
    224		flushbits = BIT(8);
    225		break;
    226	case LM_3:
    227		flushbits = BIT(9);
    228		break;
    229	case LM_4:
    230		flushbits = BIT(10);
    231		break;
    232	case LM_5:
    233		flushbits = BIT(20);
    234		break;
    235	default:
    236		return -EINVAL;
    237	}
    238
    239	flushbits |= CTL_FLUSH_MASK_CTL;
    240
    241	return flushbits;
    242}
    243
    244static void dpu_hw_ctl_update_pending_flush_intf(struct dpu_hw_ctl *ctx,
    245		enum dpu_intf intf)
    246{
    247	switch (intf) {
    248	case INTF_0:
    249		ctx->pending_flush_mask |= BIT(31);
    250		break;
    251	case INTF_1:
    252		ctx->pending_flush_mask |= BIT(30);
    253		break;
    254	case INTF_2:
    255		ctx->pending_flush_mask |= BIT(29);
    256		break;
    257	case INTF_3:
    258		ctx->pending_flush_mask |= BIT(28);
    259		break;
    260	default:
    261		break;
    262	}
    263}
    264
    265static void dpu_hw_ctl_update_pending_flush_wb(struct dpu_hw_ctl *ctx,
    266		enum dpu_wb wb)
    267{
    268	switch (wb) {
    269	case WB_0:
    270	case WB_1:
    271	case WB_2:
    272		ctx->pending_flush_mask |= BIT(WB_IDX);
    273		break;
    274	default:
    275		break;
    276	}
    277}
    278
    279static void dpu_hw_ctl_update_pending_flush_wb_v1(struct dpu_hw_ctl *ctx,
    280		enum dpu_wb wb)
    281{
    282	ctx->pending_wb_flush_mask |= BIT(wb - WB_0);
    283	ctx->pending_flush_mask |= BIT(WB_IDX);
    284}
    285
    286static void dpu_hw_ctl_update_pending_flush_intf_v1(struct dpu_hw_ctl *ctx,
    287		enum dpu_intf intf)
    288{
    289	ctx->pending_intf_flush_mask |= BIT(intf - INTF_0);
    290	ctx->pending_flush_mask |= BIT(INTF_IDX);
    291}
    292
    293static void dpu_hw_ctl_update_pending_flush_merge_3d_v1(struct dpu_hw_ctl *ctx,
    294		enum dpu_merge_3d merge_3d)
    295{
    296	ctx->pending_merge_3d_flush_mask |= BIT(merge_3d - MERGE_3D_0);
    297	ctx->pending_flush_mask |= BIT(MERGE_3D_IDX);
    298}
    299
    300static uint32_t dpu_hw_ctl_get_bitmask_dspp(struct dpu_hw_ctl *ctx,
    301	enum dpu_dspp dspp)
    302{
    303	uint32_t flushbits = 0;
    304
    305	switch (dspp) {
    306	case DSPP_0:
    307		flushbits = BIT(13);
    308		break;
    309	case DSPP_1:
    310		flushbits = BIT(14);
    311		break;
    312	case DSPP_2:
    313		flushbits = BIT(15);
    314		break;
    315	case DSPP_3:
    316		flushbits = BIT(21);
    317		break;
    318	default:
    319		return 0;
    320	}
    321
    322	return flushbits;
    323}
    324
    325static u32 dpu_hw_ctl_poll_reset_status(struct dpu_hw_ctl *ctx, u32 timeout_us)
    326{
    327	struct dpu_hw_blk_reg_map *c = &ctx->hw;
    328	ktime_t timeout;
    329	u32 status;
    330
    331	timeout = ktime_add_us(ktime_get(), timeout_us);
    332
    333	/*
    334	 * it takes around 30us to have mdp finish resetting its ctl path
    335	 * poll every 50us so that reset should be completed at 1st poll
    336	 */
    337	do {
    338		status = DPU_REG_READ(c, CTL_SW_RESET);
    339		status &= 0x1;
    340		if (status)
    341			usleep_range(20, 50);
    342	} while (status && ktime_compare_safe(ktime_get(), timeout) < 0);
    343
    344	return status;
    345}
    346
    347static int dpu_hw_ctl_reset_control(struct dpu_hw_ctl *ctx)
    348{
    349	struct dpu_hw_blk_reg_map *c = &ctx->hw;
    350
    351	pr_debug("issuing hw ctl reset for ctl:%d\n", ctx->idx);
    352	DPU_REG_WRITE(c, CTL_SW_RESET, 0x1);
    353	if (dpu_hw_ctl_poll_reset_status(ctx, DPU_REG_RESET_TIMEOUT_US))
    354		return -EINVAL;
    355
    356	return 0;
    357}
    358
    359static int dpu_hw_ctl_wait_reset_status(struct dpu_hw_ctl *ctx)
    360{
    361	struct dpu_hw_blk_reg_map *c = &ctx->hw;
    362	u32 status;
    363
    364	status = DPU_REG_READ(c, CTL_SW_RESET);
    365	status &= 0x01;
    366	if (!status)
    367		return 0;
    368
    369	pr_debug("hw ctl reset is set for ctl:%d\n", ctx->idx);
    370	if (dpu_hw_ctl_poll_reset_status(ctx, DPU_REG_RESET_TIMEOUT_US)) {
    371		pr_err("hw recovery is not complete for ctl:%d\n", ctx->idx);
    372		return -EINVAL;
    373	}
    374
    375	return 0;
    376}
    377
    378static void dpu_hw_ctl_clear_all_blendstages(struct dpu_hw_ctl *ctx)
    379{
    380	struct dpu_hw_blk_reg_map *c = &ctx->hw;
    381	int i;
    382
    383	for (i = 0; i < ctx->mixer_count; i++) {
    384		enum dpu_lm mixer_id = ctx->mixer_hw_caps[i].id;
    385
    386		DPU_REG_WRITE(c, CTL_LAYER(mixer_id), 0);
    387		DPU_REG_WRITE(c, CTL_LAYER_EXT(mixer_id), 0);
    388		DPU_REG_WRITE(c, CTL_LAYER_EXT2(mixer_id), 0);
    389		DPU_REG_WRITE(c, CTL_LAYER_EXT3(mixer_id), 0);
    390	}
    391
    392	DPU_REG_WRITE(c, CTL_FETCH_PIPE_ACTIVE, 0);
    393}
    394
    395static void dpu_hw_ctl_setup_blendstage(struct dpu_hw_ctl *ctx,
    396	enum dpu_lm lm, struct dpu_hw_stage_cfg *stage_cfg)
    397{
    398	struct dpu_hw_blk_reg_map *c = &ctx->hw;
    399	u32 mixercfg = 0, mixercfg_ext = 0, mix, ext;
    400	u32 mixercfg_ext2 = 0, mixercfg_ext3 = 0;
    401	int i, j;
    402	int stages;
    403	int pipes_per_stage;
    404
    405	stages = _mixer_stages(ctx->mixer_hw_caps, ctx->mixer_count, lm);
    406	if (stages < 0)
    407		return;
    408
    409	if (test_bit(DPU_MIXER_SOURCESPLIT,
    410		&ctx->mixer_hw_caps->features))
    411		pipes_per_stage = PIPES_PER_STAGE;
    412	else
    413		pipes_per_stage = 1;
    414
    415	mixercfg = CTL_MIXER_BORDER_OUT; /* always set BORDER_OUT */
    416
    417	if (!stage_cfg)
    418		goto exit;
    419
    420	for (i = 0; i <= stages; i++) {
    421		/* overflow to ext register if 'i + 1 > 7' */
    422		mix = (i + 1) & 0x7;
    423		ext = i >= 7;
    424
    425		for (j = 0 ; j < pipes_per_stage; j++) {
    426			enum dpu_sspp_multirect_index rect_index =
    427				stage_cfg->multirect_index[i][j];
    428
    429			switch (stage_cfg->stage[i][j]) {
    430			case SSPP_VIG0:
    431				if (rect_index == DPU_SSPP_RECT_1) {
    432					mixercfg_ext3 |= ((i + 1) & 0xF) << 0;
    433				} else {
    434					mixercfg |= mix << 0;
    435					mixercfg_ext |= ext << 0;
    436				}
    437				break;
    438			case SSPP_VIG1:
    439				if (rect_index == DPU_SSPP_RECT_1) {
    440					mixercfg_ext3 |= ((i + 1) & 0xF) << 4;
    441				} else {
    442					mixercfg |= mix << 3;
    443					mixercfg_ext |= ext << 2;
    444				}
    445				break;
    446			case SSPP_VIG2:
    447				if (rect_index == DPU_SSPP_RECT_1) {
    448					mixercfg_ext3 |= ((i + 1) & 0xF) << 8;
    449				} else {
    450					mixercfg |= mix << 6;
    451					mixercfg_ext |= ext << 4;
    452				}
    453				break;
    454			case SSPP_VIG3:
    455				if (rect_index == DPU_SSPP_RECT_1) {
    456					mixercfg_ext3 |= ((i + 1) & 0xF) << 12;
    457				} else {
    458					mixercfg |= mix << 26;
    459					mixercfg_ext |= ext << 6;
    460				}
    461				break;
    462			case SSPP_RGB0:
    463				mixercfg |= mix << 9;
    464				mixercfg_ext |= ext << 8;
    465				break;
    466			case SSPP_RGB1:
    467				mixercfg |= mix << 12;
    468				mixercfg_ext |= ext << 10;
    469				break;
    470			case SSPP_RGB2:
    471				mixercfg |= mix << 15;
    472				mixercfg_ext |= ext << 12;
    473				break;
    474			case SSPP_RGB3:
    475				mixercfg |= mix << 29;
    476				mixercfg_ext |= ext << 14;
    477				break;
    478			case SSPP_DMA0:
    479				if (rect_index == DPU_SSPP_RECT_1) {
    480					mixercfg_ext2 |= ((i + 1) & 0xF) << 8;
    481				} else {
    482					mixercfg |= mix << 18;
    483					mixercfg_ext |= ext << 16;
    484				}
    485				break;
    486			case SSPP_DMA1:
    487				if (rect_index == DPU_SSPP_RECT_1) {
    488					mixercfg_ext2 |= ((i + 1) & 0xF) << 12;
    489				} else {
    490					mixercfg |= mix << 21;
    491					mixercfg_ext |= ext << 18;
    492				}
    493				break;
    494			case SSPP_DMA2:
    495				if (rect_index == DPU_SSPP_RECT_1) {
    496					mixercfg_ext2 |= ((i + 1) & 0xF) << 16;
    497				} else {
    498					mix |= (i + 1) & 0xF;
    499					mixercfg_ext2 |= mix << 0;
    500				}
    501				break;
    502			case SSPP_DMA3:
    503				if (rect_index == DPU_SSPP_RECT_1) {
    504					mixercfg_ext2 |= ((i + 1) & 0xF) << 20;
    505				} else {
    506					mix |= (i + 1) & 0xF;
    507					mixercfg_ext2 |= mix << 4;
    508				}
    509				break;
    510			case SSPP_CURSOR0:
    511				mixercfg_ext |= ((i + 1) & 0xF) << 20;
    512				break;
    513			case SSPP_CURSOR1:
    514				mixercfg_ext |= ((i + 1) & 0xF) << 26;
    515				break;
    516			default:
    517				break;
    518			}
    519		}
    520	}
    521
    522exit:
    523	DPU_REG_WRITE(c, CTL_LAYER(lm), mixercfg);
    524	DPU_REG_WRITE(c, CTL_LAYER_EXT(lm), mixercfg_ext);
    525	DPU_REG_WRITE(c, CTL_LAYER_EXT2(lm), mixercfg_ext2);
    526	DPU_REG_WRITE(c, CTL_LAYER_EXT3(lm), mixercfg_ext3);
    527}
    528
    529
    530static void dpu_hw_ctl_intf_cfg_v1(struct dpu_hw_ctl *ctx,
    531		struct dpu_hw_intf_cfg *cfg)
    532{
    533	struct dpu_hw_blk_reg_map *c = &ctx->hw;
    534	u32 intf_active = 0;
    535	u32 wb_active = 0;
    536	u32 mode_sel = 0;
    537
    538	/* CTL_TOP[31:28] carries group_id to collate CTL paths
    539	 * per VM. Explicitly disable it until VM support is
    540	 * added in SW. Power on reset value is not disable.
    541	 */
    542	if ((test_bit(DPU_CTL_VM_CFG, &ctx->caps->features)))
    543		mode_sel = CTL_DEFAULT_GROUP_ID  << 28;
    544
    545	if (cfg->dsc)
    546		DPU_REG_WRITE(&ctx->hw, CTL_DSC_FLUSH, cfg->dsc);
    547
    548	if (cfg->intf_mode_sel == DPU_CTL_MODE_SEL_CMD)
    549		mode_sel |= BIT(17);
    550
    551	intf_active = DPU_REG_READ(c, CTL_INTF_ACTIVE);
    552	wb_active = DPU_REG_READ(c, CTL_WB_ACTIVE);
    553
    554	if (cfg->intf)
    555		intf_active |= BIT(cfg->intf - INTF_0);
    556
    557	if (cfg->wb)
    558		wb_active |= BIT(cfg->wb - WB_0);
    559
    560	DPU_REG_WRITE(c, CTL_TOP, mode_sel);
    561	DPU_REG_WRITE(c, CTL_INTF_ACTIVE, intf_active);
    562	DPU_REG_WRITE(c, CTL_WB_ACTIVE, wb_active);
    563
    564	if (cfg->merge_3d)
    565		DPU_REG_WRITE(c, CTL_MERGE_3D_ACTIVE,
    566			      BIT(cfg->merge_3d - MERGE_3D_0));
    567	if (cfg->dsc) {
    568		DPU_REG_WRITE(&ctx->hw, CTL_FLUSH, DSC_IDX);
    569		DPU_REG_WRITE(c, CTL_DSC_ACTIVE, cfg->dsc);
    570	}
    571}
    572
    573static void dpu_hw_ctl_intf_cfg(struct dpu_hw_ctl *ctx,
    574		struct dpu_hw_intf_cfg *cfg)
    575{
    576	struct dpu_hw_blk_reg_map *c = &ctx->hw;
    577	u32 intf_cfg = 0;
    578
    579	intf_cfg |= (cfg->intf & 0xF) << 4;
    580
    581	if (cfg->mode_3d) {
    582		intf_cfg |= BIT(19);
    583		intf_cfg |= (cfg->mode_3d - 0x1) << 20;
    584	}
    585
    586	if (cfg->wb)
    587		intf_cfg |= (cfg->wb & 0x3) + 2;
    588
    589	switch (cfg->intf_mode_sel) {
    590	case DPU_CTL_MODE_SEL_VID:
    591		intf_cfg &= ~BIT(17);
    592		intf_cfg &= ~(0x3 << 15);
    593		break;
    594	case DPU_CTL_MODE_SEL_CMD:
    595		intf_cfg |= BIT(17);
    596		intf_cfg |= ((cfg->stream_sel & 0x3) << 15);
    597		break;
    598	default:
    599		pr_err("unknown interface type %d\n", cfg->intf_mode_sel);
    600		return;
    601	}
    602
    603	DPU_REG_WRITE(c, CTL_TOP, intf_cfg);
    604}
    605
    606static void dpu_hw_ctl_reset_intf_cfg_v1(struct dpu_hw_ctl *ctx,
    607		struct dpu_hw_intf_cfg *cfg)
    608{
    609	struct dpu_hw_blk_reg_map *c = &ctx->hw;
    610	u32 intf_active = 0;
    611	u32 wb_active = 0;
    612	u32 merge3d_active = 0;
    613
    614	/*
    615	 * This API resets each portion of the CTL path namely,
    616	 * clearing the sspps staged on the lm, merge_3d block,
    617	 * interfaces , writeback etc to ensure clean teardown of the pipeline.
    618	 * This will be used for writeback to begin with to have a
    619	 * proper teardown of the writeback session but upon further
    620	 * validation, this can be extended to all interfaces.
    621	 */
    622	if (cfg->merge_3d) {
    623		merge3d_active = DPU_REG_READ(c, CTL_MERGE_3D_ACTIVE);
    624		merge3d_active &= ~BIT(cfg->merge_3d - MERGE_3D_0);
    625		DPU_REG_WRITE(c, CTL_MERGE_3D_ACTIVE,
    626				merge3d_active);
    627	}
    628
    629	dpu_hw_ctl_clear_all_blendstages(ctx);
    630
    631	if (cfg->intf) {
    632		intf_active = DPU_REG_READ(c, CTL_INTF_ACTIVE);
    633		intf_active &= ~BIT(cfg->intf - INTF_0);
    634		DPU_REG_WRITE(c, CTL_INTF_ACTIVE, intf_active);
    635	}
    636
    637	if (cfg->wb) {
    638		wb_active = DPU_REG_READ(c, CTL_WB_ACTIVE);
    639		wb_active &= ~BIT(cfg->wb - WB_0);
    640		DPU_REG_WRITE(c, CTL_WB_ACTIVE, wb_active);
    641	}
    642}
    643
    644static void dpu_hw_ctl_set_fetch_pipe_active(struct dpu_hw_ctl *ctx,
    645	unsigned long *fetch_active)
    646{
    647	int i;
    648	u32 val = 0;
    649
    650	if (fetch_active) {
    651		for (i = 0; i < SSPP_MAX; i++) {
    652			if (test_bit(i, fetch_active) &&
    653				fetch_tbl[i] != CTL_INVALID_BIT)
    654				val |= BIT(fetch_tbl[i]);
    655		}
    656	}
    657
    658	DPU_REG_WRITE(&ctx->hw, CTL_FETCH_PIPE_ACTIVE, val);
    659}
    660
    661static void _setup_ctl_ops(struct dpu_hw_ctl_ops *ops,
    662		unsigned long cap)
    663{
    664	if (cap & BIT(DPU_CTL_ACTIVE_CFG)) {
    665		ops->trigger_flush = dpu_hw_ctl_trigger_flush_v1;
    666		ops->setup_intf_cfg = dpu_hw_ctl_intf_cfg_v1;
    667		ops->reset_intf_cfg = dpu_hw_ctl_reset_intf_cfg_v1;
    668		ops->update_pending_flush_intf =
    669			dpu_hw_ctl_update_pending_flush_intf_v1;
    670		ops->update_pending_flush_merge_3d =
    671			dpu_hw_ctl_update_pending_flush_merge_3d_v1;
    672		ops->update_pending_flush_wb = dpu_hw_ctl_update_pending_flush_wb_v1;
    673	} else {
    674		ops->trigger_flush = dpu_hw_ctl_trigger_flush;
    675		ops->setup_intf_cfg = dpu_hw_ctl_intf_cfg;
    676		ops->update_pending_flush_intf =
    677			dpu_hw_ctl_update_pending_flush_intf;
    678		ops->update_pending_flush_wb = dpu_hw_ctl_update_pending_flush_wb;
    679	}
    680	ops->clear_pending_flush = dpu_hw_ctl_clear_pending_flush;
    681	ops->update_pending_flush = dpu_hw_ctl_update_pending_flush;
    682	ops->get_pending_flush = dpu_hw_ctl_get_pending_flush;
    683	ops->get_flush_register = dpu_hw_ctl_get_flush_register;
    684	ops->trigger_start = dpu_hw_ctl_trigger_start;
    685	ops->is_started = dpu_hw_ctl_is_started;
    686	ops->trigger_pending = dpu_hw_ctl_trigger_pending;
    687	ops->reset = dpu_hw_ctl_reset_control;
    688	ops->wait_reset_status = dpu_hw_ctl_wait_reset_status;
    689	ops->clear_all_blendstages = dpu_hw_ctl_clear_all_blendstages;
    690	ops->setup_blendstage = dpu_hw_ctl_setup_blendstage;
    691	ops->get_bitmask_sspp = dpu_hw_ctl_get_bitmask_sspp;
    692	ops->get_bitmask_mixer = dpu_hw_ctl_get_bitmask_mixer;
    693	ops->get_bitmask_dspp = dpu_hw_ctl_get_bitmask_dspp;
    694	if (cap & BIT(DPU_CTL_FETCH_ACTIVE))
    695		ops->set_active_pipes = dpu_hw_ctl_set_fetch_pipe_active;
    696};
    697
    698struct dpu_hw_ctl *dpu_hw_ctl_init(enum dpu_ctl idx,
    699		void __iomem *addr,
    700		const struct dpu_mdss_cfg *m)
    701{
    702	struct dpu_hw_ctl *c;
    703	const struct dpu_ctl_cfg *cfg;
    704
    705	c = kzalloc(sizeof(*c), GFP_KERNEL);
    706	if (!c)
    707		return ERR_PTR(-ENOMEM);
    708
    709	cfg = _ctl_offset(idx, m, addr, &c->hw);
    710	if (IS_ERR_OR_NULL(cfg)) {
    711		kfree(c);
    712		pr_err("failed to create dpu_hw_ctl %d\n", idx);
    713		return ERR_PTR(-EINVAL);
    714	}
    715
    716	c->caps = cfg;
    717	_setup_ctl_ops(&c->ops, c->caps->features);
    718	c->idx = idx;
    719	c->mixer_count = m->mixer_count;
    720	c->mixer_hw_caps = m->mixer;
    721
    722	return c;
    723}
    724
    725void dpu_hw_ctl_destroy(struct dpu_hw_ctl *ctx)
    726{
    727	kfree(ctx);
    728}