xref: /openbmc/linux/drivers/gpu/drm/mediatek/mtk_drm_plane.c (revision 7e24a55b2122746c2eef192296fc84624354f895)
11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2119f5173SCK Hu /*
3119f5173SCK Hu  * Copyright (c) 2015 MediaTek Inc.
4119f5173SCK Hu  * Author: CK Hu <ck.hu@mediatek.com>
5119f5173SCK Hu  */
6119f5173SCK Hu 
7119f5173SCK Hu #include <drm/drm_atomic.h>
8119f5173SCK Hu #include <drm/drm_atomic_helper.h>
9920fffccSBibby Hsieh #include <drm/drm_atomic_uapi.h>
1090bb087fSVille Syrjälä #include <drm/drm_blend.h>
11820c1707SThomas Zimmermann #include <drm/drm_fourcc.h>
12720cf96dSVille Syrjälä #include <drm/drm_framebuffer.h>
13820c1707SThomas Zimmermann #include <drm/drm_gem_atomic_helper.h>
14c410fa9bSJustin Green #include <linux/align.h>
15119f5173SCK Hu 
16119f5173SCK Hu #include "mtk_drm_crtc.h"
17119f5173SCK Hu #include "mtk_drm_ddp_comp.h"
18119f5173SCK Hu #include "mtk_drm_drv.h"
19119f5173SCK Hu #include "mtk_drm_gem.h"
20119f5173SCK Hu #include "mtk_drm_plane.h"
21119f5173SCK Hu 
22c410fa9bSJustin Green static const u64 modifiers[] = {
23c410fa9bSJustin Green 	DRM_FORMAT_MOD_LINEAR,
24c410fa9bSJustin Green 	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 |
25c410fa9bSJustin Green 				AFBC_FORMAT_MOD_SPLIT |
26c410fa9bSJustin Green 				AFBC_FORMAT_MOD_SPARSE),
27c410fa9bSJustin Green 	DRM_FORMAT_MOD_INVALID,
28c410fa9bSJustin Green };
29c410fa9bSJustin Green 
mtk_plane_reset(struct drm_plane * plane)30119f5173SCK Hu static void mtk_plane_reset(struct drm_plane *plane)
31119f5173SCK Hu {
32119f5173SCK Hu 	struct mtk_plane_state *state;
33119f5173SCK Hu 
34119f5173SCK Hu 	if (plane->state) {
35903daff6SBibby Hsieh 		__drm_atomic_helper_plane_destroy_state(plane->state);
36119f5173SCK Hu 
37119f5173SCK Hu 		state = to_mtk_plane_state(plane->state);
38119f5173SCK Hu 		memset(state, 0, sizeof(*state));
39119f5173SCK Hu 	} else {
40119f5173SCK Hu 		state = kzalloc(sizeof(*state), GFP_KERNEL);
41119f5173SCK Hu 		if (!state)
42119f5173SCK Hu 			return;
43119f5173SCK Hu 	}
44119f5173SCK Hu 
45d95b00f1SMark Yacoub 	__drm_atomic_helper_plane_reset(plane, &state->base);
46d95b00f1SMark Yacoub 
47119f5173SCK Hu 	state->base.plane = plane;
48119f5173SCK Hu 	state->pending.format = DRM_FORMAT_RGB565;
49c410fa9bSJustin Green 	state->pending.modifier = DRM_FORMAT_MOD_LINEAR;
50119f5173SCK Hu }
51119f5173SCK Hu 
mtk_plane_duplicate_state(struct drm_plane * plane)52119f5173SCK Hu static struct drm_plane_state *mtk_plane_duplicate_state(struct drm_plane *plane)
53119f5173SCK Hu {
54119f5173SCK Hu 	struct mtk_plane_state *old_state = to_mtk_plane_state(plane->state);
55119f5173SCK Hu 	struct mtk_plane_state *state;
56119f5173SCK Hu 
57d327bc37SAngeloGioacchino Del Regno 	state = kmalloc(sizeof(*state), GFP_KERNEL);
58119f5173SCK Hu 	if (!state)
59119f5173SCK Hu 		return NULL;
60119f5173SCK Hu 
61119f5173SCK Hu 	__drm_atomic_helper_plane_duplicate_state(plane, &state->base);
62119f5173SCK Hu 
63119f5173SCK Hu 	WARN_ON(state->base.plane != plane);
64119f5173SCK Hu 
65119f5173SCK Hu 	state->pending = old_state->pending;
66119f5173SCK Hu 
67119f5173SCK Hu 	return &state->base;
68119f5173SCK Hu }
69119f5173SCK Hu 
mtk_plane_format_mod_supported(struct drm_plane * plane,uint32_t format,uint64_t modifier)70c410fa9bSJustin Green static bool mtk_plane_format_mod_supported(struct drm_plane *plane,
71c410fa9bSJustin Green 					   uint32_t format,
72c410fa9bSJustin Green 					   uint64_t modifier)
73c410fa9bSJustin Green {
74c410fa9bSJustin Green 	if (modifier == DRM_FORMAT_MOD_LINEAR)
75c410fa9bSJustin Green 		return true;
76c410fa9bSJustin Green 
77c410fa9bSJustin Green 	if (modifier != DRM_FORMAT_MOD_ARM_AFBC(
78c410fa9bSJustin Green 				AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 |
79c410fa9bSJustin Green 				AFBC_FORMAT_MOD_SPLIT |
80c410fa9bSJustin Green 				AFBC_FORMAT_MOD_SPARSE))
81c410fa9bSJustin Green 		return false;
82c410fa9bSJustin Green 
83c410fa9bSJustin Green 	if (format != DRM_FORMAT_XRGB8888 &&
84c410fa9bSJustin Green 	    format != DRM_FORMAT_ARGB8888 &&
85c410fa9bSJustin Green 	    format != DRM_FORMAT_BGRX8888 &&
86c410fa9bSJustin Green 	    format != DRM_FORMAT_BGRA8888 &&
87c410fa9bSJustin Green 	    format != DRM_FORMAT_ABGR8888 &&
88c410fa9bSJustin Green 	    format != DRM_FORMAT_XBGR8888 &&
89c410fa9bSJustin Green 	    format != DRM_FORMAT_RGB888 &&
90c410fa9bSJustin Green 	    format != DRM_FORMAT_BGR888)
91c410fa9bSJustin Green 		return false;
92c410fa9bSJustin Green 
93c410fa9bSJustin Green 	return true;
94c410fa9bSJustin Green }
95c410fa9bSJustin Green 
mtk_drm_plane_destroy_state(struct drm_plane * plane,struct drm_plane_state * state)96119f5173SCK Hu static void mtk_drm_plane_destroy_state(struct drm_plane *plane,
97119f5173SCK Hu 					struct drm_plane_state *state)
98119f5173SCK Hu {
992f701695SDaniel Vetter 	__drm_atomic_helper_plane_destroy_state(state);
100119f5173SCK Hu 	kfree(to_mtk_plane_state(state));
101119f5173SCK Hu }
102119f5173SCK Hu 
mtk_plane_atomic_async_check(struct drm_plane * plane,struct drm_atomic_state * state)103920fffccSBibby Hsieh static int mtk_plane_atomic_async_check(struct drm_plane *plane,
1045ddb0bd4SMaxime Ripard 					struct drm_atomic_state *state)
105920fffccSBibby Hsieh {
1065ddb0bd4SMaxime Ripard 	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
1075ddb0bd4SMaxime Ripard 										 plane);
108920fffccSBibby Hsieh 	struct drm_crtc_state *crtc_state;
109551c5f55SBibby Hsieh 	int ret;
110920fffccSBibby Hsieh 
1115ddb0bd4SMaxime Ripard 	if (plane != new_plane_state->crtc->cursor)
112920fffccSBibby Hsieh 		return -EINVAL;
113920fffccSBibby Hsieh 
114920fffccSBibby Hsieh 	if (!plane->state)
115920fffccSBibby Hsieh 		return -EINVAL;
116920fffccSBibby Hsieh 
117920fffccSBibby Hsieh 	if (!plane->state->fb)
118920fffccSBibby Hsieh 		return -EINVAL;
119920fffccSBibby Hsieh 
1205ddb0bd4SMaxime Ripard 	ret = mtk_drm_crtc_plane_check(new_plane_state->crtc, plane,
1215ddb0bd4SMaxime Ripard 				       to_mtk_plane_state(new_plane_state));
122551c5f55SBibby Hsieh 	if (ret)
123551c5f55SBibby Hsieh 		return ret;
124551c5f55SBibby Hsieh 
125ed6adfb7SJason-JH.Lin 	crtc_state = drm_atomic_get_existing_crtc_state(state, new_plane_state->crtc);
126920fffccSBibby Hsieh 
127920fffccSBibby Hsieh 	return drm_atomic_helper_check_plane_state(plane->state, crtc_state,
128cce32e4eSThomas Zimmermann 						   DRM_PLANE_NO_SCALING,
129cce32e4eSThomas Zimmermann 						   DRM_PLANE_NO_SCALING,
130920fffccSBibby Hsieh 						   true, true);
131920fffccSBibby Hsieh }
132920fffccSBibby Hsieh 
mtk_plane_update_new_state(struct drm_plane_state * new_state,struct mtk_plane_state * mtk_plane_state)1331a64a7afSjason-jh.lin static void mtk_plane_update_new_state(struct drm_plane_state *new_state,
1341a64a7afSjason-jh.lin 				       struct mtk_plane_state *mtk_plane_state)
1351a64a7afSjason-jh.lin {
1361a64a7afSjason-jh.lin 	struct drm_framebuffer *fb = new_state->fb;
1371a64a7afSjason-jh.lin 	struct drm_gem_object *gem;
1381a64a7afSjason-jh.lin 	struct mtk_drm_gem_obj *mtk_gem;
1391a64a7afSjason-jh.lin 	unsigned int pitch, format;
140c410fa9bSJustin Green 	u64 modifier;
1411a64a7afSjason-jh.lin 	dma_addr_t addr;
142c410fa9bSJustin Green 	dma_addr_t hdr_addr = 0;
143c410fa9bSJustin Green 	unsigned int hdr_pitch = 0;
14496312a25SJason-JH.Lin 	int offset;
1451a64a7afSjason-jh.lin 
1461a64a7afSjason-jh.lin 	gem = fb->obj[0];
1471a64a7afSjason-jh.lin 	mtk_gem = to_mtk_gem_obj(gem);
1481a64a7afSjason-jh.lin 	addr = mtk_gem->dma_addr;
1491a64a7afSjason-jh.lin 	pitch = fb->pitches[0];
1501a64a7afSjason-jh.lin 	format = fb->format->format;
151c410fa9bSJustin Green 	modifier = fb->modifier;
1521a64a7afSjason-jh.lin 
153c410fa9bSJustin Green 	if (modifier == DRM_FORMAT_MOD_LINEAR) {
15496312a25SJason-JH.Lin 		/*
15596312a25SJason-JH.Lin 		 * Using dma_addr_t variable to calculate with multiplier of different types,
15696312a25SJason-JH.Lin 		 * for example: addr += (new_state->src.x1 >> 16) * fb->format->cpp[0];
15796312a25SJason-JH.Lin 		 * may cause coverity issue with unintentional overflow.
15896312a25SJason-JH.Lin 		 */
15996312a25SJason-JH.Lin 		offset = (new_state->src.x1 >> 16) * fb->format->cpp[0];
16096312a25SJason-JH.Lin 		addr += offset;
16196312a25SJason-JH.Lin 		offset = (new_state->src.y1 >> 16) * pitch;
16296312a25SJason-JH.Lin 		addr += offset;
163c410fa9bSJustin Green 	} else {
164c410fa9bSJustin Green 		int width_in_blocks = ALIGN(fb->width, AFBC_DATA_BLOCK_WIDTH)
165c410fa9bSJustin Green 				      / AFBC_DATA_BLOCK_WIDTH;
166c410fa9bSJustin Green 		int height_in_blocks = ALIGN(fb->height, AFBC_DATA_BLOCK_HEIGHT)
167c410fa9bSJustin Green 				       / AFBC_DATA_BLOCK_HEIGHT;
168c410fa9bSJustin Green 		int x_offset_in_blocks = (new_state->src.x1 >> 16) / AFBC_DATA_BLOCK_WIDTH;
169c410fa9bSJustin Green 		int y_offset_in_blocks = (new_state->src.y1 >> 16) / AFBC_DATA_BLOCK_HEIGHT;
17096312a25SJason-JH.Lin 		int hdr_size, hdr_offset;
171c410fa9bSJustin Green 
172c410fa9bSJustin Green 		hdr_pitch = width_in_blocks * AFBC_HEADER_BLOCK_SIZE;
173c410fa9bSJustin Green 		pitch = width_in_blocks * AFBC_DATA_BLOCK_WIDTH *
174c410fa9bSJustin Green 			AFBC_DATA_BLOCK_HEIGHT * fb->format->cpp[0];
175c410fa9bSJustin Green 
176c410fa9bSJustin Green 		hdr_size = ALIGN(hdr_pitch * height_in_blocks, AFBC_HEADER_ALIGNMENT);
17796312a25SJason-JH.Lin 		hdr_offset = hdr_pitch * y_offset_in_blocks +
178c410fa9bSJustin Green 			AFBC_HEADER_BLOCK_SIZE * x_offset_in_blocks;
17996312a25SJason-JH.Lin 
18096312a25SJason-JH.Lin 		/*
18196312a25SJason-JH.Lin 		 * Using dma_addr_t variable to calculate with multiplier of different types,
18296312a25SJason-JH.Lin 		 * for example: addr += hdr_pitch * y_offset_in_blocks;
18396312a25SJason-JH.Lin 		 * may cause coverity issue with unintentional overflow.
18496312a25SJason-JH.Lin 		 */
18596312a25SJason-JH.Lin 		hdr_addr = addr + hdr_offset;
18696312a25SJason-JH.Lin 
187c410fa9bSJustin Green 		/* The data plane is offset by 1 additional block. */
18896312a25SJason-JH.Lin 		offset = pitch * y_offset_in_blocks +
189c410fa9bSJustin Green 			 AFBC_DATA_BLOCK_WIDTH * AFBC_DATA_BLOCK_HEIGHT *
190c410fa9bSJustin Green 			 fb->format->cpp[0] * (x_offset_in_blocks + 1);
19196312a25SJason-JH.Lin 
19296312a25SJason-JH.Lin 		/*
19396312a25SJason-JH.Lin 		 * Using dma_addr_t variable to calculate with multiplier of different types,
19496312a25SJason-JH.Lin 		 * for example: addr += pitch * y_offset_in_blocks;
19596312a25SJason-JH.Lin 		 * may cause coverity issue with unintentional overflow.
19696312a25SJason-JH.Lin 		 */
19796312a25SJason-JH.Lin 		addr = addr + hdr_size + offset;
198c410fa9bSJustin Green 	}
1991a64a7afSjason-jh.lin 
2001a64a7afSjason-jh.lin 	mtk_plane_state->pending.enable = true;
2011a64a7afSjason-jh.lin 	mtk_plane_state->pending.pitch = pitch;
202c410fa9bSJustin Green 	mtk_plane_state->pending.hdr_pitch = hdr_pitch;
2031a64a7afSjason-jh.lin 	mtk_plane_state->pending.format = format;
204c410fa9bSJustin Green 	mtk_plane_state->pending.modifier = modifier;
2051a64a7afSjason-jh.lin 	mtk_plane_state->pending.addr = addr;
206c410fa9bSJustin Green 	mtk_plane_state->pending.hdr_addr = hdr_addr;
2071a64a7afSjason-jh.lin 	mtk_plane_state->pending.x = new_state->dst.x1;
2081a64a7afSjason-jh.lin 	mtk_plane_state->pending.y = new_state->dst.y1;
2091a64a7afSjason-jh.lin 	mtk_plane_state->pending.width = drm_rect_width(&new_state->dst);
2101a64a7afSjason-jh.lin 	mtk_plane_state->pending.height = drm_rect_height(&new_state->dst);
2111a64a7afSjason-jh.lin 	mtk_plane_state->pending.rotation = new_state->rotation;
2125621416bSNancy.Lin 	mtk_plane_state->pending.color_encoding = new_state->color_encoding;
2131a64a7afSjason-jh.lin }
2141a64a7afSjason-jh.lin 
mtk_plane_atomic_async_update(struct drm_plane * plane,struct drm_atomic_state * state)215920fffccSBibby Hsieh static void mtk_plane_atomic_async_update(struct drm_plane *plane,
2165ddb0bd4SMaxime Ripard 					  struct drm_atomic_state *state)
217920fffccSBibby Hsieh {
2185ddb0bd4SMaxime Ripard 	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
2195ddb0bd4SMaxime Ripard 									   plane);
2205ddb0bd4SMaxime Ripard 	struct mtk_plane_state *new_plane_state = to_mtk_plane_state(plane->state);
221920fffccSBibby Hsieh 
222920fffccSBibby Hsieh 	plane->state->crtc_x = new_state->crtc_x;
223920fffccSBibby Hsieh 	plane->state->crtc_y = new_state->crtc_y;
224920fffccSBibby Hsieh 	plane->state->crtc_h = new_state->crtc_h;
225920fffccSBibby Hsieh 	plane->state->crtc_w = new_state->crtc_w;
226920fffccSBibby Hsieh 	plane->state->src_x = new_state->src_x;
227920fffccSBibby Hsieh 	plane->state->src_y = new_state->src_y;
228920fffccSBibby Hsieh 	plane->state->src_h = new_state->src_h;
229920fffccSBibby Hsieh 	plane->state->src_w = new_state->src_w;
230*df55acaaSHsiao Chien Sung 	plane->state->dst.x1 = new_state->dst.x1;
231*df55acaaSHsiao Chien Sung 	plane->state->dst.y1 = new_state->dst.y1;
232920fffccSBibby Hsieh 
2331a64a7afSjason-jh.lin 	mtk_plane_update_new_state(new_state, new_plane_state);
2340776389bSJason-JH.Lin 	swap(plane->state->fb, new_state->fb);
2351a64a7afSjason-jh.lin 	wmb(); /* Make sure the above parameters are set before update */
2361a64a7afSjason-jh.lin 	new_plane_state->pending.async_dirty = true;
237977697e2SMaxime Ripard 	mtk_drm_crtc_async_update(new_state->crtc, plane, state);
238920fffccSBibby Hsieh }
239920fffccSBibby Hsieh 
240119f5173SCK Hu static const struct drm_plane_funcs mtk_plane_funcs = {
241119f5173SCK Hu 	.update_plane = drm_atomic_helper_update_plane,
242119f5173SCK Hu 	.disable_plane = drm_atomic_helper_disable_plane,
243119f5173SCK Hu 	.destroy = drm_plane_cleanup,
244119f5173SCK Hu 	.reset = mtk_plane_reset,
245119f5173SCK Hu 	.atomic_duplicate_state = mtk_plane_duplicate_state,
246119f5173SCK Hu 	.atomic_destroy_state = mtk_drm_plane_destroy_state,
247c410fa9bSJustin Green 	.format_mod_supported = mtk_plane_format_mod_supported,
248119f5173SCK Hu };
249119f5173SCK Hu 
mtk_plane_atomic_check(struct drm_plane * plane,struct drm_atomic_state * state)250119f5173SCK Hu static int mtk_plane_atomic_check(struct drm_plane *plane,
2517c11b99aSMaxime Ripard 				  struct drm_atomic_state *state)
252119f5173SCK Hu {
2537c11b99aSMaxime Ripard 	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
2547c11b99aSMaxime Ripard 										 plane);
255ba5c1649SMaxime Ripard 	struct drm_framebuffer *fb = new_plane_state->fb;
256119f5173SCK Hu 	struct drm_crtc_state *crtc_state;
257f7c710d1SSean Paul 	int ret;
258119f5173SCK Hu 
259119f5173SCK Hu 	if (!fb)
260119f5173SCK Hu 		return 0;
261119f5173SCK Hu 
262ba5c1649SMaxime Ripard 	if (WARN_ON(!new_plane_state->crtc))
263119f5173SCK Hu 		return 0;
264119f5173SCK Hu 
265ba5c1649SMaxime Ripard 	ret = mtk_drm_crtc_plane_check(new_plane_state->crtc, plane,
266ba5c1649SMaxime Ripard 				       to_mtk_plane_state(new_plane_state));
267f7c710d1SSean Paul 	if (ret)
268f7c710d1SSean Paul 		return ret;
269f7c710d1SSean Paul 
270dec92020SMaxime Ripard 	crtc_state = drm_atomic_get_crtc_state(state,
271ba5c1649SMaxime Ripard 					       new_plane_state->crtc);
272119f5173SCK Hu 	if (IS_ERR(crtc_state))
273119f5173SCK Hu 		return PTR_ERR(crtc_state);
274119f5173SCK Hu 
275ba5c1649SMaxime Ripard 	return drm_atomic_helper_check_plane_state(new_plane_state,
276ba5c1649SMaxime Ripard 						   crtc_state,
277cce32e4eSThomas Zimmermann 						   DRM_PLANE_NO_SCALING,
278cce32e4eSThomas Zimmermann 						   DRM_PLANE_NO_SCALING,
2790e4faf67SVille Syrjälä 						   true, true);
280119f5173SCK Hu }
281119f5173SCK Hu 
mtk_plane_atomic_disable(struct drm_plane * plane,struct drm_atomic_state * state)282c0b8892eSHsin-Yi Wang static void mtk_plane_atomic_disable(struct drm_plane *plane,
283977697e2SMaxime Ripard 				     struct drm_atomic_state *state)
284c0b8892eSHsin-Yi Wang {
28537418bf1SMaxime Ripard 	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
28637418bf1SMaxime Ripard 									   plane);
28741016fe1SMaxime Ripard 	struct mtk_plane_state *mtk_plane_state = to_mtk_plane_state(new_state);
28841016fe1SMaxime Ripard 	mtk_plane_state->pending.enable = false;
289c0b8892eSHsin-Yi Wang 	wmb(); /* Make sure the above parameter is set before update */
29041016fe1SMaxime Ripard 	mtk_plane_state->pending.dirty = true;
291c0b8892eSHsin-Yi Wang }
292c0b8892eSHsin-Yi Wang 
mtk_plane_atomic_update(struct drm_plane * plane,struct drm_atomic_state * state)293119f5173SCK Hu static void mtk_plane_atomic_update(struct drm_plane *plane,
294977697e2SMaxime Ripard 				    struct drm_atomic_state *state)
295119f5173SCK Hu {
29637418bf1SMaxime Ripard 	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
29737418bf1SMaxime Ripard 									   plane);
29841016fe1SMaxime Ripard 	struct mtk_plane_state *mtk_plane_state = to_mtk_plane_state(new_state);
299119f5173SCK Hu 
3001a64a7afSjason-jh.lin 	if (!new_state->crtc || WARN_ON(!new_state->fb))
301119f5173SCK Hu 		return;
302119f5173SCK Hu 
303e05162c0SMaxime Ripard 	if (!new_state->visible) {
304977697e2SMaxime Ripard 		mtk_plane_atomic_disable(plane, state);
305c0b8892eSHsin-Yi Wang 		return;
306c0b8892eSHsin-Yi Wang 	}
307c0b8892eSHsin-Yi Wang 
3081a64a7afSjason-jh.lin 	mtk_plane_update_new_state(new_state, mtk_plane_state);
309f176cbf6SDaniel Kurtz 	wmb(); /* Make sure the above parameters are set before update */
31041016fe1SMaxime Ripard 	mtk_plane_state->pending.dirty = true;
311119f5173SCK Hu }
312119f5173SCK Hu 
313119f5173SCK Hu static const struct drm_plane_helper_funcs mtk_plane_helper_funcs = {
314119f5173SCK Hu 	.atomic_check = mtk_plane_atomic_check,
315119f5173SCK Hu 	.atomic_update = mtk_plane_atomic_update,
316119f5173SCK Hu 	.atomic_disable = mtk_plane_atomic_disable,
317920fffccSBibby Hsieh 	.atomic_async_update = mtk_plane_atomic_async_update,
318920fffccSBibby Hsieh 	.atomic_async_check = mtk_plane_atomic_async_check,
319119f5173SCK Hu };
320119f5173SCK Hu 
mtk_plane_init(struct drm_device * dev,struct drm_plane * plane,unsigned long possible_crtcs,enum drm_plane_type type,unsigned int supported_rotations,const u32 * formats,size_t num_formats)3215bfafad8SDaniel Kurtz int mtk_plane_init(struct drm_device *dev, struct drm_plane *plane,
322ef87d3e2SSean Paul 		   unsigned long possible_crtcs, enum drm_plane_type type,
323f287c66aSJustin Green 		   unsigned int supported_rotations, const u32 *formats,
324f287c66aSJustin Green 		   size_t num_formats)
325119f5173SCK Hu {
326119f5173SCK Hu 	int err;
327119f5173SCK Hu 
328f287c66aSJustin Green 	if (!formats || !num_formats) {
329f287c66aSJustin Green 		DRM_ERROR("no formats for plane\n");
330f287c66aSJustin Green 		return -EINVAL;
331f287c66aSJustin Green 	}
332f287c66aSJustin Green 
3335bfafad8SDaniel Kurtz 	err = drm_universal_plane_init(dev, plane, possible_crtcs,
334119f5173SCK Hu 				       &mtk_plane_funcs, formats,
335f287c66aSJustin Green 				       num_formats, modifiers, type, NULL);
336119f5173SCK Hu 	if (err) {
337119f5173SCK Hu 		DRM_ERROR("failed to initialize plane\n");
338119f5173SCK Hu 		return err;
339119f5173SCK Hu 	}
340119f5173SCK Hu 
341ef87d3e2SSean Paul 	if (supported_rotations & ~DRM_MODE_ROTATE_0) {
342ef87d3e2SSean Paul 		err = drm_plane_create_rotation_property(plane,
343ef87d3e2SSean Paul 							 DRM_MODE_ROTATE_0,
344ef87d3e2SSean Paul 							 supported_rotations);
345ef87d3e2SSean Paul 		if (err)
346ef87d3e2SSean Paul 			DRM_INFO("Create rotation property failed\n");
347ef87d3e2SSean Paul 	}
348ef87d3e2SSean Paul 
3495bfafad8SDaniel Kurtz 	drm_plane_helper_add(plane, &mtk_plane_helper_funcs);
350119f5173SCK Hu 
351119f5173SCK Hu 	return 0;
352119f5173SCK Hu }
353