File Index
Files and directories
Sign in
FILE

dpu_hw_ctl.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  3 * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
  4 */
  5
  6#include <linux/delay.h>
  7
  8#include <drm/drm_managed.h>
  9
 10#include "dpu_hwio.h"
 11#include "dpu_hw_ctl.h"
 12#include "dpu_kms.h"
 13#include "dpu_trace.h"
 14
 15#define   CTL_LAYER(lm)                 \
 16	(((lm) == LM_5) ? (0x024) : (((lm) - LM_0) * 0x004))
 17#define   CTL_LAYER_EXT(lm)             \
 18	(0x40 + (((lm) - LM_0) * 0x004))
 19#define   CTL_LAYER_EXT2(lm)             \
 20	(0x70 + (((lm) - LM_0) * 0x004))
 21#define   CTL_LAYER_EXT3(lm)             \
 22	(0xA0 + (((lm) - LM_0) * 0x004))
 23#define CTL_LAYER_EXT4(lm)             \
 24	(0xB8 + (((lm) - LM_0) * 0x004))
 25#define   CTL_TOP                       0x014
 26#define   CTL_FLUSH                     0x018
 27#define   CTL_START                     0x01C
 28#define   CTL_PREPARE                   0x0d0
 29#define   CTL_SW_RESET                  0x030
 30#define   CTL_LAYER_EXTN_OFFSET         0x40
 31#define   CTL_MERGE_3D_ACTIVE           0x0E4
 32#define   CTL_DSC_ACTIVE                0x0E8
 33#define   CTL_WB_ACTIVE                 0x0EC
 34#define   CTL_CWB_ACTIVE                0x0F0
 35#define   CTL_INTF_ACTIVE               0x0F4
 36#define   CTL_CDM_ACTIVE                0x0F8
 37#define   CTL_FETCH_PIPE_ACTIVE         0x0FC
 38#define   CTL_MERGE_3D_FLUSH            0x100
 39#define   CTL_DSC_FLUSH                0x104
 40#define   CTL_WB_FLUSH                  0x108
 41#define   CTL_CWB_FLUSH                 0x10C
 42#define   CTL_INTF_FLUSH                0x110
 43#define   CTL_CDM_FLUSH                0x114
 44#define   CTL_PERIPH_FLUSH              0x128
 45#define   CTL_PIPE_ACTIVE               0x12c
 46#define   CTL_LAYER_ACTIVE              0x130
 47#define   CTL_INTF_MASTER               0x134
 48#define   CTL_DSPP_n_FLUSH(n)           ((0x13C) + ((n) * 4))
 49
 50#define CTL_MIXER_BORDER_OUT            BIT(24)
 51#define CTL_FLUSH_MASK_CTL              BIT(17)
 52
 53#define DPU_REG_RESET_TIMEOUT_US        2000
 54#define  MERGE_3D_IDX   23
 55#define  DSC_IDX        22
 56#define CDM_IDX         26
 57#define  PERIPH_IDX     30
 58#define  INTF_IDX       31
 59#define WB_IDX          16
 60#define CWB_IDX         28
 61#define  DSPP_IDX       29  /* From DPU hw rev 7.x.x */
 62#define CTL_INVALID_BIT                 0xffff
 63#define CTL_DEFAULT_GROUP_ID		0xf
 64
 65static const u32 fetch_tbl[SSPP_MAX] = {CTL_INVALID_BIT, 16, 17, 18, 19,
 66	CTL_INVALID_BIT, CTL_INVALID_BIT, CTL_INVALID_BIT, CTL_INVALID_BIT, 0,
 67	1, 2, 3, 4, 5};
 68
 69static const u32 lm_tbl[LM_MAX] = {CTL_INVALID_BIT, 0, 1, 2, 3, 4, 5, 6, 7};
 70
 71static int _mixer_stages(const struct dpu_lm_cfg *mixer, int count,
 72		enum dpu_lm lm)
 73{
 74	int i;
 75	int stages = -EINVAL;
 76
 77	for (i = 0; i < count; i++) {
 78		if (lm == mixer[i].id) {
 79			stages = mixer[i].sblk->maxblendstages;
 80			break;
 81		}
 82	}
 83
 84	return stages;
 85}
 86
 87static inline u32 dpu_hw_ctl_get_flush_register(struct dpu_hw_ctl *ctx)
 88{
 89	struct dpu_hw_blk_reg_map *c = &ctx->hw;
 90
 91	return DPU_REG_READ(c, CTL_FLUSH);
 92}
 93
 94static inline void dpu_hw_ctl_trigger_start(struct dpu_hw_ctl *ctx)
 95{
 96	trace_dpu_hw_ctl_trigger_start(ctx->pending_flush_mask,
 97				       dpu_hw_ctl_get_flush_register(ctx));
 98	DPU_REG_WRITE(&ctx->hw, CTL_START, 0x1);
 99}
