blob: 52784cb6bee4dce5af04275af88f1b4747aa02e8 [file] [log] [blame]
Philipp Zabelb8d181e2013-10-10 16:18:45 +02001/*
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>
Liu Ying5f2f9112016-07-08 17:40:59 +080017#include <drm/drm_atomic.h>
Liu Ying255c35f2016-07-08 17:40:56 +080018#include <drm/drm_atomic_helper.h>
Philipp Zabelb8d181e2013-10-10 16:18:45 +020019#include <drm/drm_fb_cma_helper.h>
20#include <drm/drm_gem_cma_helper.h>
Liu Ying33f14232016-07-08 17:40:55 +080021#include <drm/drm_plane_helper.h>
Philipp Zabelb8d181e2013-10-10 16:18:45 +020022
Philipp Zabel39b90042013-09-30 16:13:39 +020023#include "video/imx-ipu-v3.h"
Philipp Zabelb8d181e2013-10-10 16:18:45 +020024#include "ipuv3-plane.h"
25
Philipp Zabel3df07392016-07-06 15:47:11 +020026static inline struct ipu_plane *to_ipu_plane(struct drm_plane *p)
27{
28 return container_of(p, struct ipu_plane, base);
29}
Philipp Zabelb8d181e2013-10-10 16:18:45 +020030
31static const uint32_t ipu_plane_formats[] = {
Philipp Zabelc639a1c2014-12-12 13:40:38 +010032 DRM_FORMAT_ARGB1555,
Philipp Zabelb8d181e2013-10-10 16:18:45 +020033 DRM_FORMAT_XRGB1555,
Philipp Zabelc639a1c2014-12-12 13:40:38 +010034 DRM_FORMAT_ABGR1555,
Philipp Zabelb8d181e2013-10-10 16:18:45 +020035 DRM_FORMAT_XBGR1555,
Philipp Zabelc639a1c2014-12-12 13:40:38 +010036 DRM_FORMAT_RGBA5551,
37 DRM_FORMAT_BGRA5551,
Lucas Stachcb166a32015-08-04 17:22:06 +020038 DRM_FORMAT_ARGB4444,
Philipp Zabelb8d181e2013-10-10 16:18:45 +020039 DRM_FORMAT_ARGB8888,
40 DRM_FORMAT_XRGB8888,
41 DRM_FORMAT_ABGR8888,
42 DRM_FORMAT_XBGR8888,
Philipp Zabel59d6b712015-04-16 15:56:40 +020043 DRM_FORMAT_RGBA8888,
44 DRM_FORMAT_RGBX8888,
45 DRM_FORMAT_BGRA8888,
46 DRM_FORMAT_BGRA8888,
Philipp Zabel79321312016-02-12 14:35:55 +010047 DRM_FORMAT_UYVY,
48 DRM_FORMAT_VYUY,
Philipp Zabelb8d181e2013-10-10 16:18:45 +020049 DRM_FORMAT_YUYV,
50 DRM_FORMAT_YVYU,
51 DRM_FORMAT_YUV420,
52 DRM_FORMAT_YVU420,
Enrico Jorns33bee522015-11-24 16:29:22 +010053 DRM_FORMAT_RGB565,
Philipp Zabelb8d181e2013-10-10 16:18:45 +020054};
55
56int ipu_plane_irq(struct ipu_plane *ipu_plane)
57{
58 return ipu_idmac_channel_irq(ipu_plane->ipu, ipu_plane->ipu_ch,
59 IPU_IRQ_EOF);
60}
61
Liu Ying33f14232016-07-08 17:40:55 +080062static inline unsigned long
63drm_plane_state_to_eba(struct drm_plane_state *state)
64{
65 struct drm_framebuffer *fb = state->fb;
66 struct drm_gem_cma_object *cma_obj;
Philipp Zabelf2fa3532016-10-18 12:26:19 +020067 int x = state->src_x >> 16;
68 int y = state->src_y >> 16;
Liu Ying33f14232016-07-08 17:40:55 +080069
70 cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
71 BUG_ON(!cma_obj);
72
Philipp Zabelf2fa3532016-10-18 12:26:19 +020073 return cma_obj->paddr + fb->offsets[0] + fb->pitches[0] * y +
74 drm_format_plane_cpp(fb->pixel_format, 0) * x;
Liu Ying33f14232016-07-08 17:40:55 +080075}
76
77static inline unsigned long
78drm_plane_state_to_ubo(struct drm_plane_state *state)
79{
80 struct drm_framebuffer *fb = state->fb;
81 struct drm_gem_cma_object *cma_obj;
82 unsigned long eba = drm_plane_state_to_eba(state);
Philipp Zabelf2fa3532016-10-18 12:26:19 +020083 int x = state->src_x >> 16;
84 int y = state->src_y >> 16;
Liu Ying33f14232016-07-08 17:40:55 +080085
86 cma_obj = drm_fb_cma_get_gem_obj(fb, 1);
87 BUG_ON(!cma_obj);
88
Philipp Zabelf2fa3532016-10-18 12:26:19 +020089 x /= drm_format_horz_chroma_subsampling(fb->pixel_format);
90 y /= drm_format_vert_chroma_subsampling(fb->pixel_format);
91
92 return cma_obj->paddr + fb->offsets[1] + fb->pitches[1] * y +
93 drm_format_plane_cpp(fb->pixel_format, 1) * x - eba;
Liu Ying33f14232016-07-08 17:40:55 +080094}
95
96static inline unsigned long
97drm_plane_state_to_vbo(struct drm_plane_state *state)
98{
99 struct drm_framebuffer *fb = state->fb;
100 struct drm_gem_cma_object *cma_obj;
101 unsigned long eba = drm_plane_state_to_eba(state);
Philipp Zabelf2fa3532016-10-18 12:26:19 +0200102 int x = state->src_x >> 16;
103 int y = state->src_y >> 16;
Liu Ying33f14232016-07-08 17:40:55 +0800104
105 cma_obj = drm_fb_cma_get_gem_obj(fb, 2);
106 BUG_ON(!cma_obj);
107
Philipp Zabelf2fa3532016-10-18 12:26:19 +0200108 x /= drm_format_horz_chroma_subsampling(fb->pixel_format);
109 y /= drm_format_vert_chroma_subsampling(fb->pixel_format);
110
111 return cma_obj->paddr + fb->offsets[2] + fb->pitches[2] * y +
112 drm_format_plane_cpp(fb->pixel_format, 2) * x - eba;
Liu Ying33f14232016-07-08 17:40:55 +0800113}
114
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200115void ipu_plane_put_resources(struct ipu_plane *ipu_plane)
116{
117 if (!IS_ERR_OR_NULL(ipu_plane->dp))
118 ipu_dp_put(ipu_plane->dp);
119 if (!IS_ERR_OR_NULL(ipu_plane->dmfc))
120 ipu_dmfc_put(ipu_plane->dmfc);
121 if (!IS_ERR_OR_NULL(ipu_plane->ipu_ch))
122 ipu_idmac_put(ipu_plane->ipu_ch);
123}
124
125int ipu_plane_get_resources(struct ipu_plane *ipu_plane)
126{
127 int ret;
128
129 ipu_plane->ipu_ch = ipu_idmac_get(ipu_plane->ipu, ipu_plane->dma);
130 if (IS_ERR(ipu_plane->ipu_ch)) {
131 ret = PTR_ERR(ipu_plane->ipu_ch);
132 DRM_ERROR("failed to get idmac channel: %d\n", ret);
133 return ret;
134 }
135
136 ipu_plane->dmfc = ipu_dmfc_get(ipu_plane->ipu, ipu_plane->dma);
137 if (IS_ERR(ipu_plane->dmfc)) {
138 ret = PTR_ERR(ipu_plane->dmfc);
139 DRM_ERROR("failed to get dmfc: ret %d\n", ret);
140 goto err_out;
141 }
142
143 if (ipu_plane->dp_flow >= 0) {
144 ipu_plane->dp = ipu_dp_get(ipu_plane->ipu, ipu_plane->dp_flow);
145 if (IS_ERR(ipu_plane->dp)) {
146 ret = PTR_ERR(ipu_plane->dp);
147 DRM_ERROR("failed to get dp flow: %d\n", ret);
148 goto err_out;
149 }
150 }
151
152 return 0;
153err_out:
154 ipu_plane_put_resources(ipu_plane);
155
156 return ret;
157}
158
Liu Ying33f14232016-07-08 17:40:55 +0800159static void ipu_plane_enable(struct ipu_plane *ipu_plane)
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200160{
Philipp Zabel285bbb02014-04-14 23:53:20 +0200161 if (ipu_plane->dp)
162 ipu_dp_enable(ipu_plane->ipu);
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200163 ipu_dmfc_enable_channel(ipu_plane->dmfc);
164 ipu_idmac_enable_channel(ipu_plane->ipu_ch);
165 if (ipu_plane->dp)
166 ipu_dp_enable_channel(ipu_plane->dp);
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200167}
168
Lucas Stachdf4b2232016-08-11 11:18:50 +0200169static int ipu_disable_plane(struct drm_plane *plane)
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200170{
Lucas Stachdf4b2232016-08-11 11:18:50 +0200171 struct ipu_plane *ipu_plane = to_ipu_plane(plane);
172
173 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
174
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200175 ipu_idmac_wait_busy(ipu_plane->ipu_ch, 50);
176
177 if (ipu_plane->dp)
178 ipu_dp_disable_channel(ipu_plane->dp);
179 ipu_idmac_disable_channel(ipu_plane->ipu_ch);
180 ipu_dmfc_disable_channel(ipu_plane->dmfc);
Philipp Zabel285bbb02014-04-14 23:53:20 +0200181 if (ipu_plane->dp)
182 ipu_dp_disable(ipu_plane->ipu);
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200183
184 return 0;
185}
186
187static void ipu_plane_destroy(struct drm_plane *plane)
188{
189 struct ipu_plane *ipu_plane = to_ipu_plane(plane);
190
191 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
192
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200193 drm_plane_cleanup(plane);
194 kfree(ipu_plane);
195}
196
Liu Ying8b3ce872016-05-24 18:10:40 +0800197static const struct drm_plane_funcs ipu_plane_funcs = {
Liu Ying5f2f9112016-07-08 17:40:59 +0800198 .update_plane = drm_atomic_helper_update_plane,
199 .disable_plane = drm_atomic_helper_disable_plane,
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200200 .destroy = ipu_plane_destroy,
Liu Ying255c35f2016-07-08 17:40:56 +0800201 .reset = drm_atomic_helper_plane_reset,
202 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
203 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200204};
205
Liu Ying33f14232016-07-08 17:40:55 +0800206static int ipu_plane_atomic_check(struct drm_plane *plane,
207 struct drm_plane_state *state)
208{
209 struct drm_plane_state *old_state = plane->state;
210 struct drm_crtc_state *crtc_state;
211 struct device *dev = plane->dev->dev;
212 struct drm_framebuffer *fb = state->fb;
213 struct drm_framebuffer *old_fb = old_state->fb;
214 unsigned long eba, ubo, vbo, old_ubo, old_vbo;
Philipp Zabel5fb57ab2016-10-18 12:30:36 +0200215 int hsub, vsub;
Liu Ying33f14232016-07-08 17:40:55 +0800216
217 /* Ok to disable */
218 if (!fb)
Liu Ying5f2f9112016-07-08 17:40:59 +0800219 return 0;
220
221 if (!state->crtc)
222 return -EINVAL;
223
224 crtc_state =
225 drm_atomic_get_existing_crtc_state(state->state, state->crtc);
226 if (WARN_ON(!crtc_state))
227 return -EINVAL;
Liu Ying33f14232016-07-08 17:40:55 +0800228
229 /* CRTC should be enabled */
Liu Ying5f2f9112016-07-08 17:40:59 +0800230 if (!crtc_state->enable)
Liu Ying33f14232016-07-08 17:40:55 +0800231 return -EINVAL;
232
233 /* no scaling */
234 if (state->src_w >> 16 != state->crtc_w ||
235 state->src_h >> 16 != state->crtc_h)
236 return -EINVAL;
237
Liu Ying33f14232016-07-08 17:40:55 +0800238 switch (plane->type) {
239 case DRM_PLANE_TYPE_PRIMARY:
240 /* full plane doesn't support partial off screen */
241 if (state->crtc_x || state->crtc_y ||
242 state->crtc_w != crtc_state->adjusted_mode.hdisplay ||
243 state->crtc_h != crtc_state->adjusted_mode.vdisplay)
244 return -EINVAL;
245
246 /* full plane minimum width is 13 pixels */
247 if (state->crtc_w < 13)
248 return -EINVAL;
249 break;
250 case DRM_PLANE_TYPE_OVERLAY:
251 if (state->crtc_x < 0 || state->crtc_y < 0)
252 return -EINVAL;
253
254 if (state->crtc_x + state->crtc_w >
255 crtc_state->adjusted_mode.hdisplay)
256 return -EINVAL;
257 if (state->crtc_y + state->crtc_h >
258 crtc_state->adjusted_mode.vdisplay)
259 return -EINVAL;
260 break;
261 default:
262 dev_warn(dev, "Unsupported plane type\n");
263 return -EINVAL;
264 }
265
266 if (state->crtc_h < 2)
267 return -EINVAL;
268
269 /*
Liu Ying17809992016-08-26 15:30:44 +0800270 * We support resizing active plane or changing its format by
271 * forcing CRTC mode change in plane's ->atomic_check callback
272 * and disabling all affected active planes in CRTC's ->atomic_disable
273 * callback. The planes will be reenabled in plane's ->atomic_update
274 * callback.
Liu Ying33f14232016-07-08 17:40:55 +0800275 */
276 if (old_fb && (state->src_w != old_state->src_w ||
277 state->src_h != old_state->src_h ||
278 fb->pixel_format != old_fb->pixel_format))
Liu Ying17809992016-08-26 15:30:44 +0800279 crtc_state->mode_changed = true;
Liu Ying33f14232016-07-08 17:40:55 +0800280
281 eba = drm_plane_state_to_eba(state);
282
283 if (eba & 0x7)
284 return -EINVAL;
285
286 if (fb->pitches[0] < 1 || fb->pitches[0] > 16384)
287 return -EINVAL;
288
289 if (old_fb && fb->pitches[0] != old_fb->pitches[0])
Liu Ying17809992016-08-26 15:30:44 +0800290 crtc_state->mode_changed = true;
Liu Ying33f14232016-07-08 17:40:55 +0800291
292 switch (fb->pixel_format) {
293 case DRM_FORMAT_YUV420:
294 case DRM_FORMAT_YVU420:
295 /*
296 * Multiplanar formats have to meet the following restrictions:
297 * - The (up to) three plane addresses are EBA, EBA+UBO, EBA+VBO
298 * - EBA, UBO and VBO are a multiple of 8
299 * - UBO and VBO are unsigned and not larger than 0xfffff8
300 * - Only EBA may be changed while scanout is active
301 * - The strides of U and V planes must be identical.
302 */
303 ubo = drm_plane_state_to_ubo(state);
304 vbo = drm_plane_state_to_vbo(state);
305
306 if ((ubo & 0x7) || (vbo & 0x7))
307 return -EINVAL;
308
309 if ((ubo > 0xfffff8) || (vbo > 0xfffff8))
310 return -EINVAL;
311
Philipp Zabel181c9bf2016-10-18 12:13:15 +0200312 if (old_fb && (fb->pixel_format == old_fb->pixel_format)) {
Liu Ying33f14232016-07-08 17:40:55 +0800313 old_ubo = drm_plane_state_to_ubo(old_state);
314 old_vbo = drm_plane_state_to_vbo(old_state);
315 if (ubo != old_ubo || vbo != old_vbo)
Philipp Zabel181c9bf2016-10-18 12:13:15 +0200316 crtc_state->mode_changed = true;
Liu Ying33f14232016-07-08 17:40:55 +0800317 }
318
319 if (fb->pitches[1] != fb->pitches[2])
320 return -EINVAL;
321
322 if (fb->pitches[1] < 1 || fb->pitches[1] > 16384)
323 return -EINVAL;
324
325 if (old_fb && old_fb->pitches[1] != fb->pitches[1])
Liu Ying17809992016-08-26 15:30:44 +0800326 crtc_state->mode_changed = true;
Philipp Zabel5fb57ab2016-10-18 12:30:36 +0200327
328 /*
329 * The x/y offsets must be even in case of horizontal/vertical
330 * chroma subsampling.
331 */
332 hsub = drm_format_horz_chroma_subsampling(fb->pixel_format);
333 vsub = drm_format_vert_chroma_subsampling(fb->pixel_format);
334 if (((state->src_x >> 16) & (hsub - 1)) ||
335 ((state->src_y >> 16) & (vsub - 1)))
336 return -EINVAL;
Liu Ying33f14232016-07-08 17:40:55 +0800337 }
338
339 return 0;
340}
341
342static void ipu_plane_atomic_disable(struct drm_plane *plane,
343 struct drm_plane_state *old_state)
344{
345 ipu_disable_plane(plane);
346}
347
348static void ipu_plane_atomic_update(struct drm_plane *plane,
349 struct drm_plane_state *old_state)
350{
351 struct ipu_plane *ipu_plane = to_ipu_plane(plane);
352 struct drm_plane_state *state = plane->state;
Philipp Zabel3fd8b292016-10-18 11:40:25 +0200353 struct drm_crtc_state *crtc_state = state->crtc->state;
354 struct drm_framebuffer *fb = state->fb;
355 unsigned long eba, ubo, vbo;
Liu Ying33f14232016-07-08 17:40:55 +0800356 enum ipu_color_space ics;
Philipp Zabel3fd8b292016-10-18 11:40:25 +0200357 int active;
Liu Ying33f14232016-07-08 17:40:55 +0800358
Philipp Zabel3fd8b292016-10-18 11:40:25 +0200359 eba = drm_plane_state_to_eba(state);
Liu Ying5f4df0c2016-08-26 15:30:43 +0800360
Philipp Zabel3fd8b292016-10-18 11:40:25 +0200361 if (old_state->fb && !drm_atomic_crtc_needs_modeset(crtc_state)) {
362 active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch);
363 ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba);
364 ipu_idmac_select_buffer(ipu_plane->ipu_ch, !active);
365 return;
Liu Ying33f14232016-07-08 17:40:55 +0800366 }
367
368 switch (ipu_plane->dp_flow) {
369 case IPU_DP_FLOW_SYNC_BG:
370 ipu_dp_setup_channel(ipu_plane->dp,
371 IPUV3_COLORSPACE_RGB,
372 IPUV3_COLORSPACE_RGB);
373 ipu_dp_set_global_alpha(ipu_plane->dp, true, 0, true);
374 break;
375 case IPU_DP_FLOW_SYNC_FG:
376 ics = ipu_drm_fourcc_to_colorspace(state->fb->pixel_format);
377 ipu_dp_setup_channel(ipu_plane->dp, ics,
378 IPUV3_COLORSPACE_UNKNOWN);
379 ipu_dp_set_window_pos(ipu_plane->dp, state->crtc_x,
380 state->crtc_y);
381 /* Enable local alpha on partial plane */
382 switch (state->fb->pixel_format) {
383 case DRM_FORMAT_ARGB1555:
384 case DRM_FORMAT_ABGR1555:
385 case DRM_FORMAT_RGBA5551:
386 case DRM_FORMAT_BGRA5551:
387 case DRM_FORMAT_ARGB4444:
388 case DRM_FORMAT_ARGB8888:
389 case DRM_FORMAT_ABGR8888:
390 case DRM_FORMAT_RGBA8888:
391 case DRM_FORMAT_BGRA8888:
392 ipu_dp_set_global_alpha(ipu_plane->dp, false, 0, false);
393 break;
394 default:
Philipp Zabel86126742016-10-18 17:09:30 +0200395 ipu_dp_set_global_alpha(ipu_plane->dp, true, 0, true);
Liu Ying33f14232016-07-08 17:40:55 +0800396 break;
397 }
398 }
399
400 ipu_dmfc_config_wait4eot(ipu_plane->dmfc, state->crtc_w);
401
402 ipu_cpmem_zero(ipu_plane->ipu_ch);
403 ipu_cpmem_set_resolution(ipu_plane->ipu_ch, state->src_w >> 16,
404 state->src_h >> 16);
405 ipu_cpmem_set_fmt(ipu_plane->ipu_ch, state->fb->pixel_format);
406 ipu_cpmem_set_high_priority(ipu_plane->ipu_ch);
407 ipu_idmac_set_double_buffer(ipu_plane->ipu_ch, 1);
408 ipu_cpmem_set_stride(ipu_plane->ipu_ch, state->fb->pitches[0]);
Philipp Zabel3fd8b292016-10-18 11:40:25 +0200409 switch (fb->pixel_format) {
410 case DRM_FORMAT_YUV420:
411 case DRM_FORMAT_YVU420:
412 ubo = drm_plane_state_to_ubo(state);
413 vbo = drm_plane_state_to_vbo(state);
414
415 if (fb->pixel_format == DRM_FORMAT_YUV420)
416 ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch,
417 fb->pitches[1], ubo, vbo);
418 else
419 ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch,
420 fb->pitches[1], vbo, ubo);
421
422 dev_dbg(ipu_plane->base.dev->dev,
423 "phy = %lu %lu %lu, x = %d, y = %d", eba, ubo, vbo,
424 state->src_x >> 16, state->src_y >> 16);
425 break;
426 default:
427 dev_dbg(ipu_plane->base.dev->dev, "phys = %lu, x = %d, y = %d",
428 eba, state->src_x >> 16, state->src_y >> 16);
429 break;
430 }
431 ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 0, eba);
432 ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 1, eba);
Liu Ying33f14232016-07-08 17:40:55 +0800433 ipu_plane_enable(ipu_plane);
434}
435
436static const struct drm_plane_helper_funcs ipu_plane_helper_funcs = {
437 .atomic_check = ipu_plane_atomic_check,
438 .atomic_disable = ipu_plane_atomic_disable,
439 .atomic_update = ipu_plane_atomic_update,
440};
441
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200442struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
443 int dma, int dp, unsigned int possible_crtcs,
Philipp Zabel43895592015-11-06 11:08:02 +0100444 enum drm_plane_type type)
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200445{
446 struct ipu_plane *ipu_plane;
447 int ret;
448
449 DRM_DEBUG_KMS("channel %d, dp flow %d, possible_crtcs=0x%x\n",
450 dma, dp, possible_crtcs);
451
452 ipu_plane = kzalloc(sizeof(*ipu_plane), GFP_KERNEL);
453 if (!ipu_plane) {
454 DRM_ERROR("failed to allocate plane\n");
455 return ERR_PTR(-ENOMEM);
456 }
457
458 ipu_plane->ipu = ipu;
459 ipu_plane->dma = dma;
460 ipu_plane->dp_flow = dp;
461
Philipp Zabel43895592015-11-06 11:08:02 +0100462 ret = drm_universal_plane_init(dev, &ipu_plane->base, possible_crtcs,
463 &ipu_plane_funcs, ipu_plane_formats,
Ville Syrjäläb0b3b792015-12-09 16:19:55 +0200464 ARRAY_SIZE(ipu_plane_formats), type,
465 NULL);
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200466 if (ret) {
467 DRM_ERROR("failed to initialize plane\n");
468 kfree(ipu_plane);
469 return ERR_PTR(ret);
470 }
471
Liu Ying33f14232016-07-08 17:40:55 +0800472 drm_plane_helper_add(&ipu_plane->base, &ipu_plane_helper_funcs);
473
Philipp Zabelb8d181e2013-10-10 16:18:45 +0200474 return ipu_plane;
475}