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 
205833bd2fSRob Clark #include "drm_flip_work.h"
218bb0daffSRob Clark 
228bb0daffSRob Clark #include "omap_drv.h"
238bb0daffSRob Clark #include "omap_dmm_tiler.h"
248bb0daffSRob Clark 
258bb0daffSRob Clark /* some hackery because omapdss has an 'enum omap_plane' (which would be
268bb0daffSRob Clark  * better named omap_plane_id).. and compiler seems unhappy about having
278bb0daffSRob Clark  * both a 'struct omap_plane' and 'enum omap_plane'
288bb0daffSRob Clark  */
298bb0daffSRob Clark #define omap_plane _omap_plane
308bb0daffSRob Clark 
318bb0daffSRob Clark /*
328bb0daffSRob Clark  * plane funcs
338bb0daffSRob Clark  */
348bb0daffSRob Clark 
358bb0daffSRob Clark struct callback {
368bb0daffSRob Clark 	void (*fxn)(void *);
378bb0daffSRob Clark 	void *arg;
388bb0daffSRob Clark };
398bb0daffSRob Clark 
408bb0daffSRob Clark #define to_omap_plane(x) container_of(x, struct omap_plane, base)
418bb0daffSRob Clark 
428bb0daffSRob Clark struct omap_plane {
438bb0daffSRob Clark 	struct drm_plane base;
448bb0daffSRob Clark 	int id;  /* TODO rename omap_plane -> omap_plane_id in omapdss so I can use the enum */
458bb0daffSRob Clark 	const char *name;
468bb0daffSRob Clark 	struct omap_overlay_info info;
478bb0daffSRob Clark 	struct omap_drm_apply apply;
488bb0daffSRob Clark 
498bb0daffSRob Clark 	/* position/orientation of scanout within the fb: */
508bb0daffSRob Clark 	struct omap_drm_window win;
518bb0daffSRob Clark 	bool enabled;
528bb0daffSRob Clark 
538bb0daffSRob Clark 	/* last fb that we pinned: */
548bb0daffSRob Clark 	struct drm_framebuffer *pinned_fb;
558bb0daffSRob Clark 
568bb0daffSRob Clark 	uint32_t nformats;
578bb0daffSRob Clark 	uint32_t formats[32];
588bb0daffSRob Clark 
598bb0daffSRob Clark 	struct omap_drm_irq error_irq;
608bb0daffSRob Clark 
615833bd2fSRob Clark 	/* for deferring bo unpin's until next post_apply(): */
625833bd2fSRob Clark 	struct drm_flip_work unpin_work;
638bb0daffSRob Clark 
648bb0daffSRob Clark 	// XXX maybe get rid of this and handle vblank in crtc too?
658bb0daffSRob Clark 	struct callback apply_done_cb;
668bb0daffSRob Clark };
678bb0daffSRob Clark 
685833bd2fSRob Clark static void unpin_worker(struct drm_flip_work *work, void *val)
698bb0daffSRob Clark {
705833bd2fSRob Clark 	struct omap_plane *omap_plane =
715833bd2fSRob Clark 			container_of(work, struct omap_plane, unpin_work);
725833bd2fSRob Clark 	struct drm_device *dev = omap_plane->base.dev;
738bb0daffSRob Clark 
745833bd2fSRob Clark 	omap_framebuffer_unpin(val);
755833bd2fSRob Clark 	mutex_lock(&dev->mode_config.mutex);
765833bd2fSRob Clark 	drm_framebuffer_unreference(val);
775833bd2fSRob Clark 	mutex_unlock(&dev->mode_config.mutex);
788bb0daffSRob Clark }
798bb0daffSRob Clark 
808bb0daffSRob Clark /* update which fb (if any) is pinned for scanout */
818bb0daffSRob Clark static int update_pin(struct drm_plane *plane, struct drm_framebuffer *fb)
828bb0daffSRob Clark {
838bb0daffSRob Clark 	struct omap_plane *omap_plane = to_omap_plane(plane);
848bb0daffSRob Clark 	struct drm_framebuffer *pinned_fb = omap_plane->pinned_fb;
858bb0daffSRob Clark 
868bb0daffSRob Clark 	if (pinned_fb != fb) {
875833bd2fSRob Clark 		int ret = 0;
888bb0daffSRob Clark 
898bb0daffSRob Clark 		DBG("%p -> %p", pinned_fb, fb);
908bb0daffSRob Clark 
915833bd2fSRob Clark 		if (fb) {
928bb0daffSRob Clark 			drm_framebuffer_reference(fb);
935833bd2fSRob Clark 			ret = omap_framebuffer_pin(fb);
945833bd2fSRob Clark 		}
958bb0daffSRob Clark 
968bb0daffSRob Clark 		if (pinned_fb)
975833bd2fSRob Clark 			drm_flip_work_queue(&omap_plane->unpin_work, pinned_fb);
988bb0daffSRob Clark 
998bb0daffSRob Clark 		if (ret) {
1008bb0daffSRob Clark 			dev_err(plane->dev->dev, "could not swap %p -> %p\n",
1018bb0daffSRob Clark 					omap_plane->pinned_fb, fb);
1028bb0daffSRob Clark 			drm_framebuffer_unreference(fb);
1038bb0daffSRob Clark 			omap_plane->pinned_fb = NULL;
1048bb0daffSRob Clark 			return ret;
1058bb0daffSRob Clark 		}
1068bb0daffSRob Clark 
1078bb0daffSRob Clark 		omap_plane->pinned_fb = fb;
1088bb0daffSRob Clark 	}
1098bb0daffSRob Clark 
1108bb0daffSRob Clark 	return 0;
1118bb0daffSRob Clark }
1128bb0daffSRob Clark 
1138bb0daffSRob Clark static void omap_plane_pre_apply(struct omap_drm_apply *apply)
1148bb0daffSRob Clark {
1158bb0daffSRob Clark 	struct omap_plane *omap_plane =
1168bb0daffSRob Clark 			container_of(apply, struct omap_plane, apply);
1178bb0daffSRob Clark 	struct omap_drm_window *win = &omap_plane->win;
1188bb0daffSRob Clark 	struct drm_plane *plane = &omap_plane->base;
1198bb0daffSRob Clark 	struct drm_device *dev = plane->dev;
1208bb0daffSRob Clark 	struct omap_overlay_info *info = &omap_plane->info;
1218bb0daffSRob Clark 	struct drm_crtc *crtc = plane->crtc;
1228bb0daffSRob Clark 	enum omap_channel channel;
1238bb0daffSRob Clark 	bool enabled = omap_plane->enabled && crtc;
1248bb0daffSRob Clark 	bool ilace, replication;
1258bb0daffSRob Clark 	int ret;
1268bb0daffSRob Clark 
1278bb0daffSRob Clark 	DBG("%s, enabled=%d", omap_plane->name, enabled);
1288bb0daffSRob Clark 
1298bb0daffSRob Clark 	/* if fb has changed, pin new fb: */
1308bb0daffSRob Clark 	update_pin(plane, enabled ? plane->fb : NULL);
1318bb0daffSRob Clark 
1328bb0daffSRob Clark 	if (!enabled) {
1338bb0daffSRob Clark 		dispc_ovl_enable(omap_plane->id, false);
1348bb0daffSRob Clark 		return;
1358bb0daffSRob Clark 	}
1368bb0daffSRob Clark 
1378bb0daffSRob Clark 	channel = omap_crtc_channel(crtc);
1388bb0daffSRob Clark 
1398bb0daffSRob Clark 	/* update scanout: */
1408bb0daffSRob Clark 	omap_framebuffer_update_scanout(plane->fb, win, info);
1418bb0daffSRob Clark 
1428bb0daffSRob Clark 	DBG("%dx%d -> %dx%d (%d)", info->width, info->height,
1438bb0daffSRob Clark 			info->out_width, info->out_height,
1448bb0daffSRob Clark 			info->screen_width);
1452d31ca3aSRussell King 	DBG("%d,%d %pad %pad", info->pos_x, info->pos_y,
1462d31ca3aSRussell King 			&info->paddr, &info->p_uv_addr);
1478bb0daffSRob Clark 
1488bb0daffSRob Clark 	/* TODO: */
1498bb0daffSRob Clark 	ilace = false;
1508bb0daffSRob Clark 	replication = false;
1518bb0daffSRob Clark 
1528bb0daffSRob Clark 	/* and finally, update omapdss: */
1538bb0daffSRob Clark 	ret = dispc_ovl_setup(omap_plane->id, info,
1548bb0daffSRob Clark 			replication, omap_crtc_timings(crtc), false);
1558bb0daffSRob Clark 	if (ret) {
1568bb0daffSRob Clark 		dev_err(dev->dev, "dispc_ovl_setup failed: %d\n", ret);
1578bb0daffSRob Clark 		return;
1588bb0daffSRob Clark 	}
1598bb0daffSRob Clark 
1608bb0daffSRob Clark 	dispc_ovl_enable(omap_plane->id, true);
1618bb0daffSRob Clark 	dispc_ovl_set_channel_out(omap_plane->id, channel);
1628bb0daffSRob Clark }
1638bb0daffSRob Clark 
1648bb0daffSRob Clark static void omap_plane_post_apply(struct omap_drm_apply *apply)
1658bb0daffSRob Clark {
1668bb0daffSRob Clark 	struct omap_plane *omap_plane =
1678bb0daffSRob Clark 			container_of(apply, struct omap_plane, apply);
1688bb0daffSRob Clark 	struct drm_plane *plane = &omap_plane->base;
1695833bd2fSRob Clark 	struct omap_drm_private *priv = plane->dev->dev_private;
1708bb0daffSRob Clark 	struct omap_overlay_info *info = &omap_plane->info;
1718bb0daffSRob Clark 	struct callback cb;
1728bb0daffSRob Clark 
1738bb0daffSRob Clark 	cb = omap_plane->apply_done_cb;
1748bb0daffSRob Clark 	omap_plane->apply_done_cb.fxn = NULL;
1758bb0daffSRob Clark 
1765833bd2fSRob Clark 	drm_flip_work_commit(&omap_plane->unpin_work, priv->wq);
1778bb0daffSRob Clark 
1788bb0daffSRob Clark 	if (cb.fxn)
1798bb0daffSRob Clark 		cb.fxn(cb.arg);
1808bb0daffSRob Clark 
1818bb0daffSRob Clark 	if (omap_plane->enabled) {
1828bb0daffSRob Clark 		omap_framebuffer_flush(plane->fb, info->pos_x, info->pos_y,
1838bb0daffSRob Clark 				info->out_width, info->out_height);
1848bb0daffSRob Clark 	}
1858bb0daffSRob Clark }
1868bb0daffSRob Clark 
1878bb0daffSRob Clark static int apply(struct drm_plane *plane)
1888bb0daffSRob Clark {
1898bb0daffSRob Clark 	if (plane->crtc) {
1908bb0daffSRob Clark 		struct omap_plane *omap_plane = to_omap_plane(plane);
1918bb0daffSRob Clark 		return omap_crtc_apply(plane->crtc, &omap_plane->apply);
1928bb0daffSRob Clark 	}
1938bb0daffSRob Clark 	return 0;
1948bb0daffSRob Clark }
1958bb0daffSRob Clark 
1968bb0daffSRob Clark int omap_plane_mode_set(struct drm_plane *plane,
1978bb0daffSRob Clark 		struct drm_crtc *crtc, struct drm_framebuffer *fb,
1988bb0daffSRob Clark 		int crtc_x, int crtc_y,
1998bb0daffSRob Clark 		unsigned int crtc_w, unsigned int crtc_h,
2008bb0daffSRob Clark 		uint32_t src_x, uint32_t src_y,
2018bb0daffSRob Clark 		uint32_t src_w, uint32_t src_h,
2028bb0daffSRob Clark 		void (*fxn)(void *), void *arg)
2038bb0daffSRob Clark {
2048bb0daffSRob Clark 	struct omap_plane *omap_plane = to_omap_plane(plane);
2058bb0daffSRob Clark 	struct omap_drm_window *win = &omap_plane->win;
2068bb0daffSRob Clark 
2078bb0daffSRob Clark 	win->crtc_x = crtc_x;
2088bb0daffSRob Clark 	win->crtc_y = crtc_y;
2098bb0daffSRob Clark 	win->crtc_w = crtc_w;
2108bb0daffSRob Clark 	win->crtc_h = crtc_h;
2118bb0daffSRob Clark 
2128bb0daffSRob Clark 	/* src values are in Q16 fixed point, convert to integer: */
2138bb0daffSRob Clark 	win->src_x = src_x >> 16;
2148bb0daffSRob Clark 	win->src_y = src_y >> 16;
2158bb0daffSRob Clark 	win->src_w = src_w >> 16;
2168bb0daffSRob Clark 	win->src_h = src_h >> 16;
2178bb0daffSRob Clark 
2188bb0daffSRob Clark 	if (fxn) {
2198bb0daffSRob Clark 		/* omap_crtc should ensure that a new page flip
2208bb0daffSRob Clark 		 * isn't permitted while there is one pending:
2218bb0daffSRob Clark 		 */
2228bb0daffSRob Clark 		BUG_ON(omap_plane->apply_done_cb.fxn);
2238bb0daffSRob Clark 
2248bb0daffSRob Clark 		omap_plane->apply_done_cb.fxn = fxn;
2258bb0daffSRob Clark 		omap_plane->apply_done_cb.arg = arg;
2268bb0daffSRob Clark 	}
2278bb0daffSRob Clark 
228f2d022aaSTomi Valkeinen 	if (plane->fb)
229f2d022aaSTomi Valkeinen 		drm_framebuffer_unreference(plane->fb);
230f2d022aaSTomi Valkeinen 
231f2d022aaSTomi Valkeinen 	drm_framebuffer_reference(fb);
232f2d022aaSTomi Valkeinen 
2338bb0daffSRob Clark 	plane->fb = fb;
2348bb0daffSRob Clark 	plane->crtc = crtc;
2358bb0daffSRob Clark 
2368bb0daffSRob Clark 	return apply(plane);
2378bb0daffSRob Clark }
2388bb0daffSRob Clark 
2398bb0daffSRob Clark static int omap_plane_update(struct drm_plane *plane,
2408bb0daffSRob Clark 		struct drm_crtc *crtc, struct drm_framebuffer *fb,
2418bb0daffSRob Clark 		int crtc_x, int crtc_y,
2428bb0daffSRob Clark 		unsigned int crtc_w, unsigned int crtc_h,
2438bb0daffSRob Clark 		uint32_t src_x, uint32_t src_y,
2448bb0daffSRob Clark 		uint32_t src_w, uint32_t src_h)
2458bb0daffSRob Clark {
2468bb0daffSRob Clark 	struct omap_plane *omap_plane = to_omap_plane(plane);
2478bb0daffSRob Clark 	omap_plane->enabled = true;
248b03e14fdSArchit Taneja 
249d4586604SGrazvydas Ignotas 	/* omap_plane_mode_set() takes adjusted src */
250d4586604SGrazvydas Ignotas 	switch (omap_plane->win.rotation & 0xf) {
251d4586604SGrazvydas Ignotas 	case BIT(DRM_ROTATE_90):
252d4586604SGrazvydas Ignotas 	case BIT(DRM_ROTATE_270):
253d4586604SGrazvydas Ignotas 		swap(src_w, src_h);
254d4586604SGrazvydas Ignotas 		break;
255d4586604SGrazvydas Ignotas 	}
256d4586604SGrazvydas Ignotas 
2578bb0daffSRob Clark 	return omap_plane_mode_set(plane, crtc, fb,
2588bb0daffSRob Clark 			crtc_x, crtc_y, crtc_w, crtc_h,
2598bb0daffSRob Clark 			src_x, src_y, src_w, src_h,
2608bb0daffSRob Clark 			NULL, NULL);
2618bb0daffSRob Clark }
2628bb0daffSRob Clark 
2638bb0daffSRob Clark static int omap_plane_disable(struct drm_plane *plane)
2648bb0daffSRob Clark {
2658bb0daffSRob Clark 	struct omap_plane *omap_plane = to_omap_plane(plane);
2668bb0daffSRob Clark 	omap_plane->win.rotation = BIT(DRM_ROTATE_0);
2678bb0daffSRob Clark 	return omap_plane_dpms(plane, DRM_MODE_DPMS_OFF);
2688bb0daffSRob Clark }
2698bb0daffSRob Clark 
2708bb0daffSRob Clark static void omap_plane_destroy(struct drm_plane *plane)
2718bb0daffSRob Clark {
2728bb0daffSRob Clark 	struct omap_plane *omap_plane = to_omap_plane(plane);
2738bb0daffSRob Clark 
2748bb0daffSRob Clark 	DBG("%s", omap_plane->name);
2758bb0daffSRob Clark 
2768bb0daffSRob Clark 	omap_irq_unregister(plane->dev, &omap_plane->error_irq);
2778bb0daffSRob Clark 
2788bb0daffSRob Clark 	omap_plane_disable(plane);
2798bb0daffSRob Clark 	drm_plane_cleanup(plane);
2808bb0daffSRob Clark 
2815833bd2fSRob Clark 	drm_flip_work_cleanup(&omap_plane->unpin_work);
2828bb0daffSRob Clark 
2838bb0daffSRob Clark 	kfree(omap_plane);
2848bb0daffSRob Clark }
2858bb0daffSRob Clark 
2868bb0daffSRob Clark int omap_plane_dpms(struct drm_plane *plane, int mode)
2878bb0daffSRob Clark {
2888bb0daffSRob Clark 	struct omap_plane *omap_plane = to_omap_plane(plane);
2898bb0daffSRob Clark 	bool enabled = (mode == DRM_MODE_DPMS_ON);
2908bb0daffSRob Clark 	int ret = 0;
2918bb0daffSRob Clark 
2928bb0daffSRob Clark 	if (enabled != omap_plane->enabled) {
2938bb0daffSRob Clark 		omap_plane->enabled = enabled;
2948bb0daffSRob Clark 		ret = apply(plane);
2958bb0daffSRob Clark 	}
2968bb0daffSRob Clark 
2978bb0daffSRob Clark 	return ret;
2988bb0daffSRob Clark }
2998bb0daffSRob Clark 
3008bb0daffSRob Clark /* helper to install properties which are common to planes and crtcs */
3018bb0daffSRob Clark void omap_plane_install_properties(struct drm_plane *plane,
3028bb0daffSRob Clark 		struct drm_mode_object *obj)
3038bb0daffSRob Clark {
3048bb0daffSRob Clark 	struct drm_device *dev = plane->dev;
3058bb0daffSRob Clark 	struct omap_drm_private *priv = dev->dev_private;
3068bb0daffSRob Clark 	struct drm_property *prop;
3078bb0daffSRob Clark 
3088bb0daffSRob Clark 	if (priv->has_dmm) {
3098bb0daffSRob Clark 		prop = priv->rotation_prop;
3108bb0daffSRob Clark 		if (!prop) {
311a4969dd7SVille Syrjälä 			prop = drm_mode_create_rotation_property(dev,
312a4969dd7SVille Syrjälä 								 BIT(DRM_ROTATE_0) |
313a4969dd7SVille Syrjälä 								 BIT(DRM_ROTATE_90) |
314a4969dd7SVille Syrjälä 								 BIT(DRM_ROTATE_180) |
315a4969dd7SVille Syrjälä 								 BIT(DRM_ROTATE_270) |
316a4969dd7SVille Syrjälä 								 BIT(DRM_REFLECT_X) |
317a4969dd7SVille Syrjälä 								 BIT(DRM_REFLECT_Y));
3188bb0daffSRob Clark 			if (prop == NULL)
3198bb0daffSRob Clark 				return;
3208bb0daffSRob Clark 			priv->rotation_prop = prop;
3218bb0daffSRob Clark 		}
3228bb0daffSRob Clark 		drm_object_attach_property(obj, prop, 0);
3238bb0daffSRob Clark 	}
3248bb0daffSRob Clark 
3258bb0daffSRob Clark 	prop = priv->zorder_prop;
3268bb0daffSRob Clark 	if (!prop) {
3278bb0daffSRob Clark 		prop = drm_property_create_range(dev, 0, "zorder", 0, 3);
3288bb0daffSRob Clark 		if (prop == NULL)
3298bb0daffSRob Clark 			return;
3308bb0daffSRob Clark 		priv->zorder_prop = prop;
3318bb0daffSRob Clark 	}
3328bb0daffSRob Clark 	drm_object_attach_property(obj, prop, 0);
3338bb0daffSRob Clark }
3348bb0daffSRob Clark 
3358bb0daffSRob Clark int omap_plane_set_property(struct drm_plane *plane,
3368bb0daffSRob Clark 		struct drm_property *property, uint64_t val)
3378bb0daffSRob Clark {
3388bb0daffSRob Clark 	struct omap_plane *omap_plane = to_omap_plane(plane);
3398bb0daffSRob Clark 	struct omap_drm_private *priv = plane->dev->dev_private;
3408bb0daffSRob Clark 	int ret = -EINVAL;
3418bb0daffSRob Clark 
3428bb0daffSRob Clark 	if (property == priv->rotation_prop) {
3438bb0daffSRob Clark 		DBG("%s: rotation: %02x", omap_plane->name, (uint32_t)val);
3448bb0daffSRob Clark 		omap_plane->win.rotation = val;
3458bb0daffSRob Clark 		ret = apply(plane);
3468bb0daffSRob Clark 	} else if (property == priv->zorder_prop) {
3478bb0daffSRob Clark 		DBG("%s: zorder: %02x", omap_plane->name, (uint32_t)val);
3488bb0daffSRob Clark 		omap_plane->info.zorder = val;
3498bb0daffSRob Clark 		ret = apply(plane);
3508bb0daffSRob Clark 	}
3518bb0daffSRob Clark 
3528bb0daffSRob Clark 	return ret;
3538bb0daffSRob Clark }
3548bb0daffSRob Clark 
3558bb0daffSRob Clark static const struct drm_plane_funcs omap_plane_funcs = {
3568bb0daffSRob Clark 	.update_plane = omap_plane_update,
3578bb0daffSRob Clark 	.disable_plane = omap_plane_disable,
3588bb0daffSRob Clark 	.destroy = omap_plane_destroy,
3598bb0daffSRob Clark 	.set_property = omap_plane_set_property,
3608bb0daffSRob Clark };
3618bb0daffSRob Clark 
3628bb0daffSRob Clark static void omap_plane_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
3638bb0daffSRob Clark {
3648bb0daffSRob Clark 	struct omap_plane *omap_plane =
3658bb0daffSRob Clark 			container_of(irq, struct omap_plane, error_irq);
3668bb0daffSRob Clark 	DRM_ERROR("%s: errors: %08x\n", omap_plane->name, irqstatus);
3678bb0daffSRob Clark }
3688bb0daffSRob Clark 
3698bb0daffSRob Clark static const char *plane_names[] = {
3708bb0daffSRob Clark 	[OMAP_DSS_GFX] = "gfx",
3718bb0daffSRob Clark 	[OMAP_DSS_VIDEO1] = "vid1",
3728bb0daffSRob Clark 	[OMAP_DSS_VIDEO2] = "vid2",
3738bb0daffSRob Clark 	[OMAP_DSS_VIDEO3] = "vid3",
3748bb0daffSRob Clark };
3758bb0daffSRob Clark 
3768bb0daffSRob Clark static const uint32_t error_irqs[] = {
3778bb0daffSRob Clark 	[OMAP_DSS_GFX] = DISPC_IRQ_GFX_FIFO_UNDERFLOW,
3788bb0daffSRob Clark 	[OMAP_DSS_VIDEO1] = DISPC_IRQ_VID1_FIFO_UNDERFLOW,
3798bb0daffSRob Clark 	[OMAP_DSS_VIDEO2] = DISPC_IRQ_VID2_FIFO_UNDERFLOW,
3808bb0daffSRob Clark 	[OMAP_DSS_VIDEO3] = DISPC_IRQ_VID3_FIFO_UNDERFLOW,
3818bb0daffSRob Clark };
3828bb0daffSRob Clark 
3838bb0daffSRob Clark /* initialize plane */
3848bb0daffSRob Clark struct drm_plane *omap_plane_init(struct drm_device *dev,
3858bb0daffSRob Clark 		int id, bool private_plane)
3868bb0daffSRob Clark {
3878bb0daffSRob Clark 	struct omap_drm_private *priv = dev->dev_private;
3888bb0daffSRob Clark 	struct drm_plane *plane = NULL;
3898bb0daffSRob Clark 	struct omap_plane *omap_plane;
3908bb0daffSRob Clark 	struct omap_overlay_info *info;
3918bb0daffSRob Clark 
3928bb0daffSRob Clark 	DBG("%s: priv=%d", plane_names[id], private_plane);
3938bb0daffSRob Clark 
3948bb0daffSRob Clark 	omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL);
395fffddfd6SLinus Torvalds 	if (!omap_plane)
396fb9a35f8SLaurent Pinchart 		return ERR_PTR(-ENOMEM);
3978bb0daffSRob Clark 
398d7f8db53SBoris BREZILLON 	drm_flip_work_init(&omap_plane->unpin_work,
3995833bd2fSRob Clark 			"unpin", unpin_worker);
4008bb0daffSRob Clark 
4018bb0daffSRob Clark 	omap_plane->nformats = omap_framebuffer_get_formats(
4028bb0daffSRob Clark 			omap_plane->formats, ARRAY_SIZE(omap_plane->formats),
4038bb0daffSRob Clark 			dss_feat_get_supported_color_modes(id));
4048bb0daffSRob Clark 	omap_plane->id = id;
4058bb0daffSRob Clark 	omap_plane->name = plane_names[id];
4068bb0daffSRob Clark 
4078bb0daffSRob Clark 	plane = &omap_plane->base;
4088bb0daffSRob Clark 
4098bb0daffSRob Clark 	omap_plane->apply.pre_apply  = omap_plane_pre_apply;
4108bb0daffSRob Clark 	omap_plane->apply.post_apply = omap_plane_post_apply;
4118bb0daffSRob Clark 
4128bb0daffSRob Clark 	omap_plane->error_irq.irqmask = error_irqs[id];
4138bb0daffSRob Clark 	omap_plane->error_irq.irq = omap_plane_error_irq;
4148bb0daffSRob Clark 	omap_irq_register(dev, &omap_plane->error_irq);
4158bb0daffSRob Clark 
4168bb0daffSRob Clark 	drm_plane_init(dev, plane, (1 << priv->num_crtcs) - 1, &omap_plane_funcs,
4178bb0daffSRob Clark 			omap_plane->formats, omap_plane->nformats, private_plane);
4188bb0daffSRob Clark 
4198bb0daffSRob Clark 	omap_plane_install_properties(plane, &plane->base);
4208bb0daffSRob Clark 
4218bb0daffSRob Clark 	/* get our starting configuration, set defaults for parameters
4228bb0daffSRob Clark 	 * we don't currently use, etc:
4238bb0daffSRob Clark 	 */
4248bb0daffSRob Clark 	info = &omap_plane->info;
4258bb0daffSRob Clark 	info->rotation_type = OMAP_DSS_ROT_DMA;
4268bb0daffSRob Clark 	info->rotation = OMAP_DSS_ROT_0;
4278bb0daffSRob Clark 	info->global_alpha = 0xff;
4288bb0daffSRob Clark 	info->mirror = 0;
4298bb0daffSRob Clark 
4308bb0daffSRob Clark 	/* Set defaults depending on whether we are a CRTC or overlay
4318bb0daffSRob Clark 	 * layer.
4328bb0daffSRob Clark 	 * TODO add ioctl to give userspace an API to change this.. this
4338bb0daffSRob Clark 	 * will come in a subsequent patch.
4348bb0daffSRob Clark 	 */
4358bb0daffSRob Clark 	if (private_plane)
4368bb0daffSRob Clark 		omap_plane->info.zorder = 0;
4378bb0daffSRob Clark 	else
4388bb0daffSRob Clark 		omap_plane->info.zorder = id;
4398bb0daffSRob Clark 
4408bb0daffSRob Clark 	return plane;
4418bb0daffSRob Clark }
442