100
101static inline bool dpu_hw_ctl_is_started(struct dpu_hw_ctl *ctx)
102{
103	return !!(DPU_REG_READ(&ctx->hw, CTL_START) & BIT(0));
104}
105
106static inline void dpu_hw_ctl_trigger_pending(struct dpu_hw_ctl *ctx)
107{
108	trace_dpu_hw_ctl_trigger_prepare(ctx->pending_flush_mask,
109					 dpu_hw_ctl_get_flush_register(ctx));
110	DPU_REG_WRITE(&ctx->hw, CTL_PREPARE, 0x1);
111}
112
113static inline void dpu_hw_ctl_clear_pending_flush(struct dpu_hw_ctl *ctx)
114{
115	trace_dpu_hw_ctl_clear_pending_flush(ctx->pending_flush_mask,
116				     dpu_hw_ctl_get_flush_register(ctx));
117	ctx->pending_flush_mask = 0x0;
118	ctx->pending_intf_flush_mask = 0;
119	ctx->pending_wb_flush_mask = 0;
120	ctx->pending_cwb_flush_mask = 0;
121	ctx->pending_merge_3d_flush_mask = 0;
122	ctx->pending_dsc_flush_mask = 0;
123	ctx->pending_cdm_flush_mask = 0;
124
125	memset(ctx->pending_dspp_flush_mask, 0,
126		sizeof(ctx->pending_dspp_flush_mask));
127}
128
129static inline void dpu_hw_ctl_update_pending_flush(struct dpu_hw_ctl *ctx,
130		u32 flushbits)
131{
132	trace_dpu_hw_ctl_update_pending_flush(flushbits,
133					      ctx->pending_flush_mask);
134	ctx->pending_flush_mask |= flushbits;
135}
136
137static u32 dpu_hw_ctl_get_pending_flush(struct dpu_hw_ctl *ctx)
138{
139	return ctx->pending_flush_mask;
140}
141
142static inline void dpu_hw_ctl_trigger_flush_v1(struct dpu_hw_ctl *ctx)
143{
144	int dspp;
145
146	if (ctx->pending_flush_mask & BIT(MERGE_3D_IDX))
147		DPU_REG_WRITE(&ctx->hw, CTL_MERGE_3D_FLUSH,
148				ctx->pending_merge_3d_flush_mask);
149	if (ctx->pending_flush_mask & BIT(INTF_IDX))
150		DPU_REG_WRITE(&ctx->hw, CTL_INTF_FLUSH,
151				ctx->pending_intf_flush_mask);
152	if (ctx->pending_flush_mask & BIT(WB_IDX))
153		DPU_REG_WRITE(&ctx->hw, CTL_WB_FLUSH,
154				ctx->pending_wb_flush_mask);
155	if (ctx->pending_flush_mask & BIT(CWB_IDX))
156		DPU_REG_WRITE(&ctx->hw, CTL_CWB_FLUSH,
157				ctx->pending_cwb_flush_mask);
158
159	if (ctx->pending_flush_mask & BIT(DSPP_IDX))
160		for (dspp = DSPP_0; dspp < DSPP_MAX; dspp++) {
161			if (ctx->pending_dspp_flush_mask[dspp - DSPP_0])
162				DPU_REG_WRITE(&ctx->hw,
163				CTL_DSPP_n_FLUSH(dspp - DSPP_0),
164				ctx->pending_dspp_flush_mask[dspp - DSPP_0]);
165		}
166
167	if (ctx->pending_flush_mask & BIT(PERIPH_IDX))
168		DPU_REG_WRITE(&ctx->hw, CTL_PERIPH_FLUSH,
169			      ctx->pending_periph_flush_mask);
170
171	if (ctx->pending_flush_mask & BIT(DSC_IDX))
172		DPU_REG_WRITE(&ctx->hw, CTL_DSC_FLUSH,
173			      ctx->pending_dsc_flush_mask);
174
175	if (ctx->pending_flush_mask & BIT(CDM_IDX))
176		DPU_REG_WRITE(&ctx->hw, CTL_CDM_FLUSH,
177			      ctx->pending_cdm_flush_mask);
178
179	DPU_REG_WRITE(&ctx->hw, CTL_FLUSH, ctx->pending_flush_mask);
180}
181
182static inline void dpu_hw_ctl_trigger_flush(struct dpu_hw_ctl *ctx)
183{
184	trace_dpu_hw_ctl_trigger_pending_flush(ctx->pending_flush_mask,
185				     dpu_hw_ctl_get_flush_register(ctx));
186	DPU_REG_WRITE(&ctx->hw, CTL_FLUSH, ctx->pending_flush_mask);
187}
188
189static void dpu_hw_ctl_update_pending_flush_sspp(struct dpu_hw_ctl *ctx,
190	enum dpu_sspp sspp)
191{
192	switch (sspp) {
193	case SSPP_VIG0:
194		ctx->pending_flush_mask |=  BIT(0);
195		break;
196	case SSPP_VIG1:
197		ctx->pending_flush_mask |= BIT(1);
198		break;
199	case SSPP_VIG2:
200		ctx->pending_flush_mask |= BIT(2);
201		break;
202	case SSPP_VIG3:
203		ctx->pending_flush_mask |= BIT(18);
204		break;
205	case SSPP_RGB0:
206		ctx->pending_flush_mask |= BIT(3);
207		break;
208	case SSPP_RGB1:
209		ctx->pending_flush_mask |= BIT(4);
210		break;
211	case SSPP_RGB2:
212		ctx->pending_flush_mask |= BIT(5);
213		break;
214	case SSPP_RGB3:
215		ctx->pending_flush_mask |= BIT(19);
216		break;
217	case SSPP_DMA0:
218		ctx->pending_flush_mask |= BIT(11);
219		break;
220	case SSPP_DMA1:
221		ctx->pending_flush_mask |= BIT(12);
222		break;
223	case SSPP_DMA2:
224		ctx->pending_flush_mask |= BIT(24);
225		break;
226	case SSPP_DMA3:
227		ctx->pending_flush_mask |= BIT(25);
228		break;
229	case SSPP_DMA4:
230		ctx->pending_flush_mask |= BIT(13);
231		break;
232	case SSPP_DMA5:
233		ctx->pending_flush_mask |= BIT(14);
234		break;
235	case SSPP_CURSOR0:
236		ctx->pending_flush_mask |= BIT(22);
237		break;
238	case SSPP_CURSOR1:
239		ctx->pending_flush_mask |= BIT(23);
240		break;
241	default:
242		break;
243	}
244}
245
246static void dpu_hw_ctl_update_pending_flush_mixer(struct dpu_hw_ctl *ctx,
247	enum dpu_lm lm)
248{
249	switch (lm) {
250	case LM_0:
251		ctx->pending_flush_mask |= BIT(6);
252		break;
253	case LM_1:
254		ctx->pending_flush_mask |= BIT(7);
255		break;
256	case LM_2:
257		ctx->pending_flush_mask |= BIT(8);
258		break;
259	case LM_3:
260		ctx->pending_flush_mask |= BIT(9);
261		break;
262	case LM_4:
263		ctx->pending_flush_mask |= BIT(10);
264		break;
265	case LM_5:
266		ctx->pending_flush_mask |= BIT(20);
267		break;
268	case LM_6:
269		ctx->pending_flush_mask |= BIT(21);
270		break;
271	case LM_7:
272		ctx->pending_flush_mask |= BIT(27);
273		break;
274	default:
275		break;
276	}
277
278	ctx->pending_flush_mask |= CTL_FLUSH_MASK_CTL;
279}
280
281static void dpu_hw_ctl_update_pending_flush_intf(struct dpu_hw_ctl *ctx,
282		enum dpu_intf intf)
283{
284	switch (intf) {
285	case INTF_0:
286		ctx->pending_flush_mask |= BIT(31);
287		break;
288	case INTF_1:
289		ctx->pending_flush_mask |= BIT(30);
290		break;
291	case INTF_2:
292		ctx->pending_flush_mask |= BIT(29);
293		break;
294	case INTF_3:
295		ctx->pending_flush_mask |= BIT(28);
296		break;
297	default:
298		break;
299	}
300}
301
302static void dpu_hw_ctl_update_pending_flush_wb(struct dpu_hw_ctl *ctx,
303		enum dpu_wb wb)
304{
305	switch (wb) {
306	case WB_0:
307	case WB_1:
308	case WB_2:
309		ctx->pending_flush_mask |= BIT(WB_IDX);
310		break;
311	default:
312		break;
313	}
314}
315
316static void dpu_hw_ctl_update_pending_flush_cdm(struct dpu_hw_ctl *ctx, enum dpu_cdm cdm_num)
317{
318	/* update pending flush only if CDM_0 is flushed */
319	if (cdm_num == CDM_0)
320		ctx->pending_flush_mask |= BIT(CDM_IDX);
321}
322
323static void dpu_hw_ctl_update_pending_flush_wb_v1(struct dpu_hw_ctl *ctx,
324		enum dpu_wb wb)
325{
326	ctx->pending_wb_flush_mask |= BIT(wb - WB_0);
327	ctx->pending_flush_mask |= BIT(WB_IDX);
328}
329
330static void dpu_hw_ctl_update_pending_flush_cwb_v1(struct dpu_hw_ctl *ctx,
331		enum dpu_cwb cwb)
332{
333	ctx->pending_cwb_flush_mask |= BIT(cwb - CWB_0);
334	ctx->pending_flush_mask |= BIT(CWB_IDX);
335}
336
337static void dpu_hw_ctl_update_pending_flush_intf_v1(struct dpu_hw_ctl *ctx,
338		enum dpu_intf intf)
339{
340	ctx->pending_intf_flush_mask |= BIT(intf - INTF_0);
341	ctx->pending_flush_mask |= BIT(INTF_IDX);
342}
343
344static void dpu_hw_ctl_update_pending_flush_periph_v1(struct dpu_hw_ctl *ctx,
345						      enum dpu_intf intf)
346{
347	ctx->pending_periph_flush_mask |= BIT(intf - INTF_0);
348	ctx->pending_flush_mask |= BIT(PERIPH_IDX);
349}
350
351static void dpu_hw_ctl_update_pending_flush_merge_3d_v1(struct dpu_hw_ctl *ctx,
352		enum dpu_merge_3d merge_3d)
353{
354	ctx->pending_merge_3d_flush_mask |= BIT(merge_3d - MERGE_3D_0);
355	ctx->pending_flush_mask |= BIT(MERGE_3D_IDX);
356}
357
358static void dpu_hw_ctl_update_pending_flush_dsc_v1(struct dpu_hw_ctl *ctx,
359						   enum dpu_dsc dsc_num)
360{
361	ctx->pending_dsc_flush_mask |= BIT(dsc_num - DSC_0);
362	ctx->pending_flush_mask |= BIT(DSC_IDX);
363}
364
365static void dpu_hw_ctl_update_pending_flush_cdm_v1(struct dpu_hw_ctl *ctx, enum dpu_cdm cdm_num)
366{
367	ctx->pending_cdm_flush_mask |= BIT(cdm_num - CDM_0);
368	ctx->pending_flush_mask |= BIT(CDM_IDX);
369}
370
371static void dpu_hw_ctl_update_pending_flush_dspp(struct dpu_hw_ctl *ctx,
372	enum dpu_dspp dspp, u32 dspp_sub_blk)
373{
374	switch (dspp) {
375	case DSPP_0:
376		ctx->pending_flush_mask |= BIT(13);
377		break;
378	case DSPP_1:
379		ctx->pending_flush_mask |= BIT(14);
380		break;
381	case DSPP_2:
382		ctx->pending_flush_mask |= BIT(15);
383		break;
384	case DSPP_3:
385		ctx->pending_flush_mask |= BIT(21);
386		break;
387	default:
388		break;
389	}
390}
391
392static void dpu_hw_ctl_update_pending_flush_dspp_sub_blocks(
393	struct dpu_hw_ctl *ctx,	enum dpu_dspp dspp, u32 dspp_sub_blk)
394{
395	if (dspp >= DSPP_MAX)
396		return;
397
398	switch (dspp_sub_blk) {
399	case DPU_DSPP_PCC:
400		ctx->pending_dspp_flush_mask[dspp - DSPP_0] |= BIT(4);
401		break;
402	default:
403		return;
404	}
405
406	ctx->pending_flush_mask |= BIT(DSPP_IDX);
407}
408
409static u32 dpu_hw_ctl_poll_reset_status(struct dpu_hw_ctl *ctx, u32 timeout_us)
410{
411	struct dpu_hw_blk_reg_map *c = &ctx->hw;
412	ktime_t timeout;
413	u32 status;
414
415	timeout = ktime_add_us(ktime_get(), timeout_us);
416
417	/*
418	 * it takes around 30us to have mdp finish resetting its ctl path
419	 * poll every 50us so that reset should be completed at 1st poll
420	 */
421	do {
422		status = DPU_REG_READ(c, CTL_SW_RESET);
423		status &= 0x1;
424		if (status)
425			usleep_range(20, 50);
426	} while (status && ktime_compare_safe(ktime_get(), timeout) < 0);
427
428	return status;
429}
430
431static int dpu_hw_ctl_reset_control(struct dpu_hw_ctl *ctx)
432{
433	struct dpu_hw_blk_reg_map *c = &ctx->hw;
434
435	pr_debug("issuing hw ctl reset for ctl:%d\n", ctx->idx);
436	DPU_REG_WRITE(c, CTL_SW_RESET, 0x1);
437	if (dpu_hw_ctl_poll_reset_status(ctx, DPU_REG_RESET_TIMEOUT_US))
438		return -EINVAL;
439
440	return 0;
441}
442
443static int dpu_hw_ctl_wait_reset_status(struct dpu_hw_ctl *ctx)
444{
445	struct dpu_hw_blk_reg_map *c = &ctx->hw;
446	u32 status;
447
448	status = DPU_REG_READ(c, CTL_SW_RESET);
449	status &= 0x01;
450	if (!status)
451		return 0;
452
453	pr_debug("hw ctl reset is set for ctl:%d\n", ctx->idx);
454	if (dpu_hw_ctl_poll_reset_status(ctx, DPU_REG_RESET_TIMEOUT_US)) {
455		pr_err("hw recovery is not complete for ctl:%d\n", ctx->idx);
456		return -EINVAL;
457	}
458
459	return 0;
460}
461
462static void dpu_hw_ctl_clear_all_blendstages(struct dpu_hw_ctl *ctx)
463{
464	struct dpu_hw_blk_reg_map *c = &ctx->hw;
465	int i;
466
467	for (i = 0; i < ctx->mixer_count; i++) {
468		enum dpu_lm mixer_id = ctx->mixer_hw_caps[i].id;
469
470		DPU_REG_WRITE(c, CTL_LAYER(mixer_id), 0);
471		DPU_REG_WRITE(c, CTL_LAYER_EXT(mixer_id), 0);
472		DPU_REG_WRITE(c, CTL_LAYER_EXT2(mixer_id), 0);
473		DPU_REG_WRITE(c, CTL_LAYER_EXT3(mixer_id), 0);
474	}
475
476	DPU_REG_WRITE(c, CTL_FETCH_PIPE_ACTIVE, 0);
477}
478
479struct ctl_blend_config {
480	int idx, shift, ext_shift;
481};
482
483static const struct ctl_blend_config ctl_blend_config[][2] = {
484	[SSPP_NONE] = { { -1 }, { -1 } },
485	[SSPP_MAX] =  { { -1 }, { -1 } },
486	[SSPP_VIG0] = { { 0, 0,  0  }, { 3, 0 } },
487	[SSPP_VIG1] = { { 0, 3,  2  }, { 3, 4 } },
488	[SSPP_VIG2] = { { 0, 6,  4  }, { 3, 8 } },
489	[SSPP_VIG3] = { { 0, 26, 6  }, { 3, 12 } },
490	[SSPP_RGB0] = { { 0, 9,  8  }, { -1 } },
491	[SSPP_RGB1] = { { 0, 12, 10 }, { -1 } },
492	[SSPP_RGB2] = { { 0, 15, 12 }, { -1 } },
493	[SSPP_RGB3] = { { 0, 29, 14 }, { -1 } },
494	[SSPP_DMA0] = { { 0, 18, 16 }, { 2, 8 } },
495	[SSPP_DMA1] = { { 0, 21, 18 }, { 2, 12 } },
496	[SSPP_DMA2] = { { 2, 0      }, { 2, 16 } },
497	[SSPP_DMA3] = { { 2, 4      }, { 2, 20 } },
498	[SSPP_DMA4] = { { 4, 0      }, { 4, 8 } },
499	[SSPP_DMA5] = { { 4, 4      }, { 4, 12 } },
500	[SSPP_CURSOR0] =  { { 1, 20 }, { -1 } },
501	[SSPP_CURSOR1] =  { { 1, 26 }, { -1 } },
502};
503
504static void dpu_hw_ctl_setup_blendstage(struct dpu_hw_ctl *ctx,
505	enum dpu_lm lm, struct dpu_hw_stage_cfg *stage_cfg)
506{
507	struct dpu_hw_blk_reg_map *c = &ctx->hw;
508	u32 mix, ext, mix_ext;
509	u32 mixercfg[5] = { 0 };
510	int i, j;
511	int stages;
512	int pipes_per_stage;
513
514	stages = _mixer_stages(ctx->mixer_hw_caps, ctx->mixer_count, lm);
515	if (stages < 0)
516		return;
517
518	if (test_bit(DPU_MIXER_SOURCESPLIT,
519		&ctx->mixer_hw_caps->features))
520		pipes_per_stage = PIPES_PER_STAGE;
521	else
522		pipes_per_stage = 1;
523
524	mixercfg[0] = CTL_MIXER_BORDER_OUT; /* always set BORDER_OUT */
525
526	if (!stage_cfg)
527		goto exit;
528
529	for (i = 0; i <= stages; i++) {
530		/* overflow to ext register if 'i + 1 > 7' */
531		mix = (i + 1) & 0x7;
532		ext = i >= 7;
533		mix_ext = (i + 1) & 0xf;
534
535		for (j = 0 ; j < pipes_per_stage; j++) {
536			enum dpu_sspp_multirect_index rect_index =
537				stage_cfg->multirect_index[i][j];
538			enum dpu_sspp pipe = stage_cfg->stage[i][j];
539			const struct ctl_blend_config *cfg =
540				&ctl_blend_config[pipe][rect_index == DPU_SSPP_RECT_1];
541
542			/*
543			 * CTL_LAYER has 3-bit field (and extra bits in EXT register),
544			 * all EXT registers has 4-bit fields.
545			 */
546			if (cfg->idx == -1) {
547				continue;
548			} else if (cfg->idx == 0) {
549				mixercfg[0] |= mix << cfg->shift;
550				mixercfg[1] |= ext << cfg->ext_shift;
551			} else {
552				mixercfg[cfg->idx] |= mix_ext << cfg->shift;
553			}
554		}
555	}
556
557exit:
558	DPU_REG_WRITE(c, CTL_LAYER(lm), mixercfg[0]);
559	DPU_REG_WRITE(c, CTL_LAYER_EXT(lm), mixercfg[1]);
560	DPU_REG_WRITE(c, CTL_LAYER_EXT2(lm), mixercfg[2]);
561	DPU_REG_WRITE(c, CTL_LAYER_EXT3(lm), mixercfg[3]);
562	if (ctx->mdss_ver->core_major_ver >= 9)
563		DPU_REG_WRITE(c, CTL_LAYER_EXT4(lm), mixercfg[4]);
564}
565
566
567static void dpu_hw_ctl_intf_cfg_v1(struct dpu_hw_ctl *ctx,
568		struct dpu_hw_intf_cfg *cfg)
569{
570	struct dpu_hw_blk_reg_map *c = &ctx->hw;
571	u32 intf_active = 0;
572	u32 dsc_active = 0;
573	u32 wb_active = 0;
574	u32 cwb_active = 0;
575	u32 mode_sel = 0;
576	u32 merge_3d_active = 0;
577
578	/* CTL_TOP[31:28] carries group_id to collate CTL paths
579	 * per VM. Explicitly disable it until VM support is
580	 * added in SW. Power on reset value is not disable.
581	 */
582	if (ctx->mdss_ver->core_major_ver >= 7)
583		mode_sel = CTL_DEFAULT_GROUP_ID  << 28;
584
585	if (cfg->intf_mode_sel == DPU_CTL_MODE_SEL_CMD)
586		mode_sel |= BIT(17);
587
588	intf_active = DPU_REG_READ(c, CTL_INTF_ACTIVE);
589	wb_active = DPU_REG_READ(c, CTL_WB_ACTIVE);
590	cwb_active = DPU_REG_READ(c, CTL_CWB_ACTIVE);
591	dsc_active = DPU_REG_READ(c, CTL_DSC_ACTIVE);
592	merge_3d_active = DPU_REG_READ(c, CTL_MERGE_3D_ACTIVE);
593
594	if (cfg->intf)
595		intf_active |= BIT(cfg->intf - INTF_0);
596
597	if (cfg->wb)
598		wb_active |= BIT(cfg->wb - WB_0);
599
600	if (cfg->cwb)
601		cwb_active |= cfg->cwb;
602
603	if (cfg->dsc)
604		dsc_active |= cfg->dsc;
605
606	if (cfg->merge_3d)
607		merge_3d_active |= BIT(cfg->merge_3d - MERGE_3D_0);
608
609	DPU_REG_WRITE(c, CTL_TOP, mode_sel);
610	DPU_REG_WRITE(c, CTL_INTF_ACTIVE, intf_active);
611	DPU_REG_WRITE(c, CTL_WB_ACTIVE, wb_active);
612	DPU_REG_WRITE(c, CTL_CWB_ACTIVE, cwb_active);
613	DPU_REG_WRITE(c, CTL_DSC_ACTIVE, dsc_active);
614	DPU_REG_WRITE(c, CTL_MERGE_3D_ACTIVE, merge_3d_active);
615
616	if (cfg->intf_master)
617		DPU_REG_WRITE(c, CTL_INTF_MASTER, BIT(cfg->intf_master - INTF_0));
618
619	if (cfg->cdm)
620		DPU_REG_WRITE(c, CTL_CDM_ACTIVE, cfg->cdm);
621}
622
623static void dpu_hw_ctl_intf_cfg(struct dpu_hw_ctl *ctx,
624		struct dpu_hw_intf_cfg *cfg)
625{
626	struct dpu_hw_blk_reg_map *c = &ctx->hw;
627	u32 intf_cfg = 0;
628
629	intf_cfg |= (cfg->intf & 0xF) << 4;
630
631	if (cfg->mode_3d) {
632		intf_cfg |= BIT(19);
633		intf_cfg |= (cfg->mode_3d - 0x1) << 20;
634	}
635
636	if (cfg->wb)
637		intf_cfg |= (cfg->wb & 0x3) + 2;
638
639	switch (cfg->intf_mode_sel) {
640	case DPU_CTL_MODE_SEL_VID:
641		intf_cfg &= ~BIT(17);
642		intf_cfg &= ~(0x3 << 15);
643		break;
644	case DPU_CTL_MODE_SEL_CMD:
645		intf_cfg |= BIT(17);
646		intf_cfg |= ((cfg->stream_sel & 0x3) << 15);
647		break;
648	default:
649		pr_err("unknown interface type %d\n", cfg->intf_mode_sel);
650		return;
651	}
652
653	DPU_REG_WRITE(c, CTL_TOP, intf_cfg);
654}
655
656static void dpu_hw_ctl_reset_intf_cfg_v1(struct dpu_hw_ctl *ctx,
657		struct dpu_hw_intf_cfg *cfg)
658{
659	struct dpu_hw_blk_reg_map *c = &ctx->hw;
660	u32 intf_active = 0;
661	u32 intf_master = 0;
662	u32 wb_active = 0;
663	u32 cwb_active = 0;
664	u32 merge3d_active = 0;
665	u32 dsc_active;
666	u32 cdm_active;
667
668	/*
669	 * This API resets each portion of the CTL path namely,
670	 * clearing the sspps staged on the lm, merge_3d block,
671	 * interfaces , writeback etc to ensure clean teardown of the pipeline.
672	 * This will be used for writeback to begin with to have a
673	 * proper teardown of the writeback session but upon further
674	 * validation, this can be extended to all interfaces.
675	 */
676	if (cfg->merge_3d) {
677		merge3d_active = DPU_REG_READ(c, CTL_MERGE_3D_ACTIVE);
678		merge3d_active &= ~BIT(cfg->merge_3d - MERGE_3D_0);
679		DPU_REG_WRITE(c, CTL_MERGE_3D_ACTIVE,
680				merge3d_active);
681	}
682
683	if (ctx->ops.clear_all_blendstages)
684		ctx->ops.clear_all_blendstages(ctx);
685
686	if (ctx->ops.set_active_lms)
687		ctx->ops.set_active_lms(ctx, NULL);
688
689	if (ctx->ops.set_active_fetch_pipes)
690		ctx->ops.set_active_fetch_pipes(ctx, NULL);
691
692	if (ctx->ops.set_active_pipes)
693		ctx->ops.set_active_pipes(ctx, NULL);
694
695	if (cfg->intf) {
696		intf_active = DPU_REG_READ(c, CTL_INTF_ACTIVE);
697		intf_active &= ~BIT(cfg->intf - INTF_0);
698		DPU_REG_WRITE(c, CTL_INTF_ACTIVE, intf_active);
699
700		intf_master = DPU_REG_READ(c, CTL_INTF_MASTER);
701
702		/* Unset this intf as master, if it is the current master */
703		if (intf_master == BIT(cfg->intf - INTF_0)) {
704			DPU_DEBUG_DRIVER("Unsetting INTF_%d master\n", cfg->intf - INTF_0);
705			DPU_REG_WRITE(c, CTL_INTF_MASTER, 0);
706		}
707	}
708
709	if (cfg->cwb) {
710		cwb_active = DPU_REG_READ(c, CTL_CWB_ACTIVE);
711		cwb_active &= ~cfg->cwb;
712		DPU_REG_WRITE(c, CTL_CWB_ACTIVE, cwb_active);
713	}
714
715	if (cfg->wb) {
716		wb_active = DPU_REG_READ(c, CTL_WB_ACTIVE);
717		wb_active &= ~BIT(cfg->wb - WB_0);
718		DPU_REG_WRITE(c, CTL_WB_ACTIVE, wb_active);
719	}
720
721	if (cfg->dsc) {
722		dsc_active = DPU_REG_READ(c, CTL_DSC_ACTIVE);
723		dsc_active &= ~cfg->dsc;
724		DPU_REG_WRITE(c, CTL_DSC_ACTIVE, dsc_active);
725	}
726
727	if (cfg->cdm) {
728		cdm_active = DPU_REG_READ(c, CTL_CDM_ACTIVE);
729		cdm_active &= ~cfg->cdm;
730		DPU_REG_WRITE(c, CTL_CDM_ACTIVE, cdm_active);
731	}
732}
733
734static void dpu_hw_ctl_set_active_fetch_pipes(struct dpu_hw_ctl *ctx,
735					      unsigned long *fetch_active)
736{
737	int i;
738	u32 val = 0;
739
740	if (fetch_active) {
741		for (i = 0; i < SSPP_MAX; i++) {
742			if (test_bit(i, fetch_active) &&
743				fetch_tbl[i] != CTL_INVALID_BIT)
744				val |= BIT(fetch_tbl[i]);
745		}
746	}
747
748	DPU_REG_WRITE(&ctx->hw, CTL_FETCH_PIPE_ACTIVE, val);
749}
750
751static void dpu_hw_ctl_set_active_pipes(struct dpu_hw_ctl *ctx,
752					unsigned long *active_pipes)
753{
754	int i;
755	u32 val = 0;
756
757	if (active_pipes) {
758		for (i = 0; i < SSPP_MAX; i++) {
759			if (test_bit(i, active_pipes) &&
760			    fetch_tbl[i] != CTL_INVALID_BIT)
761				val |= BIT(fetch_tbl[i]);
762		}
763	}
764
765	DPU_REG_WRITE(&ctx->hw, CTL_PIPE_ACTIVE, val);
766}
767
768static void dpu_hw_ctl_set_active_lms(struct dpu_hw_ctl *ctx,
769				      unsigned long *active_lms)
770{
771	int i;
772	u32 val = 0;
773
774	if (active_lms) {
775		for (i = LM_0; i < LM_MAX; i++) {
776			if (test_bit(i, active_lms) &&
777			    lm_tbl[i] != CTL_INVALID_BIT)
778				val |= BIT(lm_tbl[i]);
779		}
780	}
781
782	DPU_REG_WRITE(&ctx->hw, CTL_LAYER_ACTIVE, val);
783}
784
785/**
786 * dpu_hw_ctl_init() - Initializes the ctl_path hw driver object.
787 * Should be called before accessing any ctl_path register.
788 * @dev:  Corresponding device for devres management
789 * @cfg:  ctl_path catalog entry for which driver object is required
790 * @addr: mapped register io address of MDP
791 * @mdss_ver: dpu core's major and minor versions
792 * @mixer_count: Number of mixers in @mixer
793 * @mixer: Pointer to an array of Layer Mixers defined in the catalog
794 */
795struct dpu_hw_ctl *dpu_hw_ctl_init(struct drm_device *dev,
796				   const struct dpu_ctl_cfg *cfg,
797				   void __iomem *addr,
798				   const struct dpu_mdss_version *mdss_ver,
799				   u32 mixer_count,
800				   const struct dpu_lm_cfg *mixer)
801{
802	struct dpu_hw_ctl *c;
803
804	c = drmm_kzalloc(dev, sizeof(*c), GFP_KERNEL);
805	if (!c)
806		return ERR_PTR(-ENOMEM);
807
808	c->hw.blk_addr = addr + cfg->base;
809	c->hw.log_mask = DPU_DBG_MASK_CTL;
810
811	c->caps = cfg;
812	c->mdss_ver = mdss_ver;
813
814	if (mdss_ver->core_major_ver >= 5) {
815		c->ops.trigger_flush = dpu_hw_ctl_trigger_flush_v1;
816		c->ops.setup_intf_cfg = dpu_hw_ctl_intf_cfg_v1;
817		c->ops.reset_intf_cfg = dpu_hw_ctl_reset_intf_cfg_v1;
818		c->ops.update_pending_flush_intf =
819			dpu_hw_ctl_update_pending_flush_intf_v1;
820
821		c->ops.update_pending_flush_periph =
822			dpu_hw_ctl_update_pending_flush_periph_v1;
823
824		c->ops.update_pending_flush_merge_3d =
825			dpu_hw_ctl_update_pending_flush_merge_3d_v1;
826		c->ops.update_pending_flush_wb = dpu_hw_ctl_update_pending_flush_wb_v1;
827		c->ops.update_pending_flush_cwb = dpu_hw_ctl_update_pending_flush_cwb_v1;
828		c->ops.update_pending_flush_dsc =
829			dpu_hw_ctl_update_pending_flush_dsc_v1;
830		c->ops.update_pending_flush_cdm = dpu_hw_ctl_update_pending_flush_cdm_v1;
831	} else {
832		c->ops.trigger_flush = dpu_hw_ctl_trigger_flush;
833		c->ops.setup_intf_cfg = dpu_hw_ctl_intf_cfg;
834		c->ops.update_pending_flush_intf =
835			dpu_hw_ctl_update_pending_flush_intf;
836		c->ops.update_pending_flush_wb = dpu_hw_ctl_update_pending_flush_wb;
837		c->ops.update_pending_flush_cdm = dpu_hw_ctl_update_pending_flush_cdm;
838	}
839	c->ops.clear_pending_flush = dpu_hw_ctl_clear_pending_flush;
840	c->ops.update_pending_flush = dpu_hw_ctl_update_pending_flush;
841	c->ops.get_pending_flush = dpu_hw_ctl_get_pending_flush;
842	c->ops.get_flush_register = dpu_hw_ctl_get_flush_register;
843	c->ops.trigger_start = dpu_hw_ctl_trigger_start;
844	c->ops.is_started = dpu_hw_ctl_is_started;
845	c->ops.trigger_pending = dpu_hw_ctl_trigger_pending;
846	c->ops.reset = dpu_hw_ctl_reset_control;
847	c->ops.wait_reset_status = dpu_hw_ctl_wait_reset_status;
848	if (mdss_ver->core_major_ver < 12) {
849		c->ops.clear_all_blendstages = dpu_hw_ctl_clear_all_blendstages;
850		c->ops.setup_blendstage = dpu_hw_ctl_setup_blendstage;
851	} else {
852		c->ops.set_active_pipes = dpu_hw_ctl_set_active_pipes;
853		c->ops.set_active_lms = dpu_hw_ctl_set_active_lms;
854	}
855	c->ops.update_pending_flush_sspp = dpu_hw_ctl_update_pending_flush_sspp;
856	c->ops.update_pending_flush_mixer = dpu_hw_ctl_update_pending_flush_mixer;
857	if (mdss_ver->core_major_ver >= 7)
858		c->ops.update_pending_flush_dspp = dpu_hw_ctl_update_pending_flush_dspp_sub_blocks;
859	else
860		c->ops.update_pending_flush_dspp = dpu_hw_ctl_update_pending_flush_dspp;
861
862	if (mdss_ver->core_major_ver >= 7)
863		c->ops.set_active_fetch_pipes = dpu_hw_ctl_set_active_fetch_pipes;
864
865	c->idx = cfg->id;
866	c->mixer_count = mixer_count;
867	c->mixer_hw_caps = mixer;
868
869	return c;
870}
~/ Read-only file preview.