xref: /linux/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.c (revision fbf5df34a4dbcd09d433dd4f0916bf9b2ddb16de)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved.
4  */
5 
6 #include <linux/string_choices.h>
7 #include "mdp5_kms.h"
8 #include "mdp5_ctl.h"
9 
10 /*
11  * CTL - MDP Control Pool Manager
12  *
13  * Controls are shared between all display interfaces.
14  *
15  * They are intended to be used for data path configuration.
16  * The top level register programming describes the complete data path for
17  * a specific data path ID - REG_MDP5_CTL_*(<id>, ...)
18  *
19  * Hardware capabilities determine the number of concurrent data paths
20  */
21 
22 #define CTL_STAT_BUSY		0x1
23 #define CTL_STAT_BOOKED	0x2
24 
25 struct mdp5_ctl {
26 	struct mdp5_ctl_manager *ctlm;
27 
28 	u32 id;
29 
30 	/* CTL status bitmask */
31 	u32 status;
32 
33 	bool encoder_enabled;
34 
35 	/* pending flush_mask bits */
36 	u32 flush_mask;
37 
38 	/* REG_MDP5_CTL_*(<id>) registers access info + lock: */
39 	spinlock_t hw_lock;
40 	u32 reg_offset;
41 
42 	/* when do CTL registers need to be flushed? (mask of trigger bits) */
43 	u32 pending_ctl_trigger;
44 
45 	bool cursor_on;
46 };
47 
48 struct mdp5_ctl_manager {
49 	struct drm_device *dev;
50 
51 	/* number of CTL / Layer Mixers in this hw config: */
52 	u32 nlm;
53 	u32 nctl;
54 
55 	/* to filter out non-present bits in the current hardware config */
56 	u32 flush_hw_mask;
57 
58 	/* pool of CTLs + lock to protect resource allocation (ctls[i].busy) */
59 	spinlock_t pool_lock;
60 	struct mdp5_ctl ctls[MAX_CTL];
61 };
62 
63 static inline
64 struct mdp5_kms *get_kms(struct mdp5_ctl_manager *ctl_mgr)
65 {
66 	struct msm_drm_private *priv = ctl_mgr->dev->dev_private;
67 
68 	return to_mdp5_kms(to_mdp_kms(priv->kms));
69 }
70 
71 static inline
72 void ctl_write(struct mdp5_ctl *ctl, u32 reg, u32 data)
73 {
74 	struct mdp5_kms *mdp5_kms = get_kms(ctl->ctlm);
75 
76 	(void)ctl->reg_offset; /* TODO use this instead of mdp5_write */
77 	mdp5_write(mdp5_kms, reg, data);
78 }
79 
80 static inline
81 u32 ctl_read(struct mdp5_ctl *ctl, u32 reg)
82 {
83 	struct mdp5_kms *mdp5_kms = get_kms(ctl->ctlm);
84 
85 	(void)ctl->reg_offset; /* TODO use this instead of mdp5_write */
86 	return mdp5_read(mdp5_kms, reg);
87 }
88 
89 static void set_display_intf(struct mdp5_kms *mdp5_kms,
90 		struct mdp5_interface *intf)
91 {
92 	unsigned long flags;
93 	u32 intf_sel;
94 
95 	spin_lock_irqsave(&mdp5_kms->resource_lock, flags);
96 	intf_sel = mdp5_read(mdp5_kms, REG_MDP5_DISP_INTF_SEL);
97 
98 	switch (intf->num) {
99 	case 0:
100 		intf_sel &= ~MDP5_DISP_INTF_SEL_INTF0__MASK;
101 		intf_sel |= MDP5_DISP_INTF_SEL_INTF0(intf->type);
102 		break;
103 	case 1:
104 		intf_sel &= ~MDP5_DISP_INTF_SEL_INTF1__MASK;
105 		intf_sel |= MDP5_DISP_INTF_SEL_INTF1(intf->type);
106 		break;
107 	case 2:
108 		intf_sel &= ~MDP5_DISP_INTF_SEL_INTF2__MASK;
109 		intf_sel |= MDP5_DISP_INTF_SEL_INTF2(intf->type);
110 		break;
111 	case 3:
112 		intf_sel &= ~MDP5_DISP_INTF_SEL_INTF3__MASK;
113 		intf_sel |= MDP5_DISP_INTF_SEL_INTF3(intf->type);
114 		break;
115 	default:
116 		BUG();
117 		break;
118 	}
119 
120 	mdp5_write(mdp5_kms, REG_MDP5_DISP_INTF_SEL, intf_sel);
121 	spin_unlock_irqrestore(&mdp5_kms->resource_lock, flags);
122 }
123 
124 static void set_ctl_op(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline)
125 {
126 	unsigned long flags;
127 	struct mdp5_interface *intf = pipeline->intf;
128 	u32 ctl_op = 0;
129 
130 	if (!mdp5_cfg_intf_is_virtual(intf->type))
131 		ctl_op |= MDP5_CTL_OP_INTF_NUM(INTF0 + intf->num);
132 
133 	switch (intf->type) {
134 	case INTF_DSI:
135 		if (intf->mode == MDP5_INTF_DSI_MODE_COMMAND)
136 			ctl_op |= MDP5_CTL_OP_CMD_MODE;
137 		break;
138 
139 	case INTF_WB:
140 		if (intf->mode == MDP5_INTF_WB_MODE_LINE)
141 			ctl_op |= MDP5_CTL_OP_MODE(MODE_WB_2_LINE);
142 		break;
143 
144 	default:
145 		break;
146 	}
147 
148 	if (pipeline->r_mixer)
149 		ctl_op |= MDP5_CTL_OP_PACK_3D_ENABLE |
150 			  MDP5_CTL_OP_PACK_3D(1);
151 
152 	spin_lock_irqsave(&ctl->hw_lock, flags);
153 	ctl_write(ctl, REG_MDP5_CTL_OP(ctl->id), ctl_op);
154 	spin_unlock_irqrestore(&ctl->hw_lock, flags);
155 }
156 
157 int mdp5_ctl_set_pipeline(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline)
158 {
159 	struct mdp5_kms *mdp5_kms = get_kms(ctl->ctlm);
160 	struct mdp5_interface *intf = pipeline->intf;
161 
162 	/* Virtual interfaces need not set a display intf (e.g.: Writeback) */
163 	if (!mdp5_cfg_intf_is_virtual(intf->type))
164 		set_display_intf(mdp5_kms, intf);
165 
166 	set_ctl_op(ctl, pipeline);
167 
168 	return 0;
169 }
170 
171 static bool start_signal_needed(struct mdp5_ctl *ctl,
172 				struct mdp5_pipeline *pipeline)
173 {
174 	struct mdp5_interface *intf = pipeline->intf;
175 
176 	if (!ctl->encoder_enabled)
177 		return false;
178 
179 	switch (intf->type) {
180 	case INTF_WB:
181 		return true;
182 	case INTF_DSI:
183 		return intf->mode == MDP5_INTF_DSI_MODE_COMMAND;
184 	default:
185 		return false;
186 	}
187 }
188 
189 /*
190  * send_start_signal() - Overlay Processor Start Signal
191  *
192  * For a given control operation (display pipeline), a START signal needs to be
193  * executed in order to kick off operation and activate all layers.
194  * e.g.: DSI command mode, Writeback
195  */
196 static void send_start_signal(struct mdp5_ctl *ctl)
197 {
198 	unsigned long flags;
199 
200 	spin_lock_irqsave(&ctl->hw_lock, flags);
201 	ctl_write(ctl, REG_MDP5_CTL_START(ctl->id), 1);
202 	spin_unlock_irqrestore(&ctl->hw_lock, flags);
203 }
204 
205 /**
206  * mdp5_ctl_set_encoder_state() - set the encoder state
207  *
208  * @ctl:      the CTL instance
209  * @pipeline: the encoder's INTF + MIXER configuration
210  * @enabled:  true, when encoder is ready for data streaming; false, otherwise.
211  *
212  * Note:
213  * This encoder state is needed to trigger START signal (data path kickoff).
214  */
215 int mdp5_ctl_set_encoder_state(struct mdp5_ctl *ctl,
216 			       struct mdp5_pipeline *pipeline,
217 			       bool enabled)
218 {
219 	struct mdp5_interface *intf = pipeline->intf;
220 
221 	if (WARN_ON(!ctl))
222 		return -EINVAL;
223 
224 	ctl->encoder_enabled = enabled;
225 	DBG("intf_%d: %s", intf->num, str_on_off(enabled));
226 
227 	if (start_signal_needed(ctl, pipeline)) {
228 		send_start_signal(ctl);
229 	}
230 
231 	return 0;
232 }
233 
234 /*
235  * Note:
236  * CTL registers need to be flushed after calling this function
237  * (call mdp5_ctl_commit() with mdp_ctl_flush_mask_ctl() mask)
238  */
239 int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline,
240 			int cursor_id, bool enable)
241 {
242 	struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
243 	unsigned long flags;
244 	u32 blend_cfg;
245 	struct mdp5_hw_mixer *mixer = pipeline->mixer;
246 
247 	if (WARN_ON(!mixer)) {
248 		DRM_DEV_ERROR(ctl_mgr->dev->dev, "CTL %d cannot find LM",
249 			ctl->id);
250 		return -EINVAL;
251 	}
252 
253 	if (pipeline->r_mixer) {
254 		DRM_DEV_ERROR(ctl_mgr->dev->dev, "unsupported configuration");
255 		return -EINVAL;
256 	}
257 
258 	spin_lock_irqsave(&ctl->hw_lock, flags);
259 
260 	blend_cfg = ctl_read(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, mixer->lm));
261 
262 	if (enable)
263 		blend_cfg |=  MDP5_CTL_LAYER_REG_CURSOR_OUT;
264 	else
265 		blend_cfg &= ~MDP5_CTL_LAYER_REG_CURSOR_OUT;
266 
267 	ctl_write(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, mixer->lm), blend_cfg);
268 	ctl->cursor_on = enable;
269 
270 	spin_unlock_irqrestore(&ctl->hw_lock, flags);
271 
272 	ctl->pending_ctl_trigger = mdp_ctl_flush_mask_cursor(cursor_id);
273 
274 	return 0;
275 }
276 
277 static u32 mdp_ctl_blend_mask(enum mdp5_pipe pipe,
278 		enum mdp_mixer_stage_id stage)
279 {
280 	switch (pipe) {
281 	case SSPP_VIG0: return MDP5_CTL_LAYER_REG_VIG0(stage);
282 	case SSPP_VIG1: return MDP5_CTL_LAYER_REG_VIG1(stage);
283 	case SSPP_VIG2: return MDP5_CTL_LAYER_REG_VIG2(stage);
284 	case SSPP_RGB0: return MDP5_CTL_LAYER_REG_RGB0(stage);
285 	case SSPP_RGB1: return MDP5_CTL_LAYER_REG_RGB1(stage);
286 	case SSPP_RGB2: return MDP5_CTL_LAYER_REG_RGB2(stage);
287 	case SSPP_DMA0: return MDP5_CTL_LAYER_REG_DMA0(stage);
288 	case SSPP_DMA1: return MDP5_CTL_LAYER_REG_DMA1(stage);
289 	case SSPP_VIG3: return MDP5_CTL_LAYER_REG_VIG3(stage);
290 	case SSPP_RGB3: return MDP5_CTL_LAYER_REG_RGB3(stage);
291 	case SSPP_CURSOR0:
292 	case SSPP_CURSOR1:
293 	default:	return 0;
294 	}
295 }
296 
297 static u32 mdp_ctl_blend_ext_mask(enum mdp5_pipe pipe,
298 		enum mdp_mixer_stage_id stage)
299 {
300 	if (stage < STAGE6 && (pipe != SSPP_CURSOR0 && pipe != SSPP_CURSOR1))
301 		return 0;
302 
303 	switch (pipe) {
304 	case SSPP_VIG0: return MDP5_CTL_LAYER_EXT_REG_VIG0_BIT3;
305 	case SSPP_VIG1: return MDP5_CTL_LAYER_EXT_REG_VIG1_BIT3;
306 	case SSPP_VIG2: return MDP5_CTL_LAYER_EXT_REG_VIG2_BIT3;
307 	case SSPP_RGB0: return MDP5_CTL_LAYER_EXT_REG_RGB0_BIT3;
308 	case SSPP_RGB1: return MDP5_CTL_LAYER_EXT_REG_RGB1_BIT3;
309 	case SSPP_RGB2: return MDP5_CTL_LAYER_EXT_REG_RGB2_BIT3;
310 	case SSPP_DMA0: return MDP5_CTL_LAYER_EXT_REG_DMA0_BIT3;
311 	case SSPP_DMA1: return MDP5_CTL_LAYER_EXT_REG_DMA1_BIT3;
312 	case SSPP_VIG3: return MDP5_CTL_LAYER_EXT_REG_VIG3_BIT3;
313 	case SSPP_RGB3: return MDP5_CTL_LAYER_EXT_REG_RGB3_BIT3;
314 	case SSPP_CURSOR0: return MDP5_CTL_LAYER_EXT_REG_CURSOR0(stage);
315 	case SSPP_CURSOR1: return MDP5_CTL_LAYER_EXT_REG_CURSOR1(stage);
316 	default:	return 0;
317 	}
318 }
319 
320 static void mdp5_ctl_reset_blend_regs(struct mdp5_ctl *ctl)
321 {
322 	unsigned long flags;
323 	struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
324 	int i;
325 
326 	spin_lock_irqsave(&ctl->hw_lock, flags);
327 
328 	for (i = 0; i < ctl_mgr->nlm; i++) {
329 		ctl_write(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, i), 0x0);
330 		ctl_write(ctl, REG_MDP5_CTL_LAYER_EXT_REG(ctl->id, i), 0x0);
331 	}
332 
333 	spin_unlock_irqrestore(&ctl->hw_lock, flags);
334 }
335 
336 #define PIPE_LEFT	0
337 #define PIPE_RIGHT	1
338 int mdp5_ctl_blend(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline,
339 		   enum mdp5_pipe stage[][MAX_PIPE_STAGE],
340 		   enum mdp5_pipe r_stage[][MAX_PIPE_STAGE],
341 		   u32 stage_cnt, u32 ctl_blend_op_flags)
342 {
343 	struct mdp5_hw_mixer *mixer = pipeline->mixer;
344 	struct mdp5_hw_mixer *r_mixer = pipeline->r_mixer;
345 	unsigned long flags;
346 	u32 blend_cfg = 0, blend_ext_cfg = 0;
347 	u32 r_blend_cfg = 0, r_blend_ext_cfg = 0;
348 	int i, start_stage;
349 
350 	mdp5_ctl_reset_blend_regs(ctl);
351 
352 	if (ctl_blend_op_flags & MDP5_CTL_BLEND_OP_FLAG_BORDER_OUT) {
353 		start_stage = STAGE0;
354 		blend_cfg |= MDP5_CTL_LAYER_REG_BORDER_COLOR;
355 		if (r_mixer)
356 			r_blend_cfg |= MDP5_CTL_LAYER_REG_BORDER_COLOR;
357 	} else {
358 		start_stage = STAGE_BASE;
359 	}
360 
361 	for (i = start_stage; stage_cnt && i <= STAGE_MAX; i++) {
362 		blend_cfg |=
363 			mdp_ctl_blend_mask(stage[i][PIPE_LEFT], i) |
364 			mdp_ctl_blend_mask(stage[i][PIPE_RIGHT], i);
365 		blend_ext_cfg |=
366 			mdp_ctl_blend_ext_mask(stage[i][PIPE_LEFT], i) |
367 			mdp_ctl_blend_ext_mask(stage[i][PIPE_RIGHT], i);
368 		if (r_mixer) {
369 			r_blend_cfg |=
370 				mdp_ctl_blend_mask(r_stage[i][PIPE_LEFT], i) |
371 				mdp_ctl_blend_mask(r_stage[i][PIPE_RIGHT], i);
372 			r_blend_ext_cfg |=
373 			     mdp_ctl_blend_ext_mask(r_stage[i][PIPE_LEFT], i) |
374 			     mdp_ctl_blend_ext_mask(r_stage[i][PIPE_RIGHT], i);
375 		}
376 	}
377 
378 	spin_lock_irqsave(&ctl->hw_lock, flags);
379 	if (ctl->cursor_on)
380 		blend_cfg |=  MDP5_CTL_LAYER_REG_CURSOR_OUT;
381 
382 	ctl_write(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, mixer->lm), blend_cfg);
383 	ctl_write(ctl, REG_MDP5_CTL_LAYER_EXT_REG(ctl->id, mixer->lm),
384 		  blend_ext_cfg);
385 	if (r_mixer) {
386 		ctl_write(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, r_mixer->lm),
387 			  r_blend_cfg);
388 		ctl_write(ctl, REG_MDP5_CTL_LAYER_EXT_REG(ctl->id, r_mixer->lm),
389 			  r_blend_ext_cfg);
390 	}
391 	spin_unlock_irqrestore(&ctl->hw_lock, flags);
392 
393 	ctl->pending_ctl_trigger = mdp_ctl_flush_mask_lm(mixer->lm);
394 	if (r_mixer)
395 		ctl->pending_ctl_trigger |= mdp_ctl_flush_mask_lm(r_mixer->lm);
396 
397 	DBG("lm%d: blend config = 0x%08x. ext_cfg = 0x%08x", mixer->lm,
398 		blend_cfg, blend_ext_cfg);
399 	if (r_mixer)
400 		DBG("lm%d: blend config = 0x%08x. ext_cfg = 0x%08x",
401 		    r_mixer->lm, r_blend_cfg, r_blend_ext_cfg);
402 
403 	return 0;
404 }
405 
406 u32 mdp_ctl_flush_mask_encoder(struct mdp5_interface *intf)
407 {
408 	if (intf->type == INTF_WB)
409 		return MDP5_CTL_FLUSH_WB;
410 
411 	switch (intf->num) {
412 	case 0: return MDP5_CTL_FLUSH_TIMING_0;
413 	case 1: return MDP5_CTL_FLUSH_TIMING_1;
414 	case 2: return MDP5_CTL_FLUSH_TIMING_2;
415 	case 3: return MDP5_CTL_FLUSH_TIMING_3;
416 	default: return 0;
417 	}
418 }
419 
420 u32 mdp_ctl_flush_mask_cursor(int cursor_id)
421 {
422 	switch (cursor_id) {
423 	case 0: return MDP5_CTL_FLUSH_CURSOR_0;
424 	case 1: return MDP5_CTL_FLUSH_CURSOR_1;
425 	default: return 0;
426 	}
427 }
428 
429 u32 mdp_ctl_flush_mask_pipe(enum mdp5_pipe pipe)
430 {
431 	switch (pipe) {
432 	case SSPP_VIG0: return MDP5_CTL_FLUSH_VIG0;
433 	case SSPP_VIG1: return MDP5_CTL_FLUSH_VIG1;
434 	case SSPP_VIG2: return MDP5_CTL_FLUSH_VIG2;
435 	case SSPP_RGB0: return MDP5_CTL_FLUSH_RGB0;
436 	case SSPP_RGB1: return MDP5_CTL_FLUSH_RGB1;
437 	case SSPP_RGB2: return MDP5_CTL_FLUSH_RGB2;
438 	case SSPP_DMA0: return MDP5_CTL_FLUSH_DMA0;
439 	case SSPP_DMA1: return MDP5_CTL_FLUSH_DMA1;
440 	case SSPP_VIG3: return MDP5_CTL_FLUSH_VIG3;
441 	case SSPP_RGB3: return MDP5_CTL_FLUSH_RGB3;
442 	case SSPP_CURSOR0: return MDP5_CTL_FLUSH_CURSOR_0;
443 	case SSPP_CURSOR1: return MDP5_CTL_FLUSH_CURSOR_1;
444 	default:        return 0;
445 	}
446 }
447 
448 u32 mdp_ctl_flush_mask_lm(int lm)
449 {
450 	switch (lm) {
451 	case 0:  return MDP5_CTL_FLUSH_LM0;
452 	case 1:  return MDP5_CTL_FLUSH_LM1;
453 	case 2:  return MDP5_CTL_FLUSH_LM2;
454 	case 3:  return MDP5_CTL_FLUSH_LM3;
455 	case 4:  return MDP5_CTL_FLUSH_LM4;
456 	case 5:  return MDP5_CTL_FLUSH_LM5;
457 	default: return 0;
458 	}
459 }
460 
461 static u32 fix_sw_flush(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline,
462 			u32 flush_mask)
463 {
464 	struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
465 	u32 sw_mask = 0;
466 #define BIT_NEEDS_SW_FIX(bit) \
467 	(!(ctl_mgr->flush_hw_mask & bit) && (flush_mask & bit))
468 
469 	/* for some targets, cursor bit is the same as LM bit */
470 	if (BIT_NEEDS_SW_FIX(MDP5_CTL_FLUSH_CURSOR_0))
471 		sw_mask |= mdp_ctl_flush_mask_lm(pipeline->mixer->lm);
472 
473 	return sw_mask;
474 }
475 
476 /**
477  * mdp5_ctl_commit() - Register Flush
478  *
479  * @ctl:        the CTL instance
480  * @pipeline:   the encoder's INTF + MIXER configuration
481  * @flush_mask: bitmask of display controller hw blocks to flush
482  * @start:      if true, immediately update flush registers and set START
483  *              bit, otherwise accumulate flush_mask bits until we are
484  *              ready to START
485  *
486  * The flush register is used to indicate several registers are all
487  * programmed, and are safe to update to the back copy of the double
488  * buffered registers.
489  *
490  * Some registers FLUSH bits are shared when the hardware does not have
491  * dedicated bits for them; handling these is the job of fix_sw_flush().
492  *
493  * CTL registers need to be flushed in some circumstances; if that is the
494  * case, some trigger bits will be present in both flush mask and
495  * ctl->pending_ctl_trigger.
496  *
497  * Return H/W flushed bit mask.
498  */
499 u32 mdp5_ctl_commit(struct mdp5_ctl *ctl,
500 		    struct mdp5_pipeline *pipeline,
501 		    u32 flush_mask, bool start)
502 {
503 	struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
504 	unsigned long flags;
505 	u32 flush_id = ctl->id;
506 	u32 curr_ctl_flush_mask;
507 
508 	VERB("flush_mask=%x, trigger=%x", flush_mask, ctl->pending_ctl_trigger);
509 
510 	if (ctl->pending_ctl_trigger & flush_mask) {
511 		flush_mask |= MDP5_CTL_FLUSH_CTL;
512 		ctl->pending_ctl_trigger = 0;
513 	}
514 
515 	flush_mask |= fix_sw_flush(ctl, pipeline, flush_mask);
516 
517 	flush_mask &= ctl_mgr->flush_hw_mask;
518 
519 	curr_ctl_flush_mask = flush_mask;
520 
521 	if (!start) {
522 		ctl->flush_mask |= flush_mask;
523 		return curr_ctl_flush_mask;
524 	} else {
525 		flush_mask |= ctl->flush_mask;
526 		ctl->flush_mask = 0;
527 	}
528 
529 	if (flush_mask) {
530 		spin_lock_irqsave(&ctl->hw_lock, flags);
531 		ctl_write(ctl, REG_MDP5_CTL_FLUSH(flush_id), flush_mask);
532 		spin_unlock_irqrestore(&ctl->hw_lock, flags);
533 	}
534 
535 	if (start_signal_needed(ctl, pipeline)) {
536 		send_start_signal(ctl);
537 	}
538 
539 	return curr_ctl_flush_mask;
540 }
541 
542 u32 mdp5_ctl_get_commit_status(struct mdp5_ctl *ctl)
543 {
544 	return ctl_read(ctl, REG_MDP5_CTL_FLUSH(ctl->id));
545 }
546 
547 int mdp5_ctl_get_ctl_id(struct mdp5_ctl *ctl)
548 {
549 	return WARN_ON(!ctl) ? -EINVAL : ctl->id;
550 }
551 
552 /*
553  * mdp5_ctl_request() - CTL allocation
554  *
555  * Try to return booked CTL for @intf_num is 1 or 2, unbooked for other INTFs.
556  * If no CTL is available in preferred category, allocate from the other one.
557  *
558  * @return fail if no CTL is available.
559  */
560 struct mdp5_ctl *mdp5_ctlm_request(struct mdp5_ctl_manager *ctl_mgr,
561 		int intf_num)
562 {
563 	struct mdp5_ctl *ctl = NULL;
564 	const u32 checkm = CTL_STAT_BUSY | CTL_STAT_BOOKED;
565 	u32 match = ((intf_num == 1) || (intf_num == 2)) ? CTL_STAT_BOOKED : 0;
566 	unsigned long flags;
567 	int c;
568 
569 	spin_lock_irqsave(&ctl_mgr->pool_lock, flags);
570 
571 	/* search the preferred */
572 	for (c = 0; c < ctl_mgr->nctl; c++)
573 		if ((ctl_mgr->ctls[c].status & checkm) == match)
574 			goto found;
575 
576 	dev_warn(ctl_mgr->dev->dev,
577 		"fall back to the other CTL category for INTF %d!\n", intf_num);
578 
579 	match ^= CTL_STAT_BOOKED;
580 	for (c = 0; c < ctl_mgr->nctl; c++)
581 		if ((ctl_mgr->ctls[c].status & checkm) == match)
582 			goto found;
583 
584 	DRM_DEV_ERROR(ctl_mgr->dev->dev, "No more CTL available!");
585 	goto unlock;
586 
587 found:
588 	ctl = &ctl_mgr->ctls[c];
589 	ctl->status |= CTL_STAT_BUSY;
590 	ctl->pending_ctl_trigger = 0;
591 	DBG("CTL %d allocated", ctl->id);
592 
593 unlock:
594 	spin_unlock_irqrestore(&ctl_mgr->pool_lock, flags);
595 	return ctl;
596 }
597 
598 void mdp5_ctlm_hw_reset(struct mdp5_ctl_manager *ctl_mgr)
599 {
600 	unsigned long flags;
601 	int c;
602 
603 	for (c = 0; c < ctl_mgr->nctl; c++) {
604 		struct mdp5_ctl *ctl = &ctl_mgr->ctls[c];
605 
606 		spin_lock_irqsave(&ctl->hw_lock, flags);
607 		ctl_write(ctl, REG_MDP5_CTL_OP(ctl->id), 0);
608 		spin_unlock_irqrestore(&ctl->hw_lock, flags);
609 	}
610 }
611 
612 struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev,
613 		void __iomem *mmio_base, struct mdp5_cfg_handler *cfg_hnd)
614 {
615 	struct mdp5_ctl_manager *ctl_mgr;
616 	const struct mdp5_cfg_hw *hw_cfg = mdp5_cfg_get_hw_config(cfg_hnd);
617 	const struct mdp5_ctl_block *ctl_cfg = &hw_cfg->ctl;
618 	unsigned long flags;
619 	int c, ret;
620 
621 	ctl_mgr = devm_kzalloc(dev->dev, sizeof(*ctl_mgr), GFP_KERNEL);
622 	if (!ctl_mgr) {
623 		DRM_DEV_ERROR(dev->dev, "failed to allocate CTL manager\n");
624 		return ERR_PTR(-ENOMEM);
625 	}
626 
627 	if (WARN_ON(ctl_cfg->count > MAX_CTL)) {
628 		DRM_DEV_ERROR(dev->dev, "Increase static pool size to at least %d\n",
629 				ctl_cfg->count);
630 		return ERR_PTR(-ENOSPC);
631 	}
632 
633 	/* initialize the CTL manager: */
634 	ctl_mgr->dev = dev;
635 	ctl_mgr->nlm = hw_cfg->lm.count;
636 	ctl_mgr->nctl = ctl_cfg->count;
637 	ctl_mgr->flush_hw_mask = ctl_cfg->flush_hw_mask;
638 	spin_lock_init(&ctl_mgr->pool_lock);
639 
640 	/* initialize each CTL of the pool: */
641 	spin_lock_irqsave(&ctl_mgr->pool_lock, flags);
642 	for (c = 0; c < ctl_mgr->nctl; c++) {
643 		struct mdp5_ctl *ctl = &ctl_mgr->ctls[c];
644 
645 		if (WARN_ON(!ctl_cfg->base[c])) {
646 			DRM_DEV_ERROR(dev->dev, "CTL_%d: base is null!\n", c);
647 			ret = -EINVAL;
648 			spin_unlock_irqrestore(&ctl_mgr->pool_lock, flags);
649 			return ERR_PTR(ret);
650 		}
651 		ctl->ctlm = ctl_mgr;
652 		ctl->id = c;
653 		ctl->reg_offset = ctl_cfg->base[c];
654 		ctl->status = 0;
655 		spin_lock_init(&ctl->hw_lock);
656 	}
657 
658 	spin_unlock_irqrestore(&ctl_mgr->pool_lock, flags);
659 	DBG("Pool of %d CTLs created.", ctl_mgr->nctl);
660 
661 	return ctl_mgr;
662 }
663