File Index
Files and directories
Sign in
FILE

omap_overlay.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/omapdrm/omap_overlay.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Copyright (C) 2018 Texas Instruments Incorporated -  http://www.ti.com/
  4 * Author: Benoit Parrot <bparrot@ti.com>
  5 */
  6
  7#include <drm/drm_atomic.h>
  8#include <drm/drm_atomic_helper.h>
  9#include <drm/drm_print.h>
 10
 11#include "omap_dmm_tiler.h"
 12#include "omap_drv.h"
 13
 14/*
 15 * overlay funcs
 16 */
 17static const char * const overlay_id_to_name[] = {
 18	[OMAP_DSS_GFX] = "gfx",
 19	[OMAP_DSS_VIDEO1] = "vid1",
 20	[OMAP_DSS_VIDEO2] = "vid2",
 21	[OMAP_DSS_VIDEO3] = "vid3",
 22};
 23
 24/*
 25 * Find a free overlay with the required caps and supported fourcc
 26 */
 27static struct omap_hw_overlay *
 28omap_plane_find_free_overlay(struct drm_device *dev, struct drm_plane *hwoverlay_to_plane[],
 29			     u32 caps, u32 fourcc)
 30{
 31	struct omap_drm_private *priv = dev->dev_private;
 32	int i;
 33
 34	DBG("caps: %x fourcc: %x", caps, fourcc);
 35
 36	for (i = 0; i < priv->num_ovls; i++) {
 37		struct omap_hw_overlay *cur = priv->overlays[i];
 38
 39		DBG("%d: id: %d cur->caps: %x",
 40		    cur->idx, cur->id, cur->caps);
 41
 42		/* skip if already in-use */
 43		if (hwoverlay_to_plane[cur->idx])
 44			continue;
 45
 46		/* skip if doesn't support some required caps: */
 47		if (caps & ~cur->caps)
 48			continue;
 49
 50		/* check supported format */
 51		if (!dispc_ovl_color_mode_supported(priv->dispc,
 52						    cur->id, fourcc))
 53			continue;
 54
 55		return cur;
 56	}
 57
 58	DBG("no match");
 59	return NULL;
 60}
 61
 62/*
 63 * Assign a new overlay to a plane with the required caps and supported fourcc
 64 * If a plane need a new overlay, the previous one should have been released
 65 * with omap_overlay_release()
 66 * This should be called from the plane atomic_check() in order to prepare the
 67 * next global overlay_map to be enabled when atomic transaction is valid.
 68 */
 69int omap_overlay_assign(struct drm_atomic_state *s, struct drm_plane *plane,
 70			u32 caps, u32 fourcc, struct omap_hw_overlay **overlay,
 71			struct omap_hw_overlay **r_overlay)
 72{
 73	/* Get the global state of the current atomic transaction */
 74	struct omap_global_state *state = omap_get_global_state(s);
 75	struct drm_plane **overlay_map = state->hwoverlay_to_plane;
 76	struct omap_hw_overlay *ovl, *r_ovl;
 77
 78	ovl = omap_plane_find_free_overlay(s->dev, overlay_map, caps, fourcc);
 79	if (!ovl)
 80		return -ENOMEM;
 81
 82	overlay_map[ovl->idx] = plane;
 83	*overlay = ovl;
 84
 85	if (r_overlay) {
 86		r_ovl = omap_plane_find_free_overlay(s->dev, overlay_map,
 87						     caps, fourcc);
 88		if (!r_ovl) {
 89			overlay_map[ovl->idx] = NULL;
 90			*overlay = NULL;
 91			return -ENOMEM;
 92		}
 93
 94		overlay_map[r_ovl->idx] = plane;
 95		*r_overlay = r_ovl;
 96	}
 97
 98	DBG("%s: assign to plane %s caps %x", ovl->name, plane->name, caps);
 99
100	if (r_overlay) {
101		DBG("%s: assign to right of plane %s caps %x",
102		    r_ovl->name, plane->name, caps);
103	}
104
105	return 0;
106}
107
108/*
109 * Release an overlay from a plane if the plane gets not visible or the plane
110 * need a new overlay if overlay caps changes.
111 * This should be called from the plane atomic_check() in order to prepare the
112 * next global overlay_map to be enabled when atomic transaction is valid.
113 */
114void omap_overlay_release(struct drm_atomic_state *s, struct omap_hw_overlay *overlay)
115{
116	/* Get the global state of the current atomic transaction */
117	struct omap_global_state *state = omap_get_global_state(s);
118	struct drm_plane **overlay_map = state->hwoverlay_to_plane;
119
120	if (!overlay)
121		return;
122
123	if (WARN_ON(!overlay_map[overlay->idx]))
124		return;
125
126	DBG("%s: release from plane %s", overlay->name, overlay_map[overlay->idx]->name);
127
128	overlay_map[overlay->idx] = NULL;
129}
130
131/*
132 * Update an overlay state that was attached to a plane before the current atomic state.
133 * This should be called from the plane atomic_update() or atomic_disable(),
134 * where an overlay association to a plane could have changed between the old and current
135 * atomic state.
136 */
137void omap_overlay_update_state(struct omap_drm_private *priv,
138			       struct omap_hw_overlay *overlay)
139{
140	struct omap_global_state *state = omap_get_existing_global_state(priv);
141	struct drm_plane **overlay_map = state->hwoverlay_to_plane;
142
143	/* Check if this overlay is not used anymore, then disable it */
144	if (!overlay_map[overlay->idx]) {
145		DBG("%s: disabled", overlay->name);
146
147		/* disable the overlay */
148		dispc_ovl_enable(priv->dispc, overlay->id, false);
149	}
150}
151
152static void omap_overlay_destroy(struct omap_hw_overlay *overlay)
153{
154	kfree(overlay);
155}
156
157static struct omap_hw_overlay *omap_overlay_init(enum omap_plane_id overlay_id,
158						 enum omap_overlay_caps caps)
159{
160	struct omap_hw_overlay *overlay;
161
162	overlay = kzalloc(sizeof(*overlay), GFP_KERNEL);
163	if (!overlay)
164		return ERR_PTR(-ENOMEM);
165
166	overlay->name = overlay_id_to_name[overlay_id];
167	overlay->id = overlay_id;
168	overlay->caps = caps;
169
170	return overlay;
171}
172
173int omap_hwoverlays_init(struct omap_drm_private *priv)
174{
175	static const enum omap_plane_id hw_plane_ids[] = {
176			OMAP_DSS_GFX, OMAP_DSS_VIDEO1,
177			OMAP_DSS_VIDEO2, OMAP_DSS_VIDEO3,
178	};
179	u32 num_overlays = dispc_get_num_ovls(priv->dispc);
180	enum omap_overlay_caps caps;
181	int i, ret;
182
183	for (i = 0; i < num_overlays; i++) {
184		struct omap_hw_overlay *overlay;
185
186		caps = dispc_ovl_get_caps(priv->dispc, hw_plane_ids[i]);
187		overlay = omap_overlay_init(hw_plane_ids[i], caps);
188		if (IS_ERR(overlay)) {
189			ret = PTR_ERR(overlay);
190			dev_err(priv->dev, "failed to construct overlay for %s (%d)\n",
191				overlay_id_to_name[i], ret);
192			omap_hwoverlays_destroy(priv);
193			return ret;
194		}
195		overlay->idx = priv->num_ovls;
196		priv->overlays[priv->num_ovls++] = overlay;
197	}
198
199	return 0;
200}
201
202void omap_hwoverlays_destroy(struct omap_drm_private *priv)
203{
204	int i;
205
206	for (i = 0; i < priv->num_ovls; i++) {
207		omap_overlay_destroy(priv->overlays[i]);
208		priv->overlays[i] = NULL;
209	}
210
211	priv->num_ovls = 0;
212}
~/ Read-only file preview.