]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/gpu/drm/drm_plane_helper.c
06c761db6e8030f568b6c6b57300929954e24526
[linux.git] / drivers / gpu / drm / drm_plane_helper.c
1 /*
2  * Copyright (C) 2014 Intel Corporation
3  *
4  * DRM universal plane helper functions
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the next
14  * paragraph) shall be included in all copies or substantial portions of the
15  * Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  */
25
26 #include <linux/list.h>
27 #include <drm/drmP.h>
28 #include <drm/drm_plane_helper.h>
29 #include <drm/drm_rect.h>
30 #include <drm/drm_atomic.h>
31 #include <drm/drm_atomic_uapi.h>
32 #include <drm/drm_crtc_helper.h>
33 #include <drm/drm_encoder.h>
34 #include <drm/drm_atomic_helper.h>
35
36 #define SUBPIXEL_MASK 0xffff
37
38 /**
39  * DOC: overview
40  *
41  * This helper library has two parts. The first part has support to implement
42  * primary plane support on top of the normal CRTC configuration interface.
43  * Since the legacy &drm_mode_config_funcs.set_config interface ties the primary
44  * plane together with the CRTC state this does not allow userspace to disable
45  * the primary plane itself. The default primary plane only expose XRBG8888 and
46  * ARGB8888 as valid pixel formats for the attached framebuffer.
47  *
48  * Drivers are highly recommended to implement proper support for primary
49  * planes, and newly merged drivers must not rely upon these transitional
50  * helpers.
51  *
52  * The second part also implements transitional helpers which allow drivers to
53  * gradually switch to the atomic helper infrastructure for plane updates. Once
54  * that switch is complete drivers shouldn't use these any longer, instead using
55  * the proper legacy implementations for update and disable plane hooks provided
56  * by the atomic helpers.
57  *
58  * Again drivers are strongly urged to switch to the new interfaces.
59  *
60  * The plane helpers share the function table structures with other helpers,
61  * specifically also the atomic helpers. See &struct drm_plane_helper_funcs for
62  * the details.
63  */
64
65 /*
66  * Returns the connectors currently associated with a CRTC.  This function
67  * should be called twice:  once with a NULL connector list to retrieve
68  * the list size, and once with the properly allocated list to be filled in.
69  */
70 static int get_connectors_for_crtc(struct drm_crtc *crtc,
71                                    struct drm_connector **connector_list,
72                                    int num_connectors)
73 {
74         struct drm_device *dev = crtc->dev;
75         struct drm_connector *connector;
76         struct drm_connector_list_iter conn_iter;
77         int count = 0;
78
79         /*
80          * Note: Once we change the plane hooks to more fine-grained locking we
81          * need to grab the connection_mutex here to be able to make these
82          * checks.
83          */
84         WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
85
86         drm_connector_list_iter_begin(dev, &conn_iter);
87         drm_for_each_connector_iter(connector, &conn_iter) {
88                 if (connector->encoder && connector->encoder->crtc == crtc) {
89                         if (connector_list != NULL && count < num_connectors)
90                                 *(connector_list++) = connector;
91
92                         count++;
93                 }
94         }
95         drm_connector_list_iter_end(&conn_iter);
96
97         return count;
98 }
99
100 /**
101  * drm_plane_helper_check_update() - Check plane update for validity
102  * @plane: plane object to update
103  * @crtc: owning CRTC of owning plane
104  * @fb: framebuffer to flip onto plane
105  * @src: source coordinates in 16.16 fixed point
106  * @dst: integer destination coordinates
107  * @rotation: plane rotation
108  * @min_scale: minimum @src:@dest scaling factor in 16.16 fixed point
109  * @max_scale: maximum @src:@dest scaling factor in 16.16 fixed point
110  * @can_position: is it legal to position the plane such that it
111  *                doesn't cover the entire crtc?  This will generally
112  *                only be false for primary planes.
113  * @can_update_disabled: can the plane be updated while the crtc
114  *                       is disabled?
115  * @visible: output parameter indicating whether plane is still visible after
116  *           clipping
117  *
118  * Checks that a desired plane update is valid.  Drivers that provide
119  * their own plane handling rather than helper-provided implementations may
120  * still wish to call this function to avoid duplication of error checking
121  * code.
122  *
123  * RETURNS:
124  * Zero if update appears valid, error code on failure
125  */
126 int drm_plane_helper_check_update(struct drm_plane *plane,
127                                   struct drm_crtc *crtc,
128                                   struct drm_framebuffer *fb,
129                                   struct drm_rect *src,
130                                   struct drm_rect *dst,
131                                   unsigned int rotation,
132                                   int min_scale,
133                                   int max_scale,
134                                   bool can_position,
135                                   bool can_update_disabled,
136                                   bool *visible)
137 {
138         struct drm_plane_state plane_state = {
139                 .plane = plane,
140                 .crtc = crtc,
141                 .fb = fb,
142                 .src_x = src->x1,
143                 .src_y = src->y1,
144                 .src_w = drm_rect_width(src),
145                 .src_h = drm_rect_height(src),
146                 .crtc_x = dst->x1,
147                 .crtc_y = dst->y1,
148                 .crtc_w = drm_rect_width(dst),
149                 .crtc_h = drm_rect_height(dst),
150                 .rotation = rotation,
151                 .visible = *visible,
152         };
153         struct drm_crtc_state crtc_state = {
154                 .crtc = crtc,
155                 .enable = crtc->enabled,
156                 .mode = crtc->mode,
157         };
158         int ret;
159
160         ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
161                                                   min_scale, max_scale,
162                                                   can_position,
163                                                   can_update_disabled);
164         if (ret)
165                 return ret;
166
167         *src = plane_state.src;
168         *dst = plane_state.dst;
169         *visible = plane_state.visible;
170
171         return 0;
172 }
173 EXPORT_SYMBOL(drm_plane_helper_check_update);
174
175 static int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
176                                      struct drm_framebuffer *fb,
177                                      int crtc_x, int crtc_y,
178                                      unsigned int crtc_w, unsigned int crtc_h,
179                                      uint32_t src_x, uint32_t src_y,
180                                      uint32_t src_w, uint32_t src_h,
181                                      struct drm_modeset_acquire_ctx *ctx)
182 {
183         struct drm_mode_set set = {
184                 .crtc = crtc,
185                 .fb = fb,
186                 .mode = &crtc->mode,
187                 .x = src_x >> 16,
188                 .y = src_y >> 16,
189         };
190         struct drm_rect src = {
191                 .x1 = src_x,
192                 .y1 = src_y,
193                 .x2 = src_x + src_w,
194                 .y2 = src_y + src_h,
195         };
196         struct drm_rect dest = {
197                 .x1 = crtc_x,
198                 .y1 = crtc_y,
199                 .x2 = crtc_x + crtc_w,
200                 .y2 = crtc_y + crtc_h,
201         };
202         struct drm_connector **connector_list;
203         int num_connectors, ret;
204         bool visible;
205
206         ret = drm_plane_helper_check_update(plane, crtc, fb,
207                                             &src, &dest,
208                                             DRM_MODE_ROTATE_0,
209                                             DRM_PLANE_HELPER_NO_SCALING,
210                                             DRM_PLANE_HELPER_NO_SCALING,
211                                             false, false, &visible);
212         if (ret)
213                 return ret;
214
215         if (!visible)
216                 /*
217                  * Primary plane isn't visible.  Note that unless a driver
218                  * provides their own disable function, this will just
219                  * wind up returning -EINVAL to userspace.
220                  */
221                 return plane->funcs->disable_plane(plane, ctx);
222
223         /* Find current connectors for CRTC */
224         num_connectors = get_connectors_for_crtc(crtc, NULL, 0);
225         BUG_ON(num_connectors == 0);
226         connector_list = kcalloc(num_connectors, sizeof(*connector_list),
227                                  GFP_KERNEL);
228         if (!connector_list)
229                 return -ENOMEM;
230         get_connectors_for_crtc(crtc, connector_list, num_connectors);
231
232         set.connectors = connector_list;
233         set.num_connectors = num_connectors;
234
235         /*
236          * We call set_config() directly here rather than using
237          * drm_mode_set_config_internal.  We're reprogramming the same
238          * connectors that were already in use, so we shouldn't need the extra
239          * cross-CRTC fb refcounting to accomodate stealing connectors.
240          * drm_mode_setplane() already handles the basic refcounting for the
241          * framebuffers involved in this operation.
242          */
243         ret = crtc->funcs->set_config(&set, ctx);
244
245         kfree(connector_list);
246         return ret;
247 }
248
249 static int drm_primary_helper_disable(struct drm_plane *plane,
250                                       struct drm_modeset_acquire_ctx *ctx)
251 {
252         return -EINVAL;
253 }
254
255 /**
256  * drm_primary_helper_destroy() - Helper for primary plane destruction
257  * @plane: plane to destroy
258  *
259  * Provides a default plane destroy handler for primary planes.  This handler
260  * is called during CRTC destruction.  We disable the primary plane, remove
261  * it from the DRM plane list, and deallocate the plane structure.
262  */
263 void drm_primary_helper_destroy(struct drm_plane *plane)
264 {
265         drm_plane_cleanup(plane);
266         kfree(plane);
267 }
268 EXPORT_SYMBOL(drm_primary_helper_destroy);
269
270 const struct drm_plane_funcs drm_primary_helper_funcs = {
271         .update_plane = drm_primary_helper_update,
272         .disable_plane = drm_primary_helper_disable,
273         .destroy = drm_primary_helper_destroy,
274 };
275 EXPORT_SYMBOL(drm_primary_helper_funcs);