Linux Audio

Check our new training course

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