diff options
Diffstat (limited to 'drivers/gpu/drm/drm_atomic_helper.c')
-rw-r--r-- | drivers/gpu/drm/drm_atomic_helper.c | 1966 |
1 files changed, 1966 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c new file mode 100644 index 000000000000..4a78a773151c --- /dev/null +++ b/drivers/gpu/drm/drm_atomic_helper.c | |||
@@ -0,0 +1,1966 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 Red Hat | ||
3 | * Copyright (C) 2014 Intel Corp. | ||
4 | * | ||
5 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
6 | * copy of this software and associated documentation files (the "Software"), | ||
7 | * to deal in the Software without restriction, including without limitation | ||
8 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
9 | * and/or sell copies of the Software, and to permit persons to whom the | ||
10 | * Software is furnished to do so, subject to the following conditions: | ||
11 | * | ||
12 | * The above copyright notice and this permission notice shall be included in | ||
13 | * all copies or substantial portions of the 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
19 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
20 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
21 | * OTHER DEALINGS IN THE SOFTWARE. | ||
22 | * | ||
23 | * Authors: | ||
24 | * Rob Clark <robdclark@gmail.com> | ||
25 | * Daniel Vetter <daniel.vetter@ffwll.ch> | ||
26 | */ | ||
27 | |||
28 | #include <drm/drmP.h> | ||
29 | #include <drm/drm_atomic.h> | ||
30 | #include <drm/drm_plane_helper.h> | ||
31 | #include <drm/drm_crtc_helper.h> | ||
32 | #include <drm/drm_atomic_helper.h> | ||
33 | #include <linux/fence.h> | ||
34 | |||
35 | /** | ||
36 | * DOC: overview | ||
37 | * | ||
38 | * This helper library provides implementations of check and commit functions on | ||
39 | * top of the CRTC modeset helper callbacks and the plane helper callbacks. It | ||
40 | * also provides convenience implementations for the atomic state handling | ||
41 | * callbacks for drivers which don't need to subclass the drm core structures to | ||
42 | * add their own additional internal state. | ||
43 | * | ||
44 | * This library also provides default implementations for the check callback in | ||
45 | * drm_atomic_helper_check and for the commit callback with | ||
46 | * drm_atomic_helper_commit. But the individual stages and callbacks are expose | ||
47 | * to allow drivers to mix and match and e.g. use the plane helpers only | ||
48 | * together with a driver private modeset implementation. | ||
49 | * | ||
50 | * This library also provides implementations for all the legacy driver | ||
51 | * interfaces on top of the atomic interface. See drm_atomic_helper_set_config, | ||
52 | * drm_atomic_helper_disable_plane, drm_atomic_helper_disable_plane and the | ||
53 | * various functions to implement set_property callbacks. New drivers must not | ||
54 | * implement these functions themselves but must use the provided helpers. | ||
55 | */ | ||
56 | static void | ||
57 | drm_atomic_helper_plane_changed(struct drm_atomic_state *state, | ||
58 | struct drm_plane_state *plane_state, | ||
59 | struct drm_plane *plane) | ||
60 | { | ||
61 | struct drm_crtc_state *crtc_state; | ||
62 | |||
63 | if (plane->state->crtc) { | ||
64 | crtc_state = state->crtc_states[drm_crtc_index(plane->crtc)]; | ||
65 | |||
66 | if (WARN_ON(!crtc_state)) | ||
67 | return; | ||
68 | |||
69 | crtc_state->planes_changed = true; | ||
70 | } | ||
71 | |||
72 | if (plane_state->crtc) { | ||
73 | crtc_state = | ||
74 | state->crtc_states[drm_crtc_index(plane_state->crtc)]; | ||
75 | |||
76 | if (WARN_ON(!crtc_state)) | ||
77 | return; | ||
78 | |||
79 | crtc_state->planes_changed = true; | ||
80 | } | ||
81 | } | ||
82 | |||
83 | static struct drm_crtc * | ||
84 | get_current_crtc_for_encoder(struct drm_device *dev, | ||
85 | struct drm_encoder *encoder) | ||
86 | { | ||
87 | struct drm_mode_config *config = &dev->mode_config; | ||
88 | struct drm_connector *connector; | ||
89 | |||
90 | WARN_ON(!drm_modeset_is_locked(&config->connection_mutex)); | ||
91 | |||
92 | list_for_each_entry(connector, &config->connector_list, head) { | ||
93 | if (connector->state->best_encoder != encoder) | ||
94 | continue; | ||
95 | |||
96 | return connector->state->crtc; | ||
97 | } | ||
98 | |||
99 | return NULL; | ||
100 | } | ||
101 | |||
102 | static int | ||
103 | steal_encoder(struct drm_atomic_state *state, | ||
104 | struct drm_encoder *encoder, | ||
105 | struct drm_crtc *encoder_crtc) | ||
106 | { | ||
107 | struct drm_mode_config *config = &state->dev->mode_config; | ||
108 | struct drm_crtc_state *crtc_state; | ||
109 | struct drm_connector *connector; | ||
110 | struct drm_connector_state *connector_state; | ||
111 | int ret; | ||
112 | |||
113 | /* | ||
114 | * We can only steal an encoder coming from a connector, which means we | ||
115 | * must already hold the connection_mutex. | ||
116 | */ | ||
117 | WARN_ON(!drm_modeset_is_locked(&config->connection_mutex)); | ||
118 | |||
119 | DRM_DEBUG_KMS("[ENCODER:%d:%s] in use on [CRTC:%d], stealing it\n", | ||
120 | encoder->base.id, encoder->name, | ||
121 | encoder_crtc->base.id); | ||
122 | |||
123 | crtc_state = drm_atomic_get_crtc_state(state, encoder_crtc); | ||
124 | if (IS_ERR(crtc_state)) | ||
125 | return PTR_ERR(crtc_state); | ||
126 | |||
127 | crtc_state->mode_changed = true; | ||
128 | |||
129 | list_for_each_entry(connector, &config->connector_list, head) { | ||
130 | if (connector->state->best_encoder != encoder) | ||
131 | continue; | ||
132 | |||
133 | DRM_DEBUG_KMS("Stealing encoder from [CONNECTOR:%d:%s]\n", | ||
134 | connector->base.id, | ||
135 | connector->name); | ||
136 | |||
137 | connector_state = drm_atomic_get_connector_state(state, | ||
138 | connector); | ||
139 | if (IS_ERR(connector_state)) | ||
140 | return PTR_ERR(connector_state); | ||
141 | |||
142 | ret = drm_atomic_set_crtc_for_connector(connector_state, NULL); | ||
143 | if (ret) | ||
144 | return ret; | ||
145 | connector_state->best_encoder = NULL; | ||
146 | } | ||
147 | |||
148 | return 0; | ||
149 | } | ||
150 | |||
151 | static int | ||
152 | update_connector_routing(struct drm_atomic_state *state, int conn_idx) | ||
153 | { | ||
154 | struct drm_connector_helper_funcs *funcs; | ||
155 | struct drm_encoder *new_encoder; | ||
156 | struct drm_crtc *encoder_crtc; | ||
157 | struct drm_connector *connector; | ||
158 | struct drm_connector_state *connector_state; | ||
159 | struct drm_crtc_state *crtc_state; | ||
160 | int idx, ret; | ||
161 | |||
162 | connector = state->connectors[conn_idx]; | ||
163 | connector_state = state->connector_states[conn_idx]; | ||
164 | |||
165 | if (!connector) | ||
166 | return 0; | ||
167 | |||
168 | DRM_DEBUG_KMS("Updating routing for [CONNECTOR:%d:%s]\n", | ||
169 | connector->base.id, | ||
170 | connector->name); | ||
171 | |||
172 | if (connector->state->crtc != connector_state->crtc) { | ||
173 | if (connector->state->crtc) { | ||
174 | idx = drm_crtc_index(connector->state->crtc); | ||
175 | |||
176 | crtc_state = state->crtc_states[idx]; | ||
177 | crtc_state->mode_changed = true; | ||
178 | } | ||
179 | |||
180 | if (connector_state->crtc) { | ||
181 | idx = drm_crtc_index(connector_state->crtc); | ||
182 | |||
183 | crtc_state = state->crtc_states[idx]; | ||
184 | crtc_state->mode_changed = true; | ||
185 | } | ||
186 | } | ||
187 | |||
188 | if (!connector_state->crtc) { | ||
189 | DRM_DEBUG_KMS("Disabling [CONNECTOR:%d:%s]\n", | ||
190 | connector->base.id, | ||
191 | connector->name); | ||
192 | |||
193 | connector_state->best_encoder = NULL; | ||
194 | |||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | funcs = connector->helper_private; | ||
199 | new_encoder = funcs->best_encoder(connector); | ||
200 | |||
201 | if (!new_encoder) { | ||
202 | DRM_DEBUG_KMS("No suitable encoder found for [CONNECTOR:%d:%s]\n", | ||
203 | connector->base.id, | ||
204 | connector->name); | ||
205 | return -EINVAL; | ||
206 | } | ||
207 | |||
208 | if (new_encoder == connector_state->best_encoder) { | ||
209 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s] keeps [ENCODER:%d:%s], now on [CRTC:%d]\n", | ||
210 | connector->base.id, | ||
211 | connector->name, | ||
212 | new_encoder->base.id, | ||
213 | new_encoder->name, | ||
214 | connector_state->crtc->base.id); | ||
215 | |||
216 | return 0; | ||
217 | } | ||
218 | |||
219 | encoder_crtc = get_current_crtc_for_encoder(state->dev, | ||
220 | new_encoder); | ||
221 | |||
222 | if (encoder_crtc) { | ||
223 | ret = steal_encoder(state, new_encoder, encoder_crtc); | ||
224 | if (ret) { | ||
225 | DRM_DEBUG_KMS("Encoder stealing failed for [CONNECTOR:%d:%s]\n", | ||
226 | connector->base.id, | ||
227 | connector->name); | ||
228 | return ret; | ||
229 | } | ||
230 | } | ||
231 | |||
232 | connector_state->best_encoder = new_encoder; | ||
233 | idx = drm_crtc_index(connector_state->crtc); | ||
234 | |||
235 | crtc_state = state->crtc_states[idx]; | ||
236 | crtc_state->mode_changed = true; | ||
237 | |||
238 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s] using [ENCODER:%d:%s] on [CRTC:%d]\n", | ||
239 | connector->base.id, | ||
240 | connector->name, | ||
241 | new_encoder->base.id, | ||
242 | new_encoder->name, | ||
243 | connector_state->crtc->base.id); | ||
244 | |||
245 | return 0; | ||
246 | } | ||
247 | |||
248 | static int | ||
249 | mode_fixup(struct drm_atomic_state *state) | ||
250 | { | ||
251 | int ncrtcs = state->dev->mode_config.num_crtc; | ||
252 | struct drm_crtc_state *crtc_state; | ||
253 | struct drm_connector_state *conn_state; | ||
254 | int i; | ||
255 | bool ret; | ||
256 | |||
257 | for (i = 0; i < ncrtcs; i++) { | ||
258 | crtc_state = state->crtc_states[i]; | ||
259 | |||
260 | if (!crtc_state || !crtc_state->mode_changed) | ||
261 | continue; | ||
262 | |||
263 | drm_mode_copy(&crtc_state->adjusted_mode, &crtc_state->mode); | ||
264 | } | ||
265 | |||
266 | for (i = 0; i < state->num_connector; i++) { | ||
267 | struct drm_encoder_helper_funcs *funcs; | ||
268 | struct drm_encoder *encoder; | ||
269 | |||
270 | conn_state = state->connector_states[i]; | ||
271 | |||
272 | if (!conn_state) | ||
273 | continue; | ||
274 | |||
275 | WARN_ON(!!conn_state->best_encoder != !!conn_state->crtc); | ||
276 | |||
277 | if (!conn_state->crtc || !conn_state->best_encoder) | ||
278 | continue; | ||
279 | |||
280 | crtc_state = | ||
281 | state->crtc_states[drm_crtc_index(conn_state->crtc)]; | ||
282 | |||
283 | /* | ||
284 | * Each encoder has at most one connector (since we always steal | ||
285 | * it away), so we won't call ->mode_fixup twice. | ||
286 | */ | ||
287 | encoder = conn_state->best_encoder; | ||
288 | funcs = encoder->helper_private; | ||
289 | |||
290 | if (encoder->bridge && encoder->bridge->funcs->mode_fixup) { | ||
291 | ret = encoder->bridge->funcs->mode_fixup( | ||
292 | encoder->bridge, &crtc_state->mode, | ||
293 | &crtc_state->adjusted_mode); | ||
294 | if (!ret) { | ||
295 | DRM_DEBUG_KMS("Bridge fixup failed\n"); | ||
296 | return -EINVAL; | ||
297 | } | ||
298 | } | ||
299 | |||
300 | |||
301 | ret = funcs->mode_fixup(encoder, &crtc_state->mode, | ||
302 | &crtc_state->adjusted_mode); | ||
303 | if (!ret) { | ||
304 | DRM_DEBUG_KMS("[ENCODER:%d:%s] fixup failed\n", | ||
305 | encoder->base.id, encoder->name); | ||
306 | return -EINVAL; | ||
307 | } | ||
308 | } | ||
309 | |||
310 | for (i = 0; i < ncrtcs; i++) { | ||
311 | struct drm_crtc_helper_funcs *funcs; | ||
312 | struct drm_crtc *crtc; | ||
313 | |||
314 | crtc_state = state->crtc_states[i]; | ||
315 | crtc = state->crtcs[i]; | ||
316 | |||
317 | if (!crtc_state || !crtc_state->mode_changed) | ||
318 | continue; | ||
319 | |||
320 | funcs = crtc->helper_private; | ||
321 | ret = funcs->mode_fixup(crtc, &crtc_state->mode, | ||
322 | &crtc_state->adjusted_mode); | ||
323 | if (!ret) { | ||
324 | DRM_DEBUG_KMS("[CRTC:%d] fixup failed\n", | ||
325 | crtc->base.id); | ||
326 | return -EINVAL; | ||
327 | } | ||
328 | } | ||
329 | |||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | static int | ||
334 | drm_atomic_helper_check_modeset(struct drm_device *dev, | ||
335 | struct drm_atomic_state *state) | ||
336 | { | ||
337 | int ncrtcs = dev->mode_config.num_crtc; | ||
338 | struct drm_crtc *crtc; | ||
339 | struct drm_crtc_state *crtc_state; | ||
340 | int i, ret; | ||
341 | |||
342 | for (i = 0; i < ncrtcs; i++) { | ||
343 | crtc = state->crtcs[i]; | ||
344 | crtc_state = state->crtc_states[i]; | ||
345 | |||
346 | if (!crtc) | ||
347 | continue; | ||
348 | |||
349 | if (!drm_mode_equal(&crtc->state->mode, &crtc_state->mode)) { | ||
350 | DRM_DEBUG_KMS("[CRTC:%d] mode changed\n", | ||
351 | crtc->base.id); | ||
352 | crtc_state->mode_changed = true; | ||
353 | } | ||
354 | |||
355 | if (crtc->state->enable != crtc_state->enable) { | ||
356 | DRM_DEBUG_KMS("[CRTC:%d] enable changed\n", | ||
357 | crtc->base.id); | ||
358 | crtc_state->mode_changed = true; | ||
359 | } | ||
360 | } | ||
361 | |||
362 | for (i = 0; i < state->num_connector; i++) { | ||
363 | /* | ||
364 | * This only sets crtc->mode_changed for routing changes, | ||
365 | * drivers must set crtc->mode_changed themselves when connector | ||
366 | * properties need to be updated. | ||
367 | */ | ||
368 | ret = update_connector_routing(state, i); | ||
369 | if (ret) | ||
370 | return ret; | ||
371 | } | ||
372 | |||
373 | /* | ||
374 | * After all the routing has been prepared we need to add in any | ||
375 | * connector which is itself unchanged, but who's crtc changes it's | ||
376 | * configuration. This must be done before calling mode_fixup in case a | ||
377 | * crtc only changed its mode but has the same set of connectors. | ||
378 | */ | ||
379 | for (i = 0; i < ncrtcs; i++) { | ||
380 | int num_connectors; | ||
381 | |||
382 | crtc = state->crtcs[i]; | ||
383 | crtc_state = state->crtc_states[i]; | ||
384 | |||
385 | if (!crtc || !crtc_state->mode_changed) | ||
386 | continue; | ||
387 | |||
388 | DRM_DEBUG_KMS("[CRTC:%d] needs full modeset, enable: %c\n", | ||
389 | crtc->base.id, | ||
390 | crtc_state->enable ? 'y' : 'n'); | ||
391 | |||
392 | ret = drm_atomic_add_affected_connectors(state, crtc); | ||
393 | if (ret != 0) | ||
394 | return ret; | ||
395 | |||
396 | num_connectors = drm_atomic_connectors_for_crtc(state, | ||
397 | crtc); | ||
398 | |||
399 | if (crtc_state->enable != !!num_connectors) { | ||
400 | DRM_DEBUG_KMS("[CRTC:%d] enabled/connectors mismatch\n", | ||
401 | crtc->base.id); | ||
402 | |||
403 | return -EINVAL; | ||
404 | } | ||
405 | } | ||
406 | |||
407 | return mode_fixup(state); | ||
408 | } | ||
409 | |||
410 | /** | ||
411 | * drm_atomic_helper_check - validate state object | ||
412 | * @dev: DRM device | ||
413 | * @state: the driver state object | ||
414 | * | ||
415 | * Check the state object to see if the requested state is physically possible. | ||
416 | * Only crtcs and planes have check callbacks, so for any additional (global) | ||
417 | * checking that a driver needs it can simply wrap that around this function. | ||
418 | * Drivers without such needs can directly use this as their ->atomic_check() | ||
419 | * callback. | ||
420 | * | ||
421 | * RETURNS | ||
422 | * Zero for success or -errno | ||
423 | */ | ||
424 | int drm_atomic_helper_check(struct drm_device *dev, | ||
425 | struct drm_atomic_state *state) | ||
426 | { | ||
427 | int nplanes = dev->mode_config.num_total_plane; | ||
428 | int ncrtcs = dev->mode_config.num_crtc; | ||
429 | int i, ret = 0; | ||
430 | |||
431 | for (i = 0; i < nplanes; i++) { | ||
432 | struct drm_plane_helper_funcs *funcs; | ||
433 | struct drm_plane *plane = state->planes[i]; | ||
434 | struct drm_plane_state *plane_state = state->plane_states[i]; | ||
435 | |||
436 | if (!plane) | ||
437 | continue; | ||
438 | |||
439 | funcs = plane->helper_private; | ||
440 | |||
441 | drm_atomic_helper_plane_changed(state, plane_state, plane); | ||
442 | |||
443 | if (!funcs || !funcs->atomic_check) | ||
444 | continue; | ||
445 | |||
446 | ret = funcs->atomic_check(plane, plane_state); | ||
447 | if (ret) { | ||
448 | DRM_DEBUG_KMS("[PLANE:%d] atomic check failed\n", | ||
449 | plane->base.id); | ||
450 | return ret; | ||
451 | } | ||
452 | } | ||
453 | |||
454 | for (i = 0; i < ncrtcs; i++) { | ||
455 | struct drm_crtc_helper_funcs *funcs; | ||
456 | struct drm_crtc *crtc = state->crtcs[i]; | ||
457 | |||
458 | if (!crtc) | ||
459 | continue; | ||
460 | |||
461 | funcs = crtc->helper_private; | ||
462 | |||
463 | if (!funcs || !funcs->atomic_check) | ||
464 | continue; | ||
465 | |||
466 | ret = funcs->atomic_check(crtc, state->crtc_states[i]); | ||
467 | if (ret) { | ||
468 | DRM_DEBUG_KMS("[CRTC:%d] atomic check failed\n", | ||
469 | crtc->base.id); | ||
470 | return ret; | ||
471 | } | ||
472 | } | ||
473 | |||
474 | ret = drm_atomic_helper_check_modeset(dev, state); | ||
475 | if (ret) | ||
476 | return ret; | ||
477 | |||
478 | return ret; | ||
479 | } | ||
480 | EXPORT_SYMBOL(drm_atomic_helper_check); | ||
481 | |||
482 | static void | ||
483 | disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) | ||
484 | { | ||
485 | int ncrtcs = old_state->dev->mode_config.num_crtc; | ||
486 | int i; | ||
487 | |||
488 | for (i = 0; i < old_state->num_connector; i++) { | ||
489 | struct drm_connector_state *old_conn_state; | ||
490 | struct drm_connector *connector; | ||
491 | struct drm_encoder_helper_funcs *funcs; | ||
492 | struct drm_encoder *encoder; | ||
493 | |||
494 | old_conn_state = old_state->connector_states[i]; | ||
495 | connector = old_state->connectors[i]; | ||
496 | |||
497 | /* Shut down everything that's in the changeset and currently | ||
498 | * still on. So need to check the old, saved state. */ | ||
499 | if (!old_conn_state || !old_conn_state->crtc) | ||
500 | continue; | ||
501 | |||
502 | encoder = old_conn_state->best_encoder; | ||
503 | |||
504 | /* We shouldn't get this far if we didn't previously have | ||
505 | * an encoder.. but WARN_ON() rather than explode. | ||
506 | */ | ||
507 | if (WARN_ON(!encoder)) | ||
508 | continue; | ||
509 | |||
510 | funcs = encoder->helper_private; | ||
511 | |||
512 | /* | ||
513 | * Each encoder has at most one connector (since we always steal | ||
514 | * it away), so we won't call call disable hooks twice. | ||
515 | */ | ||
516 | if (encoder->bridge) | ||
517 | encoder->bridge->funcs->disable(encoder->bridge); | ||
518 | |||
519 | /* Right function depends upon target state. */ | ||
520 | if (connector->state->crtc) | ||
521 | funcs->prepare(encoder); | ||
522 | else if (funcs->disable) | ||
523 | funcs->disable(encoder); | ||
524 | else | ||
525 | funcs->dpms(encoder, DRM_MODE_DPMS_OFF); | ||
526 | |||
527 | if (encoder->bridge) | ||
528 | encoder->bridge->funcs->post_disable(encoder->bridge); | ||
529 | } | ||
530 | |||
531 | for (i = 0; i < ncrtcs; i++) { | ||
532 | struct drm_crtc_helper_funcs *funcs; | ||
533 | struct drm_crtc *crtc; | ||
534 | |||
535 | crtc = old_state->crtcs[i]; | ||
536 | |||
537 | /* Shut down everything that needs a full modeset. */ | ||
538 | if (!crtc || !crtc->state->mode_changed) | ||
539 | continue; | ||
540 | |||
541 | funcs = crtc->helper_private; | ||
542 | |||
543 | /* Right function depends upon target state. */ | ||
544 | if (crtc->state->enable) | ||
545 | funcs->prepare(crtc); | ||
546 | else if (funcs->disable) | ||
547 | funcs->disable(crtc); | ||
548 | else | ||
549 | funcs->dpms(crtc, DRM_MODE_DPMS_OFF); | ||
550 | } | ||
551 | } | ||
552 | |||
553 | static void | ||
554 | set_routing_links(struct drm_device *dev, struct drm_atomic_state *old_state) | ||
555 | { | ||
556 | int ncrtcs = old_state->dev->mode_config.num_crtc; | ||
557 | int i; | ||
558 | |||
559 | /* clear out existing links */ | ||
560 | for (i = 0; i < old_state->num_connector; i++) { | ||
561 | struct drm_connector *connector; | ||
562 | |||
563 | connector = old_state->connectors[i]; | ||
564 | |||
565 | if (!connector || !connector->encoder) | ||
566 | continue; | ||
567 | |||
568 | WARN_ON(!connector->encoder->crtc); | ||
569 | |||
570 | connector->encoder->crtc = NULL; | ||
571 | connector->encoder = NULL; | ||
572 | } | ||
573 | |||
574 | /* set new links */ | ||
575 | for (i = 0; i < old_state->num_connector; i++) { | ||
576 | struct drm_connector *connector; | ||
577 | |||
578 | connector = old_state->connectors[i]; | ||
579 | |||
580 | if (!connector || !connector->state->crtc) | ||
581 | continue; | ||
582 | |||
583 | if (WARN_ON(!connector->state->best_encoder)) | ||
584 | continue; | ||
585 | |||
586 | connector->encoder = connector->state->best_encoder; | ||
587 | connector->encoder->crtc = connector->state->crtc; | ||
588 | } | ||
589 | |||
590 | /* set legacy state in the crtc structure */ | ||
591 | for (i = 0; i < ncrtcs; i++) { | ||
592 | struct drm_crtc *crtc; | ||
593 | |||
594 | crtc = old_state->crtcs[i]; | ||
595 | |||
596 | if (!crtc) | ||
597 | continue; | ||
598 | |||
599 | crtc->mode = crtc->state->mode; | ||
600 | crtc->enabled = crtc->state->enable; | ||
601 | crtc->x = crtc->primary->state->src_x >> 16; | ||
602 | crtc->y = crtc->primary->state->src_y >> 16; | ||
603 | } | ||
604 | } | ||
605 | |||
606 | static void | ||
607 | crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state) | ||
608 | { | ||
609 | int ncrtcs = old_state->dev->mode_config.num_crtc; | ||
610 | int i; | ||
611 | |||
612 | for (i = 0; i < ncrtcs; i++) { | ||
613 | struct drm_crtc_helper_funcs *funcs; | ||
614 | struct drm_crtc *crtc; | ||
615 | |||
616 | crtc = old_state->crtcs[i]; | ||
617 | |||
618 | if (!crtc || !crtc->state->mode_changed) | ||
619 | continue; | ||
620 | |||
621 | funcs = crtc->helper_private; | ||
622 | |||
623 | if (crtc->state->enable) | ||
624 | funcs->mode_set_nofb(crtc); | ||
625 | } | ||
626 | |||
627 | for (i = 0; i < old_state->num_connector; i++) { | ||
628 | struct drm_connector *connector; | ||
629 | struct drm_crtc_state *new_crtc_state; | ||
630 | struct drm_encoder_helper_funcs *funcs; | ||
631 | struct drm_encoder *encoder; | ||
632 | struct drm_display_mode *mode, *adjusted_mode; | ||
633 | |||
634 | connector = old_state->connectors[i]; | ||
635 | |||
636 | if (!connector || !connector->state->best_encoder) | ||
637 | continue; | ||
638 | |||
639 | encoder = connector->state->best_encoder; | ||
640 | funcs = encoder->helper_private; | ||
641 | new_crtc_state = connector->state->crtc->state; | ||
642 | mode = &new_crtc_state->mode; | ||
643 | adjusted_mode = &new_crtc_state->adjusted_mode; | ||
644 | |||
645 | /* | ||
646 | * Each encoder has at most one connector (since we always steal | ||
647 | * it away), so we won't call call mode_set hooks twice. | ||
648 | */ | ||
649 | funcs->mode_set(encoder, mode, adjusted_mode); | ||
650 | |||
651 | if (encoder->bridge && encoder->bridge->funcs->mode_set) | ||
652 | encoder->bridge->funcs->mode_set(encoder->bridge, | ||
653 | mode, adjusted_mode); | ||
654 | } | ||
655 | } | ||
656 | |||
657 | /** | ||
658 | * drm_atomic_helper_commit_pre_planes - modeset commit before plane updates | ||
659 | * @dev: DRM device | ||
660 | * @state: atomic state | ||
661 | * | ||
662 | * This function commits the modeset changes that need to be committed before | ||
663 | * updating planes. It shuts down all the outputs that need to be shut down and | ||
664 | * prepares them (if required) with the new mode. | ||
665 | */ | ||
666 | void drm_atomic_helper_commit_pre_planes(struct drm_device *dev, | ||
667 | struct drm_atomic_state *state) | ||
668 | { | ||
669 | disable_outputs(dev, state); | ||
670 | set_routing_links(dev, state); | ||
671 | crtc_set_mode(dev, state); | ||
672 | } | ||
673 | EXPORT_SYMBOL(drm_atomic_helper_commit_pre_planes); | ||
674 | |||
675 | /** | ||
676 | * drm_atomic_helper_commit_post_planes - modeset commit after plane updates | ||
677 | * @dev: DRM device | ||
678 | * @old_state: atomic state object with old state structures | ||
679 | * | ||
680 | * This function commits the modeset changes that need to be committed after | ||
681 | * updating planes: It enables all the outputs with the new configuration which | ||
682 | * had to be turned off for the update. | ||
683 | */ | ||
684 | void drm_atomic_helper_commit_post_planes(struct drm_device *dev, | ||
685 | struct drm_atomic_state *old_state) | ||
686 | { | ||
687 | int ncrtcs = old_state->dev->mode_config.num_crtc; | ||
688 | int i; | ||
689 | |||
690 | for (i = 0; i < ncrtcs; i++) { | ||
691 | struct drm_crtc_helper_funcs *funcs; | ||
692 | struct drm_crtc *crtc; | ||
693 | |||
694 | crtc = old_state->crtcs[i]; | ||
695 | |||
696 | /* Need to filter out CRTCs where only planes change. */ | ||
697 | if (!crtc || !crtc->state->mode_changed) | ||
698 | continue; | ||
699 | |||
700 | funcs = crtc->helper_private; | ||
701 | |||
702 | if (crtc->state->enable) | ||
703 | funcs->commit(crtc); | ||
704 | } | ||
705 | |||
706 | for (i = 0; i < old_state->num_connector; i++) { | ||
707 | struct drm_connector *connector; | ||
708 | struct drm_encoder_helper_funcs *funcs; | ||
709 | struct drm_encoder *encoder; | ||
710 | |||
711 | connector = old_state->connectors[i]; | ||
712 | |||
713 | if (!connector || !connector->state->best_encoder) | ||
714 | continue; | ||
715 | |||
716 | encoder = connector->state->best_encoder; | ||
717 | funcs = encoder->helper_private; | ||
718 | |||
719 | /* | ||
720 | * Each encoder has at most one connector (since we always steal | ||
721 | * it away), so we won't call call enable hooks twice. | ||
722 | */ | ||
723 | if (encoder->bridge) | ||
724 | encoder->bridge->funcs->pre_enable(encoder->bridge); | ||
725 | |||
726 | funcs->commit(encoder); | ||
727 | |||
728 | if (encoder->bridge) | ||
729 | encoder->bridge->funcs->enable(encoder->bridge); | ||
730 | } | ||
731 | } | ||
732 | EXPORT_SYMBOL(drm_atomic_helper_commit_post_planes); | ||
733 | |||
734 | static void wait_for_fences(struct drm_device *dev, | ||
735 | struct drm_atomic_state *state) | ||
736 | { | ||
737 | int nplanes = dev->mode_config.num_total_plane; | ||
738 | int i; | ||
739 | |||
740 | for (i = 0; i < nplanes; i++) { | ||
741 | struct drm_plane *plane = state->planes[i]; | ||
742 | |||
743 | if (!plane || !plane->state->fence) | ||
744 | continue; | ||
745 | |||
746 | WARN_ON(!plane->state->fb); | ||
747 | |||
748 | fence_wait(plane->state->fence, false); | ||
749 | fence_put(plane->state->fence); | ||
750 | plane->state->fence = NULL; | ||
751 | } | ||
752 | } | ||
753 | |||
754 | static bool framebuffer_changed(struct drm_device *dev, | ||
755 | struct drm_atomic_state *old_state, | ||
756 | struct drm_crtc *crtc) | ||
757 | { | ||
758 | struct drm_plane *plane; | ||
759 | struct drm_plane_state *old_plane_state; | ||
760 | int nplanes = old_state->dev->mode_config.num_total_plane; | ||
761 | int i; | ||
762 | |||
763 | for (i = 0; i < nplanes; i++) { | ||
764 | plane = old_state->planes[i]; | ||
765 | old_plane_state = old_state->plane_states[i]; | ||
766 | |||
767 | if (!plane) | ||
768 | continue; | ||
769 | |||
770 | if (plane->state->crtc != crtc && | ||
771 | old_plane_state->crtc != crtc) | ||
772 | continue; | ||
773 | |||
774 | if (plane->state->fb != old_plane_state->fb) | ||
775 | return true; | ||
776 | } | ||
777 | |||
778 | return false; | ||
779 | } | ||
780 | |||
781 | /** | ||
782 | * drm_atomic_helper_wait_for_vblanks - wait for vblank on crtcs | ||
783 | * @dev: DRM device | ||
784 | * @old_state: atomic state object with old state structures | ||
785 | * | ||
786 | * Helper to, after atomic commit, wait for vblanks on all effected | ||
787 | * crtcs (ie. before cleaning up old framebuffers using | ||
788 | * drm_atomic_helper_cleanup_planes()). It will only wait on crtcs where the | ||
789 | * framebuffers have actually changed to optimize for the legacy cursor and | ||
790 | * plane update use-case. | ||
791 | */ | ||
792 | void | ||
793 | drm_atomic_helper_wait_for_vblanks(struct drm_device *dev, | ||
794 | struct drm_atomic_state *old_state) | ||
795 | { | ||
796 | struct drm_crtc *crtc; | ||
797 | struct drm_crtc_state *old_crtc_state; | ||
798 | int ncrtcs = old_state->dev->mode_config.num_crtc; | ||
799 | int i, ret; | ||
800 | |||
801 | for (i = 0; i < ncrtcs; i++) { | ||
802 | crtc = old_state->crtcs[i]; | ||
803 | old_crtc_state = old_state->crtc_states[i]; | ||
804 | |||
805 | if (!crtc) | ||
806 | continue; | ||
807 | |||
808 | /* No one cares about the old state, so abuse it for tracking | ||
809 | * and store whether we hold a vblank reference (and should do a | ||
810 | * vblank wait) in the ->enable boolean. */ | ||
811 | old_crtc_state->enable = false; | ||
812 | |||
813 | if (!crtc->state->enable) | ||
814 | continue; | ||
815 | |||
816 | if (!framebuffer_changed(dev, old_state, crtc)) | ||
817 | continue; | ||
818 | |||
819 | ret = drm_crtc_vblank_get(crtc); | ||
820 | if (ret != 0) | ||
821 | continue; | ||
822 | |||
823 | old_crtc_state->enable = true; | ||
824 | old_crtc_state->last_vblank_count = drm_vblank_count(dev, i); | ||
825 | } | ||
826 | |||
827 | for (i = 0; i < ncrtcs; i++) { | ||
828 | crtc = old_state->crtcs[i]; | ||
829 | old_crtc_state = old_state->crtc_states[i]; | ||
830 | |||
831 | if (!crtc || !old_crtc_state->enable) | ||
832 | continue; | ||
833 | |||
834 | ret = wait_event_timeout(dev->vblank[i].queue, | ||
835 | old_crtc_state->last_vblank_count != | ||
836 | drm_vblank_count(dev, i), | ||
837 | msecs_to_jiffies(50)); | ||
838 | |||
839 | drm_crtc_vblank_put(crtc); | ||
840 | } | ||
841 | } | ||
842 | EXPORT_SYMBOL(drm_atomic_helper_wait_for_vblanks); | ||
843 | |||
844 | /** | ||
845 | * drm_atomic_helper_commit - commit validated state object | ||
846 | * @dev: DRM device | ||
847 | * @state: the driver state object | ||
848 | * @async: asynchronous commit | ||
849 | * | ||
850 | * This function commits a with drm_atomic_helper_check() pre-validated state | ||
851 | * object. This can still fail when e.g. the framebuffer reservation fails. For | ||
852 | * now this doesn't implement asynchronous commits. | ||
853 | * | ||
854 | * RETURNS | ||
855 | * Zero for success or -errno. | ||
856 | */ | ||
857 | int drm_atomic_helper_commit(struct drm_device *dev, | ||
858 | struct drm_atomic_state *state, | ||
859 | bool async) | ||
860 | { | ||
861 | int ret; | ||
862 | |||
863 | if (async) | ||
864 | return -EBUSY; | ||
865 | |||
866 | ret = drm_atomic_helper_prepare_planes(dev, state); | ||
867 | if (ret) | ||
868 | return ret; | ||
869 | |||
870 | /* | ||
871 | * This is the point of no return - everything below never fails except | ||
872 | * when the hw goes bonghits. Which means we can commit the new state on | ||
873 | * the software side now. | ||
874 | */ | ||
875 | |||
876 | drm_atomic_helper_swap_state(dev, state); | ||
877 | |||
878 | /* | ||
879 | * Everything below can be run asynchronously without the need to grab | ||
880 | * any modeset locks at all under one conditions: It must be guaranteed | ||
881 | * that the asynchronous work has either been cancelled (if the driver | ||
882 | * supports it, which at least requires that the framebuffers get | ||
883 | * cleaned up with drm_atomic_helper_cleanup_planes()) or completed | ||
884 | * before the new state gets committed on the software side with | ||
885 | * drm_atomic_helper_swap_state(). | ||
886 | * | ||
887 | * This scheme allows new atomic state updates to be prepared and | ||
888 | * checked in parallel to the asynchronous completion of the previous | ||
889 | * update. Which is important since compositors need to figure out the | ||
890 | * composition of the next frame right after having submitted the | ||
891 | * current layout. | ||
892 | */ | ||
893 | |||
894 | wait_for_fences(dev, state); | ||
895 | |||
896 | drm_atomic_helper_commit_pre_planes(dev, state); | ||
897 | |||
898 | drm_atomic_helper_commit_planes(dev, state); | ||
899 | |||
900 | drm_atomic_helper_commit_post_planes(dev, state); | ||
901 | |||
902 | drm_atomic_helper_wait_for_vblanks(dev, state); | ||
903 | |||
904 | drm_atomic_helper_cleanup_planes(dev, state); | ||
905 | |||
906 | drm_atomic_state_free(state); | ||
907 | |||
908 | return 0; | ||
909 | } | ||
910 | EXPORT_SYMBOL(drm_atomic_helper_commit); | ||
911 | |||
912 | /** | ||
913 | * DOC: implementing async commit | ||
914 | * | ||
915 | * For now the atomic helpers don't support async commit directly. If there is | ||
916 | * real need it could be added though, using the dma-buf fence infrastructure | ||
917 | * for generic synchronization with outstanding rendering. | ||
918 | * | ||
919 | * For now drivers have to implement async commit themselves, with the following | ||
920 | * sequence being the recommended one: | ||
921 | * | ||
922 | * 1. Run drm_atomic_helper_prepare_planes() first. This is the only function | ||
923 | * which commit needs to call which can fail, so we want to run it first and | ||
924 | * synchronously. | ||
925 | * | ||
926 | * 2. Synchronize with any outstanding asynchronous commit worker threads which | ||
927 | * might be affected the new state update. This can be done by either cancelling | ||
928 | * or flushing the work items, depending upon whether the driver can deal with | ||
929 | * cancelled updates. Note that it is important to ensure that the framebuffer | ||
930 | * cleanup is still done when cancelling. | ||
931 | * | ||
932 | * For sufficient parallelism it is recommended to have a work item per crtc | ||
933 | * (for updates which don't touch global state) and a global one. Then we only | ||
934 | * need to synchronize with the crtc work items for changed crtcs and the global | ||
935 | * work item, which allows nice concurrent updates on disjoint sets of crtcs. | ||
936 | * | ||
937 | * 3. The software state is updated synchronously with | ||
938 | * drm_atomic_helper_swap_state. Doing this under the protection of all modeset | ||
939 | * locks means concurrent callers never see inconsistent state. And doing this | ||
940 | * while it's guaranteed that no relevant async worker runs means that async | ||
941 | * workers do not need grab any locks. Actually they must not grab locks, for | ||
942 | * otherwise the work flushing will deadlock. | ||
943 | * | ||
944 | * 4. Schedule a work item to do all subsequent steps, using the split-out | ||
945 | * commit helpers: a) pre-plane commit b) plane commit c) post-plane commit and | ||
946 | * then cleaning up the framebuffers after the old framebuffer is no longer | ||
947 | * being displayed. | ||
948 | */ | ||
949 | |||
950 | /** | ||
951 | * drm_atomic_helper_prepare_planes - prepare plane resources after commit | ||
952 | * @dev: DRM device | ||
953 | * @state: atomic state object with old state structures | ||
954 | * | ||
955 | * This function prepares plane state, specifically framebuffers, for the new | ||
956 | * configuration. If any failure is encountered this function will call | ||
957 | * ->cleanup_fb on any already successfully prepared framebuffer. | ||
958 | * | ||
959 | * Returns: | ||
960 | * 0 on success, negative error code on failure. | ||
961 | */ | ||
962 | int drm_atomic_helper_prepare_planes(struct drm_device *dev, | ||
963 | struct drm_atomic_state *state) | ||
964 | { | ||
965 | int nplanes = dev->mode_config.num_total_plane; | ||
966 | int ret, i; | ||
967 | |||
968 | for (i = 0; i < nplanes; i++) { | ||
969 | struct drm_plane_helper_funcs *funcs; | ||
970 | struct drm_plane *plane = state->planes[i]; | ||
971 | struct drm_framebuffer *fb; | ||
972 | |||
973 | if (!plane) | ||
974 | continue; | ||
975 | |||
976 | funcs = plane->helper_private; | ||
977 | |||
978 | fb = state->plane_states[i]->fb; | ||
979 | |||
980 | if (fb && funcs->prepare_fb) { | ||
981 | ret = funcs->prepare_fb(plane, fb); | ||
982 | if (ret) | ||
983 | goto fail; | ||
984 | } | ||
985 | } | ||
986 | |||
987 | return 0; | ||
988 | |||
989 | fail: | ||
990 | for (i--; i >= 0; i--) { | ||
991 | struct drm_plane_helper_funcs *funcs; | ||
992 | struct drm_plane *plane = state->planes[i]; | ||
993 | struct drm_framebuffer *fb; | ||
994 | |||
995 | if (!plane) | ||
996 | continue; | ||
997 | |||
998 | funcs = plane->helper_private; | ||
999 | |||
1000 | fb = state->plane_states[i]->fb; | ||
1001 | |||
1002 | if (fb && funcs->cleanup_fb) | ||
1003 | funcs->cleanup_fb(plane, fb); | ||
1004 | |||
1005 | } | ||
1006 | |||
1007 | return ret; | ||
1008 | } | ||
1009 | EXPORT_SYMBOL(drm_atomic_helper_prepare_planes); | ||
1010 | |||
1011 | /** | ||
1012 | * drm_atomic_helper_commit_planes - commit plane state | ||
1013 | * @dev: DRM device | ||
1014 | * @old_state: atomic state object with old state structures | ||
1015 | * | ||
1016 | * This function commits the new plane state using the plane and atomic helper | ||
1017 | * functions for planes and crtcs. It assumes that the atomic state has already | ||
1018 | * been pushed into the relevant object state pointers, since this step can no | ||
1019 | * longer fail. | ||
1020 | * | ||
1021 | * It still requires the global state object @old_state to know which planes and | ||
1022 | * crtcs need to be updated though. | ||
1023 | */ | ||
1024 | void drm_atomic_helper_commit_planes(struct drm_device *dev, | ||
1025 | struct drm_atomic_state *old_state) | ||
1026 | { | ||
1027 | int nplanes = dev->mode_config.num_total_plane; | ||
1028 | int ncrtcs = dev->mode_config.num_crtc; | ||
1029 | int i; | ||
1030 | |||
1031 | for (i = 0; i < ncrtcs; i++) { | ||
1032 | struct drm_crtc_helper_funcs *funcs; | ||
1033 | struct drm_crtc *crtc = old_state->crtcs[i]; | ||
1034 | |||
1035 | if (!crtc) | ||
1036 | continue; | ||
1037 | |||
1038 | funcs = crtc->helper_private; | ||
1039 | |||
1040 | if (!funcs || !funcs->atomic_begin) | ||
1041 | continue; | ||
1042 | |||
1043 | funcs->atomic_begin(crtc); | ||
1044 | } | ||
1045 | |||
1046 | for (i = 0; i < nplanes; i++) { | ||
1047 | struct drm_plane_helper_funcs *funcs; | ||
1048 | struct drm_plane *plane = old_state->planes[i]; | ||
1049 | struct drm_plane_state *old_plane_state; | ||
1050 | |||
1051 | if (!plane) | ||
1052 | continue; | ||
1053 | |||
1054 | funcs = plane->helper_private; | ||
1055 | |||
1056 | if (!funcs || !funcs->atomic_update) | ||
1057 | continue; | ||
1058 | |||
1059 | old_plane_state = old_state->plane_states[i]; | ||
1060 | |||
1061 | funcs->atomic_update(plane, old_plane_state); | ||
1062 | } | ||
1063 | |||
1064 | for (i = 0; i < ncrtcs; i++) { | ||
1065 | struct drm_crtc_helper_funcs *funcs; | ||
1066 | struct drm_crtc *crtc = old_state->crtcs[i]; | ||
1067 | |||
1068 | if (!crtc) | ||
1069 | continue; | ||
1070 | |||
1071 | funcs = crtc->helper_private; | ||
1072 | |||
1073 | if (!funcs || !funcs->atomic_flush) | ||
1074 | continue; | ||
1075 | |||
1076 | funcs->atomic_flush(crtc); | ||
1077 | } | ||
1078 | } | ||
1079 | EXPORT_SYMBOL(drm_atomic_helper_commit_planes); | ||
1080 | |||
1081 | /** | ||
1082 | * drm_atomic_helper_cleanup_planes - cleanup plane resources after commit | ||
1083 | * @dev: DRM device | ||
1084 | * @old_state: atomic state object with old state structures | ||
1085 | * | ||
1086 | * This function cleans up plane state, specifically framebuffers, from the old | ||
1087 | * configuration. Hence the old configuration must be perserved in @old_state to | ||
1088 | * be able to call this function. | ||
1089 | * | ||
1090 | * This function must also be called on the new state when the atomic update | ||
1091 | * fails at any point after calling drm_atomic_helper_prepare_planes(). | ||
1092 | */ | ||
1093 | void drm_atomic_helper_cleanup_planes(struct drm_device *dev, | ||
1094 | struct drm_atomic_state *old_state) | ||
1095 | { | ||
1096 | int nplanes = dev->mode_config.num_total_plane; | ||
1097 | int i; | ||
1098 | |||
1099 | for (i = 0; i < nplanes; i++) { | ||
1100 | struct drm_plane_helper_funcs *funcs; | ||
1101 | struct drm_plane *plane = old_state->planes[i]; | ||
1102 | struct drm_framebuffer *old_fb; | ||
1103 | |||
1104 | if (!plane) | ||
1105 | continue; | ||
1106 | |||
1107 | funcs = plane->helper_private; | ||
1108 | |||
1109 | old_fb = old_state->plane_states[i]->fb; | ||
1110 | |||
1111 | if (old_fb && funcs->cleanup_fb) | ||
1112 | funcs->cleanup_fb(plane, old_fb); | ||
1113 | } | ||
1114 | } | ||
1115 | EXPORT_SYMBOL(drm_atomic_helper_cleanup_planes); | ||
1116 | |||
1117 | /** | ||
1118 | * drm_atomic_helper_swap_state - store atomic state into current sw state | ||
1119 | * @dev: DRM device | ||
1120 | * @state: atomic state | ||
1121 | * | ||
1122 | * This function stores the atomic state into the current state pointers in all | ||
1123 | * driver objects. It should be called after all failing steps have been done | ||
1124 | * and succeeded, but before the actual hardware state is committed. | ||
1125 | * | ||
1126 | * For cleanup and error recovery the current state for all changed objects will | ||
1127 | * be swaped into @state. | ||
1128 | * | ||
1129 | * With that sequence it fits perfectly into the plane prepare/cleanup sequence: | ||
1130 | * | ||
1131 | * 1. Call drm_atomic_helper_prepare_planes() with the staged atomic state. | ||
1132 | * | ||
1133 | * 2. Do any other steps that might fail. | ||
1134 | * | ||
1135 | * 3. Put the staged state into the current state pointers with this function. | ||
1136 | * | ||
1137 | * 4. Actually commit the hardware state. | ||
1138 | * | ||
1139 | * 5. Call drm_atomic_helper_cleanup_planes with @state, which since step 3 | ||
1140 | * contains the old state. Also do any other cleanup required with that state. | ||
1141 | */ | ||
1142 | void drm_atomic_helper_swap_state(struct drm_device *dev, | ||
1143 | struct drm_atomic_state *state) | ||
1144 | { | ||
1145 | int i; | ||
1146 | |||
1147 | for (i = 0; i < dev->mode_config.num_connector; i++) { | ||
1148 | struct drm_connector *connector = state->connectors[i]; | ||
1149 | |||
1150 | if (!connector) | ||
1151 | continue; | ||
1152 | |||
1153 | connector->state->state = state; | ||
1154 | swap(state->connector_states[i], connector->state); | ||
1155 | connector->state->state = NULL; | ||
1156 | } | ||
1157 | |||
1158 | for (i = 0; i < dev->mode_config.num_crtc; i++) { | ||
1159 | struct drm_crtc *crtc = state->crtcs[i]; | ||
1160 | |||
1161 | if (!crtc) | ||
1162 | continue; | ||
1163 | |||
1164 | crtc->state->state = state; | ||
1165 | swap(state->crtc_states[i], crtc->state); | ||
1166 | crtc->state->state = NULL; | ||
1167 | } | ||
1168 | |||
1169 | for (i = 0; i < dev->mode_config.num_total_plane; i++) { | ||
1170 | struct drm_plane *plane = state->planes[i]; | ||
1171 | |||
1172 | if (!plane) | ||
1173 | continue; | ||
1174 | |||
1175 | plane->state->state = state; | ||
1176 | swap(state->plane_states[i], plane->state); | ||
1177 | plane->state->state = NULL; | ||
1178 | } | ||
1179 | } | ||
1180 | EXPORT_SYMBOL(drm_atomic_helper_swap_state); | ||
1181 | |||
1182 | /** | ||
1183 | * drm_atomic_helper_update_plane - Helper for primary plane update using atomic | ||
1184 | * @plane: plane object to update | ||
1185 | * @crtc: owning CRTC of owning plane | ||
1186 | * @fb: framebuffer to flip onto plane | ||
1187 | * @crtc_x: x offset of primary plane on crtc | ||
1188 | * @crtc_y: y offset of primary plane on crtc | ||
1189 | * @crtc_w: width of primary plane rectangle on crtc | ||
1190 | * @crtc_h: height of primary plane rectangle on crtc | ||
1191 | * @src_x: x offset of @fb for panning | ||
1192 | * @src_y: y offset of @fb for panning | ||
1193 | * @src_w: width of source rectangle in @fb | ||
1194 | * @src_h: height of source rectangle in @fb | ||
1195 | * | ||
1196 | * Provides a default plane update handler using the atomic driver interface. | ||
1197 | * | ||
1198 | * RETURNS: | ||
1199 | * Zero on success, error code on failure | ||
1200 | */ | ||
1201 | int drm_atomic_helper_update_plane(struct drm_plane *plane, | ||
1202 | struct drm_crtc *crtc, | ||
1203 | struct drm_framebuffer *fb, | ||
1204 | int crtc_x, int crtc_y, | ||
1205 | unsigned int crtc_w, unsigned int crtc_h, | ||
1206 | uint32_t src_x, uint32_t src_y, | ||
1207 | uint32_t src_w, uint32_t src_h) | ||
1208 | { | ||
1209 | struct drm_atomic_state *state; | ||
1210 | struct drm_plane_state *plane_state; | ||
1211 | int ret = 0; | ||
1212 | |||
1213 | state = drm_atomic_state_alloc(plane->dev); | ||
1214 | if (!state) | ||
1215 | return -ENOMEM; | ||
1216 | |||
1217 | state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc); | ||
1218 | retry: | ||
1219 | plane_state = drm_atomic_get_plane_state(state, plane); | ||
1220 | if (IS_ERR(plane_state)) { | ||
1221 | ret = PTR_ERR(plane_state); | ||
1222 | goto fail; | ||
1223 | } | ||
1224 | |||
1225 | ret = drm_atomic_set_crtc_for_plane(state, plane, crtc); | ||
1226 | if (ret != 0) | ||
1227 | goto fail; | ||
1228 | drm_atomic_set_fb_for_plane(plane_state, fb); | ||
1229 | plane_state->crtc_x = crtc_x; | ||
1230 | plane_state->crtc_y = crtc_y; | ||
1231 | plane_state->crtc_h = crtc_h; | ||
1232 | plane_state->crtc_w = crtc_w; | ||
1233 | plane_state->src_x = src_x; | ||
1234 | plane_state->src_y = src_y; | ||
1235 | plane_state->src_h = src_h; | ||
1236 | plane_state->src_w = src_w; | ||
1237 | |||
1238 | ret = drm_atomic_commit(state); | ||
1239 | if (ret != 0) | ||
1240 | goto fail; | ||
1241 | |||
1242 | /* Driver takes ownership of state on successful commit. */ | ||
1243 | return 0; | ||
1244 | fail: | ||
1245 | if (ret == -EDEADLK) | ||
1246 | goto backoff; | ||
1247 | |||
1248 | drm_atomic_state_free(state); | ||
1249 | |||
1250 | return ret; | ||
1251 | backoff: | ||
1252 | drm_atomic_state_clear(state); | ||
1253 | drm_atomic_legacy_backoff(state); | ||
1254 | |||
1255 | /* | ||
1256 | * Someone might have exchanged the framebuffer while we dropped locks | ||
1257 | * in the backoff code. We need to fix up the fb refcount tracking the | ||
1258 | * core does for us. | ||
1259 | */ | ||
1260 | plane->old_fb = plane->fb; | ||
1261 | |||
1262 | goto retry; | ||
1263 | } | ||
1264 | EXPORT_SYMBOL(drm_atomic_helper_update_plane); | ||
1265 | |||
1266 | /** | ||
1267 | * drm_atomic_helper_disable_plane - Helper for primary plane disable using * atomic | ||
1268 | * @plane: plane to disable | ||
1269 | * | ||
1270 | * Provides a default plane disable handler using the atomic driver interface. | ||
1271 | * | ||
1272 | * RETURNS: | ||
1273 | * Zero on success, error code on failure | ||
1274 | */ | ||
1275 | int drm_atomic_helper_disable_plane(struct drm_plane *plane) | ||
1276 | { | ||
1277 | struct drm_atomic_state *state; | ||
1278 | struct drm_plane_state *plane_state; | ||
1279 | int ret = 0; | ||
1280 | |||
1281 | /* | ||
1282 | * FIXME: Without plane->crtc set we can't get at the implicit legacy | ||
1283 | * acquire context. The real fix will be to wire the acquire ctx through | ||
1284 | * everywhere we need it, but meanwhile prevent chaos by just skipping | ||
1285 | * this noop. The critical case is the cursor ioctls which a) only grab | ||
1286 | * crtc/cursor-plane locks (so we need the crtc to get at the right | ||
1287 | * acquire context) and b) can try to disable the plane multiple times. | ||
1288 | */ | ||
1289 | if (!plane->crtc) | ||
1290 | return 0; | ||
1291 | |||
1292 | state = drm_atomic_state_alloc(plane->dev); | ||
1293 | if (!state) | ||
1294 | return -ENOMEM; | ||
1295 | |||
1296 | state->acquire_ctx = drm_modeset_legacy_acquire_ctx(plane->crtc); | ||
1297 | retry: | ||
1298 | plane_state = drm_atomic_get_plane_state(state, plane); | ||
1299 | if (IS_ERR(plane_state)) { | ||
1300 | ret = PTR_ERR(plane_state); | ||
1301 | goto fail; | ||
1302 | } | ||
1303 | |||
1304 | ret = drm_atomic_set_crtc_for_plane(state, plane, NULL); | ||
1305 | if (ret != 0) | ||
1306 | goto fail; | ||
1307 | drm_atomic_set_fb_for_plane(plane_state, NULL); | ||
1308 | plane_state->crtc_x = 0; | ||
1309 | plane_state->crtc_y = 0; | ||
1310 | plane_state->crtc_h = 0; | ||
1311 | plane_state->crtc_w = 0; | ||
1312 | plane_state->src_x = 0; | ||
1313 | plane_state->src_y = 0; | ||
1314 | plane_state->src_h = 0; | ||
1315 | plane_state->src_w = 0; | ||
1316 | |||
1317 | ret = drm_atomic_commit(state); | ||
1318 | if (ret != 0) | ||
1319 | goto fail; | ||
1320 | |||
1321 | /* Driver takes ownership of state on successful commit. */ | ||
1322 | return 0; | ||
1323 | fail: | ||
1324 | if (ret == -EDEADLK) | ||
1325 | goto backoff; | ||
1326 | |||
1327 | drm_atomic_state_free(state); | ||
1328 | |||
1329 | return ret; | ||
1330 | backoff: | ||
1331 | drm_atomic_state_clear(state); | ||
1332 | drm_atomic_legacy_backoff(state); | ||
1333 | |||
1334 | /* | ||
1335 | * Someone might have exchanged the framebuffer while we dropped locks | ||
1336 | * in the backoff code. We need to fix up the fb refcount tracking the | ||
1337 | * core does for us. | ||
1338 | */ | ||
1339 | plane->old_fb = plane->fb; | ||
1340 | |||
1341 | goto retry; | ||
1342 | } | ||
1343 | EXPORT_SYMBOL(drm_atomic_helper_disable_plane); | ||
1344 | |||
1345 | static int update_output_state(struct drm_atomic_state *state, | ||
1346 | struct drm_mode_set *set) | ||
1347 | { | ||
1348 | struct drm_device *dev = set->crtc->dev; | ||
1349 | struct drm_connector_state *conn_state; | ||
1350 | int ncrtcs = state->dev->mode_config.num_crtc; | ||
1351 | int ret, i, j; | ||
1352 | |||
1353 | ret = drm_modeset_lock(&dev->mode_config.connection_mutex, | ||
1354 | state->acquire_ctx); | ||
1355 | if (ret) | ||
1356 | return ret; | ||
1357 | |||
1358 | /* First grab all affected connector/crtc states. */ | ||
1359 | for (i = 0; i < set->num_connectors; i++) { | ||
1360 | conn_state = drm_atomic_get_connector_state(state, | ||
1361 | set->connectors[i]); | ||
1362 | if (IS_ERR(conn_state)) | ||
1363 | return PTR_ERR(conn_state); | ||
1364 | } | ||
1365 | |||
1366 | for (i = 0; i < ncrtcs; i++) { | ||
1367 | struct drm_crtc *crtc = state->crtcs[i]; | ||
1368 | |||
1369 | if (!crtc) | ||
1370 | continue; | ||
1371 | |||
1372 | ret = drm_atomic_add_affected_connectors(state, crtc); | ||
1373 | if (ret) | ||
1374 | return ret; | ||
1375 | } | ||
1376 | |||
1377 | /* Then recompute connector->crtc links and crtc enabling state. */ | ||
1378 | for (i = 0; i < state->num_connector; i++) { | ||
1379 | struct drm_connector *connector; | ||
1380 | |||
1381 | connector = state->connectors[i]; | ||
1382 | conn_state = state->connector_states[i]; | ||
1383 | |||
1384 | if (!connector) | ||
1385 | continue; | ||
1386 | |||
1387 | if (conn_state->crtc == set->crtc) { | ||
1388 | ret = drm_atomic_set_crtc_for_connector(conn_state, | ||
1389 | NULL); | ||
1390 | if (ret) | ||
1391 | return ret; | ||
1392 | } | ||
1393 | |||
1394 | for (j = 0; j < set->num_connectors; j++) { | ||
1395 | if (set->connectors[j] == connector) { | ||
1396 | ret = drm_atomic_set_crtc_for_connector(conn_state, | ||
1397 | set->crtc); | ||
1398 | if (ret) | ||
1399 | return ret; | ||
1400 | break; | ||
1401 | } | ||
1402 | } | ||
1403 | } | ||
1404 | |||
1405 | for (i = 0; i < ncrtcs; i++) { | ||
1406 | struct drm_crtc *crtc = state->crtcs[i]; | ||
1407 | struct drm_crtc_state *crtc_state = state->crtc_states[i]; | ||
1408 | |||
1409 | if (!crtc) | ||
1410 | continue; | ||
1411 | |||
1412 | /* Don't update ->enable for the CRTC in the set_config request, | ||
1413 | * since a mismatch would indicate a bug in the upper layers. | ||
1414 | * The actual modeset code later on will catch any | ||
1415 | * inconsistencies here. */ | ||
1416 | if (crtc == set->crtc) | ||
1417 | continue; | ||
1418 | |||
1419 | crtc_state->enable = | ||
1420 | drm_atomic_connectors_for_crtc(state, crtc); | ||
1421 | } | ||
1422 | |||
1423 | return 0; | ||
1424 | } | ||
1425 | |||
1426 | /** | ||
1427 | * drm_atomic_helper_set_config - set a new config from userspace | ||
1428 | * @set: mode set configuration | ||
1429 | * | ||
1430 | * Provides a default crtc set_config handler using the atomic driver interface. | ||
1431 | * | ||
1432 | * Returns: | ||
1433 | * Returns 0 on success, negative errno numbers on failure. | ||
1434 | */ | ||
1435 | int drm_atomic_helper_set_config(struct drm_mode_set *set) | ||
1436 | { | ||
1437 | struct drm_atomic_state *state; | ||
1438 | struct drm_crtc *crtc = set->crtc; | ||
1439 | struct drm_crtc_state *crtc_state; | ||
1440 | struct drm_plane_state *primary_state; | ||
1441 | int ret = 0; | ||
1442 | |||
1443 | state = drm_atomic_state_alloc(crtc->dev); | ||
1444 | if (!state) | ||
1445 | return -ENOMEM; | ||
1446 | |||
1447 | state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc); | ||
1448 | retry: | ||
1449 | crtc_state = drm_atomic_get_crtc_state(state, crtc); | ||
1450 | if (IS_ERR(crtc_state)) { | ||
1451 | ret = PTR_ERR(crtc_state); | ||
1452 | goto fail; | ||
1453 | } | ||
1454 | |||
1455 | primary_state = drm_atomic_get_plane_state(state, crtc->primary); | ||
1456 | if (IS_ERR(primary_state)) { | ||
1457 | ret = PTR_ERR(primary_state); | ||
1458 | goto fail; | ||
1459 | } | ||
1460 | |||
1461 | if (!set->mode) { | ||
1462 | WARN_ON(set->fb); | ||
1463 | WARN_ON(set->num_connectors); | ||
1464 | |||
1465 | crtc_state->enable = false; | ||
1466 | |||
1467 | ret = drm_atomic_set_crtc_for_plane(state, crtc->primary, NULL); | ||
1468 | if (ret != 0) | ||
1469 | goto fail; | ||
1470 | |||
1471 | drm_atomic_set_fb_for_plane(primary_state, NULL); | ||
1472 | |||
1473 | goto commit; | ||
1474 | } | ||
1475 | |||
1476 | WARN_ON(!set->fb); | ||
1477 | WARN_ON(!set->num_connectors); | ||
1478 | |||
1479 | crtc_state->enable = true; | ||
1480 | drm_mode_copy(&crtc_state->mode, set->mode); | ||
1481 | |||
1482 | ret = drm_atomic_set_crtc_for_plane(state, crtc->primary, crtc); | ||
1483 | if (ret != 0) | ||
1484 | goto fail; | ||
1485 | drm_atomic_set_fb_for_plane(primary_state, set->fb); | ||
1486 | primary_state->crtc_x = 0; | ||
1487 | primary_state->crtc_y = 0; | ||
1488 | primary_state->crtc_h = set->mode->vdisplay; | ||
1489 | primary_state->crtc_w = set->mode->hdisplay; | ||
1490 | primary_state->src_x = set->x << 16; | ||
1491 | primary_state->src_y = set->y << 16; | ||
1492 | primary_state->src_h = set->mode->vdisplay << 16; | ||
1493 | primary_state->src_w = set->mode->hdisplay << 16; | ||
1494 | |||
1495 | commit: | ||
1496 | ret = update_output_state(state, set); | ||
1497 | if (ret) | ||
1498 | goto fail; | ||
1499 | |||
1500 | ret = drm_atomic_commit(state); | ||
1501 | if (ret != 0) | ||
1502 | goto fail; | ||
1503 | |||
1504 | /* Driver takes ownership of state on successful commit. */ | ||
1505 | return 0; | ||
1506 | fail: | ||
1507 | if (ret == -EDEADLK) | ||
1508 | goto backoff; | ||
1509 | |||
1510 | drm_atomic_state_free(state); | ||
1511 | |||
1512 | return ret; | ||
1513 | backoff: | ||
1514 | drm_atomic_state_clear(state); | ||
1515 | drm_atomic_legacy_backoff(state); | ||
1516 | |||
1517 | /* | ||
1518 | * Someone might have exchanged the framebuffer while we dropped locks | ||
1519 | * in the backoff code. We need to fix up the fb refcount tracking the | ||
1520 | * core does for us. | ||
1521 | */ | ||
1522 | crtc->primary->old_fb = crtc->primary->fb; | ||
1523 | |||
1524 | goto retry; | ||
1525 | } | ||
1526 | EXPORT_SYMBOL(drm_atomic_helper_set_config); | ||
1527 | |||
1528 | /** | ||
1529 | * drm_atomic_helper_crtc_set_property - helper for crtc prorties | ||
1530 | * @crtc: DRM crtc | ||
1531 | * @property: DRM property | ||
1532 | * @val: value of property | ||
1533 | * | ||
1534 | * Provides a default plane disablle handler using the atomic driver interface. | ||
1535 | * | ||
1536 | * RETURNS: | ||
1537 | * Zero on success, error code on failure | ||
1538 | */ | ||
1539 | int | ||
1540 | drm_atomic_helper_crtc_set_property(struct drm_crtc *crtc, | ||
1541 | struct drm_property *property, | ||
1542 | uint64_t val) | ||
1543 | { | ||
1544 | struct drm_atomic_state *state; | ||
1545 | struct drm_crtc_state *crtc_state; | ||
1546 | int ret = 0; | ||
1547 | |||
1548 | state = drm_atomic_state_alloc(crtc->dev); | ||
1549 | if (!state) | ||
1550 | return -ENOMEM; | ||
1551 | |||
1552 | /* ->set_property is always called with all locks held. */ | ||
1553 | state->acquire_ctx = crtc->dev->mode_config.acquire_ctx; | ||
1554 | retry: | ||
1555 | crtc_state = drm_atomic_get_crtc_state(state, crtc); | ||
1556 | if (IS_ERR(crtc_state)) { | ||
1557 | ret = PTR_ERR(crtc_state); | ||
1558 | goto fail; | ||
1559 | } | ||
1560 | |||
1561 | ret = crtc->funcs->atomic_set_property(crtc, crtc_state, | ||
1562 | property, val); | ||
1563 | if (ret) | ||
1564 | goto fail; | ||
1565 | |||
1566 | ret = drm_atomic_commit(state); | ||
1567 | if (ret != 0) | ||
1568 | goto fail; | ||
1569 | |||
1570 | /* Driver takes ownership of state on successful commit. */ | ||
1571 | return 0; | ||
1572 | fail: | ||
1573 | if (ret == -EDEADLK) | ||
1574 | goto backoff; | ||
1575 | |||
1576 | drm_atomic_state_free(state); | ||
1577 | |||
1578 | return ret; | ||
1579 | backoff: | ||
1580 | drm_atomic_state_clear(state); | ||
1581 | drm_atomic_legacy_backoff(state); | ||
1582 | |||
1583 | goto retry; | ||
1584 | } | ||
1585 | EXPORT_SYMBOL(drm_atomic_helper_crtc_set_property); | ||
1586 | |||
1587 | /** | ||
1588 | * drm_atomic_helper_plane_set_property - helper for plane prorties | ||
1589 | * @plane: DRM plane | ||
1590 | * @property: DRM property | ||
1591 | * @val: value of property | ||
1592 | * | ||
1593 | * Provides a default plane disable handler using the atomic driver interface. | ||
1594 | * | ||
1595 | * RETURNS: | ||
1596 | * Zero on success, error code on failure | ||
1597 | */ | ||
1598 | int | ||
1599 | drm_atomic_helper_plane_set_property(struct drm_plane *plane, | ||
1600 | struct drm_property *property, | ||
1601 | uint64_t val) | ||
1602 | { | ||
1603 | struct drm_atomic_state *state; | ||
1604 | struct drm_plane_state *plane_state; | ||
1605 | int ret = 0; | ||
1606 | |||
1607 | state = drm_atomic_state_alloc(plane->dev); | ||
1608 | if (!state) | ||
1609 | return -ENOMEM; | ||
1610 | |||
1611 | /* ->set_property is always called with all locks held. */ | ||
1612 | state->acquire_ctx = plane->dev->mode_config.acquire_ctx; | ||
1613 | retry: | ||
1614 | plane_state = drm_atomic_get_plane_state(state, plane); | ||
1615 | if (IS_ERR(plane_state)) { | ||
1616 | ret = PTR_ERR(plane_state); | ||
1617 | goto fail; | ||
1618 | } | ||
1619 | |||
1620 | ret = plane->funcs->atomic_set_property(plane, plane_state, | ||
1621 | property, val); | ||
1622 | if (ret) | ||
1623 | goto fail; | ||
1624 | |||
1625 | ret = drm_atomic_commit(state); | ||
1626 | if (ret != 0) | ||
1627 | goto fail; | ||
1628 | |||
1629 | /* Driver takes ownership of state on successful commit. */ | ||
1630 | return 0; | ||
1631 | fail: | ||
1632 | if (ret == -EDEADLK) | ||
1633 | goto backoff; | ||
1634 | |||
1635 | drm_atomic_state_free(state); | ||
1636 | |||
1637 | return ret; | ||
1638 | backoff: | ||
1639 | drm_atomic_state_clear(state); | ||
1640 | drm_atomic_legacy_backoff(state); | ||
1641 | |||
1642 | goto retry; | ||
1643 | } | ||
1644 | EXPORT_SYMBOL(drm_atomic_helper_plane_set_property); | ||
1645 | |||
1646 | /** | ||
1647 | * drm_atomic_helper_connector_set_property - helper for connector prorties | ||
1648 | * @connector: DRM connector | ||
1649 | * @property: DRM property | ||
1650 | * @val: value of property | ||
1651 | * | ||
1652 | * Provides a default plane disablle handler using the atomic driver interface. | ||
1653 | * | ||
1654 | * RETURNS: | ||
1655 | * Zero on success, error code on failure | ||
1656 | */ | ||
1657 | int | ||
1658 | drm_atomic_helper_connector_set_property(struct drm_connector *connector, | ||
1659 | struct drm_property *property, | ||
1660 | uint64_t val) | ||
1661 | { | ||
1662 | struct drm_atomic_state *state; | ||
1663 | struct drm_connector_state *connector_state; | ||
1664 | int ret = 0; | ||
1665 | |||
1666 | state = drm_atomic_state_alloc(connector->dev); | ||
1667 | if (!state) | ||
1668 | return -ENOMEM; | ||
1669 | |||
1670 | /* ->set_property is always called with all locks held. */ | ||
1671 | state->acquire_ctx = connector->dev->mode_config.acquire_ctx; | ||
1672 | retry: | ||
1673 | connector_state = drm_atomic_get_connector_state(state, connector); | ||
1674 | if (IS_ERR(connector_state)) { | ||
1675 | ret = PTR_ERR(connector_state); | ||
1676 | goto fail; | ||
1677 | } | ||
1678 | |||
1679 | ret = connector->funcs->atomic_set_property(connector, connector_state, | ||
1680 | property, val); | ||
1681 | if (ret) | ||
1682 | goto fail; | ||
1683 | |||
1684 | ret = drm_atomic_commit(state); | ||
1685 | if (ret != 0) | ||
1686 | goto fail; | ||
1687 | |||
1688 | /* Driver takes ownership of state on successful commit. */ | ||
1689 | return 0; | ||
1690 | fail: | ||
1691 | if (ret == -EDEADLK) | ||
1692 | goto backoff; | ||
1693 | |||
1694 | drm_atomic_state_free(state); | ||
1695 | |||
1696 | return ret; | ||
1697 | backoff: | ||
1698 | drm_atomic_state_clear(state); | ||
1699 | drm_atomic_legacy_backoff(state); | ||
1700 | |||
1701 | goto retry; | ||
1702 | } | ||
1703 | EXPORT_SYMBOL(drm_atomic_helper_connector_set_property); | ||
1704 | |||
1705 | /** | ||
1706 | * drm_atomic_helper_page_flip - execute a legacy page flip | ||
1707 | * @crtc: DRM crtc | ||
1708 | * @fb: DRM framebuffer | ||
1709 | * @event: optional DRM event to signal upon completion | ||
1710 | * @flags: flip flags for non-vblank sync'ed updates | ||
1711 | * | ||
1712 | * Provides a default page flip implementation using the atomic driver interface. | ||
1713 | * | ||
1714 | * Note that for now so called async page flips (i.e. updates which are not | ||
1715 | * synchronized to vblank) are not supported, since the atomic interfaces have | ||
1716 | * no provisions for this yet. | ||
1717 | * | ||
1718 | * Returns: | ||
1719 | * Returns 0 on success, negative errno numbers on failure. | ||
1720 | */ | ||
1721 | int drm_atomic_helper_page_flip(struct drm_crtc *crtc, | ||
1722 | struct drm_framebuffer *fb, | ||
1723 | struct drm_pending_vblank_event *event, | ||
1724 | uint32_t flags) | ||
1725 | { | ||
1726 | struct drm_plane *plane = crtc->primary; | ||
1727 | struct drm_atomic_state *state; | ||
1728 | struct drm_plane_state *plane_state; | ||
1729 | struct drm_crtc_state *crtc_state; | ||
1730 | int ret = 0; | ||
1731 | |||
1732 | if (flags & DRM_MODE_PAGE_FLIP_ASYNC) | ||
1733 | return -EINVAL; | ||
1734 | |||
1735 | state = drm_atomic_state_alloc(plane->dev); | ||
1736 | if (!state) | ||
1737 | return -ENOMEM; | ||
1738 | |||
1739 | state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc); | ||
1740 | retry: | ||
1741 | crtc_state = drm_atomic_get_crtc_state(state, crtc); | ||
1742 | if (IS_ERR(crtc_state)) { | ||
1743 | ret = PTR_ERR(crtc_state); | ||
1744 | goto fail; | ||
1745 | } | ||
1746 | crtc_state->event = event; | ||
1747 | |||
1748 | plane_state = drm_atomic_get_plane_state(state, plane); | ||
1749 | if (IS_ERR(plane_state)) { | ||
1750 | ret = PTR_ERR(plane_state); | ||
1751 | goto fail; | ||
1752 | } | ||
1753 | |||
1754 | ret = drm_atomic_set_crtc_for_plane(state, plane, crtc); | ||
1755 | if (ret != 0) | ||
1756 | goto fail; | ||
1757 | drm_atomic_set_fb_for_plane(plane_state, fb); | ||
1758 | |||
1759 | ret = drm_atomic_async_commit(state); | ||
1760 | if (ret != 0) | ||
1761 | goto fail; | ||
1762 | |||
1763 | /* TODO: ->page_flip is the only driver callback where the core | ||
1764 | * doesn't update plane->fb. For now patch it up here. */ | ||
1765 | plane->fb = plane->state->fb; | ||
1766 | |||
1767 | /* Driver takes ownership of state on successful async commit. */ | ||
1768 | return 0; | ||
1769 | fail: | ||
1770 | if (ret == -EDEADLK) | ||
1771 | goto backoff; | ||
1772 | |||
1773 | drm_atomic_state_free(state); | ||
1774 | |||
1775 | return ret; | ||
1776 | backoff: | ||
1777 | drm_atomic_state_clear(state); | ||
1778 | drm_atomic_legacy_backoff(state); | ||
1779 | |||
1780 | /* | ||
1781 | * Someone might have exchanged the framebuffer while we dropped locks | ||
1782 | * in the backoff code. We need to fix up the fb refcount tracking the | ||
1783 | * core does for us. | ||
1784 | */ | ||
1785 | plane->old_fb = plane->fb; | ||
1786 | |||
1787 | goto retry; | ||
1788 | } | ||
1789 | EXPORT_SYMBOL(drm_atomic_helper_page_flip); | ||
1790 | |||
1791 | /** | ||
1792 | * DOC: atomic state reset and initialization | ||
1793 | * | ||
1794 | * Both the drm core and the atomic helpers assume that there is always the full | ||
1795 | * and correct atomic software state for all connectors, CRTCs and planes | ||
1796 | * available. Which is a bit a problem on driver load and also after system | ||
1797 | * suspend. One way to solve this is to have a hardware state read-out | ||
1798 | * infrastructure which reconstructs the full software state (e.g. the i915 | ||
1799 | * driver). | ||
1800 | * | ||
1801 | * The simpler solution is to just reset the software state to everything off, | ||
1802 | * which is easiest to do by calling drm_mode_config_reset(). To facilitate this | ||
1803 | * the atomic helpers provide default reset implementations for all hooks. | ||
1804 | */ | ||
1805 | |||
1806 | /** | ||
1807 | * drm_atomic_helper_crtc_reset - default ->reset hook for CRTCs | ||
1808 | * @crtc: drm CRTC | ||
1809 | * | ||
1810 | * Resets the atomic state for @crtc by freeing the state pointer (which might | ||
1811 | * be NULL, e.g. at driver load time) and allocating a new empty state object. | ||
1812 | */ | ||
1813 | void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc) | ||
1814 | { | ||
1815 | kfree(crtc->state); | ||
1816 | crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL); | ||
1817 | } | ||
1818 | EXPORT_SYMBOL(drm_atomic_helper_crtc_reset); | ||
1819 | |||
1820 | /** | ||
1821 | * drm_atomic_helper_crtc_duplicate_state - default state duplicate hook | ||
1822 | * @crtc: drm CRTC | ||
1823 | * | ||
1824 | * Default CRTC state duplicate hook for drivers which don't have their own | ||
1825 | * subclassed CRTC state structure. | ||
1826 | */ | ||
1827 | struct drm_crtc_state * | ||
1828 | drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc) | ||
1829 | { | ||
1830 | struct drm_crtc_state *state; | ||
1831 | |||
1832 | if (WARN_ON(!crtc->state)) | ||
1833 | return NULL; | ||
1834 | |||
1835 | state = kmemdup(crtc->state, sizeof(*crtc->state), GFP_KERNEL); | ||
1836 | |||
1837 | if (state) { | ||
1838 | state->mode_changed = false; | ||
1839 | state->planes_changed = false; | ||
1840 | state->event = NULL; | ||
1841 | } | ||
1842 | |||
1843 | return state; | ||
1844 | } | ||
1845 | EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state); | ||
1846 | |||
1847 | /** | ||
1848 | * drm_atomic_helper_crtc_destroy_state - default state destroy hook | ||
1849 | * @crtc: drm CRTC | ||
1850 | * @state: CRTC state object to release | ||
1851 | * | ||
1852 | * Default CRTC state destroy hook for drivers which don't have their own | ||
1853 | * subclassed CRTC state structure. | ||
1854 | */ | ||
1855 | void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc, | ||
1856 | struct drm_crtc_state *state) | ||
1857 | { | ||
1858 | kfree(state); | ||
1859 | } | ||
1860 | EXPORT_SYMBOL(drm_atomic_helper_crtc_destroy_state); | ||
1861 | |||
1862 | /** | ||
1863 | * drm_atomic_helper_plane_reset - default ->reset hook for planes | ||
1864 | * @plane: drm plane | ||
1865 | * | ||
1866 | * Resets the atomic state for @plane by freeing the state pointer (which might | ||
1867 | * be NULL, e.g. at driver load time) and allocating a new empty state object. | ||
1868 | */ | ||
1869 | void drm_atomic_helper_plane_reset(struct drm_plane *plane) | ||
1870 | { | ||
1871 | if (plane->state && plane->state->fb) | ||
1872 | drm_framebuffer_unreference(plane->state->fb); | ||
1873 | |||
1874 | kfree(plane->state); | ||
1875 | plane->state = kzalloc(sizeof(*plane->state), GFP_KERNEL); | ||
1876 | } | ||
1877 | EXPORT_SYMBOL(drm_atomic_helper_plane_reset); | ||
1878 | |||
1879 | /** | ||
1880 | * drm_atomic_helper_plane_duplicate_state - default state duplicate hook | ||
1881 | * @plane: drm plane | ||
1882 | * | ||
1883 | * Default plane state duplicate hook for drivers which don't have their own | ||
1884 | * subclassed plane state structure. | ||
1885 | */ | ||
1886 | struct drm_plane_state * | ||
1887 | drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane) | ||
1888 | { | ||
1889 | struct drm_plane_state *state; | ||
1890 | |||
1891 | if (WARN_ON(!plane->state)) | ||
1892 | return NULL; | ||
1893 | |||
1894 | state = kmemdup(plane->state, sizeof(*plane->state), GFP_KERNEL); | ||
1895 | |||
1896 | if (state && state->fb) | ||
1897 | drm_framebuffer_reference(state->fb); | ||
1898 | |||
1899 | return state; | ||
1900 | } | ||
1901 | EXPORT_SYMBOL(drm_atomic_helper_plane_duplicate_state); | ||
1902 | |||
1903 | /** | ||
1904 | * drm_atomic_helper_plane_destroy_state - default state destroy hook | ||
1905 | * @plane: drm plane | ||
1906 | * @state: plane state object to release | ||
1907 | * | ||
1908 | * Default plane state destroy hook for drivers which don't have their own | ||
1909 | * subclassed plane state structure. | ||
1910 | */ | ||
1911 | void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane, | ||
1912 | struct drm_plane_state *state) | ||
1913 | { | ||
1914 | if (state->fb) | ||
1915 | drm_framebuffer_unreference(state->fb); | ||
1916 | |||
1917 | kfree(state); | ||
1918 | } | ||
1919 | EXPORT_SYMBOL(drm_atomic_helper_plane_destroy_state); | ||
1920 | |||
1921 | /** | ||
1922 | * drm_atomic_helper_connector_reset - default ->reset hook for connectors | ||
1923 | * @connector: drm connector | ||
1924 | * | ||
1925 | * Resets the atomic state for @connector by freeing the state pointer (which | ||
1926 | * might be NULL, e.g. at driver load time) and allocating a new empty state | ||
1927 | * object. | ||
1928 | */ | ||
1929 | void drm_atomic_helper_connector_reset(struct drm_connector *connector) | ||
1930 | { | ||
1931 | kfree(connector->state); | ||
1932 | connector->state = kzalloc(sizeof(*connector->state), GFP_KERNEL); | ||
1933 | } | ||
1934 | EXPORT_SYMBOL(drm_atomic_helper_connector_reset); | ||
1935 | |||
1936 | /** | ||
1937 | * drm_atomic_helper_connector_duplicate_state - default state duplicate hook | ||
1938 | * @connector: drm connector | ||
1939 | * | ||
1940 | * Default connector state duplicate hook for drivers which don't have their own | ||
1941 | * subclassed connector state structure. | ||
1942 | */ | ||
1943 | struct drm_connector_state * | ||
1944 | drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector) | ||
1945 | { | ||
1946 | if (WARN_ON(!connector->state)) | ||
1947 | return NULL; | ||
1948 | |||
1949 | return kmemdup(connector->state, sizeof(*connector->state), GFP_KERNEL); | ||
1950 | } | ||
1951 | EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state); | ||
1952 | |||
1953 | /** | ||
1954 | * drm_atomic_helper_connector_destroy_state - default state destroy hook | ||
1955 | * @connector: drm connector | ||
1956 | * @state: connector state object to release | ||
1957 | * | ||
1958 | * Default connector state destroy hook for drivers which don't have their own | ||
1959 | * subclassed connector state structure. | ||
1960 | */ | ||
1961 | void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector, | ||
1962 | struct drm_connector_state *state) | ||
1963 | { | ||
1964 | kfree(state); | ||
1965 | } | ||
1966 | EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state); | ||