18bb0daffSRob Clark /*
28bb0daffSRob Clark  * drivers/gpu/drm/omapdrm/omap_plane.c
38bb0daffSRob Clark  *
48bb0daffSRob Clark  * Copyright (C) 2011 Texas Instruments
58bb0daffSRob Clark  * Author: Rob Clark <rob.clark@linaro.org>
68bb0daffSRob Clark  *
78bb0daffSRob Clark  * This program is free software; you can redistribute it and/or modify it
88bb0daffSRob Clark  * under the terms of the GNU General Public License version 2 as published by
98bb0daffSRob Clark  * the Free Software Foundation.
108bb0daffSRob Clark  *
118bb0daffSRob Clark  * This program is distributed in the hope that it will be useful, but WITHOUT
128bb0daffSRob Clark  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
138bb0daffSRob Clark  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
148bb0daffSRob Clark  * more details.
158bb0daffSRob Clark  *
168bb0daffSRob Clark  * You should have received a copy of the GNU General Public License along with
178bb0daffSRob Clark  * this program.  If not, see <http://www.gnu.org/licenses/>.
188bb0daffSRob Clark  */
198bb0daffSRob Clark 
20c423bc85STomi Valkeinen #include <drm/drm_atomic.h>
2169a12263SLaurent Pinchart #include <drm/drm_atomic_helper.h>
22de8e4100SLaurent Pinchart #include <drm/drm_plane_helper.h>
2369a12263SLaurent Pinchart 
248bb0daffSRob Clark #include "omap_dmm_tiler.h"
252d278f54SLaurent Pinchart #include "omap_drv.h"
268bb0daffSRob Clark 
278bb0daffSRob Clark /*
288bb0daffSRob Clark  * plane funcs
298bb0daffSRob Clark  */
308bb0daffSRob Clark 
318bb0daffSRob Clark #define to_omap_plane(x) container_of(x, struct omap_plane, base)
328bb0daffSRob Clark 
338bb0daffSRob Clark struct omap_plane {
348bb0daffSRob Clark 	struct drm_plane base;
35694c99cfSJyri Sarha 	enum omap_plane_id id;
368bb0daffSRob Clark 	const char *name;
378bb0daffSRob Clark };
388bb0daffSRob Clark 
3911ffd031STomi Valkeinen static int omap_plane_prepare_fb(struct drm_plane *plane,
401832040dSChris Wilson 				 struct drm_plane_state *new_state)
4111ffd031STomi Valkeinen {
42844f9111SMaarten Lankhorst 	if (!new_state->fb)
43844f9111SMaarten Lankhorst 		return 0;
44844f9111SMaarten Lankhorst 
45844f9111SMaarten Lankhorst 	return omap_framebuffer_pin(new_state->fb);
4611ffd031STomi Valkeinen }
4711ffd031STomi Valkeinen 
4811ffd031STomi Valkeinen static void omap_plane_cleanup_fb(struct drm_plane *plane,
491832040dSChris Wilson 				  struct drm_plane_state *old_state)
5011ffd031STomi Valkeinen {
51844f9111SMaarten Lankhorst 	if (old_state->fb)
52844f9111SMaarten Lankhorst 		omap_framebuffer_unpin(old_state->fb);
5311ffd031STomi Valkeinen }
5411ffd031STomi Valkeinen 
5511ffd031STomi Valkeinen static void omap_plane_atomic_update(struct drm_plane *plane,
5611ffd031STomi Valkeinen 				     struct drm_plane_state *old_state)
57afc34932SLaurent Pinchart {
589f759225STomi Valkeinen 	struct omap_drm_private *priv = plane->dev->dev_private;
59edc72557SLaurent Pinchart 	struct omap_plane *omap_plane = to_omap_plane(plane);
60edc72557SLaurent Pinchart 	struct drm_plane_state *state = plane->state;
61fb730c9bSLaurent Pinchart 	struct omap_overlay_info info;
628bb0daffSRob Clark 	int ret;
638bb0daffSRob Clark 
64edc72557SLaurent Pinchart 	DBG("%s, crtc=%p fb=%p", omap_plane->name, state->crtc, state->fb);
658bb0daffSRob Clark 
66fb730c9bSLaurent Pinchart 	memset(&info, 0, sizeof(info));
67517a8a95STomi Valkeinen 	info.rotation_type = OMAP_DSS_ROT_NONE;
680bd97c42STomi Valkeinen 	info.rotation = DRM_MODE_ROTATE_0;
69fb730c9bSLaurent Pinchart 	info.global_alpha = 0xff;
70fb730c9bSLaurent Pinchart 	info.mirror = 0;
71ba527c13SLaurent Pinchart 	info.zorder = state->zpos;
72fb730c9bSLaurent Pinchart 
738bb0daffSRob Clark 	/* update scanout: */
74218ed535STomi Valkeinen 	omap_framebuffer_update_scanout(state->fb, state, &info);
758bb0daffSRob Clark 
76fb730c9bSLaurent Pinchart 	DBG("%dx%d -> %dx%d (%d)", info.width, info.height,
77fb730c9bSLaurent Pinchart 			info.out_width, info.out_height,
78fb730c9bSLaurent Pinchart 			info.screen_width);
79fb730c9bSLaurent Pinchart 	DBG("%d,%d %pad %pad", info.pos_x, info.pos_y,
80fb730c9bSLaurent Pinchart 			&info.paddr, &info.p_uv_addr);
818bb0daffSRob Clark 
828bb0daffSRob Clark 	/* and finally, update omapdss: */
83be2d68c6STomi Valkeinen 	ret = priv->dispc_ops->ovl_setup(omap_plane->id, &info,
8449a3057aSTomi Valkeinen 			      omap_crtc_timings(state->crtc), false,
8549a3057aSTomi Valkeinen 			      omap_crtc_channel(state->crtc));
86cfb73f20STomi Valkeinen 	if (ret) {
87cfb73f20STomi Valkeinen 		dev_err(plane->dev->dev, "Failed to setup plane %s\n",
88cfb73f20STomi Valkeinen 			omap_plane->name);
899f759225STomi Valkeinen 		priv->dispc_ops->ovl_enable(omap_plane->id, false);
90d9157dfdSTomi Valkeinen 		return;
91794a65ffSTomi Valkeinen 	}
928bb0daffSRob Clark 
939f759225STomi Valkeinen 	priv->dispc_ops->ovl_enable(omap_plane->id, true);
94de8e4100SLaurent Pinchart }
95de8e4100SLaurent Pinchart 
96de8e4100SLaurent Pinchart static void omap_plane_atomic_disable(struct drm_plane *plane,
97de8e4100SLaurent Pinchart 				      struct drm_plane_state *old_state)
988bb0daffSRob Clark {
999f759225STomi Valkeinen 	struct omap_drm_private *priv = plane->dev->dev_private;
1008bb0daffSRob Clark 	struct omap_plane *omap_plane = to_omap_plane(plane);
1012debab97SLaurent Pinchart 
102c2c446adSRobert Foss 	plane->state->rotation = DRM_MODE_ROTATE_0;
103ba527c13SLaurent Pinchart 	plane->state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY
10482e58855SLaurent Pinchart 			   ? 0 : omap_plane->id;
10582e58855SLaurent Pinchart 
1069f759225STomi Valkeinen 	priv->dispc_ops->ovl_enable(omap_plane->id, false);
1078bb0daffSRob Clark }
1088bb0daffSRob Clark 
109c423bc85STomi Valkeinen static int omap_plane_atomic_check(struct drm_plane *plane,
110c423bc85STomi Valkeinen 				   struct drm_plane_state *state)
111c423bc85STomi Valkeinen {
112c423bc85STomi Valkeinen 	struct drm_crtc_state *crtc_state;
113c423bc85STomi Valkeinen 
11470dd2a62STomi Valkeinen 	if (!state->fb)
115c423bc85STomi Valkeinen 		return 0;
116c423bc85STomi Valkeinen 
11770dd2a62STomi Valkeinen 	/* crtc should only be NULL when disabling (i.e., !state->fb) */
11870dd2a62STomi Valkeinen 	if (WARN_ON(!state->crtc))
11970dd2a62STomi Valkeinen 		return 0;
12070dd2a62STomi Valkeinen 
12170dd2a62STomi Valkeinen 	crtc_state = drm_atomic_get_existing_crtc_state(state->state, state->crtc);
12270dd2a62STomi Valkeinen 	/* we should have a crtc state if the plane is attached to a crtc */
12370dd2a62STomi Valkeinen 	if (WARN_ON(!crtc_state))
12470dd2a62STomi Valkeinen 		return 0;
125c423bc85STomi Valkeinen 
126aaf7642eSTomi Valkeinen 	if (!crtc_state->enable)
127aaf7642eSTomi Valkeinen 		return 0;
128aaf7642eSTomi Valkeinen 
129c423bc85STomi Valkeinen 	if (state->crtc_x < 0 || state->crtc_y < 0)
130c423bc85STomi Valkeinen 		return -EINVAL;
131c423bc85STomi Valkeinen 
132c423bc85STomi Valkeinen 	if (state->crtc_x + state->crtc_w > crtc_state->adjusted_mode.hdisplay)
133c423bc85STomi Valkeinen 		return -EINVAL;
134c423bc85STomi Valkeinen 
135c423bc85STomi Valkeinen 	if (state->crtc_y + state->crtc_h > crtc_state->adjusted_mode.vdisplay)
136c423bc85STomi Valkeinen 		return -EINVAL;
137c423bc85STomi Valkeinen 
138c2c446adSRobert Foss 	if (state->rotation != DRM_MODE_ROTATE_0 &&
139bfeece55STomi Valkeinen 	    !omap_framebuffer_supports_rotation(state->fb))
140bfeece55STomi Valkeinen 		return -EINVAL;
141bfeece55STomi Valkeinen 
142c423bc85STomi Valkeinen 	return 0;
143c423bc85STomi Valkeinen }
144c423bc85STomi Valkeinen 
145de8e4100SLaurent Pinchart static const struct drm_plane_helper_funcs omap_plane_helper_funcs = {
146de8e4100SLaurent Pinchart 	.prepare_fb = omap_plane_prepare_fb,
147de8e4100SLaurent Pinchart 	.cleanup_fb = omap_plane_cleanup_fb,
148c423bc85STomi Valkeinen 	.atomic_check = omap_plane_atomic_check,
149de8e4100SLaurent Pinchart 	.atomic_update = omap_plane_atomic_update,
150de8e4100SLaurent Pinchart 	.atomic_disable = omap_plane_atomic_disable,
151de8e4100SLaurent Pinchart };
152de8e4100SLaurent Pinchart 
1538bb0daffSRob Clark static void omap_plane_destroy(struct drm_plane *plane)
1548bb0daffSRob Clark {
1558bb0daffSRob Clark 	struct omap_plane *omap_plane = to_omap_plane(plane);
1568bb0daffSRob Clark 
1578bb0daffSRob Clark 	DBG("%s", omap_plane->name);
1588bb0daffSRob Clark 
1598bb0daffSRob Clark 	drm_plane_cleanup(plane);
1608bb0daffSRob Clark 
1618bb0daffSRob Clark 	kfree(omap_plane);
1628bb0daffSRob Clark }
1638bb0daffSRob Clark 
1648bb0daffSRob Clark /* helper to install properties which are common to planes and crtcs */
1658bb0daffSRob Clark void omap_plane_install_properties(struct drm_plane *plane,
1668bb0daffSRob Clark 		struct drm_mode_object *obj)
1678bb0daffSRob Clark {
1688bb0daffSRob Clark 	struct drm_device *dev = plane->dev;
1698bb0daffSRob Clark 	struct omap_drm_private *priv = dev->dev_private;
1708bb0daffSRob Clark 
1718bb0daffSRob Clark 	if (priv->has_dmm) {
1720da88db1SVille Syrjälä 		if (!plane->rotation_property)
1730da88db1SVille Syrjälä 			drm_plane_create_rotation_property(plane,
174c2c446adSRobert Foss 							   DRM_MODE_ROTATE_0,
175c2c446adSRobert Foss 							   DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 |
176c2c446adSRobert Foss 							   DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270 |
177c2c446adSRobert Foss 							   DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y);
178e2cd09b2SLaurent Pinchart 
1790da88db1SVille Syrjälä 		/* Attach the rotation property also to the crtc object */
1800da88db1SVille Syrjälä 		if (plane->rotation_property && obj != &plane->base)
1810da88db1SVille Syrjälä 			drm_object_attach_property(obj, plane->rotation_property,
182c2c446adSRobert Foss 						   DRM_MODE_ROTATE_0);
1838bb0daffSRob Clark 	}
1848bb0daffSRob Clark 
185e2cd09b2SLaurent Pinchart 	drm_object_attach_property(obj, priv->zorder_prop, 0);
1868bb0daffSRob Clark }
1878bb0daffSRob Clark 
188e07323cfSTomi Valkeinen static void omap_plane_reset(struct drm_plane *plane)
189e07323cfSTomi Valkeinen {
190e07323cfSTomi Valkeinen 	struct omap_plane *omap_plane = to_omap_plane(plane);
191e07323cfSTomi Valkeinen 
192d980278bSLaurent Pinchart 	drm_atomic_helper_plane_reset(plane);
193d980278bSLaurent Pinchart 	if (!plane->state)
194e07323cfSTomi Valkeinen 		return;
195e07323cfSTomi Valkeinen 
196e07323cfSTomi Valkeinen 	/*
197ba527c13SLaurent Pinchart 	 * Set the zpos default depending on whether we are a primary or overlay
198e07323cfSTomi Valkeinen 	 * plane.
199e07323cfSTomi Valkeinen 	 */
200d980278bSLaurent Pinchart 	plane->state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY
201e07323cfSTomi Valkeinen 			   ? 0 : omap_plane->id;
202e07323cfSTomi Valkeinen }
203e07323cfSTomi Valkeinen 
204afc34932SLaurent Pinchart static int omap_plane_atomic_set_property(struct drm_plane *plane,
205afc34932SLaurent Pinchart 					  struct drm_plane_state *state,
206afc34932SLaurent Pinchart 					  struct drm_property *property,
207afc34932SLaurent Pinchart 					  uint64_t val)
208afc34932SLaurent Pinchart {
209afc34932SLaurent Pinchart 	struct omap_drm_private *priv = plane->dev->dev_private;
210afc34932SLaurent Pinchart 
211afc34932SLaurent Pinchart 	if (property == priv->zorder_prop)
212ba527c13SLaurent Pinchart 		state->zpos = val;
213afc34932SLaurent Pinchart 	else
214afc34932SLaurent Pinchart 		return -EINVAL;
215afc34932SLaurent Pinchart 
216a42133a7SLaurent Pinchart 	return 0;
217afc34932SLaurent Pinchart }
218a42133a7SLaurent Pinchart 
219afc34932SLaurent Pinchart static int omap_plane_atomic_get_property(struct drm_plane *plane,
220afc34932SLaurent Pinchart 					  const struct drm_plane_state *state,
221afc34932SLaurent Pinchart 					  struct drm_property *property,
222afc34932SLaurent Pinchart 					  uint64_t *val)
223afc34932SLaurent Pinchart {
224afc34932SLaurent Pinchart 	struct omap_drm_private *priv = plane->dev->dev_private;
225a42133a7SLaurent Pinchart 
226afc34932SLaurent Pinchart 	if (property == priv->zorder_prop)
227ba527c13SLaurent Pinchart 		*val = state->zpos;
228afc34932SLaurent Pinchart 	else
229afc34932SLaurent Pinchart 		return -EINVAL;
230afc34932SLaurent Pinchart 
231afc34932SLaurent Pinchart 	return 0;
2328bb0daffSRob Clark }
2338bb0daffSRob Clark 
2348bb0daffSRob Clark static const struct drm_plane_funcs omap_plane_funcs = {
235cef77d40SLaurent Pinchart 	.update_plane = drm_atomic_helper_update_plane,
236cef77d40SLaurent Pinchart 	.disable_plane = drm_atomic_helper_disable_plane,
237afc34932SLaurent Pinchart 	.reset = omap_plane_reset,
2388bb0daffSRob Clark 	.destroy = omap_plane_destroy,
239afc34932SLaurent Pinchart 	.set_property = drm_atomic_helper_plane_set_property,
240d980278bSLaurent Pinchart 	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
241d980278bSLaurent Pinchart 	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
242afc34932SLaurent Pinchart 	.atomic_set_property = omap_plane_atomic_set_property,
243afc34932SLaurent Pinchart 	.atomic_get_property = omap_plane_atomic_get_property,
2448bb0daffSRob Clark };
2458bb0daffSRob Clark 
246e8e13b15SJyri Sarha static const char *plane_id_to_name[] = {
2478bb0daffSRob Clark 	[OMAP_DSS_GFX] = "gfx",
2488bb0daffSRob Clark 	[OMAP_DSS_VIDEO1] = "vid1",
2498bb0daffSRob Clark 	[OMAP_DSS_VIDEO2] = "vid2",
2508bb0daffSRob Clark 	[OMAP_DSS_VIDEO3] = "vid3",
2518bb0daffSRob Clark };
2528bb0daffSRob Clark 
253e8e13b15SJyri Sarha static const enum omap_plane_id plane_idx_to_id[] = {
254e8e13b15SJyri Sarha 	OMAP_DSS_GFX,
255e8e13b15SJyri Sarha 	OMAP_DSS_VIDEO1,
256e8e13b15SJyri Sarha 	OMAP_DSS_VIDEO2,
257e8e13b15SJyri Sarha 	OMAP_DSS_VIDEO3,
258e8e13b15SJyri Sarha };
259e8e13b15SJyri Sarha 
2608bb0daffSRob Clark /* initialize plane */
2618bb0daffSRob Clark struct drm_plane *omap_plane_init(struct drm_device *dev,
262e8e13b15SJyri Sarha 		int idx, enum drm_plane_type type,
263e43f2c33STomi Valkeinen 		u32 possible_crtcs)
2648bb0daffSRob Clark {
2659f759225STomi Valkeinen 	struct omap_drm_private *priv = dev->dev_private;
266dff6c246SLaurent Pinchart 	unsigned int num_planes = priv->dispc_ops->get_num_ovls();
267ef6b0e02SLaurent Pinchart 	struct drm_plane *plane;
2688bb0daffSRob Clark 	struct omap_plane *omap_plane;
269e8e13b15SJyri Sarha 	enum omap_plane_id id;
270ef6b0e02SLaurent Pinchart 	int ret;
271eecad437STomi Valkeinen 	u32 nformats;
272eecad437STomi Valkeinen 	const u32 *formats;
2738bb0daffSRob Clark 
274e8e13b15SJyri Sarha 	if (WARN_ON(idx >= ARRAY_SIZE(plane_idx_to_id)))
275e8e13b15SJyri Sarha 		return ERR_PTR(-EINVAL);
276e8e13b15SJyri Sarha 
277e8e13b15SJyri Sarha 	id = plane_idx_to_id[idx];
278e8e13b15SJyri Sarha 
279e8e13b15SJyri Sarha 	DBG("%s: type=%d", plane_id_to_name[id], type);
2808bb0daffSRob Clark 
2818bb0daffSRob Clark 	omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL);
282fffddfd6SLinus Torvalds 	if (!omap_plane)
283fb9a35f8SLaurent Pinchart 		return ERR_PTR(-ENOMEM);
2848bb0daffSRob Clark 
285eecad437STomi Valkeinen 	formats = priv->dispc_ops->ovl_get_color_modes(id);
286eecad437STomi Valkeinen 	for (nformats = 0; formats[nformats]; ++nformats)
287eecad437STomi Valkeinen 		;
2888bb0daffSRob Clark 	omap_plane->id = id;
289e8e13b15SJyri Sarha 	omap_plane->name = plane_id_to_name[id];
2908bb0daffSRob Clark 
2918bb0daffSRob Clark 	plane = &omap_plane->base;
2928bb0daffSRob Clark 
293e43f2c33STomi Valkeinen 	ret = drm_universal_plane_init(dev, plane, possible_crtcs,
294eecad437STomi Valkeinen 				       &omap_plane_funcs, formats,
295eecad437STomi Valkeinen 				       nformats, type, NULL);
296ef6b0e02SLaurent Pinchart 	if (ret < 0)
297ef6b0e02SLaurent Pinchart 		goto error;
2988bb0daffSRob Clark 
299de8e4100SLaurent Pinchart 	drm_plane_helper_add(plane, &omap_plane_helper_funcs);
300de8e4100SLaurent Pinchart 
3018bb0daffSRob Clark 	omap_plane_install_properties(plane, &plane->base);
302dff6c246SLaurent Pinchart 	drm_plane_create_zpos_property(plane, 0, 0, num_planes - 1);
3038bb0daffSRob Clark 
3048bb0daffSRob Clark 	return plane;
305ef6b0e02SLaurent Pinchart 
306ef6b0e02SLaurent Pinchart error:
307e8e13b15SJyri Sarha 	dev_err(dev->dev, "%s(): could not create plane: %s\n",
308e8e13b15SJyri Sarha 		__func__, plane_id_to_name[id]);
309e8e13b15SJyri Sarha 
310ef6b0e02SLaurent Pinchart 	kfree(omap_plane);
311ef6b0e02SLaurent Pinchart 	return NULL;
3128bb0daffSRob Clark }
313