2 * i.MX IPUv3 DP Overlay Planes
4 * Copyright (C) 2013 Philipp Zabel, Pengutronix
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.
17 #include <drm/drm_fb_cma_helper.h>
18 #include <drm/drm_gem_cma_helper.h>
19 #include <drm/drm_plane_helper.h>
21 #include "video/imx-ipu-v3.h"
22 #include "ipuv3-plane.h"
24 #define to_ipu_plane(x) container_of(x, struct ipu_plane, base)
26 static const uint32_t ipu_plane_formats[] = {
51 int ipu_plane_irq(struct ipu_plane *ipu_plane)
53 return ipu_idmac_channel_irq(ipu_plane->ipu, ipu_plane->ipu_ch,
57 int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb)
59 struct drm_gem_cma_object *cma_obj[3], *old_cma_obj[3];
60 struct drm_plane_state *state = ipu_plane->base.state;
61 struct drm_framebuffer *old_fb = state->fb;
62 unsigned long eba, ubo, vbo, old_eba, old_ubo, old_vbo;
64 int x = state->src_x >> 16;
65 int y = state->src_y >> 16;
67 for (i = 0; i < drm_format_num_planes(fb->pixel_format); i++) {
68 cma_obj[i] = drm_fb_cma_get_gem_obj(fb, i);
70 DRM_DEBUG_KMS("plane %d entry is null.\n", i);
75 for (i = 0; i < drm_format_num_planes(old_fb->pixel_format); i++) {
76 old_cma_obj[i] = drm_fb_cma_get_gem_obj(old_fb, i);
77 if (!old_cma_obj[i]) {
78 DRM_DEBUG_KMS("plane %d entry is null.\n", i);
83 eba = cma_obj[0]->paddr + fb->offsets[0] +
84 fb->pitches[0] * y + (fb->bits_per_pixel >> 3) * x;
87 DRM_DEBUG_KMS("base address must be a multiple of 8.\n");
91 if (fb->pitches[0] < 1 || fb->pitches[0] > 16384) {
92 DRM_DEBUG_KMS("pitches out of range.\n");
96 if (fb->pitches[0] != old_fb->pitches[0]) {
97 DRM_DEBUG_KMS("pitches must not change while plane is enabled.\n");
101 switch (fb->pixel_format) {
102 case DRM_FORMAT_YUV420:
103 case DRM_FORMAT_YVU420:
105 * Multiplanar formats have to meet the following restrictions:
106 * - The (up to) three plane addresses are EBA, EBA+UBO, EBA+VBO
107 * - EBA, UBO and VBO are a multiple of 8
108 * - UBO and VBO are unsigned and not larger than 0xfffff8
109 * - Only EBA may be changed while scanout is active
110 * - The strides of U and V planes must be identical.
112 ubo = cma_obj[1]->paddr + fb->offsets[1] +
113 fb->pitches[1] * y / 2 + x / 2 - eba;
114 vbo = cma_obj[2]->paddr + fb->offsets[2] +
115 fb->pitches[2] * y / 2 + x / 2 - eba;
117 old_eba = old_cma_obj[0]->paddr + old_fb->offsets[0] +
118 old_fb->pitches[0] * y +
119 (old_fb->bits_per_pixel >> 3) * x;
120 old_ubo = old_cma_obj[1]->paddr + old_fb->offsets[1] +
121 old_fb->pitches[1] * y / 2 + x / 2 - old_eba;
122 old_vbo = old_cma_obj[2]->paddr + old_fb->offsets[2] +
123 old_fb->pitches[2] * y / 2 + x / 2 - old_eba;
125 if ((ubo & 0x7) || (vbo & 0x7)) {
126 DRM_DEBUG_KMS("U/V buffer offsets must be a multiple of 8.\n");
130 if ((ubo > 0xfffff8) || (vbo > 0xfffff8)) {
131 DRM_DEBUG_KMS("U/V buffer offsets must be positive and not larger than 0xfffff8.\n");
135 if (old_ubo != ubo || old_vbo != vbo) {
136 DRM_DEBUG_KMS("U/V buffer offsets must not change while plane is enabled.\n");
140 if (fb->pitches[1] != fb->pitches[2]) {
141 DRM_DEBUG_KMS("U/V pitches must be identical.\n");
145 if (fb->pitches[1] < 1 || fb->pitches[1] > 16384) {
146 DRM_DEBUG_KMS("U/V pitches out of range.\n");
150 if (old_fb->pitches[1] != fb->pitches[1]) {
151 DRM_DEBUG_KMS("U/V pitches must not change while plane is enabled.\n");
155 dev_dbg(ipu_plane->base.dev->dev,
156 "phys = %pad %pad %pad, x = %d, y = %d",
157 &cma_obj[0]->paddr, &cma_obj[1]->paddr,
158 &cma_obj[2]->paddr, x, y);
161 dev_dbg(ipu_plane->base.dev->dev, "phys = %pad, x = %d, y = %d",
162 &cma_obj[0]->paddr, x, y);
166 active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch);
167 ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba);
168 ipu_idmac_select_buffer(ipu_plane->ipu_ch, !active);
173 static inline unsigned long
174 drm_plane_state_to_eba(struct drm_plane_state *state)
176 struct drm_framebuffer *fb = state->fb;
177 struct drm_gem_cma_object *cma_obj;
179 cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
182 return cma_obj->paddr + fb->offsets[0] +
183 fb->pitches[0] * (state->src_y >> 16) +
184 (fb->bits_per_pixel >> 3) * (state->src_x >> 16);
187 static inline unsigned long
188 drm_plane_state_to_ubo(struct drm_plane_state *state)
190 struct drm_framebuffer *fb = state->fb;
191 struct drm_gem_cma_object *cma_obj;
192 unsigned long eba = drm_plane_state_to_eba(state);
194 cma_obj = drm_fb_cma_get_gem_obj(fb, 1);
197 return cma_obj->paddr + fb->offsets[1] +
198 fb->pitches[1] * (state->src_y >> 16) / 2 +
199 (state->src_x >> 16) / 2 - eba;
202 static inline unsigned long
203 drm_plane_state_to_vbo(struct drm_plane_state *state)
205 struct drm_framebuffer *fb = state->fb;
206 struct drm_gem_cma_object *cma_obj;
207 unsigned long eba = drm_plane_state_to_eba(state);
209 cma_obj = drm_fb_cma_get_gem_obj(fb, 2);
212 return cma_obj->paddr + fb->offsets[2] +
213 fb->pitches[2] * (state->src_y >> 16) / 2 +
214 (state->src_x >> 16) / 2 - eba;
217 static void ipu_plane_atomic_set_base(struct ipu_plane *ipu_plane,
218 struct drm_plane_state *old_state)
220 struct drm_plane *plane = &ipu_plane->base;
221 struct drm_plane_state *state = plane->state;
222 struct drm_framebuffer *fb = state->fb;
223 unsigned long eba, ubo, vbo;
226 eba = drm_plane_state_to_eba(state);
228 switch (fb->pixel_format) {
229 case DRM_FORMAT_YUV420:
230 case DRM_FORMAT_YVU420:
235 * Multiplanar formats have to meet the following restrictions:
236 * - The (up to) three plane addresses are EBA, EBA+UBO, EBA+VBO
237 * - EBA, UBO and VBO are a multiple of 8
238 * - UBO and VBO are unsigned and not larger than 0xfffff8
239 * - Only EBA may be changed while scanout is active
240 * - The strides of U and V planes must be identical.
242 ubo = drm_plane_state_to_ubo(state);
243 vbo = drm_plane_state_to_vbo(state);
245 if (fb->pixel_format == DRM_FORMAT_YUV420)
246 ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch,
247 fb->pitches[1], ubo, vbo);
249 ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch,
250 fb->pitches[1], vbo, ubo);
252 dev_dbg(ipu_plane->base.dev->dev,
253 "phy = %lu %lu %lu, x = %d, y = %d", eba, ubo, vbo,
254 state->src_x >> 16, state->src_y >> 16);
257 dev_dbg(ipu_plane->base.dev->dev, "phys = %lu, x = %d, y = %d",
258 eba, state->src_x >> 16, state->src_y >> 16);
264 active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch);
265 ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba);
266 ipu_idmac_select_buffer(ipu_plane->ipu_ch, !active);
268 ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 0, eba);
269 ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 1, eba);
273 void ipu_plane_put_resources(struct ipu_plane *ipu_plane)
275 if (!IS_ERR_OR_NULL(ipu_plane->dp))
276 ipu_dp_put(ipu_plane->dp);
277 if (!IS_ERR_OR_NULL(ipu_plane->dmfc))
278 ipu_dmfc_put(ipu_plane->dmfc);
279 if (!IS_ERR_OR_NULL(ipu_plane->ipu_ch))
280 ipu_idmac_put(ipu_plane->ipu_ch);
283 int ipu_plane_get_resources(struct ipu_plane *ipu_plane)
287 ipu_plane->ipu_ch = ipu_idmac_get(ipu_plane->ipu, ipu_plane->dma);
288 if (IS_ERR(ipu_plane->ipu_ch)) {
289 ret = PTR_ERR(ipu_plane->ipu_ch);
290 DRM_ERROR("failed to get idmac channel: %d\n", ret);
294 ipu_plane->dmfc = ipu_dmfc_get(ipu_plane->ipu, ipu_plane->dma);
295 if (IS_ERR(ipu_plane->dmfc)) {
296 ret = PTR_ERR(ipu_plane->dmfc);
297 DRM_ERROR("failed to get dmfc: ret %d\n", ret);
301 if (ipu_plane->dp_flow >= 0) {
302 ipu_plane->dp = ipu_dp_get(ipu_plane->ipu, ipu_plane->dp_flow);
303 if (IS_ERR(ipu_plane->dp)) {
304 ret = PTR_ERR(ipu_plane->dp);
305 DRM_ERROR("failed to get dp flow: %d\n", ret);
312 ipu_plane_put_resources(ipu_plane);
317 static void ipu_plane_enable(struct ipu_plane *ipu_plane)
320 ipu_dp_enable(ipu_plane->ipu);
321 ipu_dmfc_enable_channel(ipu_plane->dmfc);
322 ipu_idmac_enable_channel(ipu_plane->ipu_ch);
324 ipu_dp_enable_channel(ipu_plane->dp);
327 static void ipu_plane_disable(struct ipu_plane *ipu_plane)
329 ipu_idmac_wait_busy(ipu_plane->ipu_ch, 50);
332 ipu_dp_disable_channel(ipu_plane->dp);
333 ipu_idmac_disable_channel(ipu_plane->ipu_ch);
334 ipu_dmfc_disable_channel(ipu_plane->dmfc);
336 ipu_dp_disable(ipu_plane->ipu);
339 static int ipu_disable_plane(struct drm_plane *plane)
341 struct ipu_plane *ipu_plane = to_ipu_plane(plane);
343 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
345 ipu_plane_disable(ipu_plane);
350 static void ipu_plane_destroy(struct drm_plane *plane)
352 struct ipu_plane *ipu_plane = to_ipu_plane(plane);
354 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
356 ipu_disable_plane(plane);
357 drm_plane_cleanup(plane);
361 static const struct drm_plane_funcs ipu_plane_funcs = {
362 .update_plane = drm_plane_helper_update,
363 .disable_plane = drm_plane_helper_disable,
364 .destroy = ipu_plane_destroy,
367 static int ipu_plane_atomic_check(struct drm_plane *plane,
368 struct drm_plane_state *state)
370 struct drm_plane_state *old_state = plane->state;
371 struct drm_crtc_state *crtc_state;
372 struct device *dev = plane->dev->dev;
373 struct drm_framebuffer *fb = state->fb;
374 struct drm_framebuffer *old_fb = old_state->fb;
375 unsigned long eba, ubo, vbo, old_ubo, old_vbo;
379 return old_fb ? 0 : -EINVAL;
381 /* CRTC should be enabled */
382 if (!state->crtc->enabled)
386 if (state->src_w >> 16 != state->crtc_w ||
387 state->src_h >> 16 != state->crtc_h)
390 crtc_state = state->crtc->state;
392 switch (plane->type) {
393 case DRM_PLANE_TYPE_PRIMARY:
394 /* full plane doesn't support partial off screen */
395 if (state->crtc_x || state->crtc_y ||
396 state->crtc_w != crtc_state->adjusted_mode.hdisplay ||
397 state->crtc_h != crtc_state->adjusted_mode.vdisplay)
400 /* full plane minimum width is 13 pixels */
401 if (state->crtc_w < 13)
404 case DRM_PLANE_TYPE_OVERLAY:
405 if (state->crtc_x < 0 || state->crtc_y < 0)
408 if (state->crtc_x + state->crtc_w >
409 crtc_state->adjusted_mode.hdisplay)
411 if (state->crtc_y + state->crtc_h >
412 crtc_state->adjusted_mode.vdisplay)
416 dev_warn(dev, "Unsupported plane type\n");
420 if (state->crtc_h < 2)
424 * since we cannot touch active IDMAC channels, we do not support
425 * resizing the enabled plane or changing its format
427 if (old_fb && (state->src_w != old_state->src_w ||
428 state->src_h != old_state->src_h ||
429 fb->pixel_format != old_fb->pixel_format))
432 eba = drm_plane_state_to_eba(state);
437 if (fb->pitches[0] < 1 || fb->pitches[0] > 16384)
440 if (old_fb && fb->pitches[0] != old_fb->pitches[0])
443 switch (fb->pixel_format) {
444 case DRM_FORMAT_YUV420:
445 case DRM_FORMAT_YVU420:
447 * Multiplanar formats have to meet the following restrictions:
448 * - The (up to) three plane addresses are EBA, EBA+UBO, EBA+VBO
449 * - EBA, UBO and VBO are a multiple of 8
450 * - UBO and VBO are unsigned and not larger than 0xfffff8
451 * - Only EBA may be changed while scanout is active
452 * - The strides of U and V planes must be identical.
454 ubo = drm_plane_state_to_ubo(state);
455 vbo = drm_plane_state_to_vbo(state);
457 if ((ubo & 0x7) || (vbo & 0x7))
460 if ((ubo > 0xfffff8) || (vbo > 0xfffff8))
464 old_ubo = drm_plane_state_to_ubo(old_state);
465 old_vbo = drm_plane_state_to_vbo(old_state);
466 if (ubo != old_ubo || vbo != old_vbo)
470 if (fb->pitches[1] != fb->pitches[2])
473 if (fb->pitches[1] < 1 || fb->pitches[1] > 16384)
476 if (old_fb && old_fb->pitches[1] != fb->pitches[1])
483 static void ipu_plane_atomic_disable(struct drm_plane *plane,
484 struct drm_plane_state *old_state)
486 ipu_disable_plane(plane);
489 static void ipu_plane_atomic_update(struct drm_plane *plane,
490 struct drm_plane_state *old_state)
492 struct ipu_plane *ipu_plane = to_ipu_plane(plane);
493 struct drm_plane_state *state = plane->state;
494 enum ipu_color_space ics;
497 ipu_plane_atomic_set_base(ipu_plane, old_state);
501 switch (ipu_plane->dp_flow) {
502 case IPU_DP_FLOW_SYNC_BG:
503 ipu_dp_setup_channel(ipu_plane->dp,
504 IPUV3_COLORSPACE_RGB,
505 IPUV3_COLORSPACE_RGB);
506 ipu_dp_set_global_alpha(ipu_plane->dp, true, 0, true);
508 case IPU_DP_FLOW_SYNC_FG:
509 ics = ipu_drm_fourcc_to_colorspace(state->fb->pixel_format);
510 ipu_dp_setup_channel(ipu_plane->dp, ics,
511 IPUV3_COLORSPACE_UNKNOWN);
512 ipu_dp_set_window_pos(ipu_plane->dp, state->crtc_x,
514 /* Enable local alpha on partial plane */
515 switch (state->fb->pixel_format) {
516 case DRM_FORMAT_ARGB1555:
517 case DRM_FORMAT_ABGR1555:
518 case DRM_FORMAT_RGBA5551:
519 case DRM_FORMAT_BGRA5551:
520 case DRM_FORMAT_ARGB4444:
521 case DRM_FORMAT_ARGB8888:
522 case DRM_FORMAT_ABGR8888:
523 case DRM_FORMAT_RGBA8888:
524 case DRM_FORMAT_BGRA8888:
525 ipu_dp_set_global_alpha(ipu_plane->dp, false, 0, false);
532 ipu_dmfc_config_wait4eot(ipu_plane->dmfc, state->crtc_w);
534 ipu_cpmem_zero(ipu_plane->ipu_ch);
535 ipu_cpmem_set_resolution(ipu_plane->ipu_ch, state->src_w >> 16,
537 ipu_cpmem_set_fmt(ipu_plane->ipu_ch, state->fb->pixel_format);
538 ipu_cpmem_set_high_priority(ipu_plane->ipu_ch);
539 ipu_idmac_set_double_buffer(ipu_plane->ipu_ch, 1);
540 ipu_cpmem_set_stride(ipu_plane->ipu_ch, state->fb->pitches[0]);
541 ipu_plane_atomic_set_base(ipu_plane, old_state);
542 ipu_plane_enable(ipu_plane);
545 static const struct drm_plane_helper_funcs ipu_plane_helper_funcs = {
546 .atomic_check = ipu_plane_atomic_check,
547 .atomic_disable = ipu_plane_atomic_disable,
548 .atomic_update = ipu_plane_atomic_update,
551 struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
552 int dma, int dp, unsigned int possible_crtcs,
553 enum drm_plane_type type)
555 struct ipu_plane *ipu_plane;
558 DRM_DEBUG_KMS("channel %d, dp flow %d, possible_crtcs=0x%x\n",
559 dma, dp, possible_crtcs);
561 ipu_plane = kzalloc(sizeof(*ipu_plane), GFP_KERNEL);
563 DRM_ERROR("failed to allocate plane\n");
564 return ERR_PTR(-ENOMEM);
567 ipu_plane->ipu = ipu;
568 ipu_plane->dma = dma;
569 ipu_plane->dp_flow = dp;
571 ret = drm_universal_plane_init(dev, &ipu_plane->base, possible_crtcs,
572 &ipu_plane_funcs, ipu_plane_formats,
573 ARRAY_SIZE(ipu_plane_formats), type,
576 DRM_ERROR("failed to initialize plane\n");
581 drm_plane_helper_add(&ipu_plane->base, &ipu_plane_helper_funcs);