Line data Source code
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 :
28 : #include <drm/drm_atomic.h>
29 : #include <drm/drm_atomic_helper.h>
30 : #include <drm/drm_atomic_uapi.h>
31 : #include <drm/drm_device.h>
32 : #include <drm/drm_drv.h>
33 : #include <drm/drm_encoder.h>
34 : #include <drm/drm_plane_helper.h>
35 : #include <drm/drm_print.h>
36 : #include <drm/drm_rect.h>
37 :
38 : #define SUBPIXEL_MASK 0xffff
39 :
40 : /**
41 : * DOC: overview
42 : *
43 : * This helper library has two parts. The first part has support to implement
44 : * primary plane support on top of the normal CRTC configuration interface.
45 : * Since the legacy &drm_mode_config_funcs.set_config interface ties the primary
46 : * plane together with the CRTC state this does not allow userspace to disable
47 : * the primary plane itself. The default primary plane only expose XRBG8888 and
48 : * ARGB8888 as valid pixel formats for the attached framebuffer.
49 : *
50 : * Drivers are highly recommended to implement proper support for primary
51 : * planes, and newly merged drivers must not rely upon these transitional
52 : * helpers.
53 : *
54 : * The second part also implements transitional helpers which allow drivers to
55 : * gradually switch to the atomic helper infrastructure for plane updates. Once
56 : * that switch is complete drivers shouldn't use these any longer, instead using
57 : * the proper legacy implementations for update and disable plane hooks provided
58 : * by the atomic helpers.
59 : *
60 : * Again drivers are strongly urged to switch to the new interfaces.
61 : *
62 : * The plane helpers share the function table structures with other helpers,
63 : * specifically also the atomic helpers. See &struct drm_plane_helper_funcs for
64 : * the details.
65 : */
66 :
67 : /*
68 : * Returns the connectors currently associated with a CRTC. This function
69 : * should be called twice: once with a NULL connector list to retrieve
70 : * the list size, and once with the properly allocated list to be filled in.
71 : */
72 0 : static int get_connectors_for_crtc(struct drm_crtc *crtc,
73 : struct drm_connector **connector_list,
74 : int num_connectors)
75 : {
76 0 : struct drm_device *dev = crtc->dev;
77 : struct drm_connector *connector;
78 : struct drm_connector_list_iter conn_iter;
79 0 : int count = 0;
80 :
81 : /*
82 : * Note: Once we change the plane hooks to more fine-grained locking we
83 : * need to grab the connection_mutex here to be able to make these
84 : * checks.
85 : */
86 0 : WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
87 :
88 0 : drm_connector_list_iter_begin(dev, &conn_iter);
89 0 : drm_for_each_connector_iter(connector, &conn_iter) {
90 0 : if (connector->encoder && connector->encoder->crtc == crtc) {
91 0 : if (connector_list != NULL && count < num_connectors)
92 0 : *(connector_list++) = connector;
93 :
94 0 : count++;
95 : }
96 : }
97 0 : drm_connector_list_iter_end(&conn_iter);
98 :
99 0 : return count;
100 : }
101 :
102 0 : static int drm_plane_helper_check_update(struct drm_plane *plane,
103 : struct drm_crtc *crtc,
104 : struct drm_framebuffer *fb,
105 : struct drm_rect *src,
106 : struct drm_rect *dst,
107 : unsigned int rotation,
108 : int min_scale,
109 : int max_scale,
110 : bool can_position,
111 : bool can_update_disabled,
112 : bool *visible)
113 : {
114 0 : struct drm_plane_state plane_state = {
115 : .plane = plane,
116 : .crtc = crtc,
117 : .fb = fb,
118 0 : .src_x = src->x1,
119 0 : .src_y = src->y1,
120 0 : .src_w = drm_rect_width(src),
121 0 : .src_h = drm_rect_height(src),
122 0 : .crtc_x = dst->x1,
123 0 : .crtc_y = dst->y1,
124 0 : .crtc_w = drm_rect_width(dst),
125 0 : .crtc_h = drm_rect_height(dst),
126 : .rotation = rotation,
127 : };
128 0 : struct drm_crtc_state crtc_state = {
129 : .crtc = crtc,
130 0 : .enable = crtc->enabled,
131 : .mode = crtc->mode,
132 : };
133 : int ret;
134 :
135 0 : ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
136 : min_scale, max_scale,
137 : can_position,
138 : can_update_disabled);
139 0 : if (ret)
140 : return ret;
141 :
142 0 : *src = plane_state.src;
143 0 : *dst = plane_state.dst;
144 0 : *visible = plane_state.visible;
145 :
146 0 : return 0;
147 : }
148 :
149 : /**
150 : * drm_plane_helper_update_primary - Helper for updating primary planes
151 : * @plane: plane to update
152 : * @crtc: the plane's new CRTC
153 : * @fb: the plane's new framebuffer
154 : * @crtc_x: x coordinate within CRTC
155 : * @crtc_y: y coordinate within CRTC
156 : * @crtc_w: width coordinate within CRTC
157 : * @crtc_h: height coordinate within CRTC
158 : * @src_x: x coordinate within source
159 : * @src_y: y coordinate within source
160 : * @src_w: width coordinate within source
161 : * @src_h: height coordinate within source
162 : * @ctx: modeset locking context
163 : *
164 : * This helper validates the given parameters and updates the primary plane.
165 : *
166 : * This function is only useful for non-atomic modesetting. Don't use
167 : * it in new drivers.
168 : *
169 : * Returns:
170 : * Zero on success, or an errno code otherwise.
171 : */
172 0 : int drm_plane_helper_update_primary(struct drm_plane *plane, struct drm_crtc *crtc,
173 : struct drm_framebuffer *fb,
174 : int crtc_x, int crtc_y,
175 : unsigned int crtc_w, unsigned int crtc_h,
176 : uint32_t src_x, uint32_t src_y,
177 : uint32_t src_w, uint32_t src_h,
178 : struct drm_modeset_acquire_ctx *ctx)
179 : {
180 0 : struct drm_mode_set set = {
181 : .crtc = crtc,
182 : .fb = fb,
183 0 : .mode = &crtc->mode,
184 0 : .x = src_x >> 16,
185 0 : .y = src_y >> 16,
186 : };
187 0 : struct drm_rect src = {
188 : .x1 = src_x,
189 : .y1 = src_y,
190 0 : .x2 = src_x + src_w,
191 0 : .y2 = src_y + src_h,
192 : };
193 0 : struct drm_rect dest = {
194 : .x1 = crtc_x,
195 : .y1 = crtc_y,
196 0 : .x2 = crtc_x + crtc_w,
197 0 : .y2 = crtc_y + crtc_h,
198 : };
199 0 : struct drm_device *dev = plane->dev;
200 : struct drm_connector **connector_list;
201 : int num_connectors, ret;
202 : bool visible;
203 :
204 0 : if (drm_WARN_ON_ONCE(dev, drm_drv_uses_atomic_modeset(dev)))
205 : return -EINVAL;
206 :
207 0 : ret = drm_plane_helper_check_update(plane, crtc, fb,
208 : &src, &dest,
209 : DRM_MODE_ROTATE_0,
210 : DRM_PLANE_NO_SCALING,
211 : DRM_PLANE_NO_SCALING,
212 : false, false, &visible);
213 0 : if (ret)
214 : return ret;
215 :
216 0 : if (!visible)
217 : /*
218 : * Primary plane isn't visible. Note that unless a driver
219 : * provides their own disable function, this will just
220 : * wind up returning -EINVAL to userspace.
221 : */
222 0 : return plane->funcs->disable_plane(plane, ctx);
223 :
224 : /* Find current connectors for CRTC */
225 0 : num_connectors = get_connectors_for_crtc(crtc, NULL, 0);
226 0 : BUG_ON(num_connectors == 0);
227 0 : connector_list = kcalloc(num_connectors, sizeof(*connector_list),
228 : GFP_KERNEL);
229 0 : if (!connector_list)
230 : return -ENOMEM;
231 0 : get_connectors_for_crtc(crtc, connector_list, num_connectors);
232 :
233 0 : set.connectors = connector_list;
234 0 : set.num_connectors = num_connectors;
235 :
236 : /*
237 : * We call set_config() directly here rather than using
238 : * drm_mode_set_config_internal. We're reprogramming the same
239 : * connectors that were already in use, so we shouldn't need the extra
240 : * cross-CRTC fb refcounting to accommodate stealing connectors.
241 : * drm_mode_setplane() already handles the basic refcounting for the
242 : * framebuffers involved in this operation.
243 : */
244 0 : ret = crtc->funcs->set_config(&set, ctx);
245 :
246 0 : kfree(connector_list);
247 0 : return ret;
248 : }
249 : EXPORT_SYMBOL(drm_plane_helper_update_primary);
250 :
251 : /**
252 : * drm_plane_helper_disable_primary - Helper for disabling primary planes
253 : * @plane: plane to disable
254 : * @ctx: modeset locking context
255 : *
256 : * This helper returns an error when trying to disable the primary
257 : * plane.
258 : *
259 : * This function is only useful for non-atomic modesetting. Don't use
260 : * it in new drivers.
261 : *
262 : * Returns:
263 : * An errno code.
264 : */
265 0 : int drm_plane_helper_disable_primary(struct drm_plane *plane,
266 : struct drm_modeset_acquire_ctx *ctx)
267 : {
268 0 : struct drm_device *dev = plane->dev;
269 :
270 0 : drm_WARN_ON_ONCE(dev, drm_drv_uses_atomic_modeset(dev));
271 :
272 0 : return -EINVAL;
273 : }
274 : EXPORT_SYMBOL(drm_plane_helper_disable_primary);
275 :
276 : /**
277 : * drm_plane_helper_destroy() - Helper for primary plane destruction
278 : * @plane: plane to destroy
279 : *
280 : * Provides a default plane destroy handler for primary planes. This handler
281 : * is called during CRTC destruction. We disable the primary plane, remove
282 : * it from the DRM plane list, and deallocate the plane structure.
283 : */
284 0 : void drm_plane_helper_destroy(struct drm_plane *plane)
285 : {
286 0 : drm_plane_cleanup(plane);
287 0 : kfree(plane);
288 0 : }
289 : EXPORT_SYMBOL(drm_plane_helper_destroy);
290 :
291 : /**
292 : * drm_plane_helper_atomic_check() - Helper to check plane atomic-state
293 : * @plane: plane to check
294 : * @state: atomic state object
295 : *
296 : * Provides a default plane-state check handler for planes whose atomic-state
297 : * scale and positioning are not expected to change since the plane is always
298 : * a fullscreen scanout buffer.
299 : *
300 : * This is often the case for the primary plane of simple framebuffers. See
301 : * also drm_crtc_helper_atomic_check() for the respective CRTC-state check
302 : * helper function.
303 : *
304 : * RETURNS:
305 : * Zero on success, or an errno code otherwise.
306 : */
307 0 : int drm_plane_helper_atomic_check(struct drm_plane *plane, struct drm_atomic_state *state)
308 : {
309 0 : struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
310 0 : struct drm_crtc *new_crtc = new_plane_state->crtc;
311 0 : struct drm_crtc_state *new_crtc_state = NULL;
312 :
313 0 : if (new_crtc)
314 0 : new_crtc_state = drm_atomic_get_new_crtc_state(state, new_crtc);
315 :
316 0 : return drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state,
317 : DRM_PLANE_NO_SCALING,
318 : DRM_PLANE_NO_SCALING,
319 : false, false);
320 : }
321 : EXPORT_SYMBOL(drm_plane_helper_atomic_check);
|