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