1caab277bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
28bb0daffSRob Clark /*
31b409fdaSAlexander A. Klimov  * Copyright (C) 2011 Texas Instruments Incorporated - https://www.ti.com/
48bb0daffSRob Clark  * Author: Rob Clark <rob.clark@linaro.org>
58bb0daffSRob Clark  */
68bb0daffSRob Clark 
7c423bc85STomi Valkeinen #include <drm/drm_atomic.h>
869a12263SLaurent Pinchart #include <drm/drm_atomic_helper.h>
9942d8344SDaniel Vetter #include <drm/drm_gem_atomic_helper.h>
10de8e4100SLaurent Pinchart #include <drm/drm_plane_helper.h>
112e54ff0eSBenoit Parrot #include <drm/drm_fourcc.h>
1269a12263SLaurent Pinchart 
138bb0daffSRob Clark #include "omap_dmm_tiler.h"
142d278f54SLaurent Pinchart #include "omap_drv.h"
158bb0daffSRob Clark 
168bb0daffSRob Clark /*
178bb0daffSRob Clark  * plane funcs
188bb0daffSRob Clark  */
198bb0daffSRob Clark 
203c265d92SBenoit Parrot #define to_omap_plane_state(x) container_of(x, struct omap_plane_state, base)
213c265d92SBenoit Parrot 
223c265d92SBenoit Parrot struct omap_plane_state {
233c265d92SBenoit Parrot 	/* Must be first. */
243c265d92SBenoit Parrot 	struct drm_plane_state base;
252e54ff0eSBenoit Parrot 
262e54ff0eSBenoit Parrot 	struct omap_hw_overlay *overlay;
273c265d92SBenoit Parrot };
283c265d92SBenoit Parrot 
298bb0daffSRob Clark #define to_omap_plane(x) container_of(x, struct omap_plane, base)
308bb0daffSRob Clark 
318bb0daffSRob Clark struct omap_plane {
328bb0daffSRob Clark 	struct drm_plane base;
33694c99cfSJyri Sarha 	enum omap_plane_id id;
348bb0daffSRob Clark };
358bb0daffSRob Clark 
3611ffd031STomi Valkeinen static int omap_plane_prepare_fb(struct drm_plane *plane,
371832040dSChris Wilson 				 struct drm_plane_state *new_state)
3811ffd031STomi Valkeinen {
39844f9111SMaarten Lankhorst 	if (!new_state->fb)
40844f9111SMaarten Lankhorst 		return 0;
41844f9111SMaarten Lankhorst 
42942d8344SDaniel Vetter 	drm_gem_plane_helper_prepare_fb(plane, new_state);
43942d8344SDaniel Vetter 
44844f9111SMaarten Lankhorst 	return omap_framebuffer_pin(new_state->fb);
4511ffd031STomi Valkeinen }
4611ffd031STomi Valkeinen 
4711ffd031STomi Valkeinen static void omap_plane_cleanup_fb(struct drm_plane *plane,
481832040dSChris Wilson 				  struct drm_plane_state *old_state)
4911ffd031STomi Valkeinen {
50844f9111SMaarten Lankhorst 	if (old_state->fb)
51844f9111SMaarten Lankhorst 		omap_framebuffer_unpin(old_state->fb);
5211ffd031STomi Valkeinen }
5311ffd031STomi Valkeinen 
5411ffd031STomi Valkeinen static void omap_plane_atomic_update(struct drm_plane *plane,
55977697e2SMaxime Ripard 				     struct drm_atomic_state *state)
56afc34932SLaurent Pinchart {
579f759225STomi Valkeinen 	struct omap_drm_private *priv = plane->dev->dev_private;
5837418bf1SMaxime Ripard 	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
5937418bf1SMaxime Ripard 									   plane);
602e54ff0eSBenoit Parrot 	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
612e54ff0eSBenoit Parrot 									   plane);
622e54ff0eSBenoit Parrot 	struct omap_plane_state *new_omap_state;
632e54ff0eSBenoit Parrot 	struct omap_plane_state *old_omap_state;
64fb730c9bSLaurent Pinchart 	struct omap_overlay_info info;
652e54ff0eSBenoit Parrot 	enum omap_plane_id ovl_id;
668bb0daffSRob Clark 	int ret;
678bb0daffSRob Clark 
682e54ff0eSBenoit Parrot 	new_omap_state = to_omap_plane_state(new_state);
692e54ff0eSBenoit Parrot 	old_omap_state = to_omap_plane_state(old_state);
702e54ff0eSBenoit Parrot 
712e54ff0eSBenoit Parrot 	/* Cleanup previously held overlay if needed */
722e54ff0eSBenoit Parrot 	if (old_omap_state->overlay)
732e54ff0eSBenoit Parrot 		omap_overlay_update_state(priv, old_omap_state->overlay);
742e54ff0eSBenoit Parrot 
752e54ff0eSBenoit Parrot 	if (!new_omap_state->overlay) {
762e54ff0eSBenoit Parrot 		DBG("[PLANE:%d:%s] no overlay attached", plane->base.id, plane->name);
772e54ff0eSBenoit Parrot 		return;
782e54ff0eSBenoit Parrot 	}
792e54ff0eSBenoit Parrot 
802e54ff0eSBenoit Parrot 	ovl_id = new_omap_state->overlay->id;
81c8fa1e73SBenoit Parrot 	DBG("%s, crtc=%p fb=%p", plane->name, new_state->crtc,
8241016fe1SMaxime Ripard 	    new_state->fb);
838bb0daffSRob Clark 
84fb730c9bSLaurent Pinchart 	memset(&info, 0, sizeof(info));
85517a8a95STomi Valkeinen 	info.rotation_type = OMAP_DSS_ROT_NONE;
860bd97c42STomi Valkeinen 	info.rotation = DRM_MODE_ROTATE_0;
8741016fe1SMaxime Ripard 	info.global_alpha = new_state->alpha >> 8;
8841016fe1SMaxime Ripard 	info.zorder = new_state->normalized_zpos;
8941016fe1SMaxime Ripard 	if (new_state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI)
903037e0c5SJean-Jacques Hiblot 		info.pre_mult_alpha = 1;
913037e0c5SJean-Jacques Hiblot 	else
923037e0c5SJean-Jacques Hiblot 		info.pre_mult_alpha = 0;
9341016fe1SMaxime Ripard 	info.color_encoding = new_state->color_encoding;
9441016fe1SMaxime Ripard 	info.color_range = new_state->color_range;
95fb730c9bSLaurent Pinchart 
968bb0daffSRob Clark 	/* update scanout: */
9741016fe1SMaxime Ripard 	omap_framebuffer_update_scanout(new_state->fb, new_state, &info);
988bb0daffSRob Clark 
992e54ff0eSBenoit Parrot 	DBG("%s: %dx%d -> %dx%d (%d)",
1002e54ff0eSBenoit Parrot 			new_omap_state->overlay->name, info.width, info.height,
1012e54ff0eSBenoit Parrot 			info.out_width, info.out_height, info.screen_width);
102fb730c9bSLaurent Pinchart 	DBG("%d,%d %pad %pad", info.pos_x, info.pos_y,
103fb730c9bSLaurent Pinchart 			&info.paddr, &info.p_uv_addr);
1048bb0daffSRob Clark 
1058bb0daffSRob Clark 	/* and finally, update omapdss: */
106c8fa1e73SBenoit Parrot 	ret = dispc_ovl_setup(priv->dispc, ovl_id, &info,
10741016fe1SMaxime Ripard 			      omap_crtc_timings(new_state->crtc), false,
10841016fe1SMaxime Ripard 			      omap_crtc_channel(new_state->crtc));
109cfb73f20STomi Valkeinen 	if (ret) {
110cfb73f20STomi Valkeinen 		dev_err(plane->dev->dev, "Failed to setup plane %s\n",
111c8fa1e73SBenoit Parrot 			plane->name);
112c8fa1e73SBenoit Parrot 		dispc_ovl_enable(priv->dispc, ovl_id, false);
113d9157dfdSTomi Valkeinen 		return;
114794a65ffSTomi Valkeinen 	}
1158bb0daffSRob Clark 
116c8fa1e73SBenoit Parrot 	dispc_ovl_enable(priv->dispc, ovl_id, true);
117de8e4100SLaurent Pinchart }
118de8e4100SLaurent Pinchart 
119de8e4100SLaurent Pinchart static void omap_plane_atomic_disable(struct drm_plane *plane,
120977697e2SMaxime Ripard 				      struct drm_atomic_state *state)
1218bb0daffSRob Clark {
1229f759225STomi Valkeinen 	struct omap_drm_private *priv = plane->dev->dev_private;
1238bb0daffSRob Clark 	struct omap_plane *omap_plane = to_omap_plane(plane);
1242e54ff0eSBenoit Parrot 	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
1252e54ff0eSBenoit Parrot 									   plane);
1262e54ff0eSBenoit Parrot 	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
1272e54ff0eSBenoit Parrot 									   plane);
1282e54ff0eSBenoit Parrot 	struct omap_plane_state *new_omap_state;
1292e54ff0eSBenoit Parrot 	struct omap_plane_state *old_omap_state;
1302e54ff0eSBenoit Parrot 
1312e54ff0eSBenoit Parrot 	new_omap_state = to_omap_plane_state(new_state);
1322e54ff0eSBenoit Parrot 	old_omap_state = to_omap_plane_state(old_state);
1332e54ff0eSBenoit Parrot 
1342e54ff0eSBenoit Parrot 	if (!old_omap_state->overlay)
1352e54ff0eSBenoit Parrot 		return;
1362debab97SLaurent Pinchart 
137e05162c0SMaxime Ripard 	new_state->rotation = DRM_MODE_ROTATE_0;
138e05162c0SMaxime Ripard 	new_state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY ? 0 : omap_plane->id;
13982e58855SLaurent Pinchart 
1402e54ff0eSBenoit Parrot 	omap_overlay_update_state(priv, old_omap_state->overlay);
1412e54ff0eSBenoit Parrot 	new_omap_state->overlay = NULL;
1428bb0daffSRob Clark }
1438bb0daffSRob Clark 
144c21134b0SNeil Armstrong #define FRAC_16_16(mult, div)    (((mult) << 16) / (div))
145c21134b0SNeil Armstrong 
146c423bc85STomi Valkeinen static int omap_plane_atomic_check(struct drm_plane *plane,
1477c11b99aSMaxime Ripard 				   struct drm_atomic_state *state)
148c423bc85STomi Valkeinen {
1497c11b99aSMaxime Ripard 	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
1507c11b99aSMaxime Ripard 										 plane);
1512e54ff0eSBenoit Parrot 	struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state,
1522e54ff0eSBenoit Parrot 										 plane);
153d484c20dSBenoit Parrot 	struct omap_drm_private *priv = plane->dev->dev_private;
1542e54ff0eSBenoit Parrot 	struct omap_plane_state *omap_state = to_omap_plane_state(new_plane_state);
1552e54ff0eSBenoit Parrot 	struct omap_global_state *omap_overlay_global_state;
156c423bc85STomi Valkeinen 	struct drm_crtc_state *crtc_state;
1572e54ff0eSBenoit Parrot 	bool new_hw_overlay = false;
158d484c20dSBenoit Parrot 	u32 max_width, max_height;
1592e54ff0eSBenoit Parrot 	struct drm_crtc *crtc;
160d484c20dSBenoit Parrot 	u16 width, height;
1612e54ff0eSBenoit Parrot 	u32 caps = 0;
1622e54ff0eSBenoit Parrot 	u32 fourcc;
163c21134b0SNeil Armstrong 	int ret;
164c423bc85STomi Valkeinen 
1652e54ff0eSBenoit Parrot 	omap_overlay_global_state = omap_get_global_state(state);
1662e54ff0eSBenoit Parrot 	if (IS_ERR(omap_overlay_global_state))
1672e54ff0eSBenoit Parrot 		return PTR_ERR(omap_overlay_global_state);
168c423bc85STomi Valkeinen 
169d484c20dSBenoit Parrot 	dispc_ovl_get_max_size(priv->dispc, &width, &height);
170d484c20dSBenoit Parrot 	max_width = width << 16;
171d484c20dSBenoit Parrot 	max_height = height << 16;
172d484c20dSBenoit Parrot 
1732e54ff0eSBenoit Parrot 	crtc = new_plane_state->crtc ? new_plane_state->crtc : plane->state->crtc;
1742e54ff0eSBenoit Parrot 	if (!crtc)
17570dd2a62STomi Valkeinen 		return 0;
17670dd2a62STomi Valkeinen 
1772e54ff0eSBenoit Parrot 	crtc_state = drm_atomic_get_existing_crtc_state(state, crtc);
17870dd2a62STomi Valkeinen 	/* we should have a crtc state if the plane is attached to a crtc */
17970dd2a62STomi Valkeinen 	if (WARN_ON(!crtc_state))
18070dd2a62STomi Valkeinen 		return 0;
181c423bc85STomi Valkeinen 
182c21134b0SNeil Armstrong 	/*
183c21134b0SNeil Armstrong 	 * Note: these are just sanity checks to filter out totally bad scaling
184c21134b0SNeil Armstrong 	 * factors. The real limits must be calculated case by case, and
185c21134b0SNeil Armstrong 	 * unfortunately we currently do those checks only at the commit
186c21134b0SNeil Armstrong 	 * phase in dispc.
187c21134b0SNeil Armstrong 	 */
188c21134b0SNeil Armstrong 	ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
189c21134b0SNeil Armstrong 						  FRAC_16_16(1, 8), FRAC_16_16(8, 1),
190c21134b0SNeil Armstrong 						  true, true);
191c21134b0SNeil Armstrong 	if (ret)
192c21134b0SNeil Armstrong 		return ret;
193c21134b0SNeil Armstrong 
1942e54ff0eSBenoit Parrot 	DBG("%s: visible %d -> %d", plane->name,
1952e54ff0eSBenoit Parrot 	    old_plane_state->visible, new_plane_state->visible);
1962e54ff0eSBenoit Parrot 
1972e54ff0eSBenoit Parrot 	if (!new_plane_state->visible) {
1982e54ff0eSBenoit Parrot 		omap_overlay_release(state, omap_state->overlay);
1992e54ff0eSBenoit Parrot 		omap_state->overlay = NULL;
2002e54ff0eSBenoit Parrot 		return 0;
2012e54ff0eSBenoit Parrot 	}
2022e54ff0eSBenoit Parrot 
203ba5c1649SMaxime Ripard 	if (new_plane_state->crtc_x < 0 || new_plane_state->crtc_y < 0)
204c423bc85STomi Valkeinen 		return -EINVAL;
205c423bc85STomi Valkeinen 
206ba5c1649SMaxime Ripard 	if (new_plane_state->crtc_x + new_plane_state->crtc_w > crtc_state->adjusted_mode.hdisplay)
207c423bc85STomi Valkeinen 		return -EINVAL;
208c423bc85STomi Valkeinen 
209ba5c1649SMaxime Ripard 	if (new_plane_state->crtc_y + new_plane_state->crtc_h > crtc_state->adjusted_mode.vdisplay)
210c423bc85STomi Valkeinen 		return -EINVAL;
211c423bc85STomi Valkeinen 
212d484c20dSBenoit Parrot 	/* Make sure dimensions are within bounds. */
213d484c20dSBenoit Parrot 	if (new_plane_state->src_h > max_height || new_plane_state->crtc_h > height)
214d484c20dSBenoit Parrot 		return -EINVAL;
215d484c20dSBenoit Parrot 
216d484c20dSBenoit Parrot 	if (new_plane_state->src_w > max_width || new_plane_state->crtc_w > width)
217d484c20dSBenoit Parrot 		return -EINVAL;
218d484c20dSBenoit Parrot 
219ba5c1649SMaxime Ripard 	if (new_plane_state->rotation != DRM_MODE_ROTATE_0 &&
220ba5c1649SMaxime Ripard 	    !omap_framebuffer_supports_rotation(new_plane_state->fb))
221bfeece55STomi Valkeinen 		return -EINVAL;
222bfeece55STomi Valkeinen 
2232e54ff0eSBenoit Parrot 	if ((new_plane_state->src_w >> 16) != new_plane_state->crtc_w ||
2242e54ff0eSBenoit Parrot 	    (new_plane_state->src_h >> 16) != new_plane_state->crtc_h)
2252e54ff0eSBenoit Parrot 		caps |= OMAP_DSS_OVL_CAP_SCALE;
2262e54ff0eSBenoit Parrot 
2272e54ff0eSBenoit Parrot 	fourcc = new_plane_state->fb->format->format;
2282e54ff0eSBenoit Parrot 
2292e54ff0eSBenoit Parrot 	/*
2302e54ff0eSBenoit Parrot 	 * (re)allocate hw overlay if we don't have one or
2312e54ff0eSBenoit Parrot 	 * there is a caps mismatch
2322e54ff0eSBenoit Parrot 	 */
2332e54ff0eSBenoit Parrot 	if (!omap_state->overlay || (caps & ~omap_state->overlay->caps)) {
2342e54ff0eSBenoit Parrot 		new_hw_overlay = true;
2352e54ff0eSBenoit Parrot 	} else {
2362e54ff0eSBenoit Parrot 		/* check supported format */
2372e54ff0eSBenoit Parrot 		if (!dispc_ovl_color_mode_supported(priv->dispc, omap_state->overlay->id,
2382e54ff0eSBenoit Parrot 						    fourcc))
2392e54ff0eSBenoit Parrot 			new_hw_overlay = true;
2402e54ff0eSBenoit Parrot 	}
2412e54ff0eSBenoit Parrot 
2422e54ff0eSBenoit Parrot 	if (new_hw_overlay) {
2432e54ff0eSBenoit Parrot 		struct omap_hw_overlay *old_ovl = omap_state->overlay;
2442e54ff0eSBenoit Parrot 		struct omap_hw_overlay *new_ovl = NULL;
2452e54ff0eSBenoit Parrot 
2462e54ff0eSBenoit Parrot 		omap_overlay_release(state, old_ovl);
2472e54ff0eSBenoit Parrot 
2482e54ff0eSBenoit Parrot 		ret = omap_overlay_assign(state, plane, caps, fourcc, &new_ovl);
2492e54ff0eSBenoit Parrot 		if (ret) {
2502e54ff0eSBenoit Parrot 			DBG("%s: failed to assign hw_overlay", plane->name);
2512e54ff0eSBenoit Parrot 			omap_state->overlay = NULL;
2522e54ff0eSBenoit Parrot 			return ret;
2532e54ff0eSBenoit Parrot 		}
2542e54ff0eSBenoit Parrot 
2552e54ff0eSBenoit Parrot 		omap_state->overlay = new_ovl;
2562e54ff0eSBenoit Parrot 	}
2572e54ff0eSBenoit Parrot 
2582e54ff0eSBenoit Parrot 	DBG("plane: %s overlay_id: %d", plane->name, omap_state->overlay->id);
2592e54ff0eSBenoit Parrot 
260c423bc85STomi Valkeinen 	return 0;
261c423bc85STomi Valkeinen }
262c423bc85STomi Valkeinen 
263de8e4100SLaurent Pinchart static const struct drm_plane_helper_funcs omap_plane_helper_funcs = {
264de8e4100SLaurent Pinchart 	.prepare_fb = omap_plane_prepare_fb,
265de8e4100SLaurent Pinchart 	.cleanup_fb = omap_plane_cleanup_fb,
266c423bc85STomi Valkeinen 	.atomic_check = omap_plane_atomic_check,
267de8e4100SLaurent Pinchart 	.atomic_update = omap_plane_atomic_update,
268de8e4100SLaurent Pinchart 	.atomic_disable = omap_plane_atomic_disable,
269de8e4100SLaurent Pinchart };
270de8e4100SLaurent Pinchart 
2718bb0daffSRob Clark static void omap_plane_destroy(struct drm_plane *plane)
2728bb0daffSRob Clark {
2738bb0daffSRob Clark 	struct omap_plane *omap_plane = to_omap_plane(plane);
2748bb0daffSRob Clark 
275c8fa1e73SBenoit Parrot 	DBG("%s", plane->name);
2768bb0daffSRob Clark 
2778bb0daffSRob Clark 	drm_plane_cleanup(plane);
2788bb0daffSRob Clark 
2798bb0daffSRob Clark 	kfree(omap_plane);
2808bb0daffSRob Clark }
2818bb0daffSRob Clark 
2828bb0daffSRob Clark /* helper to install properties which are common to planes and crtcs */
2838bb0daffSRob Clark void omap_plane_install_properties(struct drm_plane *plane,
2848bb0daffSRob Clark 		struct drm_mode_object *obj)
2858bb0daffSRob Clark {
2868bb0daffSRob Clark 	struct drm_device *dev = plane->dev;
2878bb0daffSRob Clark 	struct omap_drm_private *priv = dev->dev_private;
2888bb0daffSRob Clark 
2898bb0daffSRob Clark 	if (priv->has_dmm) {
2900da88db1SVille Syrjälä 		if (!plane->rotation_property)
2910da88db1SVille Syrjälä 			drm_plane_create_rotation_property(plane,
292c2c446adSRobert Foss 							   DRM_MODE_ROTATE_0,
293c2c446adSRobert Foss 							   DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 |
294c2c446adSRobert Foss 							   DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270 |
295c2c446adSRobert Foss 							   DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y);
296e2cd09b2SLaurent Pinchart 
2970da88db1SVille Syrjälä 		/* Attach the rotation property also to the crtc object */
2980da88db1SVille Syrjälä 		if (plane->rotation_property && obj != &plane->base)
2990da88db1SVille Syrjälä 			drm_object_attach_property(obj, plane->rotation_property,
300c2c446adSRobert Foss 						   DRM_MODE_ROTATE_0);
3018bb0daffSRob Clark 	}
3028bb0daffSRob Clark 
303e2cd09b2SLaurent Pinchart 	drm_object_attach_property(obj, priv->zorder_prop, 0);
3048bb0daffSRob Clark }
3058bb0daffSRob Clark 
306e07323cfSTomi Valkeinen static void omap_plane_reset(struct drm_plane *plane)
307e07323cfSTomi Valkeinen {
308e07323cfSTomi Valkeinen 	struct omap_plane *omap_plane = to_omap_plane(plane);
3093c265d92SBenoit Parrot 	struct omap_plane_state *omap_state;
310e07323cfSTomi Valkeinen 
3113c265d92SBenoit Parrot 	if (plane->state)
3123c265d92SBenoit Parrot 		drm_atomic_helper_plane_destroy_state(plane, plane->state);
3133c265d92SBenoit Parrot 
3143c265d92SBenoit Parrot 	omap_state = kzalloc(sizeof(*omap_state), GFP_KERNEL);
3153c265d92SBenoit Parrot 	if (!omap_state)
316e07323cfSTomi Valkeinen 		return;
317e07323cfSTomi Valkeinen 
3183c265d92SBenoit Parrot 	__drm_atomic_helper_plane_reset(plane, &omap_state->base);
3193c265d92SBenoit Parrot 
320e07323cfSTomi Valkeinen 	/*
321ba527c13SLaurent Pinchart 	 * Set the zpos default depending on whether we are a primary or overlay
322e07323cfSTomi Valkeinen 	 * plane.
323e07323cfSTomi Valkeinen 	 */
324d980278bSLaurent Pinchart 	plane->state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY
325e07323cfSTomi Valkeinen 			   ? 0 : omap_plane->id;
32664ff1891SJyri Sarha 	plane->state->color_encoding = DRM_COLOR_YCBCR_BT601;
32764ff1891SJyri Sarha 	plane->state->color_range = DRM_COLOR_YCBCR_FULL_RANGE;
328e07323cfSTomi Valkeinen }
329e07323cfSTomi Valkeinen 
3303c265d92SBenoit Parrot static struct drm_plane_state *
3313c265d92SBenoit Parrot omap_plane_atomic_duplicate_state(struct drm_plane *plane)
3323c265d92SBenoit Parrot {
3332e54ff0eSBenoit Parrot 	struct omap_plane_state *state, *current_state;
3343c265d92SBenoit Parrot 
3353c265d92SBenoit Parrot 	if (WARN_ON(!plane->state))
3363c265d92SBenoit Parrot 		return NULL;
3373c265d92SBenoit Parrot 
3382e54ff0eSBenoit Parrot 	current_state = to_omap_plane_state(plane->state);
3392e54ff0eSBenoit Parrot 
3403c265d92SBenoit Parrot 	state = kmalloc(sizeof(*state), GFP_KERNEL);
3413c265d92SBenoit Parrot 	if (!state)
3423c265d92SBenoit Parrot 		return NULL;
3433c265d92SBenoit Parrot 
3443c265d92SBenoit Parrot 	__drm_atomic_helper_plane_duplicate_state(plane, &state->base);
3453c265d92SBenoit Parrot 
3462e54ff0eSBenoit Parrot 	state->overlay = current_state->overlay;
3472e54ff0eSBenoit Parrot 
3483c265d92SBenoit Parrot 	return &state->base;
3493c265d92SBenoit Parrot }
3503c265d92SBenoit Parrot 
351*19e2d266SBenoit Parrot static void omap_plane_atomic_print_state(struct drm_printer *p,
352*19e2d266SBenoit Parrot 					  const struct drm_plane_state *state)
353*19e2d266SBenoit Parrot {
354*19e2d266SBenoit Parrot 	struct omap_plane_state *omap_state = to_omap_plane_state(state);
355*19e2d266SBenoit Parrot 
356*19e2d266SBenoit Parrot 	if (omap_state->overlay)
357*19e2d266SBenoit Parrot 		drm_printf(p, "\toverlay=%s (caps=0x%x)\n",
358*19e2d266SBenoit Parrot 			   omap_state->overlay->name,
359*19e2d266SBenoit Parrot 			   omap_state->overlay->caps);
360*19e2d266SBenoit Parrot 	else
361*19e2d266SBenoit Parrot 		drm_printf(p, "\toverlay=None\n");
362*19e2d266SBenoit Parrot }
363*19e2d266SBenoit Parrot 
364afc34932SLaurent Pinchart static int omap_plane_atomic_set_property(struct drm_plane *plane,
365afc34932SLaurent Pinchart 					  struct drm_plane_state *state,
366afc34932SLaurent Pinchart 					  struct drm_property *property,
367dfe9cfccSLaurent Pinchart 					  u64 val)
368afc34932SLaurent Pinchart {
369afc34932SLaurent Pinchart 	struct omap_drm_private *priv = plane->dev->dev_private;
370afc34932SLaurent Pinchart 
371afc34932SLaurent Pinchart 	if (property == priv->zorder_prop)
372ba527c13SLaurent Pinchart 		state->zpos = val;
373afc34932SLaurent Pinchart 	else
374afc34932SLaurent Pinchart 		return -EINVAL;
375afc34932SLaurent Pinchart 
376a42133a7SLaurent Pinchart 	return 0;
377afc34932SLaurent Pinchart }
378a42133a7SLaurent Pinchart 
379afc34932SLaurent Pinchart static int omap_plane_atomic_get_property(struct drm_plane *plane,
380afc34932SLaurent Pinchart 					  const struct drm_plane_state *state,
381afc34932SLaurent Pinchart 					  struct drm_property *property,
382dfe9cfccSLaurent Pinchart 					  u64 *val)
383afc34932SLaurent Pinchart {
384afc34932SLaurent Pinchart 	struct omap_drm_private *priv = plane->dev->dev_private;
385a42133a7SLaurent Pinchart 
386afc34932SLaurent Pinchart 	if (property == priv->zorder_prop)
387ba527c13SLaurent Pinchart 		*val = state->zpos;
388afc34932SLaurent Pinchart 	else
389afc34932SLaurent Pinchart 		return -EINVAL;
390afc34932SLaurent Pinchart 
391afc34932SLaurent Pinchart 	return 0;
3928bb0daffSRob Clark }
3938bb0daffSRob Clark 
3948bb0daffSRob Clark static const struct drm_plane_funcs omap_plane_funcs = {
395cef77d40SLaurent Pinchart 	.update_plane = drm_atomic_helper_update_plane,
396cef77d40SLaurent Pinchart 	.disable_plane = drm_atomic_helper_disable_plane,
397afc34932SLaurent Pinchart 	.reset = omap_plane_reset,
3988bb0daffSRob Clark 	.destroy = omap_plane_destroy,
3993c265d92SBenoit Parrot 	.atomic_duplicate_state = omap_plane_atomic_duplicate_state,
400d980278bSLaurent Pinchart 	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
401afc34932SLaurent Pinchart 	.atomic_set_property = omap_plane_atomic_set_property,
402afc34932SLaurent Pinchart 	.atomic_get_property = omap_plane_atomic_get_property,
403*19e2d266SBenoit Parrot 	.atomic_print_state = omap_plane_atomic_print_state,
4048bb0daffSRob Clark };
4058bb0daffSRob Clark 
40664ff1891SJyri Sarha static bool omap_plane_supports_yuv(struct drm_plane *plane)
40764ff1891SJyri Sarha {
40864ff1891SJyri Sarha 	struct omap_drm_private *priv = plane->dev->dev_private;
40964ff1891SJyri Sarha 	struct omap_plane *omap_plane = to_omap_plane(plane);
410dac62bcaSTomi Valkeinen 	const u32 *formats = dispc_ovl_get_color_modes(priv->dispc, omap_plane->id);
41164ff1891SJyri Sarha 	u32 i;
41264ff1891SJyri Sarha 
41364ff1891SJyri Sarha 	for (i = 0; formats[i]; i++)
41464ff1891SJyri Sarha 		if (formats[i] == DRM_FORMAT_YUYV ||
41564ff1891SJyri Sarha 		    formats[i] == DRM_FORMAT_UYVY ||
41664ff1891SJyri Sarha 		    formats[i] == DRM_FORMAT_NV12)
41764ff1891SJyri Sarha 			return true;
41864ff1891SJyri Sarha 
41964ff1891SJyri Sarha 	return false;
42064ff1891SJyri Sarha }
42164ff1891SJyri Sarha 
4228bb0daffSRob Clark /* initialize plane */
4238bb0daffSRob Clark struct drm_plane *omap_plane_init(struct drm_device *dev,
424e8e13b15SJyri Sarha 		int idx, enum drm_plane_type type,
425e43f2c33STomi Valkeinen 		u32 possible_crtcs)
4268bb0daffSRob Clark {
4279f759225STomi Valkeinen 	struct omap_drm_private *priv = dev->dev_private;
428dac62bcaSTomi Valkeinen 	unsigned int num_planes = dispc_get_num_ovls(priv->dispc);
429ef6b0e02SLaurent Pinchart 	struct drm_plane *plane;
4308bb0daffSRob Clark 	struct omap_plane *omap_plane;
431ef6b0e02SLaurent Pinchart 	int ret;
432eecad437STomi Valkeinen 	u32 nformats;
433eecad437STomi Valkeinen 	const u32 *formats;
4348bb0daffSRob Clark 
435c8fa1e73SBenoit Parrot 	if (WARN_ON(idx >= num_planes))
436e8e13b15SJyri Sarha 		return ERR_PTR(-EINVAL);
437e8e13b15SJyri Sarha 
4388bb0daffSRob Clark 	omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL);
439fffddfd6SLinus Torvalds 	if (!omap_plane)
440fb9a35f8SLaurent Pinchart 		return ERR_PTR(-ENOMEM);
4418bb0daffSRob Clark 
442c8fa1e73SBenoit Parrot 	omap_plane->id = idx;
443c8fa1e73SBenoit Parrot 
444c8fa1e73SBenoit Parrot 	DBG("%d: type=%d", omap_plane->id, type);
445c8fa1e73SBenoit Parrot 	DBG("	crtc_mask: 0x%04x", possible_crtcs);
446c8fa1e73SBenoit Parrot 
4472e54ff0eSBenoit Parrot 	formats = dispc_ovl_get_color_modes(priv->dispc, omap_plane->id);
448eecad437STomi Valkeinen 	for (nformats = 0; formats[nformats]; ++nformats)
449eecad437STomi Valkeinen 		;
4508bb0daffSRob Clark 
4518bb0daffSRob Clark 	plane = &omap_plane->base;
4528bb0daffSRob Clark 
453e43f2c33STomi Valkeinen 	ret = drm_universal_plane_init(dev, plane, possible_crtcs,
454eecad437STomi Valkeinen 				       &omap_plane_funcs, formats,
455e6fc3b68SBen Widawsky 				       nformats, NULL, type, NULL);
456ef6b0e02SLaurent Pinchart 	if (ret < 0)
457ef6b0e02SLaurent Pinchart 		goto error;
4588bb0daffSRob Clark 
459de8e4100SLaurent Pinchart 	drm_plane_helper_add(plane, &omap_plane_helper_funcs);
460de8e4100SLaurent Pinchart 
4618bb0daffSRob Clark 	omap_plane_install_properties(plane, &plane->base);
462dff6c246SLaurent Pinchart 	drm_plane_create_zpos_property(plane, 0, 0, num_planes - 1);
4633037e0c5SJean-Jacques Hiblot 	drm_plane_create_alpha_property(plane);
4643037e0c5SJean-Jacques Hiblot 	drm_plane_create_blend_mode_property(plane, BIT(DRM_MODE_BLEND_PREMULTI) |
4653037e0c5SJean-Jacques Hiblot 					     BIT(DRM_MODE_BLEND_COVERAGE));
4668bb0daffSRob Clark 
46764ff1891SJyri Sarha 	if (omap_plane_supports_yuv(plane))
46864ff1891SJyri Sarha 		drm_plane_create_color_properties(plane,
46964ff1891SJyri Sarha 						  BIT(DRM_COLOR_YCBCR_BT601) |
47064ff1891SJyri Sarha 						  BIT(DRM_COLOR_YCBCR_BT709),
47164ff1891SJyri Sarha 						  BIT(DRM_COLOR_YCBCR_FULL_RANGE) |
47264ff1891SJyri Sarha 						  BIT(DRM_COLOR_YCBCR_LIMITED_RANGE),
47364ff1891SJyri Sarha 						  DRM_COLOR_YCBCR_BT601,
47464ff1891SJyri Sarha 						  DRM_COLOR_YCBCR_FULL_RANGE);
47564ff1891SJyri Sarha 
4768bb0daffSRob Clark 	return plane;
477ef6b0e02SLaurent Pinchart 
478ef6b0e02SLaurent Pinchart error:
479c8fa1e73SBenoit Parrot 	dev_err(dev->dev, "%s(): could not create plane: %d\n",
480c8fa1e73SBenoit Parrot 		__func__, omap_plane->id);
481e8e13b15SJyri Sarha 
482ef6b0e02SLaurent Pinchart 	kfree(omap_plane);
483ef6b0e02SLaurent Pinchart 	return NULL;
4848bb0daffSRob Clark }
485