]> Git Repo - linux.git/blob - drivers/gpu/drm/omapdrm/omap_overlay.c
Merge tag 'ata-5.17-rc1-part2' of git://git.kernel.org/pub/scm/linux/kernel/git/dlemo...
[linux.git] / drivers / gpu / drm / omapdrm / omap_overlay.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2018 Texas Instruments Incorporated -  http://www.ti.com/
4  * Author: Benoit Parrot <[email protected]>
5  */
6
7 #include <drm/drm_atomic.h>
8 #include <drm/drm_atomic_helper.h>
9 #include <drm/drm_plane_helper.h>
10
11 #include "omap_dmm_tiler.h"
12 #include "omap_drv.h"
13
14 /*
15  * overlay funcs
16  */
17 static 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  */
27 static struct omap_hw_overlay *
28 omap_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  */
69 int 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[r_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  */
114 void 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  */
137 void 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
152 static void omap_overlay_destroy(struct omap_hw_overlay *overlay)
153 {
154         kfree(overlay);
155 }
156
157 static 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
173 int 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
202 void 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 }
This page took 0.038632 seconds and 4 git commands to generate.