• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * i.MX IPUv3 DP Overlay Planes
3  *
4  * Copyright (C) 2013 Philipp Zabel, Pengutronix
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  */
15 
16 #include <drm/drmP.h>
17 #include <drm/drm_atomic.h>
18 #include <drm/drm_atomic_helper.h>
19 #include <drm/drm_fb_cma_helper.h>
20 #include <drm/drm_gem_cma_helper.h>
21 #include <drm/drm_plane_helper.h>
22 
23 #include "video/imx-ipu-v3.h"
24 #include "ipuv3-plane.h"
25 
26 struct ipu_plane_state {
27 	struct drm_plane_state base;
28 	bool use_pre;
29 };
30 
31 static inline struct ipu_plane_state *
to_ipu_plane_state(struct drm_plane_state * p)32 to_ipu_plane_state(struct drm_plane_state *p)
33 {
34 	return container_of(p, struct ipu_plane_state, base);
35 }
36 
to_ipu_plane(struct drm_plane * p)37 static inline struct ipu_plane *to_ipu_plane(struct drm_plane *p)
38 {
39 	return container_of(p, struct ipu_plane, base);
40 }
41 
42 static const uint32_t ipu_plane_formats[] = {
43 	DRM_FORMAT_ARGB1555,
44 	DRM_FORMAT_XRGB1555,
45 	DRM_FORMAT_ABGR1555,
46 	DRM_FORMAT_XBGR1555,
47 	DRM_FORMAT_RGBA5551,
48 	DRM_FORMAT_BGRA5551,
49 	DRM_FORMAT_ARGB4444,
50 	DRM_FORMAT_ARGB8888,
51 	DRM_FORMAT_XRGB8888,
52 	DRM_FORMAT_ABGR8888,
53 	DRM_FORMAT_XBGR8888,
54 	DRM_FORMAT_RGBA8888,
55 	DRM_FORMAT_RGBX8888,
56 	DRM_FORMAT_BGRA8888,
57 	DRM_FORMAT_BGRX8888,
58 	DRM_FORMAT_UYVY,
59 	DRM_FORMAT_VYUY,
60 	DRM_FORMAT_YUYV,
61 	DRM_FORMAT_YVYU,
62 	DRM_FORMAT_YUV420,
63 	DRM_FORMAT_YVU420,
64 	DRM_FORMAT_YUV422,
65 	DRM_FORMAT_YVU422,
66 	DRM_FORMAT_YUV444,
67 	DRM_FORMAT_YVU444,
68 	DRM_FORMAT_NV12,
69 	DRM_FORMAT_NV16,
70 	DRM_FORMAT_RGB565,
71 	DRM_FORMAT_RGB565_A8,
72 	DRM_FORMAT_BGR565_A8,
73 	DRM_FORMAT_RGB888_A8,
74 	DRM_FORMAT_BGR888_A8,
75 	DRM_FORMAT_RGBX8888_A8,
76 	DRM_FORMAT_BGRX8888_A8,
77 };
78 
ipu_plane_irq(struct ipu_plane * ipu_plane)79 int ipu_plane_irq(struct ipu_plane *ipu_plane)
80 {
81 	return ipu_idmac_channel_irq(ipu_plane->ipu, ipu_plane->ipu_ch,
82 				     IPU_IRQ_EOF);
83 }
84 
85 static inline unsigned long
drm_plane_state_to_eba(struct drm_plane_state * state,int plane)86 drm_plane_state_to_eba(struct drm_plane_state *state, int plane)
87 {
88 	struct drm_framebuffer *fb = state->fb;
89 	struct drm_gem_cma_object *cma_obj;
90 	int x = state->src.x1 >> 16;
91 	int y = state->src.y1 >> 16;
92 
93 	cma_obj = drm_fb_cma_get_gem_obj(fb, plane);
94 	BUG_ON(!cma_obj);
95 
96 	return cma_obj->paddr + fb->offsets[plane] + fb->pitches[plane] * y +
97 	       fb->format->cpp[plane] * x;
98 }
99 
100 static inline unsigned long
drm_plane_state_to_ubo(struct drm_plane_state * state)101 drm_plane_state_to_ubo(struct drm_plane_state *state)
102 {
103 	struct drm_framebuffer *fb = state->fb;
104 	struct drm_gem_cma_object *cma_obj;
105 	unsigned long eba = drm_plane_state_to_eba(state, 0);
106 	int x = state->src.x1 >> 16;
107 	int y = state->src.y1 >> 16;
108 
109 	cma_obj = drm_fb_cma_get_gem_obj(fb, 1);
110 	BUG_ON(!cma_obj);
111 
112 	x /= drm_format_horz_chroma_subsampling(fb->format->format);
113 	y /= drm_format_vert_chroma_subsampling(fb->format->format);
114 
115 	return cma_obj->paddr + fb->offsets[1] + fb->pitches[1] * y +
116 	       fb->format->cpp[1] * x - eba;
117 }
118 
119 static inline unsigned long
drm_plane_state_to_vbo(struct drm_plane_state * state)120 drm_plane_state_to_vbo(struct drm_plane_state *state)
121 {
122 	struct drm_framebuffer *fb = state->fb;
123 	struct drm_gem_cma_object *cma_obj;
124 	unsigned long eba = drm_plane_state_to_eba(state, 0);
125 	int x = state->src.x1 >> 16;
126 	int y = state->src.y1 >> 16;
127 
128 	cma_obj = drm_fb_cma_get_gem_obj(fb, 2);
129 	BUG_ON(!cma_obj);
130 
131 	x /= drm_format_horz_chroma_subsampling(fb->format->format);
132 	y /= drm_format_vert_chroma_subsampling(fb->format->format);
133 
134 	return cma_obj->paddr + fb->offsets[2] + fb->pitches[2] * y +
135 	       fb->format->cpp[2] * x - eba;
136 }
137 
ipu_plane_put_resources(struct ipu_plane * ipu_plane)138 void ipu_plane_put_resources(struct ipu_plane *ipu_plane)
139 {
140 	if (!IS_ERR_OR_NULL(ipu_plane->dp))
141 		ipu_dp_put(ipu_plane->dp);
142 	if (!IS_ERR_OR_NULL(ipu_plane->dmfc))
143 		ipu_dmfc_put(ipu_plane->dmfc);
144 	if (!IS_ERR_OR_NULL(ipu_plane->ipu_ch))
145 		ipu_idmac_put(ipu_plane->ipu_ch);
146 	if (!IS_ERR_OR_NULL(ipu_plane->alpha_ch))
147 		ipu_idmac_put(ipu_plane->alpha_ch);
148 }
149 
ipu_plane_get_resources(struct ipu_plane * ipu_plane)150 int ipu_plane_get_resources(struct ipu_plane *ipu_plane)
151 {
152 	int ret;
153 	int alpha_ch;
154 
155 	ipu_plane->ipu_ch = ipu_idmac_get(ipu_plane->ipu, ipu_plane->dma);
156 	if (IS_ERR(ipu_plane->ipu_ch)) {
157 		ret = PTR_ERR(ipu_plane->ipu_ch);
158 		DRM_ERROR("failed to get idmac channel: %d\n", ret);
159 		return ret;
160 	}
161 
162 	alpha_ch = ipu_channel_alpha_channel(ipu_plane->dma);
163 	if (alpha_ch >= 0) {
164 		ipu_plane->alpha_ch = ipu_idmac_get(ipu_plane->ipu, alpha_ch);
165 		if (IS_ERR(ipu_plane->alpha_ch)) {
166 			ret = PTR_ERR(ipu_plane->alpha_ch);
167 			DRM_ERROR("failed to get alpha idmac channel %d: %d\n",
168 				  alpha_ch, ret);
169 			return ret;
170 		}
171 	}
172 
173 	ipu_plane->dmfc = ipu_dmfc_get(ipu_plane->ipu, ipu_plane->dma);
174 	if (IS_ERR(ipu_plane->dmfc)) {
175 		ret = PTR_ERR(ipu_plane->dmfc);
176 		DRM_ERROR("failed to get dmfc: ret %d\n", ret);
177 		goto err_out;
178 	}
179 
180 	if (ipu_plane->dp_flow >= 0) {
181 		ipu_plane->dp = ipu_dp_get(ipu_plane->ipu, ipu_plane->dp_flow);
182 		if (IS_ERR(ipu_plane->dp)) {
183 			ret = PTR_ERR(ipu_plane->dp);
184 			DRM_ERROR("failed to get dp flow: %d\n", ret);
185 			goto err_out;
186 		}
187 	}
188 
189 	return 0;
190 err_out:
191 	ipu_plane_put_resources(ipu_plane);
192 
193 	return ret;
194 }
195 
ipu_plane_separate_alpha(struct ipu_plane * ipu_plane)196 static bool ipu_plane_separate_alpha(struct ipu_plane *ipu_plane)
197 {
198 	switch (ipu_plane->base.state->fb->format->format) {
199 	case DRM_FORMAT_RGB565_A8:
200 	case DRM_FORMAT_BGR565_A8:
201 	case DRM_FORMAT_RGB888_A8:
202 	case DRM_FORMAT_BGR888_A8:
203 	case DRM_FORMAT_RGBX8888_A8:
204 	case DRM_FORMAT_BGRX8888_A8:
205 		return true;
206 	default:
207 		return false;
208 	}
209 }
210 
ipu_plane_enable(struct ipu_plane * ipu_plane)211 static void ipu_plane_enable(struct ipu_plane *ipu_plane)
212 {
213 	if (ipu_plane->dp)
214 		ipu_dp_enable(ipu_plane->ipu);
215 	ipu_dmfc_enable_channel(ipu_plane->dmfc);
216 	ipu_idmac_enable_channel(ipu_plane->ipu_ch);
217 	if (ipu_plane_separate_alpha(ipu_plane))
218 		ipu_idmac_enable_channel(ipu_plane->alpha_ch);
219 	if (ipu_plane->dp)
220 		ipu_dp_enable_channel(ipu_plane->dp);
221 }
222 
ipu_plane_disable(struct ipu_plane * ipu_plane,bool disable_dp_channel)223 void ipu_plane_disable(struct ipu_plane *ipu_plane, bool disable_dp_channel)
224 {
225 	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
226 
227 	ipu_idmac_wait_busy(ipu_plane->ipu_ch, 50);
228 
229 	if (ipu_plane->dp && disable_dp_channel)
230 		ipu_dp_disable_channel(ipu_plane->dp, false);
231 	ipu_idmac_disable_channel(ipu_plane->ipu_ch);
232 	if (ipu_plane->alpha_ch)
233 		ipu_idmac_disable_channel(ipu_plane->alpha_ch);
234 	ipu_dmfc_disable_channel(ipu_plane->dmfc);
235 	if (ipu_plane->dp)
236 		ipu_dp_disable(ipu_plane->ipu);
237 	if (ipu_prg_present(ipu_plane->ipu))
238 		ipu_prg_channel_disable(ipu_plane->ipu_ch);
239 }
240 
ipu_plane_disable_deferred(struct drm_plane * plane)241 void ipu_plane_disable_deferred(struct drm_plane *plane)
242 {
243 	struct ipu_plane *ipu_plane = to_ipu_plane(plane);
244 
245 	if (ipu_plane->disabling) {
246 		ipu_plane->disabling = false;
247 		ipu_plane_disable(ipu_plane, false);
248 	}
249 }
250 EXPORT_SYMBOL_GPL(ipu_plane_disable_deferred);
251 
ipu_plane_destroy(struct drm_plane * plane)252 static void ipu_plane_destroy(struct drm_plane *plane)
253 {
254 	struct ipu_plane *ipu_plane = to_ipu_plane(plane);
255 
256 	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
257 
258 	drm_plane_cleanup(plane);
259 	kfree(ipu_plane);
260 }
261 
ipu_plane_state_reset(struct drm_plane * plane)262 void ipu_plane_state_reset(struct drm_plane *plane)
263 {
264 	struct ipu_plane_state *ipu_state;
265 
266 	if (plane->state) {
267 		ipu_state = to_ipu_plane_state(plane->state);
268 		__drm_atomic_helper_plane_destroy_state(plane->state);
269 		kfree(ipu_state);
270 	}
271 
272 	ipu_state = kzalloc(sizeof(*ipu_state), GFP_KERNEL);
273 
274 	if (ipu_state) {
275 		ipu_state->base.plane = plane;
276 		ipu_state->base.rotation = DRM_MODE_ROTATE_0;
277 	}
278 
279 	plane->state = &ipu_state->base;
280 }
281 
ipu_plane_duplicate_state(struct drm_plane * plane)282 struct drm_plane_state *ipu_plane_duplicate_state(struct drm_plane *plane)
283 {
284 	struct ipu_plane_state *state;
285 
286 	if (WARN_ON(!plane->state))
287 		return NULL;
288 
289 	state = kmalloc(sizeof(*state), GFP_KERNEL);
290 	if (state)
291 		__drm_atomic_helper_plane_duplicate_state(plane, &state->base);
292 
293 	return &state->base;
294 }
295 
ipu_plane_destroy_state(struct drm_plane * plane,struct drm_plane_state * state)296 void ipu_plane_destroy_state(struct drm_plane *plane,
297 			     struct drm_plane_state *state)
298 {
299 	struct ipu_plane_state *ipu_state = to_ipu_plane_state(state);
300 
301 	__drm_atomic_helper_plane_destroy_state(state);
302 	kfree(ipu_state);
303 }
304 
305 static const struct drm_plane_funcs ipu_plane_funcs = {
306 	.update_plane	= drm_atomic_helper_update_plane,
307 	.disable_plane	= drm_atomic_helper_disable_plane,
308 	.destroy	= ipu_plane_destroy,
309 	.reset		= ipu_plane_state_reset,
310 	.atomic_duplicate_state	= ipu_plane_duplicate_state,
311 	.atomic_destroy_state	= ipu_plane_destroy_state,
312 };
313 
ipu_plane_atomic_check(struct drm_plane * plane,struct drm_plane_state * state)314 static int ipu_plane_atomic_check(struct drm_plane *plane,
315 				  struct drm_plane_state *state)
316 {
317 	struct drm_plane_state *old_state = plane->state;
318 	struct drm_crtc_state *crtc_state;
319 	struct device *dev = plane->dev->dev;
320 	struct drm_framebuffer *fb = state->fb;
321 	struct drm_framebuffer *old_fb = old_state->fb;
322 	unsigned long eba, ubo, vbo, old_ubo, old_vbo, alpha_eba;
323 	bool can_position = (plane->type == DRM_PLANE_TYPE_OVERLAY);
324 	struct drm_rect clip;
325 	int hsub, vsub;
326 	int ret;
327 
328 	/* Ok to disable */
329 	if (!fb)
330 		return 0;
331 
332 	if (!state->crtc)
333 		return -EINVAL;
334 
335 	crtc_state =
336 		drm_atomic_get_existing_crtc_state(state->state, state->crtc);
337 	if (WARN_ON(!crtc_state))
338 		return -EINVAL;
339 
340 	clip.x1 = 0;
341 	clip.y1 = 0;
342 	clip.x2 = crtc_state->adjusted_mode.hdisplay;
343 	clip.y2 = crtc_state->adjusted_mode.vdisplay;
344 	ret = drm_plane_helper_check_state(state, &clip,
345 					   DRM_PLANE_HELPER_NO_SCALING,
346 					   DRM_PLANE_HELPER_NO_SCALING,
347 					   can_position, true);
348 	if (ret)
349 		return ret;
350 
351 	/* nothing to check when disabling or disabled */
352 	if (!crtc_state->enable)
353 		return 0;
354 
355 	switch (plane->type) {
356 	case DRM_PLANE_TYPE_PRIMARY:
357 		/* full plane minimum width is 13 pixels */
358 		if (drm_rect_width(&state->dst) < 13)
359 			return -EINVAL;
360 		break;
361 	case DRM_PLANE_TYPE_OVERLAY:
362 		break;
363 	default:
364 		dev_warn(dev, "Unsupported plane type %d\n", plane->type);
365 		return -EINVAL;
366 	}
367 
368 	if (drm_rect_height(&state->dst) < 2)
369 		return -EINVAL;
370 
371 	/*
372 	 * We support resizing active plane or changing its format by
373 	 * forcing CRTC mode change in plane's ->atomic_check callback
374 	 * and disabling all affected active planes in CRTC's ->atomic_disable
375 	 * callback.  The planes will be reenabled in plane's ->atomic_update
376 	 * callback.
377 	 */
378 	if (old_fb &&
379 	    (drm_rect_width(&state->dst) != drm_rect_width(&old_state->dst) ||
380 	     drm_rect_height(&state->dst) != drm_rect_height(&old_state->dst) ||
381 	     fb->format != old_fb->format))
382 		crtc_state->mode_changed = true;
383 
384 	eba = drm_plane_state_to_eba(state, 0);
385 
386 	if (eba & 0x7)
387 		return -EINVAL;
388 
389 	if (fb->pitches[0] < 1 || fb->pitches[0] > 16384)
390 		return -EINVAL;
391 
392 	if (old_fb && fb->pitches[0] != old_fb->pitches[0])
393 		crtc_state->mode_changed = true;
394 
395 	switch (fb->format->format) {
396 	case DRM_FORMAT_YUV420:
397 	case DRM_FORMAT_YVU420:
398 	case DRM_FORMAT_YUV422:
399 	case DRM_FORMAT_YVU422:
400 	case DRM_FORMAT_YUV444:
401 	case DRM_FORMAT_YVU444:
402 		/*
403 		 * Multiplanar formats have to meet the following restrictions:
404 		 * - The (up to) three plane addresses are EBA, EBA+UBO, EBA+VBO
405 		 * - EBA, UBO and VBO are a multiple of 8
406 		 * - UBO and VBO are unsigned and not larger than 0xfffff8
407 		 * - Only EBA may be changed while scanout is active
408 		 * - The strides of U and V planes must be identical.
409 		 */
410 		vbo = drm_plane_state_to_vbo(state);
411 
412 		if (vbo & 0x7 || vbo > 0xfffff8)
413 			return -EINVAL;
414 
415 		if (old_fb && (fb->format == old_fb->format)) {
416 			old_vbo = drm_plane_state_to_vbo(old_state);
417 			if (vbo != old_vbo)
418 				crtc_state->mode_changed = true;
419 		}
420 
421 		if (fb->pitches[1] != fb->pitches[2])
422 			return -EINVAL;
423 
424 		/* fall-through */
425 	case DRM_FORMAT_NV12:
426 	case DRM_FORMAT_NV16:
427 		ubo = drm_plane_state_to_ubo(state);
428 
429 		if (ubo & 0x7 || ubo > 0xfffff8)
430 			return -EINVAL;
431 
432 		if (old_fb && (fb->format == old_fb->format)) {
433 			old_ubo = drm_plane_state_to_ubo(old_state);
434 			if (ubo != old_ubo)
435 				crtc_state->mode_changed = true;
436 		}
437 
438 		if (fb->pitches[1] < 1 || fb->pitches[1] > 16384)
439 			return -EINVAL;
440 
441 		if (old_fb && old_fb->pitches[1] != fb->pitches[1])
442 			crtc_state->mode_changed = true;
443 
444 		/*
445 		 * The x/y offsets must be even in case of horizontal/vertical
446 		 * chroma subsampling.
447 		 */
448 		hsub = drm_format_horz_chroma_subsampling(fb->format->format);
449 		vsub = drm_format_vert_chroma_subsampling(fb->format->format);
450 		if (((state->src.x1 >> 16) & (hsub - 1)) ||
451 		    ((state->src.y1 >> 16) & (vsub - 1)))
452 			return -EINVAL;
453 		break;
454 	case DRM_FORMAT_RGB565_A8:
455 	case DRM_FORMAT_BGR565_A8:
456 	case DRM_FORMAT_RGB888_A8:
457 	case DRM_FORMAT_BGR888_A8:
458 	case DRM_FORMAT_RGBX8888_A8:
459 	case DRM_FORMAT_BGRX8888_A8:
460 		alpha_eba = drm_plane_state_to_eba(state, 1);
461 		if (alpha_eba & 0x7)
462 			return -EINVAL;
463 
464 		if (fb->pitches[1] < 1 || fb->pitches[1] > 16384)
465 			return -EINVAL;
466 
467 		if (old_fb && old_fb->pitches[1] != fb->pitches[1])
468 			crtc_state->mode_changed = true;
469 		break;
470 	}
471 
472 	return 0;
473 }
474 
ipu_plane_atomic_disable(struct drm_plane * plane,struct drm_plane_state * old_state)475 static void ipu_plane_atomic_disable(struct drm_plane *plane,
476 				     struct drm_plane_state *old_state)
477 {
478 	struct ipu_plane *ipu_plane = to_ipu_plane(plane);
479 
480 	if (ipu_plane->dp)
481 		ipu_dp_disable_channel(ipu_plane->dp, true);
482 	ipu_plane->disabling = true;
483 }
484 
ipu_chan_assign_axi_id(int ipu_chan)485 static int ipu_chan_assign_axi_id(int ipu_chan)
486 {
487 	switch (ipu_chan) {
488 	case IPUV3_CHANNEL_MEM_BG_SYNC:
489 		return 1;
490 	case IPUV3_CHANNEL_MEM_FG_SYNC:
491 		return 2;
492 	case IPUV3_CHANNEL_MEM_DC_SYNC:
493 		return 3;
494 	default:
495 		return 0;
496 	}
497 }
498 
ipu_calculate_bursts(u32 width,u32 cpp,u32 stride,u8 * burstsize,u8 * num_bursts)499 static void ipu_calculate_bursts(u32 width, u32 cpp, u32 stride,
500 				 u8 *burstsize, u8 *num_bursts)
501 {
502 	const unsigned int width_bytes = width * cpp;
503 	unsigned int npb, bursts;
504 
505 	/* Maximum number of pixels per burst without overshooting stride */
506 	for (npb = 64 / cpp; npb > 0; --npb) {
507 		if (round_up(width_bytes, npb * cpp) <= stride)
508 			break;
509 	}
510 	*burstsize = npb;
511 
512 	/* Maximum number of consecutive bursts without overshooting stride */
513 	for (bursts = 8; bursts > 1; bursts /= 2) {
514 		if (round_up(width_bytes, npb * cpp * bursts) <= stride)
515 			break;
516 	}
517 	*num_bursts = bursts;
518 }
519 
ipu_plane_atomic_update(struct drm_plane * plane,struct drm_plane_state * old_state)520 static void ipu_plane_atomic_update(struct drm_plane *plane,
521 				    struct drm_plane_state *old_state)
522 {
523 	struct ipu_plane *ipu_plane = to_ipu_plane(plane);
524 	struct drm_plane_state *state = plane->state;
525 	struct ipu_plane_state *ipu_state = to_ipu_plane_state(state);
526 	struct drm_crtc_state *crtc_state = state->crtc->state;
527 	struct drm_framebuffer *fb = state->fb;
528 	struct drm_rect *dst = &state->dst;
529 	unsigned long eba, ubo, vbo;
530 	unsigned long alpha_eba = 0;
531 	enum ipu_color_space ics;
532 	unsigned int axi_id = 0;
533 	const struct drm_format_info *info;
534 	u8 burstsize, num_bursts;
535 	u32 width, height;
536 	int active;
537 
538 	if (ipu_plane->dp_flow == IPU_DP_FLOW_SYNC_FG)
539 		ipu_dp_set_window_pos(ipu_plane->dp, dst->x1, dst->y1);
540 
541 	eba = drm_plane_state_to_eba(state, 0);
542 
543 	/*
544 	 * Configure PRG channel and attached PRE, this changes the EBA to an
545 	 * internal SRAM location.
546 	 */
547 	if (ipu_state->use_pre) {
548 		axi_id = ipu_chan_assign_axi_id(ipu_plane->dma);
549 		ipu_prg_channel_configure(ipu_plane->ipu_ch, axi_id,
550 					  drm_rect_width(&state->src) >> 16,
551 					  drm_rect_height(&state->src) >> 16,
552 					  fb->pitches[0],
553 					  fb->format->format, &eba);
554 	}
555 
556 	if (old_state->fb && !drm_atomic_crtc_needs_modeset(crtc_state)) {
557 		/* nothing to do if PRE is used */
558 		if (ipu_state->use_pre)
559 			return;
560 		active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch);
561 		ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba);
562 		ipu_idmac_select_buffer(ipu_plane->ipu_ch, !active);
563 		if (ipu_plane_separate_alpha(ipu_plane)) {
564 			active = ipu_idmac_get_current_buffer(ipu_plane->alpha_ch);
565 			ipu_cpmem_set_buffer(ipu_plane->alpha_ch, !active,
566 					     alpha_eba);
567 			ipu_idmac_select_buffer(ipu_plane->alpha_ch, !active);
568 		}
569 		return;
570 	}
571 
572 	ics = ipu_drm_fourcc_to_colorspace(fb->format->format);
573 	switch (ipu_plane->dp_flow) {
574 	case IPU_DP_FLOW_SYNC_BG:
575 		ipu_dp_setup_channel(ipu_plane->dp, ics, IPUV3_COLORSPACE_RGB);
576 		ipu_dp_set_global_alpha(ipu_plane->dp, true, 0, true);
577 		break;
578 	case IPU_DP_FLOW_SYNC_FG:
579 		ipu_dp_setup_channel(ipu_plane->dp, ics,
580 					IPUV3_COLORSPACE_UNKNOWN);
581 		/* Enable local alpha on partial plane */
582 		switch (fb->format->format) {
583 		case DRM_FORMAT_ARGB1555:
584 		case DRM_FORMAT_ABGR1555:
585 		case DRM_FORMAT_RGBA5551:
586 		case DRM_FORMAT_BGRA5551:
587 		case DRM_FORMAT_ARGB4444:
588 		case DRM_FORMAT_ARGB8888:
589 		case DRM_FORMAT_ABGR8888:
590 		case DRM_FORMAT_RGBA8888:
591 		case DRM_FORMAT_BGRA8888:
592 		case DRM_FORMAT_RGB565_A8:
593 		case DRM_FORMAT_BGR565_A8:
594 		case DRM_FORMAT_RGB888_A8:
595 		case DRM_FORMAT_BGR888_A8:
596 		case DRM_FORMAT_RGBX8888_A8:
597 		case DRM_FORMAT_BGRX8888_A8:
598 			ipu_dp_set_global_alpha(ipu_plane->dp, false, 0, false);
599 			break;
600 		default:
601 			ipu_dp_set_global_alpha(ipu_plane->dp, true, 0, true);
602 			break;
603 		}
604 	}
605 
606 	ipu_dmfc_config_wait4eot(ipu_plane->dmfc, drm_rect_width(dst));
607 
608 	width = drm_rect_width(&state->src) >> 16;
609 	height = drm_rect_height(&state->src) >> 16;
610 	info = drm_format_info(fb->format->format);
611 	ipu_calculate_bursts(width, info->cpp[0], fb->pitches[0],
612 			     &burstsize, &num_bursts);
613 
614 	ipu_cpmem_zero(ipu_plane->ipu_ch);
615 	ipu_cpmem_set_resolution(ipu_plane->ipu_ch, width, height);
616 	ipu_cpmem_set_fmt(ipu_plane->ipu_ch, fb->format->format);
617 	ipu_cpmem_set_burstsize(ipu_plane->ipu_ch, burstsize);
618 	ipu_cpmem_set_high_priority(ipu_plane->ipu_ch);
619 	ipu_idmac_set_double_buffer(ipu_plane->ipu_ch, 1);
620 	ipu_cpmem_set_stride(ipu_plane->ipu_ch, fb->pitches[0]);
621 	ipu_cpmem_set_axi_id(ipu_plane->ipu_ch, axi_id);
622 
623 	switch (fb->format->format) {
624 	case DRM_FORMAT_YUV420:
625 	case DRM_FORMAT_YVU420:
626 	case DRM_FORMAT_YUV422:
627 	case DRM_FORMAT_YVU422:
628 	case DRM_FORMAT_YUV444:
629 	case DRM_FORMAT_YVU444:
630 		ubo = drm_plane_state_to_ubo(state);
631 		vbo = drm_plane_state_to_vbo(state);
632 		if (fb->format->format == DRM_FORMAT_YVU420 ||
633 		    fb->format->format == DRM_FORMAT_YVU422 ||
634 		    fb->format->format == DRM_FORMAT_YVU444)
635 			swap(ubo, vbo);
636 
637 		ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch,
638 					      fb->pitches[1], ubo, vbo);
639 
640 		dev_dbg(ipu_plane->base.dev->dev,
641 			"phy = %lu %lu %lu, x = %d, y = %d", eba, ubo, vbo,
642 			state->src.x1 >> 16, state->src.y1 >> 16);
643 		break;
644 	case DRM_FORMAT_NV12:
645 	case DRM_FORMAT_NV16:
646 		ubo = drm_plane_state_to_ubo(state);
647 
648 		ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch,
649 					      fb->pitches[1], ubo, ubo);
650 
651 		dev_dbg(ipu_plane->base.dev->dev,
652 			"phy = %lu %lu, x = %d, y = %d", eba, ubo,
653 			state->src.x1 >> 16, state->src.y1 >> 16);
654 		break;
655 	case DRM_FORMAT_RGB565_A8:
656 	case DRM_FORMAT_BGR565_A8:
657 	case DRM_FORMAT_RGB888_A8:
658 	case DRM_FORMAT_BGR888_A8:
659 	case DRM_FORMAT_RGBX8888_A8:
660 	case DRM_FORMAT_BGRX8888_A8:
661 		alpha_eba = drm_plane_state_to_eba(state, 1);
662 		num_bursts = 0;
663 
664 		dev_dbg(ipu_plane->base.dev->dev, "phys = %lu %lu, x = %d, y = %d",
665 			eba, alpha_eba, state->src.x1 >> 16, state->src.y1 >> 16);
666 
667 		ipu_cpmem_set_burstsize(ipu_plane->ipu_ch, 16);
668 
669 		ipu_cpmem_zero(ipu_plane->alpha_ch);
670 		ipu_cpmem_set_resolution(ipu_plane->alpha_ch,
671 					 drm_rect_width(&state->src) >> 16,
672 					 drm_rect_height(&state->src) >> 16);
673 		ipu_cpmem_set_format_passthrough(ipu_plane->alpha_ch, 8);
674 		ipu_cpmem_set_high_priority(ipu_plane->alpha_ch);
675 		ipu_idmac_set_double_buffer(ipu_plane->alpha_ch, 1);
676 		ipu_cpmem_set_stride(ipu_plane->alpha_ch, fb->pitches[1]);
677 		ipu_cpmem_set_burstsize(ipu_plane->alpha_ch, 16);
678 		ipu_cpmem_set_buffer(ipu_plane->alpha_ch, 0, alpha_eba);
679 		ipu_cpmem_set_buffer(ipu_plane->alpha_ch, 1, alpha_eba);
680 		break;
681 	default:
682 		dev_dbg(ipu_plane->base.dev->dev, "phys = %lu, x = %d, y = %d",
683 			eba, state->src.x1 >> 16, state->src.y1 >> 16);
684 		break;
685 	}
686 	ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 0, eba);
687 	ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 1, eba);
688 	ipu_idmac_lock_enable(ipu_plane->ipu_ch, num_bursts);
689 	ipu_plane_enable(ipu_plane);
690 }
691 
692 static const struct drm_plane_helper_funcs ipu_plane_helper_funcs = {
693 	.prepare_fb = drm_fb_cma_prepare_fb,
694 	.atomic_check = ipu_plane_atomic_check,
695 	.atomic_disable = ipu_plane_atomic_disable,
696 	.atomic_update = ipu_plane_atomic_update,
697 };
698 
ipu_planes_assign_pre(struct drm_device * dev,struct drm_atomic_state * state)699 int ipu_planes_assign_pre(struct drm_device *dev,
700 			  struct drm_atomic_state *state)
701 {
702 	struct drm_plane_state *plane_state;
703 	struct drm_plane *plane;
704 	int available_pres = ipu_prg_max_active_channels();
705 	int i;
706 
707 	for_each_new_plane_in_state(state, plane, plane_state, i) {
708 		struct ipu_plane_state *ipu_state =
709 				to_ipu_plane_state(plane_state);
710 		struct ipu_plane *ipu_plane = to_ipu_plane(plane);
711 
712 		if (ipu_prg_present(ipu_plane->ipu) && available_pres &&
713 		    plane_state->fb &&
714 		    ipu_prg_format_supported(ipu_plane->ipu,
715 					     plane_state->fb->format->format,
716 					     plane_state->fb->modifier)) {
717 			ipu_state->use_pre = true;
718 			available_pres--;
719 		} else {
720 			ipu_state->use_pre = false;
721 		}
722 	}
723 
724 	return 0;
725 }
726 EXPORT_SYMBOL_GPL(ipu_planes_assign_pre);
727 
ipu_plane_init(struct drm_device * dev,struct ipu_soc * ipu,int dma,int dp,unsigned int possible_crtcs,enum drm_plane_type type)728 struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
729 				 int dma, int dp, unsigned int possible_crtcs,
730 				 enum drm_plane_type type)
731 {
732 	struct ipu_plane *ipu_plane;
733 	int ret;
734 
735 	DRM_DEBUG_KMS("channel %d, dp flow %d, possible_crtcs=0x%x\n",
736 		      dma, dp, possible_crtcs);
737 
738 	ipu_plane = kzalloc(sizeof(*ipu_plane), GFP_KERNEL);
739 	if (!ipu_plane) {
740 		DRM_ERROR("failed to allocate plane\n");
741 		return ERR_PTR(-ENOMEM);
742 	}
743 
744 	ipu_plane->ipu = ipu;
745 	ipu_plane->dma = dma;
746 	ipu_plane->dp_flow = dp;
747 
748 	ret = drm_universal_plane_init(dev, &ipu_plane->base, possible_crtcs,
749 				       &ipu_plane_funcs, ipu_plane_formats,
750 				       ARRAY_SIZE(ipu_plane_formats),
751 				       NULL, type, NULL);
752 	if (ret) {
753 		DRM_ERROR("failed to initialize plane\n");
754 		kfree(ipu_plane);
755 		return ERR_PTR(ret);
756 	}
757 
758 	drm_plane_helper_add(&ipu_plane->base, &ipu_plane_helper_funcs);
759 
760 	return ipu_plane;
761 }
762