Merge tag 'fsnotify_for_v4.21-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / drivers / gpu / drm / i915 / intel_atomic_plane.c
1 /*
2  * Copyright © 2014 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23
24 /**
25  * DOC: atomic plane helpers
26  *
27  * The functions here are used by the atomic plane helper functions to
28  * implement legacy plane updates (i.e., drm_plane->update_plane() and
29  * drm_plane->disable_plane()).  This allows plane updates to use the
30  * atomic state infrastructure and perform plane updates as separate
31  * prepare/check/commit/cleanup steps.
32  */
33
34 #include <drm/drmP.h>
35 #include <drm/drm_atomic_helper.h>
36 #include <drm/drm_plane_helper.h>
37 #include "intel_drv.h"
38
39 struct intel_plane *intel_plane_alloc(void)
40 {
41         struct intel_plane_state *plane_state;
42         struct intel_plane *plane;
43
44         plane = kzalloc(sizeof(*plane), GFP_KERNEL);
45         if (!plane)
46                 return ERR_PTR(-ENOMEM);
47
48         plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
49         if (!plane_state) {
50                 kfree(plane);
51                 return ERR_PTR(-ENOMEM);
52         }
53
54         __drm_atomic_helper_plane_reset(&plane->base, &plane_state->base);
55         plane_state->scaler_id = -1;
56
57         return plane;
58 }
59
60 void intel_plane_free(struct intel_plane *plane)
61 {
62         intel_plane_destroy_state(&plane->base, plane->base.state);
63         kfree(plane);
64 }
65
66 /**
67  * intel_plane_duplicate_state - duplicate plane state
68  * @plane: drm plane
69  *
70  * Allocates and returns a copy of the plane state (both common and
71  * Intel-specific) for the specified plane.
72  *
73  * Returns: The newly allocated plane state, or NULL on failure.
74  */
75 struct drm_plane_state *
76 intel_plane_duplicate_state(struct drm_plane *plane)
77 {
78         struct drm_plane_state *state;
79         struct intel_plane_state *intel_state;
80
81         intel_state = kmemdup(plane->state, sizeof(*intel_state), GFP_KERNEL);
82
83         if (!intel_state)
84                 return NULL;
85
86         state = &intel_state->base;
87
88         __drm_atomic_helper_plane_duplicate_state(plane, state);
89
90         intel_state->vma = NULL;
91         intel_state->flags = 0;
92
93         return state;
94 }
95
96 /**
97  * intel_plane_destroy_state - destroy plane state
98  * @plane: drm plane
99  * @state: state object to destroy
100  *
101  * Destroys the plane state (both common and Intel-specific) for the
102  * specified plane.
103  */
104 void
105 intel_plane_destroy_state(struct drm_plane *plane,
106                           struct drm_plane_state *state)
107 {
108         WARN_ON(to_intel_plane_state(state)->vma);
109
110         drm_atomic_helper_plane_destroy_state(plane, state);
111 }
112
113 int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_state,
114                                         struct intel_crtc_state *crtc_state,
115                                         const struct intel_plane_state *old_plane_state,
116                                         struct intel_plane_state *intel_state)
117 {
118         struct drm_plane *plane = intel_state->base.plane;
119         struct drm_plane_state *state = &intel_state->base;
120         struct intel_plane *intel_plane = to_intel_plane(plane);
121         int ret;
122
123         crtc_state->active_planes &= ~BIT(intel_plane->id);
124         crtc_state->nv12_planes &= ~BIT(intel_plane->id);
125         intel_state->base.visible = false;
126
127         /* If this is a cursor plane, no further checks are needed. */
128         if (!intel_state->base.crtc && !old_plane_state->base.crtc)
129                 return 0;
130
131         ret = intel_plane->check_plane(crtc_state, intel_state);
132         if (ret)
133                 return ret;
134
135         /* FIXME pre-g4x don't work like this */
136         if (state->visible)
137                 crtc_state->active_planes |= BIT(intel_plane->id);
138
139         if (state->visible && state->fb->format->format == DRM_FORMAT_NV12)
140                 crtc_state->nv12_planes |= BIT(intel_plane->id);
141
142         if (state->visible || old_plane_state->base.visible)
143                 crtc_state->update_planes |= BIT(intel_plane->id);
144
145         return intel_plane_atomic_calc_changes(old_crtc_state,
146                                                &crtc_state->base,
147                                                old_plane_state,
148                                                state);
149 }
150
151 static int intel_plane_atomic_check(struct drm_plane *plane,
152                                     struct drm_plane_state *new_plane_state)
153 {
154         struct drm_atomic_state *state = new_plane_state->state;
155         const struct drm_plane_state *old_plane_state =
156                 drm_atomic_get_old_plane_state(state, plane);
157         struct drm_crtc *crtc = new_plane_state->crtc ?: old_plane_state->crtc;
158         const struct drm_crtc_state *old_crtc_state;
159         struct drm_crtc_state *new_crtc_state;
160
161         new_plane_state->visible = false;
162         if (!crtc)
163                 return 0;
164
165         old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc);
166         new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
167
168         return intel_plane_atomic_check_with_state(to_intel_crtc_state(old_crtc_state),
169                                                    to_intel_crtc_state(new_crtc_state),
170                                                    to_intel_plane_state(old_plane_state),
171                                                    to_intel_plane_state(new_plane_state));
172 }
173
174 static struct intel_plane *
175 skl_next_plane_to_commit(struct intel_atomic_state *state,
176                          struct intel_crtc *crtc,
177                          struct skl_ddb_entry entries_y[I915_MAX_PLANES],
178                          struct skl_ddb_entry entries_uv[I915_MAX_PLANES],
179                          unsigned int *update_mask)
180 {
181         struct intel_crtc_state *crtc_state =
182                 intel_atomic_get_new_crtc_state(state, crtc);
183         struct intel_plane_state *plane_state;
184         struct intel_plane *plane;
185         int i;
186
187         if (*update_mask == 0)
188                 return NULL;
189
190         for_each_new_intel_plane_in_state(state, plane, plane_state, i) {
191                 enum plane_id plane_id = plane->id;
192
193                 if (crtc->pipe != plane->pipe ||
194                     !(*update_mask & BIT(plane_id)))
195                         continue;
196
197                 if (skl_ddb_allocation_overlaps(&crtc_state->wm.skl.plane_ddb_y[plane_id],
198                                                 entries_y,
199                                                 I915_MAX_PLANES, plane_id) ||
200                     skl_ddb_allocation_overlaps(&crtc_state->wm.skl.plane_ddb_uv[plane_id],
201                                                 entries_uv,
202                                                 I915_MAX_PLANES, plane_id))
203                         continue;
204
205                 *update_mask &= ~BIT(plane_id);
206                 entries_y[plane_id] = crtc_state->wm.skl.plane_ddb_y[plane_id];
207                 entries_uv[plane_id] = crtc_state->wm.skl.plane_ddb_uv[plane_id];
208
209                 return plane;
210         }
211
212         /* should never happen */
213         WARN_ON(1);
214
215         return NULL;
216 }
217
218 void skl_update_planes_on_crtc(struct intel_atomic_state *state,
219                                struct intel_crtc *crtc)
220 {
221         struct intel_crtc_state *old_crtc_state =
222                 intel_atomic_get_old_crtc_state(state, crtc);
223         struct intel_crtc_state *new_crtc_state =
224                 intel_atomic_get_new_crtc_state(state, crtc);
225         struct skl_ddb_entry entries_y[I915_MAX_PLANES];
226         struct skl_ddb_entry entries_uv[I915_MAX_PLANES];
227         u32 update_mask = new_crtc_state->update_planes;
228         struct intel_plane *plane;
229
230         memcpy(entries_y, old_crtc_state->wm.skl.plane_ddb_y,
231                sizeof(old_crtc_state->wm.skl.plane_ddb_y));
232         memcpy(entries_uv, old_crtc_state->wm.skl.plane_ddb_uv,
233                sizeof(old_crtc_state->wm.skl.plane_ddb_uv));
234
235         while ((plane = skl_next_plane_to_commit(state, crtc,
236                                                  entries_y, entries_uv,
237                                                  &update_mask))) {
238                 struct intel_plane_state *new_plane_state =
239                         intel_atomic_get_new_plane_state(state, plane);
240
241                 if (new_plane_state->base.visible) {
242                         trace_intel_update_plane(&plane->base, crtc);
243                         plane->update_plane(plane, new_crtc_state, new_plane_state);
244                 } else if (new_plane_state->slave) {
245                         struct intel_plane *master =
246                                 new_plane_state->linked_plane;
247
248                         /*
249                          * We update the slave plane from this function because
250                          * programming it from the master plane's update_plane
251                          * callback runs into issues when the Y plane is
252                          * reassigned, disabled or used by a different plane.
253                          *
254                          * The slave plane is updated with the master plane's
255                          * plane_state.
256                          */
257                         new_plane_state =
258                                 intel_atomic_get_new_plane_state(state, master);
259
260                         trace_intel_update_plane(&plane->base, crtc);
261                         plane->update_slave(plane, new_crtc_state, new_plane_state);
262                 } else {
263                         trace_intel_disable_plane(&plane->base, crtc);
264                         plane->disable_plane(plane, new_crtc_state);
265                 }
266         }
267 }
268
269 void i9xx_update_planes_on_crtc(struct intel_atomic_state *state,
270                                 struct intel_crtc *crtc)
271 {
272         struct intel_crtc_state *new_crtc_state =
273                 intel_atomic_get_new_crtc_state(state, crtc);
274         u32 update_mask = new_crtc_state->update_planes;
275         struct intel_plane_state *new_plane_state;
276         struct intel_plane *plane;
277         int i;
278
279         for_each_new_intel_plane_in_state(state, plane, new_plane_state, i) {
280                 if (crtc->pipe != plane->pipe ||
281                     !(update_mask & BIT(plane->id)))
282                         continue;
283
284                 if (new_plane_state->base.visible) {
285                         trace_intel_update_plane(&plane->base, crtc);
286                         plane->update_plane(plane, new_crtc_state, new_plane_state);
287                 } else {
288                         trace_intel_disable_plane(&plane->base, crtc);
289                         plane->disable_plane(plane, new_crtc_state);
290                 }
291         }
292 }
293
294 const struct drm_plane_helper_funcs intel_plane_helper_funcs = {
295         .prepare_fb = intel_prepare_plane_fb,
296         .cleanup_fb = intel_cleanup_plane_fb,
297         .atomic_check = intel_plane_atomic_check,
298 };
299
300 /**
301  * intel_plane_atomic_get_property - fetch plane property value
302  * @plane: plane to fetch property for
303  * @state: state containing the property value
304  * @property: property to look up
305  * @val: pointer to write property value into
306  *
307  * The DRM core does not store shadow copies of properties for
308  * atomic-capable drivers.  This entrypoint is used to fetch
309  * the current value of a driver-specific plane property.
310  */
311 int
312 intel_plane_atomic_get_property(struct drm_plane *plane,
313                                 const struct drm_plane_state *state,
314                                 struct drm_property *property,
315                                 uint64_t *val)
316 {
317         DRM_DEBUG_KMS("Unknown property [PROP:%d:%s]\n",
318                       property->base.id, property->name);
319         return -EINVAL;
320 }
321
322 /**
323  * intel_plane_atomic_set_property - set plane property value
324  * @plane: plane to set property for
325  * @state: state to update property value in
326  * @property: property to set
327  * @val: value to set property to
328  *
329  * Writes the specified property value for a plane into the provided atomic
330  * state object.
331  *
332  * Returns 0 on success, -EINVAL on unrecognized properties
333  */
334 int
335 intel_plane_atomic_set_property(struct drm_plane *plane,
336                                 struct drm_plane_state *state,
337                                 struct drm_property *property,
338                                 uint64_t val)
339 {
340         DRM_DEBUG_KMS("Unknown property [PROP:%d:%s]\n",
341                       property->base.id, property->name);
342         return -EINVAL;
343 }