]>
Commit | Line | Data |
---|---|---|
9ef8a9dc SV |
1 | /* |
2 | * Copyright (C) 2018 Intel Corp. | |
3 | * | |
4 | * Permission is hereby granted, free of charge, to any person obtaining a | |
5 | * copy of this software and associated documentation files (the "Software"), | |
6 | * to deal in the Software without restriction, including without limitation | |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
8 | * and/or sell copies of the Software, and to permit persons to whom the | |
9 | * Software is furnished to do so, subject to the following conditions: | |
10 | * | |
11 | * The above copyright notice and this permission notice shall be included in | |
12 | * all copies or substantial portions of the Software. | |
13 | * | |
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
20 | * OTHER DEALINGS IN THE SOFTWARE. | |
21 | * | |
22 | * Authors: | |
23 | * Rob Clark <robdclark@gmail.com> | |
24 | * Daniel Vetter <daniel.vetter@ffwll.ch> | |
25 | */ | |
26 | ||
27 | #include <drm/drm_atomic_state_helper.h> | |
28 | #include <drm/drm_crtc.h> | |
29 | #include <drm/drm_plane.h> | |
30 | #include <drm/drm_connector.h> | |
31 | #include <drm/drm_atomic.h> | |
32 | #include <drm/drm_device.h> | |
e482ae9b | 33 | #include <drm/drm_writeback.h> |
9ef8a9dc SV |
34 | |
35 | #include <linux/slab.h> | |
36 | #include <linux/dma-fence.h> | |
37 | ||
38 | /** | |
39 | * DOC: atomic state reset and initialization | |
40 | * | |
41 | * Both the drm core and the atomic helpers assume that there is always the full | |
42 | * and correct atomic software state for all connectors, CRTCs and planes | |
43 | * available. Which is a bit a problem on driver load and also after system | |
44 | * suspend. One way to solve this is to have a hardware state read-out | |
45 | * infrastructure which reconstructs the full software state (e.g. the i915 | |
46 | * driver). | |
47 | * | |
48 | * The simpler solution is to just reset the software state to everything off, | |
49 | * which is easiest to do by calling drm_mode_config_reset(). To facilitate this | |
50 | * the atomic helpers provide default reset implementations for all hooks. | |
51 | * | |
52 | * On the upside the precise state tracking of atomic simplifies system suspend | |
53 | * and resume a lot. For drivers using drm_mode_config_reset() a complete recipe | |
54 | * is implemented in drm_atomic_helper_suspend() and drm_atomic_helper_resume(). | |
55 | * For other drivers the building blocks are split out, see the documentation | |
56 | * for these functions. | |
57 | */ | |
58 | ||
7d26097b ML |
59 | /** |
60 | * __drm_atomic_helper_crtc_reset - reset state on CRTC | |
61 | * @crtc: drm CRTC | |
62 | * @crtc_state: CRTC state to assign | |
63 | * | |
64 | * Initializes the newly allocated @crtc_state and assigns it to | |
65 | * the &drm_crtc->state pointer of @crtc, usually required when | |
66 | * initializing the drivers or when called from the &drm_crtc_funcs.reset | |
67 | * hook. | |
68 | * | |
69 | * This is useful for drivers that subclass the CRTC state. | |
70 | */ | |
71 | void | |
72 | __drm_atomic_helper_crtc_reset(struct drm_crtc *crtc, | |
73 | struct drm_crtc_state *crtc_state) | |
74 | { | |
75 | if (crtc_state) | |
76 | crtc_state->crtc = crtc; | |
77 | ||
78 | crtc->state = crtc_state; | |
79 | } | |
80 | EXPORT_SYMBOL(__drm_atomic_helper_crtc_reset); | |
81 | ||
9ef8a9dc SV |
82 | /** |
83 | * drm_atomic_helper_crtc_reset - default &drm_crtc_funcs.reset hook for CRTCs | |
84 | * @crtc: drm CRTC | |
85 | * | |
86 | * Resets the atomic state for @crtc by freeing the state pointer (which might | |
87 | * be NULL, e.g. at driver load time) and allocating a new empty state object. | |
88 | */ | |
89 | void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc) | |
90 | { | |
7d26097b ML |
91 | struct drm_crtc_state *crtc_state = |
92 | kzalloc(sizeof(*crtc->state), GFP_KERNEL); | |
9ef8a9dc SV |
93 | |
94 | if (crtc->state) | |
7d26097b ML |
95 | crtc->funcs->atomic_destroy_state(crtc, crtc->state); |
96 | ||
97 | __drm_atomic_helper_crtc_reset(crtc, crtc_state); | |
9ef8a9dc SV |
98 | } |
99 | EXPORT_SYMBOL(drm_atomic_helper_crtc_reset); | |
100 | ||
101 | /** | |
102 | * __drm_atomic_helper_crtc_duplicate_state - copy atomic CRTC state | |
103 | * @crtc: CRTC object | |
104 | * @state: atomic CRTC state | |
105 | * | |
106 | * Copies atomic state from a CRTC's current state and resets inferred values. | |
107 | * This is useful for drivers that subclass the CRTC state. | |
108 | */ | |
109 | void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc, | |
110 | struct drm_crtc_state *state) | |
111 | { | |
112 | memcpy(state, crtc->state, sizeof(*state)); | |
113 | ||
114 | if (state->mode_blob) | |
115 | drm_property_blob_get(state->mode_blob); | |
116 | if (state->degamma_lut) | |
117 | drm_property_blob_get(state->degamma_lut); | |
118 | if (state->ctm) | |
119 | drm_property_blob_get(state->ctm); | |
120 | if (state->gamma_lut) | |
121 | drm_property_blob_get(state->gamma_lut); | |
122 | state->mode_changed = false; | |
123 | state->active_changed = false; | |
124 | state->planes_changed = false; | |
125 | state->connectors_changed = false; | |
126 | state->color_mgmt_changed = false; | |
127 | state->zpos_changed = false; | |
128 | state->commit = NULL; | |
129 | state->event = NULL; | |
130 | state->pageflip_flags = 0; | |
131 | } | |
132 | EXPORT_SYMBOL(__drm_atomic_helper_crtc_duplicate_state); | |
133 | ||
134 | /** | |
135 | * drm_atomic_helper_crtc_duplicate_state - default state duplicate hook | |
136 | * @crtc: drm CRTC | |
137 | * | |
138 | * Default CRTC state duplicate hook for drivers which don't have their own | |
139 | * subclassed CRTC state structure. | |
140 | */ | |
141 | struct drm_crtc_state * | |
142 | drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc) | |
143 | { | |
144 | struct drm_crtc_state *state; | |
145 | ||
146 | if (WARN_ON(!crtc->state)) | |
147 | return NULL; | |
148 | ||
149 | state = kmalloc(sizeof(*state), GFP_KERNEL); | |
150 | if (state) | |
151 | __drm_atomic_helper_crtc_duplicate_state(crtc, state); | |
152 | ||
153 | return state; | |
154 | } | |
155 | EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state); | |
156 | ||
157 | /** | |
158 | * __drm_atomic_helper_crtc_destroy_state - release CRTC state | |
159 | * @state: CRTC state object to release | |
160 | * | |
161 | * Releases all resources stored in the CRTC state without actually freeing | |
162 | * the memory of the CRTC state. This is useful for drivers that subclass the | |
163 | * CRTC state. | |
164 | */ | |
165 | void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state) | |
166 | { | |
167 | if (state->commit) { | |
168 | /* | |
169 | * In the event that a non-blocking commit returns | |
170 | * -ERESTARTSYS before the commit_tail work is queued, we will | |
171 | * have an extra reference to the commit object. Release it, if | |
172 | * the event has not been consumed by the worker. | |
173 | * | |
174 | * state->event may be freed, so we can't directly look at | |
175 | * state->event->base.completion. | |
176 | */ | |
177 | if (state->event && state->commit->abort_completion) | |
178 | drm_crtc_commit_put(state->commit); | |
179 | ||
180 | kfree(state->commit->event); | |
181 | state->commit->event = NULL; | |
182 | ||
183 | drm_crtc_commit_put(state->commit); | |
184 | } | |
185 | ||
186 | drm_property_blob_put(state->mode_blob); | |
187 | drm_property_blob_put(state->degamma_lut); | |
188 | drm_property_blob_put(state->ctm); | |
189 | drm_property_blob_put(state->gamma_lut); | |
190 | } | |
191 | EXPORT_SYMBOL(__drm_atomic_helper_crtc_destroy_state); | |
192 | ||
193 | /** | |
194 | * drm_atomic_helper_crtc_destroy_state - default state destroy hook | |
195 | * @crtc: drm CRTC | |
196 | * @state: CRTC state object to release | |
197 | * | |
198 | * Default CRTC state destroy hook for drivers which don't have their own | |
199 | * subclassed CRTC state structure. | |
200 | */ | |
201 | void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc, | |
202 | struct drm_crtc_state *state) | |
203 | { | |
204 | __drm_atomic_helper_crtc_destroy_state(state); | |
205 | kfree(state); | |
206 | } | |
207 | EXPORT_SYMBOL(drm_atomic_helper_crtc_destroy_state); | |
208 | ||
209 | /** | |
210 | * __drm_atomic_helper_plane_reset - resets planes state to default values | |
211 | * @plane: plane object, must not be NULL | |
212 | * @state: atomic plane state, must not be NULL | |
213 | * | |
214 | * Initializes plane state to default. This is useful for drivers that subclass | |
215 | * the plane state. | |
216 | */ | |
217 | void __drm_atomic_helper_plane_reset(struct drm_plane *plane, | |
218 | struct drm_plane_state *state) | |
219 | { | |
220 | state->plane = plane; | |
221 | state->rotation = DRM_MODE_ROTATE_0; | |
222 | ||
223 | state->alpha = DRM_BLEND_ALPHA_OPAQUE; | |
224 | state->pixel_blend_mode = DRM_MODE_BLEND_PREMULTI; | |
225 | ||
226 | plane->state = state; | |
227 | } | |
228 | EXPORT_SYMBOL(__drm_atomic_helper_plane_reset); | |
229 | ||
230 | /** | |
231 | * drm_atomic_helper_plane_reset - default &drm_plane_funcs.reset hook for planes | |
232 | * @plane: drm plane | |
233 | * | |
234 | * Resets the atomic state for @plane by freeing the state pointer (which might | |
235 | * be NULL, e.g. at driver load time) and allocating a new empty state object. | |
236 | */ | |
237 | void drm_atomic_helper_plane_reset(struct drm_plane *plane) | |
238 | { | |
239 | if (plane->state) | |
240 | __drm_atomic_helper_plane_destroy_state(plane->state); | |
241 | ||
242 | kfree(plane->state); | |
243 | plane->state = kzalloc(sizeof(*plane->state), GFP_KERNEL); | |
244 | if (plane->state) | |
245 | __drm_atomic_helper_plane_reset(plane, plane->state); | |
246 | } | |
247 | EXPORT_SYMBOL(drm_atomic_helper_plane_reset); | |
248 | ||
249 | /** | |
250 | * __drm_atomic_helper_plane_duplicate_state - copy atomic plane state | |
251 | * @plane: plane object | |
252 | * @state: atomic plane state | |
253 | * | |
254 | * Copies atomic state from a plane's current state. This is useful for | |
255 | * drivers that subclass the plane state. | |
256 | */ | |
257 | void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane, | |
258 | struct drm_plane_state *state) | |
259 | { | |
260 | memcpy(state, plane->state, sizeof(*state)); | |
261 | ||
262 | if (state->fb) | |
263 | drm_framebuffer_get(state->fb); | |
264 | ||
265 | state->fence = NULL; | |
266 | state->commit = NULL; | |
c75ff001 | 267 | state->fb_damage_clips = NULL; |
9ef8a9dc SV |
268 | } |
269 | EXPORT_SYMBOL(__drm_atomic_helper_plane_duplicate_state); | |
270 | ||
271 | /** | |
272 | * drm_atomic_helper_plane_duplicate_state - default state duplicate hook | |
273 | * @plane: drm plane | |
274 | * | |
275 | * Default plane state duplicate hook for drivers which don't have their own | |
276 | * subclassed plane state structure. | |
277 | */ | |
278 | struct drm_plane_state * | |
279 | drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane) | |
280 | { | |
281 | struct drm_plane_state *state; | |
282 | ||
283 | if (WARN_ON(!plane->state)) | |
284 | return NULL; | |
285 | ||
286 | state = kmalloc(sizeof(*state), GFP_KERNEL); | |
287 | if (state) | |
288 | __drm_atomic_helper_plane_duplicate_state(plane, state); | |
289 | ||
290 | return state; | |
291 | } | |
292 | EXPORT_SYMBOL(drm_atomic_helper_plane_duplicate_state); | |
293 | ||
294 | /** | |
295 | * __drm_atomic_helper_plane_destroy_state - release plane state | |
296 | * @state: plane state object to release | |
297 | * | |
298 | * Releases all resources stored in the plane state without actually freeing | |
299 | * the memory of the plane state. This is useful for drivers that subclass the | |
300 | * plane state. | |
301 | */ | |
302 | void __drm_atomic_helper_plane_destroy_state(struct drm_plane_state *state) | |
303 | { | |
304 | if (state->fb) | |
305 | drm_framebuffer_put(state->fb); | |
306 | ||
307 | if (state->fence) | |
308 | dma_fence_put(state->fence); | |
309 | ||
310 | if (state->commit) | |
311 | drm_crtc_commit_put(state->commit); | |
c75ff001 DR |
312 | |
313 | drm_property_blob_put(state->fb_damage_clips); | |
9ef8a9dc SV |
314 | } |
315 | EXPORT_SYMBOL(__drm_atomic_helper_plane_destroy_state); | |
316 | ||
317 | /** | |
318 | * drm_atomic_helper_plane_destroy_state - default state destroy hook | |
319 | * @plane: drm plane | |
320 | * @state: plane state object to release | |
321 | * | |
322 | * Default plane state destroy hook for drivers which don't have their own | |
323 | * subclassed plane state structure. | |
324 | */ | |
325 | void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane, | |
326 | struct drm_plane_state *state) | |
327 | { | |
328 | __drm_atomic_helper_plane_destroy_state(state); | |
329 | kfree(state); | |
330 | } | |
331 | EXPORT_SYMBOL(drm_atomic_helper_plane_destroy_state); | |
332 | ||
333 | /** | |
334 | * __drm_atomic_helper_connector_reset - reset state on connector | |
335 | * @connector: drm connector | |
336 | * @conn_state: connector state to assign | |
337 | * | |
338 | * Initializes the newly allocated @conn_state and assigns it to | |
12d7a93c | 339 | * the &drm_connector->state pointer of @connector, usually required when |
9ef8a9dc SV |
340 | * initializing the drivers or when called from the &drm_connector_funcs.reset |
341 | * hook. | |
342 | * | |
343 | * This is useful for drivers that subclass the connector state. | |
344 | */ | |
345 | void | |
346 | __drm_atomic_helper_connector_reset(struct drm_connector *connector, | |
347 | struct drm_connector_state *conn_state) | |
348 | { | |
349 | if (conn_state) | |
350 | conn_state->connector = connector; | |
351 | ||
352 | connector->state = conn_state; | |
353 | } | |
354 | EXPORT_SYMBOL(__drm_atomic_helper_connector_reset); | |
355 | ||
356 | /** | |
357 | * drm_atomic_helper_connector_reset - default &drm_connector_funcs.reset hook for connectors | |
358 | * @connector: drm connector | |
359 | * | |
360 | * Resets the atomic state for @connector by freeing the state pointer (which | |
361 | * might be NULL, e.g. at driver load time) and allocating a new empty state | |
362 | * object. | |
363 | */ | |
364 | void drm_atomic_helper_connector_reset(struct drm_connector *connector) | |
365 | { | |
366 | struct drm_connector_state *conn_state = | |
367 | kzalloc(sizeof(*conn_state), GFP_KERNEL); | |
368 | ||
369 | if (connector->state) | |
370 | __drm_atomic_helper_connector_destroy_state(connector->state); | |
371 | ||
372 | kfree(connector->state); | |
373 | __drm_atomic_helper_connector_reset(connector, conn_state); | |
374 | } | |
375 | EXPORT_SYMBOL(drm_atomic_helper_connector_reset); | |
376 | ||
377 | /** | |
378 | * __drm_atomic_helper_connector_duplicate_state - copy atomic connector state | |
379 | * @connector: connector object | |
380 | * @state: atomic connector state | |
381 | * | |
382 | * Copies atomic state from a connector's current state. This is useful for | |
383 | * drivers that subclass the connector state. | |
384 | */ | |
385 | void | |
386 | __drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector, | |
387 | struct drm_connector_state *state) | |
388 | { | |
389 | memcpy(state, connector->state, sizeof(*state)); | |
390 | if (state->crtc) | |
391 | drm_connector_get(connector); | |
392 | state->commit = NULL; | |
393 | ||
c0b0ebb1 JK |
394 | if (state->hdr_output_metadata) |
395 | drm_property_blob_get(state->hdr_output_metadata); | |
396 | ||
9ef8a9dc SV |
397 | /* Don't copy over a writeback job, they are used only once */ |
398 | state->writeback_job = NULL; | |
399 | } | |
400 | EXPORT_SYMBOL(__drm_atomic_helper_connector_duplicate_state); | |
401 | ||
402 | /** | |
403 | * drm_atomic_helper_connector_duplicate_state - default state duplicate hook | |
404 | * @connector: drm connector | |
405 | * | |
406 | * Default connector state duplicate hook for drivers which don't have their own | |
407 | * subclassed connector state structure. | |
408 | */ | |
409 | struct drm_connector_state * | |
410 | drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector) | |
411 | { | |
412 | struct drm_connector_state *state; | |
413 | ||
414 | if (WARN_ON(!connector->state)) | |
415 | return NULL; | |
416 | ||
417 | state = kmalloc(sizeof(*state), GFP_KERNEL); | |
418 | if (state) | |
419 | __drm_atomic_helper_connector_duplicate_state(connector, state); | |
420 | ||
421 | return state; | |
422 | } | |
423 | EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state); | |
424 | ||
9ef8a9dc SV |
425 | /** |
426 | * __drm_atomic_helper_connector_destroy_state - release connector state | |
427 | * @state: connector state object to release | |
428 | * | |
429 | * Releases all resources stored in the connector state without actually | |
430 | * freeing the memory of the connector state. This is useful for drivers that | |
431 | * subclass the connector state. | |
432 | */ | |
433 | void | |
434 | __drm_atomic_helper_connector_destroy_state(struct drm_connector_state *state) | |
435 | { | |
436 | if (state->crtc) | |
437 | drm_connector_put(state->connector); | |
438 | ||
439 | if (state->commit) | |
440 | drm_crtc_commit_put(state->commit); | |
e482ae9b LP |
441 | |
442 | if (state->writeback_job) | |
443 | drm_writeback_cleanup_job(state->writeback_job); | |
c0b0ebb1 JK |
444 | |
445 | drm_property_blob_put(state->hdr_output_metadata); | |
9ef8a9dc SV |
446 | } |
447 | EXPORT_SYMBOL(__drm_atomic_helper_connector_destroy_state); | |
448 | ||
449 | /** | |
450 | * drm_atomic_helper_connector_destroy_state - default state destroy hook | |
451 | * @connector: drm connector | |
452 | * @state: connector state object to release | |
453 | * | |
454 | * Default connector state destroy hook for drivers which don't have their own | |
455 | * subclassed connector state structure. | |
456 | */ | |
457 | void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector, | |
458 | struct drm_connector_state *state) | |
459 | { | |
460 | __drm_atomic_helper_connector_destroy_state(state); | |
461 | kfree(state); | |
462 | } | |
463 | EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state); | |
464 | ||
9ef8a9dc SV |
465 | /** |
466 | * __drm_atomic_helper_private_duplicate_state - copy atomic private state | |
467 | * @obj: CRTC object | |
468 | * @state: new private object state | |
469 | * | |
470 | * Copies atomic state from a private objects's current state and resets inferred values. | |
471 | * This is useful for drivers that subclass the private state. | |
472 | */ | |
473 | void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj, | |
474 | struct drm_private_state *state) | |
475 | { | |
476 | memcpy(state, obj->state, sizeof(*state)); | |
477 | } | |
478 | EXPORT_SYMBOL(__drm_atomic_helper_private_obj_duplicate_state); |