xref: /linux/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c (revision dec1c62e91ba268ab2a6e339d4d7a59287d5eba1)
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 
48 static 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 
52 static 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 
72 static 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 
88 static 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 
95 static 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 
102 static 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 
107 static 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 
114 static 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 
121 static 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 
129 static u32 dpu_hw_ctl_get_pending_flush(struct dpu_hw_ctl *ctx)
130 {
131 	return ctx->pending_flush_mask;
132 }
133 
134 static 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 
149 static 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 
156 static 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 
211 static 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 
244 static 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 
265 static 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 
279 static 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 
286 static 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 
293 static 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 
300 static 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 
325 static 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 
347 static 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 
359 static 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 
378 static 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 
395 static 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 
522 exit:
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 
530 static 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 
573 static 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 
606 static 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 
644 static 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 
661 static 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 
698 struct 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 
725 void dpu_hw_ctl_destroy(struct dpu_hw_ctl *ctx)
726 {
727 	kfree(ctx);
728 }
729