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_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>
23 #include "video/imx-ipu-v3.h"
24 #include "ipuv3-plane.h"
26 #define to_ipu_plane(x) container_of(x, struct ipu_plane, base)
28 static const uint32_t ipu_plane_formats[] = {
53 int ipu_plane_irq(struct ipu_plane *ipu_plane)
55 return ipu_idmac_channel_irq(ipu_plane->ipu, ipu_plane->ipu_ch,
59 static inline unsigned long
60 drm_plane_state_to_eba(struct drm_plane_state *state)
62 struct drm_framebuffer *fb = state->fb;
63 struct drm_gem_cma_object *cma_obj;
65 cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
68 return cma_obj->paddr + fb->offsets[0] +
69 fb->pitches[0] * (state->src_y >> 16) +
70 (fb->bits_per_pixel >> 3) * (state->src_x >> 16);
73 static inline unsigned long
74 drm_plane_state_to_ubo(struct drm_plane_state *state)
76 struct drm_framebuffer *fb = state->fb;
77 struct drm_gem_cma_object *cma_obj;
78 unsigned long eba = drm_plane_state_to_eba(state);
80 cma_obj = drm_fb_cma_get_gem_obj(fb, 1);
83 return cma_obj->paddr + fb->offsets[1] +
84 fb->pitches[1] * (state->src_y >> 16) / 2 +
85 (state->src_x >> 16) / 2 - eba;
88 static inline unsigned long
89 drm_plane_state_to_vbo(struct drm_plane_state *state)
91 struct drm_framebuffer *fb = state->fb;
92 struct drm_gem_cma_object *cma_obj;
93 unsigned long eba = drm_plane_state_to_eba(state);
95 cma_obj = drm_fb_cma_get_gem_obj(fb, 2);
98 return cma_obj->paddr + fb->offsets[2] +
99 fb->pitches[2] * (state->src_y >> 16) / 2 +
100 (state->src_x >> 16) / 2 - eba;
103 static void ipu_plane_atomic_set_base(struct ipu_plane *ipu_plane,
104 struct drm_plane_state *old_state)
106 struct drm_plane *plane = &ipu_plane->base;
107 struct drm_plane_state *state = plane->state;
108 struct drm_framebuffer *fb = state->fb;
109 unsigned long eba, ubo, vbo;
112 eba = drm_plane_state_to_eba(state);
114 switch (fb->pixel_format) {
115 case DRM_FORMAT_YUV420:
116 case DRM_FORMAT_YVU420:
121 * Multiplanar formats have to meet the following restrictions:
122 * - The (up to) three plane addresses are EBA, EBA+UBO, EBA+VBO
123 * - EBA, UBO and VBO are a multiple of 8
124 * - UBO and VBO are unsigned and not larger than 0xfffff8
125 * - Only EBA may be changed while scanout is active
126 * - The strides of U and V planes must be identical.
128 ubo = drm_plane_state_to_ubo(state);
129 vbo = drm_plane_state_to_vbo(state);
131 if (fb->pixel_format == DRM_FORMAT_YUV420)
132 ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch,
133 fb->pitches[1], ubo, vbo);
135 ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch,
136 fb->pitches[1], vbo, ubo);
138 dev_dbg(ipu_plane->base.dev->dev,
139 "phy = %lu %lu %lu, x = %d, y = %d", eba, ubo, vbo,
140 state->src_x >> 16, state->src_y >> 16);
143 dev_dbg(ipu_plane->base.dev->dev, "phys = %lu, x = %d, y = %d",
144 eba, state->src_x >> 16, state->src_y >> 16);
150 active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch);
151 ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba);
152 ipu_idmac_select_buffer(ipu_plane->ipu_ch, !active);
154 ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 0, eba);
155 ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 1, eba);
159 void ipu_plane_put_resources(struct ipu_plane *ipu_plane)
161 if (!IS_ERR_OR_NULL(ipu_plane->dp))
162 ipu_dp_put(ipu_plane->dp);
163 if (!IS_ERR_OR_NULL(ipu_plane->dmfc))
164 ipu_dmfc_put(ipu_plane->dmfc);
165 if (!IS_ERR_OR_NULL(ipu_plane->ipu_ch))
166 ipu_idmac_put(ipu_plane->ipu_ch);
169 int ipu_plane_get_resources(struct ipu_plane *ipu_plane)
173 ipu_plane->ipu_ch = ipu_idmac_get(ipu_plane->ipu, ipu_plane->dma);
174 if (IS_ERR(ipu_plane->ipu_ch)) {
175 ret = PTR_ERR(ipu_plane->ipu_ch);
176 DRM_ERROR("failed to get idmac channel: %d\n", ret);
180 ipu_plane->dmfc = ipu_dmfc_get(ipu_plane->ipu, ipu_plane->dma);
181 if (IS_ERR(ipu_plane->dmfc)) {
182 ret = PTR_ERR(ipu_plane->dmfc);
183 DRM_ERROR("failed to get dmfc: ret %d\n", ret);
187 if (ipu_plane->dp_flow >= 0) {
188 ipu_plane->dp = ipu_dp_get(ipu_plane->ipu, ipu_plane->dp_flow);
189 if (IS_ERR(ipu_plane->dp)) {
190 ret = PTR_ERR(ipu_plane->dp);
191 DRM_ERROR("failed to get dp flow: %d\n", ret);
198 ipu_plane_put_resources(ipu_plane);
203 static void ipu_plane_enable(struct ipu_plane *ipu_plane)
206 ipu_dp_enable(ipu_plane->ipu);
207 ipu_dmfc_enable_channel(ipu_plane->dmfc);
208 ipu_idmac_enable_channel(ipu_plane->ipu_ch);
210 ipu_dp_enable_channel(ipu_plane->dp);
213 static void ipu_plane_disable(struct ipu_plane *ipu_plane)
215 ipu_idmac_wait_busy(ipu_plane->ipu_ch, 50);
218 ipu_dp_disable_channel(ipu_plane->dp);
219 ipu_idmac_disable_channel(ipu_plane->ipu_ch);
220 ipu_dmfc_disable_channel(ipu_plane->dmfc);
222 ipu_dp_disable(ipu_plane->ipu);
225 static int ipu_disable_plane(struct drm_plane *plane)
227 struct ipu_plane *ipu_plane = to_ipu_plane(plane);
229 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
231 ipu_plane_disable(ipu_plane);
236 static void ipu_plane_destroy(struct drm_plane *plane)
238 struct ipu_plane *ipu_plane = to_ipu_plane(plane);
240 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
242 ipu_disable_plane(plane);
243 drm_plane_cleanup(plane);
247 static const struct drm_plane_funcs ipu_plane_funcs = {
248 .update_plane = drm_atomic_helper_update_plane,
249 .disable_plane = drm_atomic_helper_disable_plane,
250 .destroy = ipu_plane_destroy,
251 .reset = drm_atomic_helper_plane_reset,
252 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
253 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
256 static int ipu_plane_atomic_check(struct drm_plane *plane,
257 struct drm_plane_state *state)
259 struct drm_plane_state *old_state = plane->state;
260 struct drm_crtc_state *crtc_state;
261 struct device *dev = plane->dev->dev;
262 struct drm_framebuffer *fb = state->fb;
263 struct drm_framebuffer *old_fb = old_state->fb;
264 unsigned long eba, ubo, vbo, old_ubo, old_vbo;
274 drm_atomic_get_existing_crtc_state(state->state, state->crtc);
275 if (WARN_ON(!crtc_state))
278 /* CRTC should be enabled */
279 if (!crtc_state->enable)
283 if (state->src_w >> 16 != state->crtc_w ||
284 state->src_h >> 16 != state->crtc_h)
287 switch (plane->type) {
288 case DRM_PLANE_TYPE_PRIMARY:
289 /* full plane doesn't support partial off screen */
290 if (state->crtc_x || state->crtc_y ||
291 state->crtc_w != crtc_state->adjusted_mode.hdisplay ||
292 state->crtc_h != crtc_state->adjusted_mode.vdisplay)
295 /* full plane minimum width is 13 pixels */
296 if (state->crtc_w < 13)
299 case DRM_PLANE_TYPE_OVERLAY:
300 if (state->crtc_x < 0 || state->crtc_y < 0)
303 if (state->crtc_x + state->crtc_w >
304 crtc_state->adjusted_mode.hdisplay)
306 if (state->crtc_y + state->crtc_h >
307 crtc_state->adjusted_mode.vdisplay)
311 dev_warn(dev, "Unsupported plane type\n");
315 if (state->crtc_h < 2)
319 * since we cannot touch active IDMAC channels, we do not support
320 * resizing the enabled plane or changing its format
322 if (old_fb && (state->src_w != old_state->src_w ||
323 state->src_h != old_state->src_h ||
324 fb->pixel_format != old_fb->pixel_format))
327 eba = drm_plane_state_to_eba(state);
332 if (fb->pitches[0] < 1 || fb->pitches[0] > 16384)
335 if (old_fb && fb->pitches[0] != old_fb->pitches[0])
338 switch (fb->pixel_format) {
339 case DRM_FORMAT_YUV420:
340 case DRM_FORMAT_YVU420:
342 * Multiplanar formats have to meet the following restrictions:
343 * - The (up to) three plane addresses are EBA, EBA+UBO, EBA+VBO
344 * - EBA, UBO and VBO are a multiple of 8
345 * - UBO and VBO are unsigned and not larger than 0xfffff8
346 * - Only EBA may be changed while scanout is active
347 * - The strides of U and V planes must be identical.
349 ubo = drm_plane_state_to_ubo(state);
350 vbo = drm_plane_state_to_vbo(state);
352 if ((ubo & 0x7) || (vbo & 0x7))
355 if ((ubo > 0xfffff8) || (vbo > 0xfffff8))
359 old_ubo = drm_plane_state_to_ubo(old_state);
360 old_vbo = drm_plane_state_to_vbo(old_state);
361 if (ubo != old_ubo || vbo != old_vbo)
365 if (fb->pitches[1] != fb->pitches[2])
368 if (fb->pitches[1] < 1 || fb->pitches[1] > 16384)
371 if (old_fb && old_fb->pitches[1] != fb->pitches[1])
378 static void ipu_plane_atomic_disable(struct drm_plane *plane,
379 struct drm_plane_state *old_state)
381 ipu_disable_plane(plane);
384 static void ipu_plane_atomic_update(struct drm_plane *plane,
385 struct drm_plane_state *old_state)
387 struct ipu_plane *ipu_plane = to_ipu_plane(plane);
388 struct drm_plane_state *state = plane->state;
389 enum ipu_color_space ics;
392 ipu_plane_atomic_set_base(ipu_plane, old_state);
396 switch (ipu_plane->dp_flow) {
397 case IPU_DP_FLOW_SYNC_BG:
398 ipu_dp_setup_channel(ipu_plane->dp,
399 IPUV3_COLORSPACE_RGB,
400 IPUV3_COLORSPACE_RGB);
401 ipu_dp_set_global_alpha(ipu_plane->dp, true, 0, true);
403 case IPU_DP_FLOW_SYNC_FG:
404 ics = ipu_drm_fourcc_to_colorspace(state->fb->pixel_format);
405 ipu_dp_setup_channel(ipu_plane->dp, ics,
406 IPUV3_COLORSPACE_UNKNOWN);
407 ipu_dp_set_window_pos(ipu_plane->dp, state->crtc_x,
409 /* Enable local alpha on partial plane */
410 switch (state->fb->pixel_format) {
411 case DRM_FORMAT_ARGB1555:
412 case DRM_FORMAT_ABGR1555:
413 case DRM_FORMAT_RGBA5551:
414 case DRM_FORMAT_BGRA5551:
415 case DRM_FORMAT_ARGB4444:
416 case DRM_FORMAT_ARGB8888:
417 case DRM_FORMAT_ABGR8888:
418 case DRM_FORMAT_RGBA8888:
419 case DRM_FORMAT_BGRA8888:
420 ipu_dp_set_global_alpha(ipu_plane->dp, false, 0, false);
427 ipu_dmfc_config_wait4eot(ipu_plane->dmfc, state->crtc_w);
429 ipu_cpmem_zero(ipu_plane->ipu_ch);
430 ipu_cpmem_set_resolution(ipu_plane->ipu_ch, state->src_w >> 16,
432 ipu_cpmem_set_fmt(ipu_plane->ipu_ch, state->fb->pixel_format);
433 ipu_cpmem_set_high_priority(ipu_plane->ipu_ch);
434 ipu_idmac_set_double_buffer(ipu_plane->ipu_ch, 1);
435 ipu_cpmem_set_stride(ipu_plane->ipu_ch, state->fb->pitches[0]);
436 ipu_plane_atomic_set_base(ipu_plane, old_state);
437 ipu_plane_enable(ipu_plane);
440 static const struct drm_plane_helper_funcs ipu_plane_helper_funcs = {
441 .atomic_check = ipu_plane_atomic_check,
442 .atomic_disable = ipu_plane_atomic_disable,
443 .atomic_update = ipu_plane_atomic_update,
446 struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
447 int dma, int dp, unsigned int possible_crtcs,
448 enum drm_plane_type type)
450 struct ipu_plane *ipu_plane;
453 DRM_DEBUG_KMS("channel %d, dp flow %d, possible_crtcs=0x%x\n",
454 dma, dp, possible_crtcs);
456 ipu_plane = kzalloc(sizeof(*ipu_plane), GFP_KERNEL);
458 DRM_ERROR("failed to allocate plane\n");
459 return ERR_PTR(-ENOMEM);
462 ipu_plane->ipu = ipu;
463 ipu_plane->dma = dma;
464 ipu_plane->dp_flow = dp;
466 ret = drm_universal_plane_init(dev, &ipu_plane->base, possible_crtcs,
467 &ipu_plane_funcs, ipu_plane_formats,
468 ARRAY_SIZE(ipu_plane_formats), type,
471 DRM_ERROR("failed to initialize plane\n");
476 drm_plane_helper_add(&ipu_plane->base, &ipu_plane_helper_funcs);