1c8fa1e73SBenoit Parrot // SPDX-License-Identifier: GPL-2.0
2c8fa1e73SBenoit Parrot /*
3c8fa1e73SBenoit Parrot  * Copyright (C) 2018 Texas Instruments Incorporated -  http://www.ti.com/
4c8fa1e73SBenoit Parrot  * Author: Benoit Parrot <bparrot@ti.com>
5c8fa1e73SBenoit Parrot  */
6c8fa1e73SBenoit Parrot 
7c8fa1e73SBenoit Parrot #include <drm/drm_atomic.h>
8c8fa1e73SBenoit Parrot #include <drm/drm_atomic_helper.h>
9c8fa1e73SBenoit Parrot 
10c8fa1e73SBenoit Parrot #include "omap_dmm_tiler.h"
11c8fa1e73SBenoit Parrot #include "omap_drv.h"
12c8fa1e73SBenoit Parrot 
13c8fa1e73SBenoit Parrot /*
14c8fa1e73SBenoit Parrot  * overlay funcs
15c8fa1e73SBenoit Parrot  */
16c8fa1e73SBenoit Parrot static const char * const overlay_id_to_name[] = {
17c8fa1e73SBenoit Parrot 	[OMAP_DSS_GFX] = "gfx",
18c8fa1e73SBenoit Parrot 	[OMAP_DSS_VIDEO1] = "vid1",
19c8fa1e73SBenoit Parrot 	[OMAP_DSS_VIDEO2] = "vid2",
20c8fa1e73SBenoit Parrot 	[OMAP_DSS_VIDEO3] = "vid3",
21c8fa1e73SBenoit Parrot };
22c8fa1e73SBenoit Parrot 
232e54ff0eSBenoit Parrot /*
242e54ff0eSBenoit Parrot  * Find a free overlay with the required caps and supported fourcc
252e54ff0eSBenoit Parrot  */
262e54ff0eSBenoit Parrot static struct omap_hw_overlay *
omap_plane_find_free_overlay(struct drm_device * dev,struct drm_plane * hwoverlay_to_plane[],u32 caps,u32 fourcc)272e54ff0eSBenoit Parrot omap_plane_find_free_overlay(struct drm_device *dev, struct drm_plane *hwoverlay_to_plane[],
282e54ff0eSBenoit Parrot 			     u32 caps, u32 fourcc)
292e54ff0eSBenoit Parrot {
302e54ff0eSBenoit Parrot 	struct omap_drm_private *priv = dev->dev_private;
312e54ff0eSBenoit Parrot 	int i;
322e54ff0eSBenoit Parrot 
332e54ff0eSBenoit Parrot 	DBG("caps: %x fourcc: %x", caps, fourcc);
342e54ff0eSBenoit Parrot 
352e54ff0eSBenoit Parrot 	for (i = 0; i < priv->num_ovls; i++) {
362e54ff0eSBenoit Parrot 		struct omap_hw_overlay *cur = priv->overlays[i];
372e54ff0eSBenoit Parrot 
382e54ff0eSBenoit Parrot 		DBG("%d: id: %d cur->caps: %x",
392e54ff0eSBenoit Parrot 		    cur->idx, cur->id, cur->caps);
402e54ff0eSBenoit Parrot 
412e54ff0eSBenoit Parrot 		/* skip if already in-use */
422e54ff0eSBenoit Parrot 		if (hwoverlay_to_plane[cur->idx])
432e54ff0eSBenoit Parrot 			continue;
442e54ff0eSBenoit Parrot 
452e54ff0eSBenoit Parrot 		/* skip if doesn't support some required caps: */
462e54ff0eSBenoit Parrot 		if (caps & ~cur->caps)
472e54ff0eSBenoit Parrot 			continue;
482e54ff0eSBenoit Parrot 
492e54ff0eSBenoit Parrot 		/* check supported format */
502e54ff0eSBenoit Parrot 		if (!dispc_ovl_color_mode_supported(priv->dispc,
512e54ff0eSBenoit Parrot 						    cur->id, fourcc))
522e54ff0eSBenoit Parrot 			continue;
532e54ff0eSBenoit Parrot 
542e54ff0eSBenoit Parrot 		return cur;
552e54ff0eSBenoit Parrot 	}
562e54ff0eSBenoit Parrot 
572e54ff0eSBenoit Parrot 	DBG("no match");
582e54ff0eSBenoit Parrot 	return NULL;
592e54ff0eSBenoit Parrot }
602e54ff0eSBenoit Parrot 
612e54ff0eSBenoit Parrot /*
622e54ff0eSBenoit Parrot  * Assign a new overlay to a plane with the required caps and supported fourcc
632e54ff0eSBenoit Parrot  * If a plane need a new overlay, the previous one should have been released
642e54ff0eSBenoit Parrot  * with omap_overlay_release()
652e54ff0eSBenoit Parrot  * This should be called from the plane atomic_check() in order to prepare the
662e54ff0eSBenoit Parrot  * next global overlay_map to be enabled when atomic transaction is valid.
672e54ff0eSBenoit Parrot  */
omap_overlay_assign(struct drm_atomic_state * s,struct drm_plane * plane,u32 caps,u32 fourcc,struct omap_hw_overlay ** overlay,struct omap_hw_overlay ** r_overlay)682e54ff0eSBenoit Parrot int omap_overlay_assign(struct drm_atomic_state *s, struct drm_plane *plane,
69e02b5cc9SBenoit Parrot 			u32 caps, u32 fourcc, struct omap_hw_overlay **overlay,
70e02b5cc9SBenoit Parrot 			struct omap_hw_overlay **r_overlay)
712e54ff0eSBenoit Parrot {
722e54ff0eSBenoit Parrot 	/* Get the global state of the current atomic transaction */
732e54ff0eSBenoit Parrot 	struct omap_global_state *state = omap_get_global_state(s);
742e54ff0eSBenoit Parrot 	struct drm_plane **overlay_map = state->hwoverlay_to_plane;
75e02b5cc9SBenoit Parrot 	struct omap_hw_overlay *ovl, *r_ovl;
762e54ff0eSBenoit Parrot 
772e54ff0eSBenoit Parrot 	ovl = omap_plane_find_free_overlay(s->dev, overlay_map, caps, fourcc);
782e54ff0eSBenoit Parrot 	if (!ovl)
792e54ff0eSBenoit Parrot 		return -ENOMEM;
802e54ff0eSBenoit Parrot 
812e54ff0eSBenoit Parrot 	overlay_map[ovl->idx] = plane;
822e54ff0eSBenoit Parrot 	*overlay = ovl;
832e54ff0eSBenoit Parrot 
84e02b5cc9SBenoit Parrot 	if (r_overlay) {
85e02b5cc9SBenoit Parrot 		r_ovl = omap_plane_find_free_overlay(s->dev, overlay_map,
86e02b5cc9SBenoit Parrot 						     caps, fourcc);
87e02b5cc9SBenoit Parrot 		if (!r_ovl) {
88*8f2a3970SWan Jiabing 			overlay_map[ovl->idx] = NULL;
89e02b5cc9SBenoit Parrot 			*overlay = NULL;
90e02b5cc9SBenoit Parrot 			return -ENOMEM;
91e02b5cc9SBenoit Parrot 		}
92e02b5cc9SBenoit Parrot 
93e02b5cc9SBenoit Parrot 		overlay_map[r_ovl->idx] = plane;
94e02b5cc9SBenoit Parrot 		*r_overlay = r_ovl;
95e02b5cc9SBenoit Parrot 	}
96e02b5cc9SBenoit Parrot 
972e54ff0eSBenoit Parrot 	DBG("%s: assign to plane %s caps %x", ovl->name, plane->name, caps);
982e54ff0eSBenoit Parrot 
99e02b5cc9SBenoit Parrot 	if (r_overlay) {
100e02b5cc9SBenoit Parrot 		DBG("%s: assign to right of plane %s caps %x",
101e02b5cc9SBenoit Parrot 		    r_ovl->name, plane->name, caps);
102e02b5cc9SBenoit Parrot 	}
103e02b5cc9SBenoit Parrot 
1042e54ff0eSBenoit Parrot 	return 0;
1052e54ff0eSBenoit Parrot }
1062e54ff0eSBenoit Parrot 
1072e54ff0eSBenoit Parrot /*
1082e54ff0eSBenoit Parrot  * Release an overlay from a plane if the plane gets not visible or the plane
1092e54ff0eSBenoit Parrot  * need a new overlay if overlay caps changes.
1102e54ff0eSBenoit Parrot  * This should be called from the plane atomic_check() in order to prepare the
1112e54ff0eSBenoit Parrot  * next global overlay_map to be enabled when atomic transaction is valid.
1122e54ff0eSBenoit Parrot  */
omap_overlay_release(struct drm_atomic_state * s,struct omap_hw_overlay * overlay)1132e54ff0eSBenoit Parrot void omap_overlay_release(struct drm_atomic_state *s, struct omap_hw_overlay *overlay)
1142e54ff0eSBenoit Parrot {
1152e54ff0eSBenoit Parrot 	/* Get the global state of the current atomic transaction */
1162e54ff0eSBenoit Parrot 	struct omap_global_state *state = omap_get_global_state(s);
1172e54ff0eSBenoit Parrot 	struct drm_plane **overlay_map = state->hwoverlay_to_plane;
1182e54ff0eSBenoit Parrot 
1192e54ff0eSBenoit Parrot 	if (!overlay)
1202e54ff0eSBenoit Parrot 		return;
1212e54ff0eSBenoit Parrot 
1222e54ff0eSBenoit Parrot 	if (WARN_ON(!overlay_map[overlay->idx]))
1232e54ff0eSBenoit Parrot 		return;
1242e54ff0eSBenoit Parrot 
1252e54ff0eSBenoit Parrot 	DBG("%s: release from plane %s", overlay->name, overlay_map[overlay->idx]->name);
1262e54ff0eSBenoit Parrot 
1272e54ff0eSBenoit Parrot 	overlay_map[overlay->idx] = NULL;
1282e54ff0eSBenoit Parrot }
1292e54ff0eSBenoit Parrot 
1302e54ff0eSBenoit Parrot /*
1312e54ff0eSBenoit Parrot  * Update an overlay state that was attached to a plane before the current atomic state.
1322e54ff0eSBenoit Parrot  * This should be called from the plane atomic_update() or atomic_disable(),
1332e54ff0eSBenoit Parrot  * where an overlay association to a plane could have changed between the old and current
1342e54ff0eSBenoit Parrot  * atomic state.
1352e54ff0eSBenoit Parrot  */
omap_overlay_update_state(struct omap_drm_private * priv,struct omap_hw_overlay * overlay)1362e54ff0eSBenoit Parrot void omap_overlay_update_state(struct omap_drm_private *priv,
1372e54ff0eSBenoit Parrot 			       struct omap_hw_overlay *overlay)
1382e54ff0eSBenoit Parrot {
1392e54ff0eSBenoit Parrot 	struct omap_global_state *state = omap_get_existing_global_state(priv);
1402e54ff0eSBenoit Parrot 	struct drm_plane **overlay_map = state->hwoverlay_to_plane;
1412e54ff0eSBenoit Parrot 
1422e54ff0eSBenoit Parrot 	/* Check if this overlay is not used anymore, then disable it */
1432e54ff0eSBenoit Parrot 	if (!overlay_map[overlay->idx]) {
1442e54ff0eSBenoit Parrot 		DBG("%s: disabled", overlay->name);
1452e54ff0eSBenoit Parrot 
1462e54ff0eSBenoit Parrot 		/* disable the overlay */
1472e54ff0eSBenoit Parrot 		dispc_ovl_enable(priv->dispc, overlay->id, false);
1482e54ff0eSBenoit Parrot 	}
1492e54ff0eSBenoit Parrot }
1502e54ff0eSBenoit Parrot 
omap_overlay_destroy(struct omap_hw_overlay * overlay)151c8fa1e73SBenoit Parrot static void omap_overlay_destroy(struct omap_hw_overlay *overlay)
152c8fa1e73SBenoit Parrot {
153c8fa1e73SBenoit Parrot 	kfree(overlay);
154c8fa1e73SBenoit Parrot }
155c8fa1e73SBenoit Parrot 
omap_overlay_init(enum omap_plane_id overlay_id,enum omap_overlay_caps caps)156c8fa1e73SBenoit Parrot static struct omap_hw_overlay *omap_overlay_init(enum omap_plane_id overlay_id,
157c8fa1e73SBenoit Parrot 						 enum omap_overlay_caps caps)
158c8fa1e73SBenoit Parrot {
159c8fa1e73SBenoit Parrot 	struct omap_hw_overlay *overlay;
160c8fa1e73SBenoit Parrot 
161c8fa1e73SBenoit Parrot 	overlay = kzalloc(sizeof(*overlay), GFP_KERNEL);
162c8fa1e73SBenoit Parrot 	if (!overlay)
163c8fa1e73SBenoit Parrot 		return ERR_PTR(-ENOMEM);
164c8fa1e73SBenoit Parrot 
165c8fa1e73SBenoit Parrot 	overlay->name = overlay_id_to_name[overlay_id];
166c8fa1e73SBenoit Parrot 	overlay->id = overlay_id;
167c8fa1e73SBenoit Parrot 	overlay->caps = caps;
168c8fa1e73SBenoit Parrot 
169c8fa1e73SBenoit Parrot 	return overlay;
170c8fa1e73SBenoit Parrot }
171c8fa1e73SBenoit Parrot 
omap_hwoverlays_init(struct omap_drm_private * priv)172c8fa1e73SBenoit Parrot int omap_hwoverlays_init(struct omap_drm_private *priv)
173c8fa1e73SBenoit Parrot {
174c8fa1e73SBenoit Parrot 	static const enum omap_plane_id hw_plane_ids[] = {
175c8fa1e73SBenoit Parrot 			OMAP_DSS_GFX, OMAP_DSS_VIDEO1,
176c8fa1e73SBenoit Parrot 			OMAP_DSS_VIDEO2, OMAP_DSS_VIDEO3,
177c8fa1e73SBenoit Parrot 	};
178c8fa1e73SBenoit Parrot 	u32 num_overlays = dispc_get_num_ovls(priv->dispc);
179c8fa1e73SBenoit Parrot 	enum omap_overlay_caps caps;
180c8fa1e73SBenoit Parrot 	int i, ret;
181c8fa1e73SBenoit Parrot 
182c8fa1e73SBenoit Parrot 	for (i = 0; i < num_overlays; i++) {
183c8fa1e73SBenoit Parrot 		struct omap_hw_overlay *overlay;
184c8fa1e73SBenoit Parrot 
185c8fa1e73SBenoit Parrot 		caps = dispc_ovl_get_caps(priv->dispc, hw_plane_ids[i]);
186c8fa1e73SBenoit Parrot 		overlay = omap_overlay_init(hw_plane_ids[i], caps);
187c8fa1e73SBenoit Parrot 		if (IS_ERR(overlay)) {
188c8fa1e73SBenoit Parrot 			ret = PTR_ERR(overlay);
189c8fa1e73SBenoit Parrot 			dev_err(priv->dev, "failed to construct overlay for %s (%d)\n",
190c8fa1e73SBenoit Parrot 				overlay_id_to_name[i], ret);
191c8fa1e73SBenoit Parrot 			omap_hwoverlays_destroy(priv);
192c8fa1e73SBenoit Parrot 			return ret;
193c8fa1e73SBenoit Parrot 		}
194c8fa1e73SBenoit Parrot 		overlay->idx = priv->num_ovls;
195c8fa1e73SBenoit Parrot 		priv->overlays[priv->num_ovls++] = overlay;
196c8fa1e73SBenoit Parrot 	}
197c8fa1e73SBenoit Parrot 
198c8fa1e73SBenoit Parrot 	return 0;
199c8fa1e73SBenoit Parrot }
200c8fa1e73SBenoit Parrot 
omap_hwoverlays_destroy(struct omap_drm_private * priv)201c8fa1e73SBenoit Parrot void omap_hwoverlays_destroy(struct omap_drm_private *priv)
202c8fa1e73SBenoit Parrot {
203c8fa1e73SBenoit Parrot 	int i;
204c8fa1e73SBenoit Parrot 
205c8fa1e73SBenoit Parrot 	for (i = 0; i < priv->num_ovls; i++) {
206c8fa1e73SBenoit Parrot 		omap_overlay_destroy(priv->overlays[i]);
207c8fa1e73SBenoit Parrot 		priv->overlays[i] = NULL;
208c8fa1e73SBenoit Parrot 	}
209c8fa1e73SBenoit Parrot 
210c8fa1e73SBenoit Parrot 	priv->num_ovls = 0;
211c8fa1e73SBenoit Parrot }
212