drm_plane.c revision 1.3 1 1.3 riastrad /* $NetBSD: drm_plane.c,v 1.3 2021/12/19 01:13:44 riastradh Exp $ */
2 1.1 riastrad
3 1.1 riastrad /*
4 1.1 riastrad * Copyright (c) 2016 Intel Corporation
5 1.1 riastrad *
6 1.1 riastrad * Permission to use, copy, modify, distribute, and sell this software and its
7 1.1 riastrad * documentation for any purpose is hereby granted without fee, provided that
8 1.1 riastrad * the above copyright notice appear in all copies and that both that copyright
9 1.1 riastrad * notice and this permission notice appear in supporting documentation, and
10 1.1 riastrad * that the name of the copyright holders not be used in advertising or
11 1.1 riastrad * publicity pertaining to distribution of the software without specific,
12 1.1 riastrad * written prior permission. The copyright holders make no representations
13 1.1 riastrad * about the suitability of this software for any purpose. It is provided "as
14 1.1 riastrad * is" without express or implied warranty.
15 1.1 riastrad *
16 1.1 riastrad * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 1.1 riastrad * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 1.1 riastrad * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19 1.1 riastrad * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20 1.1 riastrad * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21 1.1 riastrad * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
22 1.1 riastrad * OF THIS SOFTWARE.
23 1.1 riastrad */
24 1.1 riastrad
25 1.1 riastrad #include <sys/cdefs.h>
26 1.3 riastrad __KERNEL_RCSID(0, "$NetBSD: drm_plane.c,v 1.3 2021/12/19 01:13:44 riastradh Exp $");
27 1.1 riastrad
28 1.1 riastrad #include <linux/slab.h>
29 1.1 riastrad #include <linux/uaccess.h>
30 1.1 riastrad
31 1.1 riastrad #include <drm/drm_plane.h>
32 1.1 riastrad #include <drm/drm_drv.h>
33 1.1 riastrad #include <drm/drm_print.h>
34 1.1 riastrad #include <drm/drm_framebuffer.h>
35 1.1 riastrad #include <drm/drm_file.h>
36 1.1 riastrad #include <drm/drm_crtc.h>
37 1.1 riastrad #include <drm/drm_fourcc.h>
38 1.1 riastrad #include <drm/drm_vblank.h>
39 1.1 riastrad
40 1.1 riastrad #include "drm_crtc_internal.h"
41 1.1 riastrad
42 1.1 riastrad /**
43 1.1 riastrad * DOC: overview
44 1.1 riastrad *
45 1.1 riastrad * A plane represents an image source that can be blended with or overlayed on
46 1.1 riastrad * top of a CRTC during the scanout process. Planes take their input data from a
47 1.1 riastrad * &drm_framebuffer object. The plane itself specifies the cropping and scaling
48 1.1 riastrad * of that image, and where it is placed on the visible are of a display
49 1.1 riastrad * pipeline, represented by &drm_crtc. A plane can also have additional
50 1.1 riastrad * properties that specify how the pixels are positioned and blended, like
51 1.1 riastrad * rotation or Z-position. All these properties are stored in &drm_plane_state.
52 1.1 riastrad *
53 1.1 riastrad * To create a plane, a KMS drivers allocates and zeroes an instances of
54 1.1 riastrad * &struct drm_plane (possibly as part of a larger structure) and registers it
55 1.1 riastrad * with a call to drm_universal_plane_init().
56 1.1 riastrad *
57 1.1 riastrad * Cursor and overlay planes are optional. All drivers should provide one
58 1.1 riastrad * primary plane per CRTC to avoid surprising userspace too much. See enum
59 1.1 riastrad * drm_plane_type for a more in-depth discussion of these special uapi-relevant
60 1.1 riastrad * plane types. Special planes are associated with their CRTC by calling
61 1.1 riastrad * drm_crtc_init_with_planes().
62 1.1 riastrad *
63 1.1 riastrad * The type of a plane is exposed in the immutable "type" enumeration property,
64 1.1 riastrad * which has one of the following values: "Overlay", "Primary", "Cursor".
65 1.1 riastrad */
66 1.1 riastrad
67 1.1 riastrad static unsigned int drm_num_planes(struct drm_device *dev)
68 1.1 riastrad {
69 1.1 riastrad unsigned int num = 0;
70 1.1 riastrad struct drm_plane *tmp;
71 1.1 riastrad
72 1.1 riastrad drm_for_each_plane(tmp, dev) {
73 1.1 riastrad num++;
74 1.1 riastrad }
75 1.1 riastrad
76 1.1 riastrad return num;
77 1.1 riastrad }
78 1.1 riastrad
79 1.1 riastrad static inline u32 *
80 1.1 riastrad formats_ptr(struct drm_format_modifier_blob *blob)
81 1.1 riastrad {
82 1.1 riastrad return (u32 *)(((char *)blob) + blob->formats_offset);
83 1.1 riastrad }
84 1.1 riastrad
85 1.1 riastrad static inline struct drm_format_modifier *
86 1.1 riastrad modifiers_ptr(struct drm_format_modifier_blob *blob)
87 1.1 riastrad {
88 1.1 riastrad return (struct drm_format_modifier *)(((char *)blob) + blob->modifiers_offset);
89 1.1 riastrad }
90 1.1 riastrad
91 1.1 riastrad static int create_in_format_blob(struct drm_device *dev, struct drm_plane *plane)
92 1.1 riastrad {
93 1.1 riastrad const struct drm_mode_config *config = &dev->mode_config;
94 1.1 riastrad struct drm_property_blob *blob;
95 1.1 riastrad struct drm_format_modifier *mod;
96 1.1 riastrad size_t blob_size, formats_size, modifiers_size;
97 1.1 riastrad struct drm_format_modifier_blob *blob_data;
98 1.1 riastrad unsigned int i, j;
99 1.1 riastrad
100 1.1 riastrad formats_size = sizeof(__u32) * plane->format_count;
101 1.1 riastrad if (WARN_ON(!formats_size)) {
102 1.1 riastrad /* 0 formats are never expected */
103 1.1 riastrad return 0;
104 1.1 riastrad }
105 1.1 riastrad
106 1.1 riastrad modifiers_size =
107 1.1 riastrad sizeof(struct drm_format_modifier) * plane->modifier_count;
108 1.1 riastrad
109 1.1 riastrad blob_size = sizeof(struct drm_format_modifier_blob);
110 1.1 riastrad /* Modifiers offset is a pointer to a struct with a 64 bit field so it
111 1.1 riastrad * should be naturally aligned to 8B.
112 1.1 riastrad */
113 1.1 riastrad BUILD_BUG_ON(sizeof(struct drm_format_modifier_blob) % 8);
114 1.3 riastrad blob_size += round_up(formats_size, 8);
115 1.1 riastrad blob_size += modifiers_size;
116 1.1 riastrad
117 1.1 riastrad blob = drm_property_create_blob(dev, blob_size, NULL);
118 1.1 riastrad if (IS_ERR(blob))
119 1.1 riastrad return -1;
120 1.1 riastrad
121 1.1 riastrad blob_data = blob->data;
122 1.1 riastrad blob_data->version = FORMAT_BLOB_CURRENT;
123 1.1 riastrad blob_data->count_formats = plane->format_count;
124 1.1 riastrad blob_data->formats_offset = sizeof(struct drm_format_modifier_blob);
125 1.1 riastrad blob_data->count_modifiers = plane->modifier_count;
126 1.1 riastrad
127 1.1 riastrad blob_data->modifiers_offset =
128 1.3 riastrad round_up(blob_data->formats_offset + formats_size, 8);
129 1.1 riastrad
130 1.1 riastrad memcpy(formats_ptr(blob_data), plane->format_types, formats_size);
131 1.1 riastrad
132 1.1 riastrad /* If we can't determine support, just bail */
133 1.1 riastrad if (!plane->funcs->format_mod_supported)
134 1.1 riastrad goto done;
135 1.1 riastrad
136 1.1 riastrad mod = modifiers_ptr(blob_data);
137 1.1 riastrad for (i = 0; i < plane->modifier_count; i++) {
138 1.1 riastrad for (j = 0; j < plane->format_count; j++) {
139 1.1 riastrad if (plane->funcs->format_mod_supported(plane,
140 1.1 riastrad plane->format_types[j],
141 1.1 riastrad plane->modifiers[i])) {
142 1.1 riastrad
143 1.1 riastrad mod->formats |= 1ULL << j;
144 1.1 riastrad }
145 1.1 riastrad }
146 1.1 riastrad
147 1.1 riastrad mod->modifier = plane->modifiers[i];
148 1.1 riastrad mod->offset = 0;
149 1.1 riastrad mod->pad = 0;
150 1.1 riastrad mod++;
151 1.1 riastrad }
152 1.1 riastrad
153 1.1 riastrad done:
154 1.1 riastrad drm_object_attach_property(&plane->base, config->modifiers_property,
155 1.1 riastrad blob->base.id);
156 1.1 riastrad
157 1.1 riastrad return 0;
158 1.1 riastrad }
159 1.1 riastrad
160 1.1 riastrad /**
161 1.1 riastrad * drm_universal_plane_init - Initialize a new universal plane object
162 1.1 riastrad * @dev: DRM device
163 1.1 riastrad * @plane: plane object to init
164 1.1 riastrad * @possible_crtcs: bitmask of possible CRTCs
165 1.1 riastrad * @funcs: callbacks for the new plane
166 1.1 riastrad * @formats: array of supported formats (DRM_FORMAT\_\*)
167 1.1 riastrad * @format_count: number of elements in @formats
168 1.1 riastrad * @format_modifiers: array of struct drm_format modifiers terminated by
169 1.1 riastrad * DRM_FORMAT_MOD_INVALID
170 1.1 riastrad * @type: type of plane (overlay, primary, cursor)
171 1.1 riastrad * @name: printf style format string for the plane name, or NULL for default name
172 1.1 riastrad *
173 1.1 riastrad * Initializes a plane object of type @type.
174 1.1 riastrad *
175 1.1 riastrad * Returns:
176 1.1 riastrad * Zero on success, error code on failure.
177 1.1 riastrad */
178 1.1 riastrad int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
179 1.1 riastrad uint32_t possible_crtcs,
180 1.1 riastrad const struct drm_plane_funcs *funcs,
181 1.1 riastrad const uint32_t *formats, unsigned int format_count,
182 1.1 riastrad const uint64_t *format_modifiers,
183 1.1 riastrad enum drm_plane_type type,
184 1.1 riastrad const char *name, ...)
185 1.1 riastrad {
186 1.1 riastrad struct drm_mode_config *config = &dev->mode_config;
187 1.1 riastrad unsigned int format_modifier_count = 0;
188 1.1 riastrad int ret;
189 1.1 riastrad
190 1.1 riastrad /* plane index is used with 32bit bitmasks */
191 1.1 riastrad if (WARN_ON(config->num_total_plane >= 32))
192 1.1 riastrad return -EINVAL;
193 1.1 riastrad
194 1.1 riastrad WARN_ON(drm_drv_uses_atomic_modeset(dev) &&
195 1.1 riastrad (!funcs->atomic_destroy_state ||
196 1.1 riastrad !funcs->atomic_duplicate_state));
197 1.1 riastrad
198 1.1 riastrad ret = drm_mode_object_add(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
199 1.1 riastrad if (ret)
200 1.1 riastrad return ret;
201 1.1 riastrad
202 1.1 riastrad drm_modeset_lock_init(&plane->mutex);
203 1.1 riastrad
204 1.1 riastrad plane->base.properties = &plane->properties;
205 1.1 riastrad plane->dev = dev;
206 1.1 riastrad plane->funcs = funcs;
207 1.1 riastrad plane->format_types = kmalloc_array(format_count, sizeof(uint32_t),
208 1.1 riastrad GFP_KERNEL);
209 1.1 riastrad if (!plane->format_types) {
210 1.1 riastrad DRM_DEBUG_KMS("out of memory when allocating plane\n");
211 1.1 riastrad drm_mode_object_unregister(dev, &plane->base);
212 1.1 riastrad return -ENOMEM;
213 1.1 riastrad }
214 1.1 riastrad
215 1.1 riastrad /*
216 1.1 riastrad * First driver to need more than 64 formats needs to fix this. Each
217 1.1 riastrad * format is encoded as a bit and the current code only supports a u64.
218 1.1 riastrad */
219 1.1 riastrad if (WARN_ON(format_count > 64))
220 1.1 riastrad return -EINVAL;
221 1.1 riastrad
222 1.1 riastrad if (format_modifiers) {
223 1.1 riastrad const uint64_t *temp_modifiers = format_modifiers;
224 1.1 riastrad while (*temp_modifiers++ != DRM_FORMAT_MOD_INVALID)
225 1.1 riastrad format_modifier_count++;
226 1.1 riastrad }
227 1.1 riastrad
228 1.1 riastrad if (format_modifier_count)
229 1.1 riastrad config->allow_fb_modifiers = true;
230 1.1 riastrad
231 1.1 riastrad plane->modifier_count = format_modifier_count;
232 1.1 riastrad plane->modifiers = kmalloc_array(format_modifier_count,
233 1.1 riastrad sizeof(format_modifiers[0]),
234 1.1 riastrad GFP_KERNEL);
235 1.1 riastrad
236 1.1 riastrad if (format_modifier_count && !plane->modifiers) {
237 1.1 riastrad DRM_DEBUG_KMS("out of memory when allocating plane\n");
238 1.1 riastrad kfree(plane->format_types);
239 1.1 riastrad drm_mode_object_unregister(dev, &plane->base);
240 1.1 riastrad return -ENOMEM;
241 1.1 riastrad }
242 1.1 riastrad
243 1.1 riastrad if (name) {
244 1.1 riastrad va_list ap;
245 1.1 riastrad
246 1.1 riastrad va_start(ap, name);
247 1.1 riastrad plane->name = kvasprintf(GFP_KERNEL, name, ap);
248 1.1 riastrad va_end(ap);
249 1.1 riastrad } else {
250 1.1 riastrad plane->name = kasprintf(GFP_KERNEL, "plane-%d",
251 1.1 riastrad drm_num_planes(dev));
252 1.1 riastrad }
253 1.1 riastrad if (!plane->name) {
254 1.1 riastrad kfree(plane->format_types);
255 1.1 riastrad kfree(plane->modifiers);
256 1.1 riastrad drm_mode_object_unregister(dev, &plane->base);
257 1.1 riastrad return -ENOMEM;
258 1.1 riastrad }
259 1.1 riastrad
260 1.1 riastrad memcpy(plane->format_types, formats, format_count * sizeof(uint32_t));
261 1.1 riastrad plane->format_count = format_count;
262 1.1 riastrad memcpy(plane->modifiers, format_modifiers,
263 1.1 riastrad format_modifier_count * sizeof(format_modifiers[0]));
264 1.1 riastrad plane->possible_crtcs = possible_crtcs;
265 1.1 riastrad plane->type = type;
266 1.1 riastrad
267 1.1 riastrad list_add_tail(&plane->head, &config->plane_list);
268 1.1 riastrad plane->index = config->num_total_plane++;
269 1.1 riastrad
270 1.1 riastrad drm_object_attach_property(&plane->base,
271 1.1 riastrad config->plane_type_property,
272 1.1 riastrad plane->type);
273 1.1 riastrad
274 1.1 riastrad if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
275 1.1 riastrad drm_object_attach_property(&plane->base, config->prop_fb_id, 0);
276 1.1 riastrad drm_object_attach_property(&plane->base, config->prop_in_fence_fd, -1);
277 1.1 riastrad drm_object_attach_property(&plane->base, config->prop_crtc_id, 0);
278 1.1 riastrad drm_object_attach_property(&plane->base, config->prop_crtc_x, 0);
279 1.1 riastrad drm_object_attach_property(&plane->base, config->prop_crtc_y, 0);
280 1.1 riastrad drm_object_attach_property(&plane->base, config->prop_crtc_w, 0);
281 1.1 riastrad drm_object_attach_property(&plane->base, config->prop_crtc_h, 0);
282 1.1 riastrad drm_object_attach_property(&plane->base, config->prop_src_x, 0);
283 1.1 riastrad drm_object_attach_property(&plane->base, config->prop_src_y, 0);
284 1.1 riastrad drm_object_attach_property(&plane->base, config->prop_src_w, 0);
285 1.1 riastrad drm_object_attach_property(&plane->base, config->prop_src_h, 0);
286 1.1 riastrad }
287 1.1 riastrad
288 1.1 riastrad if (config->allow_fb_modifiers)
289 1.1 riastrad create_in_format_blob(dev, plane);
290 1.1 riastrad
291 1.1 riastrad return 0;
292 1.1 riastrad }
293 1.1 riastrad EXPORT_SYMBOL(drm_universal_plane_init);
294 1.1 riastrad
295 1.1 riastrad int drm_plane_register_all(struct drm_device *dev)
296 1.1 riastrad {
297 1.1 riastrad struct drm_plane *plane;
298 1.1 riastrad int ret = 0;
299 1.1 riastrad
300 1.1 riastrad drm_for_each_plane(plane, dev) {
301 1.1 riastrad if (plane->funcs->late_register)
302 1.1 riastrad ret = plane->funcs->late_register(plane);
303 1.1 riastrad if (ret)
304 1.1 riastrad return ret;
305 1.1 riastrad }
306 1.1 riastrad
307 1.1 riastrad return 0;
308 1.1 riastrad }
309 1.1 riastrad
310 1.1 riastrad void drm_plane_unregister_all(struct drm_device *dev)
311 1.1 riastrad {
312 1.1 riastrad struct drm_plane *plane;
313 1.1 riastrad
314 1.1 riastrad drm_for_each_plane(plane, dev) {
315 1.1 riastrad if (plane->funcs->early_unregister)
316 1.1 riastrad plane->funcs->early_unregister(plane);
317 1.1 riastrad }
318 1.1 riastrad }
319 1.1 riastrad
320 1.1 riastrad /**
321 1.1 riastrad * drm_plane_init - Initialize a legacy plane
322 1.1 riastrad * @dev: DRM device
323 1.1 riastrad * @plane: plane object to init
324 1.1 riastrad * @possible_crtcs: bitmask of possible CRTCs
325 1.1 riastrad * @funcs: callbacks for the new plane
326 1.1 riastrad * @formats: array of supported formats (DRM_FORMAT\_\*)
327 1.1 riastrad * @format_count: number of elements in @formats
328 1.1 riastrad * @is_primary: plane type (primary vs overlay)
329 1.1 riastrad *
330 1.1 riastrad * Legacy API to initialize a DRM plane.
331 1.1 riastrad *
332 1.1 riastrad * New drivers should call drm_universal_plane_init() instead.
333 1.1 riastrad *
334 1.1 riastrad * Returns:
335 1.1 riastrad * Zero on success, error code on failure.
336 1.1 riastrad */
337 1.1 riastrad int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
338 1.1 riastrad uint32_t possible_crtcs,
339 1.1 riastrad const struct drm_plane_funcs *funcs,
340 1.1 riastrad const uint32_t *formats, unsigned int format_count,
341 1.1 riastrad bool is_primary)
342 1.1 riastrad {
343 1.1 riastrad enum drm_plane_type type;
344 1.1 riastrad
345 1.1 riastrad type = is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
346 1.1 riastrad return drm_universal_plane_init(dev, plane, possible_crtcs, funcs,
347 1.1 riastrad formats, format_count,
348 1.1 riastrad NULL, type, NULL);
349 1.1 riastrad }
350 1.1 riastrad EXPORT_SYMBOL(drm_plane_init);
351 1.1 riastrad
352 1.1 riastrad /**
353 1.1 riastrad * drm_plane_cleanup - Clean up the core plane usage
354 1.1 riastrad * @plane: plane to cleanup
355 1.1 riastrad *
356 1.1 riastrad * This function cleans up @plane and removes it from the DRM mode setting
357 1.1 riastrad * core. Note that the function does *not* free the plane structure itself,
358 1.1 riastrad * this is the responsibility of the caller.
359 1.1 riastrad */
360 1.1 riastrad void drm_plane_cleanup(struct drm_plane *plane)
361 1.1 riastrad {
362 1.1 riastrad struct drm_device *dev = plane->dev;
363 1.1 riastrad
364 1.1 riastrad drm_modeset_lock_fini(&plane->mutex);
365 1.1 riastrad
366 1.1 riastrad kfree(plane->format_types);
367 1.1 riastrad kfree(plane->modifiers);
368 1.1 riastrad drm_mode_object_unregister(dev, &plane->base);
369 1.1 riastrad
370 1.1 riastrad BUG_ON(list_empty(&plane->head));
371 1.1 riastrad
372 1.1 riastrad /* Note that the plane_list is considered to be static; should we
373 1.1 riastrad * remove the drm_plane at runtime we would have to decrement all
374 1.1 riastrad * the indices on the drm_plane after us in the plane_list.
375 1.1 riastrad */
376 1.1 riastrad
377 1.1 riastrad list_del(&plane->head);
378 1.1 riastrad dev->mode_config.num_total_plane--;
379 1.1 riastrad
380 1.1 riastrad WARN_ON(plane->state && !plane->funcs->atomic_destroy_state);
381 1.1 riastrad if (plane->state && plane->funcs->atomic_destroy_state)
382 1.1 riastrad plane->funcs->atomic_destroy_state(plane, plane->state);
383 1.1 riastrad
384 1.1 riastrad kfree(plane->name);
385 1.1 riastrad
386 1.1 riastrad memset(plane, 0, sizeof(*plane));
387 1.1 riastrad }
388 1.1 riastrad EXPORT_SYMBOL(drm_plane_cleanup);
389 1.1 riastrad
390 1.1 riastrad /**
391 1.1 riastrad * drm_plane_from_index - find the registered plane at an index
392 1.1 riastrad * @dev: DRM device
393 1.1 riastrad * @idx: index of registered plane to find for
394 1.1 riastrad *
395 1.1 riastrad * Given a plane index, return the registered plane from DRM device's
396 1.1 riastrad * list of planes with matching index. This is the inverse of drm_plane_index().
397 1.1 riastrad */
398 1.1 riastrad struct drm_plane *
399 1.1 riastrad drm_plane_from_index(struct drm_device *dev, int idx)
400 1.1 riastrad {
401 1.1 riastrad struct drm_plane *plane;
402 1.1 riastrad
403 1.1 riastrad drm_for_each_plane(plane, dev)
404 1.1 riastrad if (idx == plane->index)
405 1.1 riastrad return plane;
406 1.1 riastrad
407 1.1 riastrad return NULL;
408 1.1 riastrad }
409 1.1 riastrad EXPORT_SYMBOL(drm_plane_from_index);
410 1.1 riastrad
411 1.1 riastrad /**
412 1.1 riastrad * drm_plane_force_disable - Forcibly disable a plane
413 1.1 riastrad * @plane: plane to disable
414 1.1 riastrad *
415 1.1 riastrad * Forces the plane to be disabled.
416 1.1 riastrad *
417 1.1 riastrad * Used when the plane's current framebuffer is destroyed,
418 1.1 riastrad * and when restoring fbdev mode.
419 1.1 riastrad *
420 1.1 riastrad * Note that this function is not suitable for atomic drivers, since it doesn't
421 1.1 riastrad * wire through the lock acquisition context properly and hence can't handle
422 1.1 riastrad * retries or driver private locks. You probably want to use
423 1.1 riastrad * drm_atomic_helper_disable_plane() or
424 1.1 riastrad * drm_atomic_helper_disable_planes_on_crtc() instead.
425 1.1 riastrad */
426 1.1 riastrad void drm_plane_force_disable(struct drm_plane *plane)
427 1.1 riastrad {
428 1.1 riastrad int ret;
429 1.1 riastrad
430 1.1 riastrad if (!plane->fb)
431 1.1 riastrad return;
432 1.1 riastrad
433 1.1 riastrad WARN_ON(drm_drv_uses_atomic_modeset(plane->dev));
434 1.1 riastrad
435 1.1 riastrad plane->old_fb = plane->fb;
436 1.1 riastrad ret = plane->funcs->disable_plane(plane, NULL);
437 1.1 riastrad if (ret) {
438 1.1 riastrad DRM_ERROR("failed to disable plane with busy fb\n");
439 1.1 riastrad plane->old_fb = NULL;
440 1.1 riastrad return;
441 1.1 riastrad }
442 1.1 riastrad /* disconnect the plane from the fb and crtc: */
443 1.1 riastrad drm_framebuffer_put(plane->old_fb);
444 1.1 riastrad plane->old_fb = NULL;
445 1.1 riastrad plane->fb = NULL;
446 1.1 riastrad plane->crtc = NULL;
447 1.1 riastrad }
448 1.1 riastrad EXPORT_SYMBOL(drm_plane_force_disable);
449 1.1 riastrad
450 1.1 riastrad /**
451 1.1 riastrad * drm_mode_plane_set_obj_prop - set the value of a property
452 1.1 riastrad * @plane: drm plane object to set property value for
453 1.1 riastrad * @property: property to set
454 1.1 riastrad * @value: value the property should be set to
455 1.1 riastrad *
456 1.1 riastrad * This functions sets a given property on a given plane object. This function
457 1.1 riastrad * calls the driver's ->set_property callback and changes the software state of
458 1.1 riastrad * the property if the callback succeeds.
459 1.1 riastrad *
460 1.1 riastrad * Returns:
461 1.1 riastrad * Zero on success, error code on failure.
462 1.1 riastrad */
463 1.1 riastrad int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
464 1.1 riastrad struct drm_property *property,
465 1.1 riastrad uint64_t value)
466 1.1 riastrad {
467 1.1 riastrad int ret = -EINVAL;
468 1.1 riastrad struct drm_mode_object *obj = &plane->base;
469 1.1 riastrad
470 1.1 riastrad if (plane->funcs->set_property)
471 1.1 riastrad ret = plane->funcs->set_property(plane, property, value);
472 1.1 riastrad if (!ret)
473 1.1 riastrad drm_object_property_set_value(obj, property, value);
474 1.1 riastrad
475 1.1 riastrad return ret;
476 1.1 riastrad }
477 1.1 riastrad EXPORT_SYMBOL(drm_mode_plane_set_obj_prop);
478 1.1 riastrad
479 1.1 riastrad int drm_mode_getplane_res(struct drm_device *dev, void *data,
480 1.1 riastrad struct drm_file *file_priv)
481 1.1 riastrad {
482 1.1 riastrad struct drm_mode_get_plane_res *plane_resp = data;
483 1.1 riastrad struct drm_plane *plane;
484 1.1 riastrad uint32_t __user *plane_ptr;
485 1.1 riastrad int count = 0;
486 1.1 riastrad
487 1.1 riastrad if (!drm_core_check_feature(dev, DRIVER_MODESET))
488 1.1 riastrad return -EOPNOTSUPP;
489 1.1 riastrad
490 1.1 riastrad plane_ptr = u64_to_user_ptr(plane_resp->plane_id_ptr);
491 1.1 riastrad
492 1.1 riastrad /*
493 1.1 riastrad * This ioctl is called twice, once to determine how much space is
494 1.1 riastrad * needed, and the 2nd time to fill it.
495 1.1 riastrad */
496 1.1 riastrad drm_for_each_plane(plane, dev) {
497 1.1 riastrad /*
498 1.1 riastrad * Unless userspace set the 'universal planes'
499 1.1 riastrad * capability bit, only advertise overlays.
500 1.1 riastrad */
501 1.1 riastrad if (plane->type != DRM_PLANE_TYPE_OVERLAY &&
502 1.1 riastrad !file_priv->universal_planes)
503 1.1 riastrad continue;
504 1.1 riastrad
505 1.1 riastrad if (drm_lease_held(file_priv, plane->base.id)) {
506 1.1 riastrad if (count < plane_resp->count_planes &&
507 1.1 riastrad put_user(plane->base.id, plane_ptr + count))
508 1.1 riastrad return -EFAULT;
509 1.1 riastrad count++;
510 1.1 riastrad }
511 1.1 riastrad }
512 1.1 riastrad plane_resp->count_planes = count;
513 1.1 riastrad
514 1.1 riastrad return 0;
515 1.1 riastrad }
516 1.1 riastrad
517 1.1 riastrad int drm_mode_getplane(struct drm_device *dev, void *data,
518 1.1 riastrad struct drm_file *file_priv)
519 1.1 riastrad {
520 1.1 riastrad struct drm_mode_get_plane *plane_resp = data;
521 1.1 riastrad struct drm_plane *plane;
522 1.1 riastrad uint32_t __user *format_ptr;
523 1.1 riastrad
524 1.1 riastrad if (!drm_core_check_feature(dev, DRIVER_MODESET))
525 1.1 riastrad return -EOPNOTSUPP;
526 1.1 riastrad
527 1.1 riastrad plane = drm_plane_find(dev, file_priv, plane_resp->plane_id);
528 1.1 riastrad if (!plane)
529 1.1 riastrad return -ENOENT;
530 1.1 riastrad
531 1.1 riastrad drm_modeset_lock(&plane->mutex, NULL);
532 1.1 riastrad if (plane->state && plane->state->crtc && drm_lease_held(file_priv, plane->state->crtc->base.id))
533 1.1 riastrad plane_resp->crtc_id = plane->state->crtc->base.id;
534 1.1 riastrad else if (!plane->state && plane->crtc && drm_lease_held(file_priv, plane->crtc->base.id))
535 1.1 riastrad plane_resp->crtc_id = plane->crtc->base.id;
536 1.1 riastrad else
537 1.1 riastrad plane_resp->crtc_id = 0;
538 1.1 riastrad
539 1.1 riastrad if (plane->state && plane->state->fb)
540 1.1 riastrad plane_resp->fb_id = plane->state->fb->base.id;
541 1.1 riastrad else if (!plane->state && plane->fb)
542 1.1 riastrad plane_resp->fb_id = plane->fb->base.id;
543 1.1 riastrad else
544 1.1 riastrad plane_resp->fb_id = 0;
545 1.1 riastrad drm_modeset_unlock(&plane->mutex);
546 1.1 riastrad
547 1.1 riastrad plane_resp->plane_id = plane->base.id;
548 1.1 riastrad plane_resp->possible_crtcs = drm_lease_filter_crtcs(file_priv,
549 1.1 riastrad plane->possible_crtcs);
550 1.1 riastrad
551 1.1 riastrad plane_resp->gamma_size = 0;
552 1.1 riastrad
553 1.1 riastrad /*
554 1.1 riastrad * This ioctl is called twice, once to determine how much space is
555 1.1 riastrad * needed, and the 2nd time to fill it.
556 1.1 riastrad */
557 1.1 riastrad if (plane->format_count &&
558 1.1 riastrad (plane_resp->count_format_types >= plane->format_count)) {
559 1.1 riastrad format_ptr = (uint32_t __user *)(unsigned long)plane_resp->format_type_ptr;
560 1.1 riastrad if (copy_to_user(format_ptr,
561 1.1 riastrad plane->format_types,
562 1.1 riastrad sizeof(uint32_t) * plane->format_count)) {
563 1.1 riastrad return -EFAULT;
564 1.1 riastrad }
565 1.1 riastrad }
566 1.1 riastrad plane_resp->count_format_types = plane->format_count;
567 1.1 riastrad
568 1.1 riastrad return 0;
569 1.1 riastrad }
570 1.1 riastrad
571 1.1 riastrad int drm_plane_check_pixel_format(struct drm_plane *plane,
572 1.1 riastrad u32 format, u64 modifier)
573 1.1 riastrad {
574 1.1 riastrad unsigned int i;
575 1.1 riastrad
576 1.1 riastrad for (i = 0; i < plane->format_count; i++) {
577 1.1 riastrad if (format == plane->format_types[i])
578 1.1 riastrad break;
579 1.1 riastrad }
580 1.1 riastrad if (i == plane->format_count)
581 1.1 riastrad return -EINVAL;
582 1.1 riastrad
583 1.1 riastrad if (plane->funcs->format_mod_supported) {
584 1.1 riastrad if (!plane->funcs->format_mod_supported(plane, format, modifier))
585 1.1 riastrad return -EINVAL;
586 1.1 riastrad } else {
587 1.1 riastrad if (!plane->modifier_count)
588 1.1 riastrad return 0;
589 1.1 riastrad
590 1.1 riastrad for (i = 0; i < plane->modifier_count; i++) {
591 1.1 riastrad if (modifier == plane->modifiers[i])
592 1.1 riastrad break;
593 1.1 riastrad }
594 1.1 riastrad if (i == plane->modifier_count)
595 1.1 riastrad return -EINVAL;
596 1.1 riastrad }
597 1.1 riastrad
598 1.1 riastrad return 0;
599 1.1 riastrad }
600 1.1 riastrad
601 1.1 riastrad static int __setplane_check(struct drm_plane *plane,
602 1.1 riastrad struct drm_crtc *crtc,
603 1.1 riastrad struct drm_framebuffer *fb,
604 1.1 riastrad int32_t crtc_x, int32_t crtc_y,
605 1.1 riastrad uint32_t crtc_w, uint32_t crtc_h,
606 1.1 riastrad uint32_t src_x, uint32_t src_y,
607 1.1 riastrad uint32_t src_w, uint32_t src_h)
608 1.1 riastrad {
609 1.1 riastrad int ret;
610 1.1 riastrad
611 1.1 riastrad /* Check whether this plane is usable on this CRTC */
612 1.1 riastrad if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) {
613 1.1 riastrad DRM_DEBUG_KMS("Invalid crtc for plane\n");
614 1.1 riastrad return -EINVAL;
615 1.1 riastrad }
616 1.1 riastrad
617 1.1 riastrad /* Check whether this plane supports the fb pixel format. */
618 1.1 riastrad ret = drm_plane_check_pixel_format(plane, fb->format->format,
619 1.1 riastrad fb->modifier);
620 1.1 riastrad if (ret) {
621 1.1 riastrad struct drm_format_name_buf format_name;
622 1.1 riastrad
623 1.1 riastrad DRM_DEBUG_KMS("Invalid pixel format %s, modifier 0x%llx\n",
624 1.1 riastrad drm_get_format_name(fb->format->format,
625 1.1 riastrad &format_name),
626 1.1 riastrad fb->modifier);
627 1.1 riastrad return ret;
628 1.1 riastrad }
629 1.1 riastrad
630 1.1 riastrad /* Give drivers some help against integer overflows */
631 1.1 riastrad if (crtc_w > INT_MAX ||
632 1.1 riastrad crtc_x > INT_MAX - (int32_t) crtc_w ||
633 1.1 riastrad crtc_h > INT_MAX ||
634 1.1 riastrad crtc_y > INT_MAX - (int32_t) crtc_h) {
635 1.1 riastrad DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",
636 1.1 riastrad crtc_w, crtc_h, crtc_x, crtc_y);
637 1.1 riastrad return -ERANGE;
638 1.1 riastrad }
639 1.1 riastrad
640 1.1 riastrad ret = drm_framebuffer_check_src_coords(src_x, src_y, src_w, src_h, fb);
641 1.1 riastrad if (ret)
642 1.1 riastrad return ret;
643 1.1 riastrad
644 1.1 riastrad return 0;
645 1.1 riastrad }
646 1.1 riastrad
647 1.1 riastrad /**
648 1.1 riastrad * drm_any_plane_has_format - Check whether any plane supports this format and modifier combination
649 1.1 riastrad * @dev: DRM device
650 1.1 riastrad * @format: pixel format (DRM_FORMAT_*)
651 1.1 riastrad * @modifier: data layout modifier
652 1.1 riastrad *
653 1.1 riastrad * Returns:
654 1.1 riastrad * Whether at least one plane supports the specified format and modifier combination.
655 1.1 riastrad */
656 1.1 riastrad bool drm_any_plane_has_format(struct drm_device *dev,
657 1.1 riastrad u32 format, u64 modifier)
658 1.1 riastrad {
659 1.1 riastrad struct drm_plane *plane;
660 1.1 riastrad
661 1.1 riastrad drm_for_each_plane(plane, dev) {
662 1.1 riastrad if (drm_plane_check_pixel_format(plane, format, modifier) == 0)
663 1.1 riastrad return true;
664 1.1 riastrad }
665 1.1 riastrad
666 1.1 riastrad return false;
667 1.1 riastrad }
668 1.1 riastrad EXPORT_SYMBOL(drm_any_plane_has_format);
669 1.1 riastrad
670 1.1 riastrad /*
671 1.1 riastrad * __setplane_internal - setplane handler for internal callers
672 1.1 riastrad *
673 1.1 riastrad * This function will take a reference on the new fb for the plane
674 1.1 riastrad * on success.
675 1.1 riastrad *
676 1.1 riastrad * src_{x,y,w,h} are provided in 16.16 fixed point format
677 1.1 riastrad */
678 1.1 riastrad static int __setplane_internal(struct drm_plane *plane,
679 1.1 riastrad struct drm_crtc *crtc,
680 1.1 riastrad struct drm_framebuffer *fb,
681 1.1 riastrad int32_t crtc_x, int32_t crtc_y,
682 1.1 riastrad uint32_t crtc_w, uint32_t crtc_h,
683 1.1 riastrad /* src_{x,y,w,h} values are 16.16 fixed point */
684 1.1 riastrad uint32_t src_x, uint32_t src_y,
685 1.1 riastrad uint32_t src_w, uint32_t src_h,
686 1.1 riastrad struct drm_modeset_acquire_ctx *ctx)
687 1.1 riastrad {
688 1.1 riastrad int ret = 0;
689 1.1 riastrad
690 1.1 riastrad WARN_ON(drm_drv_uses_atomic_modeset(plane->dev));
691 1.1 riastrad
692 1.1 riastrad /* No fb means shut it down */
693 1.1 riastrad if (!fb) {
694 1.1 riastrad plane->old_fb = plane->fb;
695 1.1 riastrad ret = plane->funcs->disable_plane(plane, ctx);
696 1.1 riastrad if (!ret) {
697 1.1 riastrad plane->crtc = NULL;
698 1.1 riastrad plane->fb = NULL;
699 1.1 riastrad } else {
700 1.1 riastrad plane->old_fb = NULL;
701 1.1 riastrad }
702 1.1 riastrad goto out;
703 1.1 riastrad }
704 1.1 riastrad
705 1.1 riastrad ret = __setplane_check(plane, crtc, fb,
706 1.1 riastrad crtc_x, crtc_y, crtc_w, crtc_h,
707 1.1 riastrad src_x, src_y, src_w, src_h);
708 1.1 riastrad if (ret)
709 1.1 riastrad goto out;
710 1.1 riastrad
711 1.1 riastrad plane->old_fb = plane->fb;
712 1.1 riastrad ret = plane->funcs->update_plane(plane, crtc, fb,
713 1.1 riastrad crtc_x, crtc_y, crtc_w, crtc_h,
714 1.1 riastrad src_x, src_y, src_w, src_h, ctx);
715 1.1 riastrad if (!ret) {
716 1.1 riastrad plane->crtc = crtc;
717 1.1 riastrad plane->fb = fb;
718 1.1 riastrad drm_framebuffer_get(plane->fb);
719 1.1 riastrad } else {
720 1.1 riastrad plane->old_fb = NULL;
721 1.1 riastrad }
722 1.1 riastrad
723 1.1 riastrad out:
724 1.1 riastrad if (plane->old_fb)
725 1.1 riastrad drm_framebuffer_put(plane->old_fb);
726 1.1 riastrad plane->old_fb = NULL;
727 1.1 riastrad
728 1.1 riastrad return ret;
729 1.1 riastrad }
730 1.1 riastrad
731 1.1 riastrad static int __setplane_atomic(struct drm_plane *plane,
732 1.1 riastrad struct drm_crtc *crtc,
733 1.1 riastrad struct drm_framebuffer *fb,
734 1.1 riastrad int32_t crtc_x, int32_t crtc_y,
735 1.1 riastrad uint32_t crtc_w, uint32_t crtc_h,
736 1.1 riastrad uint32_t src_x, uint32_t src_y,
737 1.1 riastrad uint32_t src_w, uint32_t src_h,
738 1.1 riastrad struct drm_modeset_acquire_ctx *ctx)
739 1.1 riastrad {
740 1.1 riastrad int ret;
741 1.1 riastrad
742 1.1 riastrad WARN_ON(!drm_drv_uses_atomic_modeset(plane->dev));
743 1.1 riastrad
744 1.1 riastrad /* No fb means shut it down */
745 1.1 riastrad if (!fb)
746 1.1 riastrad return plane->funcs->disable_plane(plane, ctx);
747 1.1 riastrad
748 1.1 riastrad /*
749 1.1 riastrad * FIXME: This is redundant with drm_atomic_plane_check(),
750 1.1 riastrad * but the legacy cursor/"async" .update_plane() tricks
751 1.1 riastrad * don't call that so we still need this here. Should remove
752 1.1 riastrad * this when all .update_plane() implementations have been
753 1.1 riastrad * fixed to call drm_atomic_plane_check().
754 1.1 riastrad */
755 1.1 riastrad ret = __setplane_check(plane, crtc, fb,
756 1.1 riastrad crtc_x, crtc_y, crtc_w, crtc_h,
757 1.1 riastrad src_x, src_y, src_w, src_h);
758 1.1 riastrad if (ret)
759 1.1 riastrad return ret;
760 1.1 riastrad
761 1.1 riastrad return plane->funcs->update_plane(plane, crtc, fb,
762 1.1 riastrad crtc_x, crtc_y, crtc_w, crtc_h,
763 1.1 riastrad src_x, src_y, src_w, src_h, ctx);
764 1.1 riastrad }
765 1.1 riastrad
766 1.1 riastrad static int setplane_internal(struct drm_plane *plane,
767 1.1 riastrad struct drm_crtc *crtc,
768 1.1 riastrad struct drm_framebuffer *fb,
769 1.1 riastrad int32_t crtc_x, int32_t crtc_y,
770 1.1 riastrad uint32_t crtc_w, uint32_t crtc_h,
771 1.1 riastrad /* src_{x,y,w,h} values are 16.16 fixed point */
772 1.1 riastrad uint32_t src_x, uint32_t src_y,
773 1.1 riastrad uint32_t src_w, uint32_t src_h)
774 1.1 riastrad {
775 1.1 riastrad struct drm_modeset_acquire_ctx ctx;
776 1.1 riastrad int ret;
777 1.1 riastrad
778 1.1 riastrad DRM_MODESET_LOCK_ALL_BEGIN(plane->dev, ctx,
779 1.1 riastrad DRM_MODESET_ACQUIRE_INTERRUPTIBLE, ret);
780 1.1 riastrad
781 1.1 riastrad if (drm_drv_uses_atomic_modeset(plane->dev))
782 1.1 riastrad ret = __setplane_atomic(plane, crtc, fb,
783 1.1 riastrad crtc_x, crtc_y, crtc_w, crtc_h,
784 1.1 riastrad src_x, src_y, src_w, src_h, &ctx);
785 1.1 riastrad else
786 1.1 riastrad ret = __setplane_internal(plane, crtc, fb,
787 1.1 riastrad crtc_x, crtc_y, crtc_w, crtc_h,
788 1.1 riastrad src_x, src_y, src_w, src_h, &ctx);
789 1.1 riastrad
790 1.1 riastrad DRM_MODESET_LOCK_ALL_END(ctx, ret);
791 1.1 riastrad
792 1.1 riastrad return ret;
793 1.1 riastrad }
794 1.1 riastrad
795 1.1 riastrad int drm_mode_setplane(struct drm_device *dev, void *data,
796 1.1 riastrad struct drm_file *file_priv)
797 1.1 riastrad {
798 1.1 riastrad struct drm_mode_set_plane *plane_req = data;
799 1.1 riastrad struct drm_plane *plane;
800 1.1 riastrad struct drm_crtc *crtc = NULL;
801 1.1 riastrad struct drm_framebuffer *fb = NULL;
802 1.1 riastrad int ret;
803 1.1 riastrad
804 1.1 riastrad if (!drm_core_check_feature(dev, DRIVER_MODESET))
805 1.1 riastrad return -EOPNOTSUPP;
806 1.1 riastrad
807 1.1 riastrad /*
808 1.1 riastrad * First, find the plane, crtc, and fb objects. If not available,
809 1.1 riastrad * we don't bother to call the driver.
810 1.1 riastrad */
811 1.1 riastrad plane = drm_plane_find(dev, file_priv, plane_req->plane_id);
812 1.1 riastrad if (!plane) {
813 1.1 riastrad DRM_DEBUG_KMS("Unknown plane ID %d\n",
814 1.1 riastrad plane_req->plane_id);
815 1.1 riastrad return -ENOENT;
816 1.1 riastrad }
817 1.1 riastrad
818 1.1 riastrad if (plane_req->fb_id) {
819 1.1 riastrad fb = drm_framebuffer_lookup(dev, file_priv, plane_req->fb_id);
820 1.1 riastrad if (!fb) {
821 1.1 riastrad DRM_DEBUG_KMS("Unknown framebuffer ID %d\n",
822 1.1 riastrad plane_req->fb_id);
823 1.1 riastrad return -ENOENT;
824 1.1 riastrad }
825 1.1 riastrad
826 1.1 riastrad crtc = drm_crtc_find(dev, file_priv, plane_req->crtc_id);
827 1.1 riastrad if (!crtc) {
828 1.1 riastrad drm_framebuffer_put(fb);
829 1.1 riastrad DRM_DEBUG_KMS("Unknown crtc ID %d\n",
830 1.1 riastrad plane_req->crtc_id);
831 1.1 riastrad return -ENOENT;
832 1.1 riastrad }
833 1.1 riastrad }
834 1.1 riastrad
835 1.1 riastrad ret = setplane_internal(plane, crtc, fb,
836 1.1 riastrad plane_req->crtc_x, plane_req->crtc_y,
837 1.1 riastrad plane_req->crtc_w, plane_req->crtc_h,
838 1.1 riastrad plane_req->src_x, plane_req->src_y,
839 1.1 riastrad plane_req->src_w, plane_req->src_h);
840 1.1 riastrad
841 1.1 riastrad if (fb)
842 1.1 riastrad drm_framebuffer_put(fb);
843 1.1 riastrad
844 1.1 riastrad return ret;
845 1.1 riastrad }
846 1.1 riastrad
847 1.1 riastrad static int drm_mode_cursor_universal(struct drm_crtc *crtc,
848 1.1 riastrad struct drm_mode_cursor2 *req,
849 1.1 riastrad struct drm_file *file_priv,
850 1.1 riastrad struct drm_modeset_acquire_ctx *ctx)
851 1.1 riastrad {
852 1.1 riastrad struct drm_device *dev = crtc->dev;
853 1.1 riastrad struct drm_plane *plane = crtc->cursor;
854 1.1 riastrad struct drm_framebuffer *fb = NULL;
855 1.1 riastrad struct drm_mode_fb_cmd2 fbreq = {
856 1.1 riastrad .width = req->width,
857 1.1 riastrad .height = req->height,
858 1.1 riastrad .pixel_format = DRM_FORMAT_ARGB8888,
859 1.1 riastrad .pitches = { req->width * 4 },
860 1.1 riastrad .handles = { req->handle },
861 1.1 riastrad };
862 1.1 riastrad int32_t crtc_x, crtc_y;
863 1.1 riastrad uint32_t crtc_w = 0, crtc_h = 0;
864 1.1 riastrad uint32_t src_w = 0, src_h = 0;
865 1.1 riastrad int ret = 0;
866 1.1 riastrad
867 1.1 riastrad BUG_ON(!plane);
868 1.1 riastrad WARN_ON(plane->crtc != crtc && plane->crtc != NULL);
869 1.1 riastrad
870 1.1 riastrad /*
871 1.1 riastrad * Obtain fb we'll be using (either new or existing) and take an extra
872 1.1 riastrad * reference to it if fb != null. setplane will take care of dropping
873 1.1 riastrad * the reference if the plane update fails.
874 1.1 riastrad */
875 1.1 riastrad if (req->flags & DRM_MODE_CURSOR_BO) {
876 1.1 riastrad if (req->handle) {
877 1.1 riastrad fb = drm_internal_framebuffer_create(dev, &fbreq, file_priv);
878 1.1 riastrad if (IS_ERR(fb)) {
879 1.1 riastrad DRM_DEBUG_KMS("failed to wrap cursor buffer in drm framebuffer\n");
880 1.1 riastrad return PTR_ERR(fb);
881 1.1 riastrad }
882 1.1 riastrad
883 1.1 riastrad fb->hot_x = req->hot_x;
884 1.1 riastrad fb->hot_y = req->hot_y;
885 1.1 riastrad } else {
886 1.1 riastrad fb = NULL;
887 1.1 riastrad }
888 1.1 riastrad } else {
889 1.1 riastrad if (plane->state)
890 1.1 riastrad fb = plane->state->fb;
891 1.1 riastrad else
892 1.1 riastrad fb = plane->fb;
893 1.1 riastrad
894 1.1 riastrad if (fb)
895 1.1 riastrad drm_framebuffer_get(fb);
896 1.1 riastrad }
897 1.1 riastrad
898 1.1 riastrad if (req->flags & DRM_MODE_CURSOR_MOVE) {
899 1.1 riastrad crtc_x = req->x;
900 1.1 riastrad crtc_y = req->y;
901 1.1 riastrad } else {
902 1.1 riastrad crtc_x = crtc->cursor_x;
903 1.1 riastrad crtc_y = crtc->cursor_y;
904 1.1 riastrad }
905 1.1 riastrad
906 1.1 riastrad if (fb) {
907 1.1 riastrad crtc_w = fb->width;
908 1.1 riastrad crtc_h = fb->height;
909 1.1 riastrad src_w = fb->width << 16;
910 1.1 riastrad src_h = fb->height << 16;
911 1.1 riastrad }
912 1.1 riastrad
913 1.1 riastrad if (drm_drv_uses_atomic_modeset(dev))
914 1.1 riastrad ret = __setplane_atomic(plane, crtc, fb,
915 1.1 riastrad crtc_x, crtc_y, crtc_w, crtc_h,
916 1.1 riastrad 0, 0, src_w, src_h, ctx);
917 1.1 riastrad else
918 1.1 riastrad ret = __setplane_internal(plane, crtc, fb,
919 1.1 riastrad crtc_x, crtc_y, crtc_w, crtc_h,
920 1.1 riastrad 0, 0, src_w, src_h, ctx);
921 1.1 riastrad
922 1.1 riastrad if (fb)
923 1.1 riastrad drm_framebuffer_put(fb);
924 1.1 riastrad
925 1.1 riastrad /* Update successful; save new cursor position, if necessary */
926 1.1 riastrad if (ret == 0 && req->flags & DRM_MODE_CURSOR_MOVE) {
927 1.1 riastrad crtc->cursor_x = req->x;
928 1.1 riastrad crtc->cursor_y = req->y;
929 1.1 riastrad }
930 1.1 riastrad
931 1.1 riastrad return ret;
932 1.1 riastrad }
933 1.1 riastrad
934 1.1 riastrad static int drm_mode_cursor_common(struct drm_device *dev,
935 1.1 riastrad struct drm_mode_cursor2 *req,
936 1.1 riastrad struct drm_file *file_priv)
937 1.1 riastrad {
938 1.1 riastrad struct drm_crtc *crtc;
939 1.1 riastrad struct drm_modeset_acquire_ctx ctx;
940 1.1 riastrad int ret = 0;
941 1.1 riastrad
942 1.1 riastrad if (!drm_core_check_feature(dev, DRIVER_MODESET))
943 1.1 riastrad return -EOPNOTSUPP;
944 1.1 riastrad
945 1.1 riastrad if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags))
946 1.1 riastrad return -EINVAL;
947 1.1 riastrad
948 1.1 riastrad crtc = drm_crtc_find(dev, file_priv, req->crtc_id);
949 1.1 riastrad if (!crtc) {
950 1.1 riastrad DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id);
951 1.1 riastrad return -ENOENT;
952 1.1 riastrad }
953 1.1 riastrad
954 1.1 riastrad drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE);
955 1.1 riastrad retry:
956 1.1 riastrad ret = drm_modeset_lock(&crtc->mutex, &ctx);
957 1.1 riastrad if (ret)
958 1.1 riastrad goto out;
959 1.1 riastrad /*
960 1.1 riastrad * If this crtc has a universal cursor plane, call that plane's update
961 1.1 riastrad * handler rather than using legacy cursor handlers.
962 1.1 riastrad */
963 1.1 riastrad if (crtc->cursor) {
964 1.1 riastrad ret = drm_modeset_lock(&crtc->cursor->mutex, &ctx);
965 1.1 riastrad if (ret)
966 1.1 riastrad goto out;
967 1.1 riastrad
968 1.1 riastrad if (!drm_lease_held(file_priv, crtc->cursor->base.id)) {
969 1.1 riastrad ret = -EACCES;
970 1.1 riastrad goto out;
971 1.1 riastrad }
972 1.1 riastrad
973 1.1 riastrad ret = drm_mode_cursor_universal(crtc, req, file_priv, &ctx);
974 1.1 riastrad goto out;
975 1.1 riastrad }
976 1.1 riastrad
977 1.1 riastrad if (req->flags & DRM_MODE_CURSOR_BO) {
978 1.1 riastrad if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) {
979 1.1 riastrad ret = -ENXIO;
980 1.1 riastrad goto out;
981 1.1 riastrad }
982 1.1 riastrad /* Turns off the cursor if handle is 0 */
983 1.1 riastrad if (crtc->funcs->cursor_set2)
984 1.1 riastrad ret = crtc->funcs->cursor_set2(crtc, file_priv, req->handle,
985 1.1 riastrad req->width, req->height, req->hot_x, req->hot_y);
986 1.1 riastrad else
987 1.1 riastrad ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle,
988 1.1 riastrad req->width, req->height);
989 1.1 riastrad }
990 1.1 riastrad
991 1.1 riastrad if (req->flags & DRM_MODE_CURSOR_MOVE) {
992 1.1 riastrad if (crtc->funcs->cursor_move) {
993 1.1 riastrad ret = crtc->funcs->cursor_move(crtc, req->x, req->y);
994 1.1 riastrad } else {
995 1.1 riastrad ret = -EFAULT;
996 1.1 riastrad goto out;
997 1.1 riastrad }
998 1.1 riastrad }
999 1.1 riastrad out:
1000 1.1 riastrad if (ret == -EDEADLK) {
1001 1.1 riastrad ret = drm_modeset_backoff(&ctx);
1002 1.1 riastrad if (!ret)
1003 1.1 riastrad goto retry;
1004 1.1 riastrad }
1005 1.1 riastrad
1006 1.1 riastrad drm_modeset_drop_locks(&ctx);
1007 1.1 riastrad drm_modeset_acquire_fini(&ctx);
1008 1.1 riastrad
1009 1.1 riastrad return ret;
1010 1.1 riastrad
1011 1.1 riastrad }
1012 1.1 riastrad
1013 1.1 riastrad
1014 1.1 riastrad int drm_mode_cursor_ioctl(struct drm_device *dev,
1015 1.1 riastrad void *data, struct drm_file *file_priv)
1016 1.1 riastrad {
1017 1.1 riastrad struct drm_mode_cursor *req = data;
1018 1.1 riastrad struct drm_mode_cursor2 new_req;
1019 1.1 riastrad
1020 1.1 riastrad memcpy(&new_req, req, sizeof(struct drm_mode_cursor));
1021 1.1 riastrad new_req.hot_x = new_req.hot_y = 0;
1022 1.1 riastrad
1023 1.1 riastrad return drm_mode_cursor_common(dev, &new_req, file_priv);
1024 1.1 riastrad }
1025 1.1 riastrad
1026 1.1 riastrad /*
1027 1.1 riastrad * Set the cursor configuration based on user request. This implements the 2nd
1028 1.1 riastrad * version of the cursor ioctl, which allows userspace to additionally specify
1029 1.1 riastrad * the hotspot of the pointer.
1030 1.1 riastrad */
1031 1.1 riastrad int drm_mode_cursor2_ioctl(struct drm_device *dev,
1032 1.1 riastrad void *data, struct drm_file *file_priv)
1033 1.1 riastrad {
1034 1.1 riastrad struct drm_mode_cursor2 *req = data;
1035 1.1 riastrad
1036 1.1 riastrad return drm_mode_cursor_common(dev, req, file_priv);
1037 1.1 riastrad }
1038 1.1 riastrad
1039 1.1 riastrad int drm_mode_page_flip_ioctl(struct drm_device *dev,
1040 1.1 riastrad void *data, struct drm_file *file_priv)
1041 1.1 riastrad {
1042 1.1 riastrad struct drm_mode_crtc_page_flip_target *page_flip = data;
1043 1.1 riastrad struct drm_crtc *crtc;
1044 1.1 riastrad struct drm_plane *plane;
1045 1.1 riastrad struct drm_framebuffer *fb = NULL, *old_fb;
1046 1.1 riastrad struct drm_pending_vblank_event *e = NULL;
1047 1.1 riastrad u32 target_vblank = page_flip->sequence;
1048 1.1 riastrad struct drm_modeset_acquire_ctx ctx;
1049 1.1 riastrad int ret = -EINVAL;
1050 1.1 riastrad
1051 1.1 riastrad if (!drm_core_check_feature(dev, DRIVER_MODESET))
1052 1.1 riastrad return -EOPNOTSUPP;
1053 1.1 riastrad
1054 1.1 riastrad if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS)
1055 1.1 riastrad return -EINVAL;
1056 1.1 riastrad
1057 1.1 riastrad if (page_flip->sequence != 0 && !(page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET))
1058 1.1 riastrad return -EINVAL;
1059 1.1 riastrad
1060 1.1 riastrad /* Only one of the DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE/RELATIVE flags
1061 1.1 riastrad * can be specified
1062 1.1 riastrad */
1063 1.1 riastrad if ((page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) == DRM_MODE_PAGE_FLIP_TARGET)
1064 1.1 riastrad return -EINVAL;
1065 1.1 riastrad
1066 1.1 riastrad if ((page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC) && !dev->mode_config.async_page_flip)
1067 1.1 riastrad return -EINVAL;
1068 1.1 riastrad
1069 1.1 riastrad crtc = drm_crtc_find(dev, file_priv, page_flip->crtc_id);
1070 1.1 riastrad if (!crtc)
1071 1.1 riastrad return -ENOENT;
1072 1.1 riastrad
1073 1.1 riastrad plane = crtc->primary;
1074 1.1 riastrad
1075 1.1 riastrad if (!drm_lease_held(file_priv, plane->base.id))
1076 1.1 riastrad return -EACCES;
1077 1.1 riastrad
1078 1.1 riastrad if (crtc->funcs->page_flip_target) {
1079 1.1 riastrad u32 current_vblank;
1080 1.1 riastrad int r;
1081 1.1 riastrad
1082 1.1 riastrad r = drm_crtc_vblank_get(crtc);
1083 1.1 riastrad if (r)
1084 1.1 riastrad return r;
1085 1.1 riastrad
1086 1.1 riastrad current_vblank = (u32)drm_crtc_vblank_count(crtc);
1087 1.1 riastrad
1088 1.1 riastrad switch (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) {
1089 1.1 riastrad case DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE:
1090 1.1 riastrad if ((int)(target_vblank - current_vblank) > 1) {
1091 1.1 riastrad DRM_DEBUG("Invalid absolute flip target %u, "
1092 1.1 riastrad "must be <= %u\n", target_vblank,
1093 1.1 riastrad current_vblank + 1);
1094 1.1 riastrad drm_crtc_vblank_put(crtc);
1095 1.1 riastrad return -EINVAL;
1096 1.1 riastrad }
1097 1.1 riastrad break;
1098 1.1 riastrad case DRM_MODE_PAGE_FLIP_TARGET_RELATIVE:
1099 1.1 riastrad if (target_vblank != 0 && target_vblank != 1) {
1100 1.1 riastrad DRM_DEBUG("Invalid relative flip target %u, "
1101 1.1 riastrad "must be 0 or 1\n", target_vblank);
1102 1.1 riastrad drm_crtc_vblank_put(crtc);
1103 1.1 riastrad return -EINVAL;
1104 1.1 riastrad }
1105 1.1 riastrad target_vblank += current_vblank;
1106 1.1 riastrad break;
1107 1.1 riastrad default:
1108 1.1 riastrad target_vblank = current_vblank +
1109 1.1 riastrad !(page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC);
1110 1.1 riastrad break;
1111 1.1 riastrad }
1112 1.1 riastrad } else if (crtc->funcs->page_flip == NULL ||
1113 1.1 riastrad (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET)) {
1114 1.1 riastrad return -EINVAL;
1115 1.1 riastrad }
1116 1.1 riastrad
1117 1.1 riastrad drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE);
1118 1.1 riastrad retry:
1119 1.1 riastrad ret = drm_modeset_lock(&crtc->mutex, &ctx);
1120 1.1 riastrad if (ret)
1121 1.1 riastrad goto out;
1122 1.1 riastrad ret = drm_modeset_lock(&plane->mutex, &ctx);
1123 1.1 riastrad if (ret)
1124 1.1 riastrad goto out;
1125 1.1 riastrad
1126 1.1 riastrad if (plane->state)
1127 1.1 riastrad old_fb = plane->state->fb;
1128 1.1 riastrad else
1129 1.1 riastrad old_fb = plane->fb;
1130 1.1 riastrad
1131 1.1 riastrad if (old_fb == NULL) {
1132 1.1 riastrad /* The framebuffer is currently unbound, presumably
1133 1.1 riastrad * due to a hotplug event, that userspace has not
1134 1.1 riastrad * yet discovered.
1135 1.1 riastrad */
1136 1.1 riastrad ret = -EBUSY;
1137 1.1 riastrad goto out;
1138 1.1 riastrad }
1139 1.1 riastrad
1140 1.1 riastrad fb = drm_framebuffer_lookup(dev, file_priv, page_flip->fb_id);
1141 1.1 riastrad if (!fb) {
1142 1.1 riastrad ret = -ENOENT;
1143 1.1 riastrad goto out;
1144 1.1 riastrad }
1145 1.1 riastrad
1146 1.1 riastrad if (plane->state) {
1147 1.1 riastrad const struct drm_plane_state *state = plane->state;
1148 1.1 riastrad
1149 1.1 riastrad ret = drm_framebuffer_check_src_coords(state->src_x,
1150 1.1 riastrad state->src_y,
1151 1.1 riastrad state->src_w,
1152 1.1 riastrad state->src_h,
1153 1.1 riastrad fb);
1154 1.1 riastrad } else {
1155 1.1 riastrad ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y,
1156 1.1 riastrad &crtc->mode, fb);
1157 1.1 riastrad }
1158 1.1 riastrad if (ret)
1159 1.1 riastrad goto out;
1160 1.1 riastrad
1161 1.1 riastrad if (old_fb->format != fb->format) {
1162 1.1 riastrad DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n");
1163 1.1 riastrad ret = -EINVAL;
1164 1.1 riastrad goto out;
1165 1.1 riastrad }
1166 1.1 riastrad
1167 1.1 riastrad if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
1168 1.1 riastrad e = kzalloc(sizeof *e, GFP_KERNEL);
1169 1.1 riastrad if (!e) {
1170 1.1 riastrad ret = -ENOMEM;
1171 1.1 riastrad goto out;
1172 1.1 riastrad }
1173 1.1 riastrad
1174 1.1 riastrad e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
1175 1.1 riastrad e->event.base.length = sizeof(e->event);
1176 1.1 riastrad e->event.vbl.user_data = page_flip->user_data;
1177 1.1 riastrad e->event.vbl.crtc_id = crtc->base.id;
1178 1.1 riastrad
1179 1.1 riastrad ret = drm_event_reserve_init(dev, file_priv, &e->base, &e->event.base);
1180 1.1 riastrad if (ret) {
1181 1.1 riastrad kfree(e);
1182 1.1 riastrad e = NULL;
1183 1.1 riastrad goto out;
1184 1.1 riastrad }
1185 1.1 riastrad }
1186 1.1 riastrad
1187 1.1 riastrad plane->old_fb = plane->fb;
1188 1.1 riastrad if (crtc->funcs->page_flip_target)
1189 1.1 riastrad ret = crtc->funcs->page_flip_target(crtc, fb, e,
1190 1.1 riastrad page_flip->flags,
1191 1.1 riastrad target_vblank,
1192 1.1 riastrad &ctx);
1193 1.1 riastrad else
1194 1.1 riastrad ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags,
1195 1.1 riastrad &ctx);
1196 1.1 riastrad if (ret) {
1197 1.1 riastrad if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT)
1198 1.1 riastrad drm_event_cancel_free(dev, &e->base);
1199 1.1 riastrad /* Keep the old fb, don't unref it. */
1200 1.1 riastrad plane->old_fb = NULL;
1201 1.1 riastrad } else {
1202 1.1 riastrad if (!plane->state) {
1203 1.1 riastrad plane->fb = fb;
1204 1.1 riastrad drm_framebuffer_get(fb);
1205 1.1 riastrad }
1206 1.1 riastrad }
1207 1.1 riastrad
1208 1.1 riastrad out:
1209 1.1 riastrad if (fb)
1210 1.1 riastrad drm_framebuffer_put(fb);
1211 1.1 riastrad if (plane->old_fb)
1212 1.1 riastrad drm_framebuffer_put(plane->old_fb);
1213 1.1 riastrad plane->old_fb = NULL;
1214 1.1 riastrad
1215 1.1 riastrad if (ret == -EDEADLK) {
1216 1.1 riastrad ret = drm_modeset_backoff(&ctx);
1217 1.1 riastrad if (!ret)
1218 1.1 riastrad goto retry;
1219 1.1 riastrad }
1220 1.1 riastrad
1221 1.1 riastrad drm_modeset_drop_locks(&ctx);
1222 1.1 riastrad drm_modeset_acquire_fini(&ctx);
1223 1.1 riastrad
1224 1.1 riastrad if (ret && crtc->funcs->page_flip_target)
1225 1.1 riastrad drm_crtc_vblank_put(crtc);
1226 1.1 riastrad
1227 1.1 riastrad return ret;
1228 1.1 riastrad }
1229