1cc4ceb48SDaniel Vetter /*
2cc4ceb48SDaniel Vetter * Copyright (C) 2014 Red Hat
3cc4ceb48SDaniel Vetter * Copyright (C) 2014 Intel Corp.
4a4324a7aSAbhinav Kumar * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
5cc4ceb48SDaniel Vetter *
6cc4ceb48SDaniel Vetter * Permission is hereby granted, free of charge, to any person obtaining a
7cc4ceb48SDaniel Vetter * copy of this software and associated documentation files (the "Software"),
8cc4ceb48SDaniel Vetter * to deal in the Software without restriction, including without limitation
9cc4ceb48SDaniel Vetter * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10cc4ceb48SDaniel Vetter * and/or sell copies of the Software, and to permit persons to whom the
11cc4ceb48SDaniel Vetter * Software is furnished to do so, subject to the following conditions:
12cc4ceb48SDaniel Vetter *
13cc4ceb48SDaniel Vetter * The above copyright notice and this permission notice shall be included in
14cc4ceb48SDaniel Vetter * all copies or substantial portions of the Software.
15cc4ceb48SDaniel Vetter *
16cc4ceb48SDaniel Vetter * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17cc4ceb48SDaniel Vetter * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18cc4ceb48SDaniel Vetter * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19cc4ceb48SDaniel Vetter * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20cc4ceb48SDaniel Vetter * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21cc4ceb48SDaniel Vetter * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22cc4ceb48SDaniel Vetter * OTHER DEALINGS IN THE SOFTWARE.
23cc4ceb48SDaniel Vetter *
24cc4ceb48SDaniel Vetter * Authors:
25cc4ceb48SDaniel Vetter * Rob Clark <robdclark@gmail.com>
26cc4ceb48SDaniel Vetter * Daniel Vetter <daniel.vetter@ffwll.ch>
27cc4ceb48SDaniel Vetter */
28cc4ceb48SDaniel Vetter
29cc4ceb48SDaniel Vetter
300500c04eSSam Ravnborg #include <linux/sync_file.h>
310500c04eSSam Ravnborg
32cc4ceb48SDaniel Vetter #include <drm/drm_atomic.h>
3372fdb40cSDaniel Vetter #include <drm/drm_atomic_uapi.h>
3490bb087fSVille Syrjälä #include <drm/drm_blend.h>
3575146591SBoris Brezillon #include <drm/drm_bridge.h>
360500c04eSSam Ravnborg #include <drm/drm_debugfs.h>
370500c04eSSam Ravnborg #include <drm/drm_device.h>
380500c04eSSam Ravnborg #include <drm/drm_drv.h>
390500c04eSSam Ravnborg #include <drm/drm_file.h>
400500c04eSSam Ravnborg #include <drm/drm_fourcc.h>
41720cf96dSVille Syrjälä #include <drm/drm_framebuffer.h>
425488dc16SLionel Landwerlin #include <drm/drm_mode.h>
43fceffb32SRob Clark #include <drm/drm_print.h>
44935774cdSBrian Starkey #include <drm/drm_writeback.h>
45cc4ceb48SDaniel Vetter
46be35f94fSThierry Reding #include "drm_crtc_internal.h"
47f02b604bSNoralf Trønnes #include "drm_internal.h"
48be35f94fSThierry Reding
__drm_crtc_commit_free(struct kref * kref)49b3ba3f6fSDaniel Vetter void __drm_crtc_commit_free(struct kref *kref)
503b24f7d6SDaniel Vetter {
513b24f7d6SDaniel Vetter struct drm_crtc_commit *commit =
523b24f7d6SDaniel Vetter container_of(kref, struct drm_crtc_commit, ref);
533b24f7d6SDaniel Vetter
543b24f7d6SDaniel Vetter kfree(commit);
553b24f7d6SDaniel Vetter }
56b3ba3f6fSDaniel Vetter EXPORT_SYMBOL(__drm_crtc_commit_free);
573b24f7d6SDaniel Vetter
58036ef573SMaarten Lankhorst /**
59b99c2c95SMaxime Ripard * drm_crtc_commit_wait - Waits for a commit to complete
60b99c2c95SMaxime Ripard * @commit: &drm_crtc_commit to wait for
61b99c2c95SMaxime Ripard *
62b99c2c95SMaxime Ripard * Waits for a given &drm_crtc_commit to be programmed into the
63b99c2c95SMaxime Ripard * hardware and flipped to.
64b99c2c95SMaxime Ripard *
65b99c2c95SMaxime Ripard * Returns:
66b99c2c95SMaxime Ripard * 0 on success, a negative error code otherwise.
67b99c2c95SMaxime Ripard */
drm_crtc_commit_wait(struct drm_crtc_commit * commit)68b99c2c95SMaxime Ripard int drm_crtc_commit_wait(struct drm_crtc_commit *commit)
69b99c2c95SMaxime Ripard {
70b99c2c95SMaxime Ripard unsigned long timeout = 10 * HZ;
71b99c2c95SMaxime Ripard int ret;
72b99c2c95SMaxime Ripard
73b99c2c95SMaxime Ripard if (!commit)
74b99c2c95SMaxime Ripard return 0;
75b99c2c95SMaxime Ripard
76b99c2c95SMaxime Ripard ret = wait_for_completion_timeout(&commit->hw_done, timeout);
77b99c2c95SMaxime Ripard if (!ret) {
786e22dc35SClaudio Suarez drm_err(commit->crtc->dev, "hw_done timed out\n");
79b99c2c95SMaxime Ripard return -ETIMEDOUT;
80b99c2c95SMaxime Ripard }
81b99c2c95SMaxime Ripard
82b99c2c95SMaxime Ripard /*
83b99c2c95SMaxime Ripard * Currently no support for overwriting flips, hence
84b99c2c95SMaxime Ripard * stall for previous one to execute completely.
85b99c2c95SMaxime Ripard */
86b99c2c95SMaxime Ripard ret = wait_for_completion_timeout(&commit->flip_done, timeout);
87b99c2c95SMaxime Ripard if (!ret) {
886e22dc35SClaudio Suarez drm_err(commit->crtc->dev, "flip_done timed out\n");
89b99c2c95SMaxime Ripard return -ETIMEDOUT;
90b99c2c95SMaxime Ripard }
91b99c2c95SMaxime Ripard
92b99c2c95SMaxime Ripard return 0;
93b99c2c95SMaxime Ripard }
94b99c2c95SMaxime Ripard EXPORT_SYMBOL(drm_crtc_commit_wait);
95b99c2c95SMaxime Ripard
96b99c2c95SMaxime Ripard /**
97036ef573SMaarten Lankhorst * drm_atomic_state_default_release -
98036ef573SMaarten Lankhorst * release memory initialized by drm_atomic_state_init
99036ef573SMaarten Lankhorst * @state: atomic state
100036ef573SMaarten Lankhorst *
101036ef573SMaarten Lankhorst * Free all the memory allocated by drm_atomic_state_init.
102da6c0596SDaniel Vetter * This should only be used by drivers which are still subclassing
103da6c0596SDaniel Vetter * &drm_atomic_state and haven't switched to &drm_private_state yet.
104036ef573SMaarten Lankhorst */
drm_atomic_state_default_release(struct drm_atomic_state * state)105036ef573SMaarten Lankhorst void drm_atomic_state_default_release(struct drm_atomic_state *state)
106cc4ceb48SDaniel Vetter {
107cc4ceb48SDaniel Vetter kfree(state->connectors);
108cc4ceb48SDaniel Vetter kfree(state->crtcs);
109cc4ceb48SDaniel Vetter kfree(state->planes);
110b430c27aSPandiyan, Dhinakaran kfree(state->private_objs);
111cc4ceb48SDaniel Vetter }
112036ef573SMaarten Lankhorst EXPORT_SYMBOL(drm_atomic_state_default_release);
113cc4ceb48SDaniel Vetter
114cc4ceb48SDaniel Vetter /**
115036ef573SMaarten Lankhorst * drm_atomic_state_init - init new atomic state
116cc4ceb48SDaniel Vetter * @dev: DRM device
117036ef573SMaarten Lankhorst * @state: atomic state
118cc4ceb48SDaniel Vetter *
119036ef573SMaarten Lankhorst * Default implementation for filling in a new atomic state.
120da6c0596SDaniel Vetter * This should only be used by drivers which are still subclassing
121da6c0596SDaniel Vetter * &drm_atomic_state and haven't switched to &drm_private_state yet.
122cc4ceb48SDaniel Vetter */
123036ef573SMaarten Lankhorst int
drm_atomic_state_init(struct drm_device * dev,struct drm_atomic_state * state)124036ef573SMaarten Lankhorst drm_atomic_state_init(struct drm_device *dev, struct drm_atomic_state *state)
125cc4ceb48SDaniel Vetter {
1260853695cSChris Wilson kref_init(&state->ref);
1270853695cSChris Wilson
128d34f20d6SRob Clark /* TODO legacy paths should maybe do a better job about
129d34f20d6SRob Clark * setting this appropriately?
130d34f20d6SRob Clark */
131d34f20d6SRob Clark state->allow_modeset = true;
132d34f20d6SRob Clark
133cc4ceb48SDaniel Vetter state->crtcs = kcalloc(dev->mode_config.num_crtc,
134cc4ceb48SDaniel Vetter sizeof(*state->crtcs), GFP_KERNEL);
135cc4ceb48SDaniel Vetter if (!state->crtcs)
136cc4ceb48SDaniel Vetter goto fail;
137cc4ceb48SDaniel Vetter state->planes = kcalloc(dev->mode_config.num_total_plane,
138cc4ceb48SDaniel Vetter sizeof(*state->planes), GFP_KERNEL);
139cc4ceb48SDaniel Vetter if (!state->planes)
140cc4ceb48SDaniel Vetter goto fail;
141cc4ceb48SDaniel Vetter
1424e076c73SDaniel Vetter /*
1434e076c73SDaniel Vetter * Because drm_atomic_state can be committed asynchronously we need our
1444e076c73SDaniel Vetter * own reference and cannot rely on the on implied by drm_file in the
1454e076c73SDaniel Vetter * ioctl call.
1464e076c73SDaniel Vetter */
1474e076c73SDaniel Vetter drm_dev_get(dev);
148cc4ceb48SDaniel Vetter state->dev = dev;
149cc4ceb48SDaniel Vetter
1506e22dc35SClaudio Suarez drm_dbg_atomic(dev, "Allocated atomic state %p\n", state);
151cc4ceb48SDaniel Vetter
152036ef573SMaarten Lankhorst return 0;
153cc4ceb48SDaniel Vetter fail:
154036ef573SMaarten Lankhorst drm_atomic_state_default_release(state);
155036ef573SMaarten Lankhorst return -ENOMEM;
156036ef573SMaarten Lankhorst }
157036ef573SMaarten Lankhorst EXPORT_SYMBOL(drm_atomic_state_init);
158cc4ceb48SDaniel Vetter
159036ef573SMaarten Lankhorst /**
160036ef573SMaarten Lankhorst * drm_atomic_state_alloc - allocate atomic state
161036ef573SMaarten Lankhorst * @dev: DRM device
162036ef573SMaarten Lankhorst *
163036ef573SMaarten Lankhorst * This allocates an empty atomic state to track updates.
164036ef573SMaarten Lankhorst */
165036ef573SMaarten Lankhorst struct drm_atomic_state *
drm_atomic_state_alloc(struct drm_device * dev)166036ef573SMaarten Lankhorst drm_atomic_state_alloc(struct drm_device *dev)
167036ef573SMaarten Lankhorst {
168036ef573SMaarten Lankhorst struct drm_mode_config *config = &dev->mode_config;
169036ef573SMaarten Lankhorst
170036ef573SMaarten Lankhorst if (!config->funcs->atomic_state_alloc) {
171ac7c7483SDawid Kurek struct drm_atomic_state *state;
172ac7c7483SDawid Kurek
173036ef573SMaarten Lankhorst state = kzalloc(sizeof(*state), GFP_KERNEL);
174036ef573SMaarten Lankhorst if (!state)
175cc4ceb48SDaniel Vetter return NULL;
176036ef573SMaarten Lankhorst if (drm_atomic_state_init(dev, state) < 0) {
177036ef573SMaarten Lankhorst kfree(state);
178036ef573SMaarten Lankhorst return NULL;
179036ef573SMaarten Lankhorst }
180036ef573SMaarten Lankhorst return state;
181036ef573SMaarten Lankhorst }
182036ef573SMaarten Lankhorst
183036ef573SMaarten Lankhorst return config->funcs->atomic_state_alloc(dev);
184cc4ceb48SDaniel Vetter }
185cc4ceb48SDaniel Vetter EXPORT_SYMBOL(drm_atomic_state_alloc);
186cc4ceb48SDaniel Vetter
187cc4ceb48SDaniel Vetter /**
188036ef573SMaarten Lankhorst * drm_atomic_state_default_clear - clear base atomic state
189cc4ceb48SDaniel Vetter * @state: atomic state
190cc4ceb48SDaniel Vetter *
191036ef573SMaarten Lankhorst * Default implementation for clearing atomic state.
192da6c0596SDaniel Vetter * This should only be used by drivers which are still subclassing
193da6c0596SDaniel Vetter * &drm_atomic_state and haven't switched to &drm_private_state yet.
194cc4ceb48SDaniel Vetter */
drm_atomic_state_default_clear(struct drm_atomic_state * state)195036ef573SMaarten Lankhorst void drm_atomic_state_default_clear(struct drm_atomic_state *state)
196cc4ceb48SDaniel Vetter {
197cc4ceb48SDaniel Vetter struct drm_device *dev = state->dev;
1986f75cea6SDaniel Vetter struct drm_mode_config *config = &dev->mode_config;
199cc4ceb48SDaniel Vetter int i;
200cc4ceb48SDaniel Vetter
2016e22dc35SClaudio Suarez drm_dbg_atomic(dev, "Clearing atomic state %p\n", state);
202cc4ceb48SDaniel Vetter
203f52b69f1SDaniel Vetter for (i = 0; i < state->num_connector; i++) {
20463e83c1dSDaniel Vetter struct drm_connector *connector = state->connectors[i].ptr;
205cc4ceb48SDaniel Vetter
206cc4ceb48SDaniel Vetter if (!connector)
207cc4ceb48SDaniel Vetter continue;
208cc4ceb48SDaniel Vetter
209d2307deaSDave Airlie connector->funcs->atomic_destroy_state(connector,
21063e83c1dSDaniel Vetter state->connectors[i].state);
21163e83c1dSDaniel Vetter state->connectors[i].ptr = NULL;
21263e83c1dSDaniel Vetter state->connectors[i].state = NULL;
213f0b408eeSVille Syrjälä state->connectors[i].old_state = NULL;
214f0b408eeSVille Syrjälä state->connectors[i].new_state = NULL;
215ad093607SThierry Reding drm_connector_put(connector);
216cc4ceb48SDaniel Vetter }
217cc4ceb48SDaniel Vetter
2186f75cea6SDaniel Vetter for (i = 0; i < config->num_crtc; i++) {
2195d943aa6SDaniel Vetter struct drm_crtc *crtc = state->crtcs[i].ptr;
220cc4ceb48SDaniel Vetter
221cc4ceb48SDaniel Vetter if (!crtc)
222cc4ceb48SDaniel Vetter continue;
223cc4ceb48SDaniel Vetter
224cc4ceb48SDaniel Vetter crtc->funcs->atomic_destroy_state(crtc,
2255d943aa6SDaniel Vetter state->crtcs[i].state);
2263b24f7d6SDaniel Vetter
2275d943aa6SDaniel Vetter state->crtcs[i].ptr = NULL;
2285d943aa6SDaniel Vetter state->crtcs[i].state = NULL;
229f0b408eeSVille Syrjälä state->crtcs[i].old_state = NULL;
230f0b408eeSVille Syrjälä state->crtcs[i].new_state = NULL;
2314364bcb2SLeo Li
2324364bcb2SLeo Li if (state->crtcs[i].commit) {
2334364bcb2SLeo Li drm_crtc_commit_put(state->crtcs[i].commit);
2344364bcb2SLeo Li state->crtcs[i].commit = NULL;
2354364bcb2SLeo Li }
236cc4ceb48SDaniel Vetter }
237cc4ceb48SDaniel Vetter
2386f75cea6SDaniel Vetter for (i = 0; i < config->num_total_plane; i++) {
239b8b5342bSDaniel Vetter struct drm_plane *plane = state->planes[i].ptr;
240cc4ceb48SDaniel Vetter
241cc4ceb48SDaniel Vetter if (!plane)
242cc4ceb48SDaniel Vetter continue;
243cc4ceb48SDaniel Vetter
244cc4ceb48SDaniel Vetter plane->funcs->atomic_destroy_state(plane,
245b8b5342bSDaniel Vetter state->planes[i].state);
246b8b5342bSDaniel Vetter state->planes[i].ptr = NULL;
247b8b5342bSDaniel Vetter state->planes[i].state = NULL;
248f0b408eeSVille Syrjälä state->planes[i].old_state = NULL;
249f0b408eeSVille Syrjälä state->planes[i].new_state = NULL;
250cc4ceb48SDaniel Vetter }
251b430c27aSPandiyan, Dhinakaran
252b430c27aSPandiyan, Dhinakaran for (i = 0; i < state->num_private_objs; i++) {
253a4370c77SVille Syrjälä struct drm_private_obj *obj = state->private_objs[i].ptr;
254b430c27aSPandiyan, Dhinakaran
255a4370c77SVille Syrjälä obj->funcs->atomic_destroy_state(obj,
256a4370c77SVille Syrjälä state->private_objs[i].state);
257a4370c77SVille Syrjälä state->private_objs[i].ptr = NULL;
258a4370c77SVille Syrjälä state->private_objs[i].state = NULL;
259b5cb2e5aSVille Syrjälä state->private_objs[i].old_state = NULL;
260b5cb2e5aSVille Syrjälä state->private_objs[i].new_state = NULL;
261b430c27aSPandiyan, Dhinakaran }
262b430c27aSPandiyan, Dhinakaran state->num_private_objs = 0;
263b430c27aSPandiyan, Dhinakaran
26421a01abbSMaarten Lankhorst if (state->fake_commit) {
26521a01abbSMaarten Lankhorst drm_crtc_commit_put(state->fake_commit);
26621a01abbSMaarten Lankhorst state->fake_commit = NULL;
26721a01abbSMaarten Lankhorst }
268cc4ceb48SDaniel Vetter }
269036ef573SMaarten Lankhorst EXPORT_SYMBOL(drm_atomic_state_default_clear);
270036ef573SMaarten Lankhorst
271036ef573SMaarten Lankhorst /**
272036ef573SMaarten Lankhorst * drm_atomic_state_clear - clear state object
273036ef573SMaarten Lankhorst * @state: atomic state
274036ef573SMaarten Lankhorst *
275036ef573SMaarten Lankhorst * When the w/w mutex algorithm detects a deadlock we need to back off and drop
276036ef573SMaarten Lankhorst * all locks. So someone else could sneak in and change the current modeset
277036ef573SMaarten Lankhorst * configuration. Which means that all the state assembled in @state is no
278036ef573SMaarten Lankhorst * longer an atomic update to the current state, but to some arbitrary earlier
279d574528aSDaniel Vetter * state. Which could break assumptions the driver's
280d574528aSDaniel Vetter * &drm_mode_config_funcs.atomic_check likely relies on.
281036ef573SMaarten Lankhorst *
282036ef573SMaarten Lankhorst * Hence we must clear all cached state and completely start over, using this
283036ef573SMaarten Lankhorst * function.
284036ef573SMaarten Lankhorst */
drm_atomic_state_clear(struct drm_atomic_state * state)285036ef573SMaarten Lankhorst void drm_atomic_state_clear(struct drm_atomic_state *state)
286036ef573SMaarten Lankhorst {
287036ef573SMaarten Lankhorst struct drm_device *dev = state->dev;
288036ef573SMaarten Lankhorst struct drm_mode_config *config = &dev->mode_config;
289036ef573SMaarten Lankhorst
290036ef573SMaarten Lankhorst if (config->funcs->atomic_state_clear)
291036ef573SMaarten Lankhorst config->funcs->atomic_state_clear(state);
292036ef573SMaarten Lankhorst else
293036ef573SMaarten Lankhorst drm_atomic_state_default_clear(state);
294036ef573SMaarten Lankhorst }
295cc4ceb48SDaniel Vetter EXPORT_SYMBOL(drm_atomic_state_clear);
296cc4ceb48SDaniel Vetter
297cc4ceb48SDaniel Vetter /**
2980853695cSChris Wilson * __drm_atomic_state_free - free all memory for an atomic state
2990853695cSChris Wilson * @ref: This atomic state to deallocate
300cc4ceb48SDaniel Vetter *
301cc4ceb48SDaniel Vetter * This frees all memory associated with an atomic state, including all the
30242240c90SThierry Reding * per-object state for planes, CRTCs and connectors.
303cc4ceb48SDaniel Vetter */
__drm_atomic_state_free(struct kref * ref)3040853695cSChris Wilson void __drm_atomic_state_free(struct kref *ref)
305cc4ceb48SDaniel Vetter {
3060853695cSChris Wilson struct drm_atomic_state *state = container_of(ref, typeof(*state), ref);
3074e076c73SDaniel Vetter struct drm_device *dev = state->dev;
3084e076c73SDaniel Vetter struct drm_mode_config *config = &dev->mode_config;
309036ef573SMaarten Lankhorst
310cc4ceb48SDaniel Vetter drm_atomic_state_clear(state);
311cc4ceb48SDaniel Vetter
3126e22dc35SClaudio Suarez drm_dbg_atomic(state->dev, "Freeing atomic state %p\n", state);
313cc4ceb48SDaniel Vetter
314036ef573SMaarten Lankhorst if (config->funcs->atomic_state_free) {
315036ef573SMaarten Lankhorst config->funcs->atomic_state_free(state);
316036ef573SMaarten Lankhorst } else {
317036ef573SMaarten Lankhorst drm_atomic_state_default_release(state);
318036ef573SMaarten Lankhorst kfree(state);
319036ef573SMaarten Lankhorst }
3204e076c73SDaniel Vetter
3214e076c73SDaniel Vetter drm_dev_put(dev);
322cc4ceb48SDaniel Vetter }
3230853695cSChris Wilson EXPORT_SYMBOL(__drm_atomic_state_free);
324cc4ceb48SDaniel Vetter
325cc4ceb48SDaniel Vetter /**
32642240c90SThierry Reding * drm_atomic_get_crtc_state - get CRTC state
327cc4ceb48SDaniel Vetter * @state: global atomic state object
32842240c90SThierry Reding * @crtc: CRTC to get state object for
329cc4ceb48SDaniel Vetter *
33042240c90SThierry Reding * This function returns the CRTC state for the given CRTC, allocating it if
33142240c90SThierry Reding * needed. It will also grab the relevant CRTC lock to make sure that the state
332cc4ceb48SDaniel Vetter * is consistent.
333cc4ceb48SDaniel Vetter *
334fb6473a4SDaniel Vetter * WARNING: Drivers may only add new CRTC states to a @state if
335fb6473a4SDaniel Vetter * drm_atomic_state.allow_modeset is set, or if it's a driver-internal commit
336fb6473a4SDaniel Vetter * not created by userspace through an IOCTL call.
337fb6473a4SDaniel Vetter *
338cc4ceb48SDaniel Vetter * Returns:
339cc4ceb48SDaniel Vetter * Either the allocated state or the error code encoded into the pointer. When
340cc4ceb48SDaniel Vetter * the error is EDEADLK then the w/w mutex code has detected a deadlock and the
341cc4ceb48SDaniel Vetter * entire atomic sequence must be restarted. All other errors are fatal.
342cc4ceb48SDaniel Vetter */
343cc4ceb48SDaniel Vetter struct drm_crtc_state *
drm_atomic_get_crtc_state(struct drm_atomic_state * state,struct drm_crtc * crtc)344cc4ceb48SDaniel Vetter drm_atomic_get_crtc_state(struct drm_atomic_state *state,
345cc4ceb48SDaniel Vetter struct drm_crtc *crtc)
346cc4ceb48SDaniel Vetter {
3471b26a5e1SMaarten Lankhorst int ret, index = drm_crtc_index(crtc);
348cc4ceb48SDaniel Vetter struct drm_crtc_state *crtc_state;
349cc4ceb48SDaniel Vetter
3507f4eaa89SMaarten Lankhorst WARN_ON(!state->acquire_ctx);
3517f4eaa89SMaarten Lankhorst
3521b26a5e1SMaarten Lankhorst crtc_state = drm_atomic_get_existing_crtc_state(state, crtc);
3531b26a5e1SMaarten Lankhorst if (crtc_state)
3541b26a5e1SMaarten Lankhorst return crtc_state;
355cc4ceb48SDaniel Vetter
356cc4ceb48SDaniel Vetter ret = drm_modeset_lock(&crtc->mutex, state->acquire_ctx);
357cc4ceb48SDaniel Vetter if (ret)
358cc4ceb48SDaniel Vetter return ERR_PTR(ret);
359cc4ceb48SDaniel Vetter
360cc4ceb48SDaniel Vetter crtc_state = crtc->funcs->atomic_duplicate_state(crtc);
361cc4ceb48SDaniel Vetter if (!crtc_state)
362cc4ceb48SDaniel Vetter return ERR_PTR(-ENOMEM);
363cc4ceb48SDaniel Vetter
3645d943aa6SDaniel Vetter state->crtcs[index].state = crtc_state;
365581e49feSMaarten Lankhorst state->crtcs[index].old_state = crtc->state;
366581e49feSMaarten Lankhorst state->crtcs[index].new_state = crtc_state;
3675d943aa6SDaniel Vetter state->crtcs[index].ptr = crtc;
368cc4ceb48SDaniel Vetter crtc_state->state = state;
369cc4ceb48SDaniel Vetter
3706e22dc35SClaudio Suarez drm_dbg_atomic(state->dev, "Added [CRTC:%d:%s] %p state to %p\n",
371fa3ab4c2SVille Syrjälä crtc->base.id, crtc->name, crtc_state, state);
372cc4ceb48SDaniel Vetter
373cc4ceb48SDaniel Vetter return crtc_state;
374cc4ceb48SDaniel Vetter }
375cc4ceb48SDaniel Vetter EXPORT_SYMBOL(drm_atomic_get_crtc_state);
376cc4ceb48SDaniel Vetter
drm_atomic_crtc_check(const struct drm_crtc_state * old_crtc_state,const struct drm_crtc_state * new_crtc_state)377b2432adfSVille Syrjälä static int drm_atomic_crtc_check(const struct drm_crtc_state *old_crtc_state,
378b2432adfSVille Syrjälä const struct drm_crtc_state *new_crtc_state)
3795e743737SRob Clark {
380b2432adfSVille Syrjälä struct drm_crtc *crtc = new_crtc_state->crtc;
381b2432adfSVille Syrjälä
3825e743737SRob Clark /* NOTE: we explicitly don't enforce constraints such as primary
3835e743737SRob Clark * layer covering entire screen, since that is something we want
3845e743737SRob Clark * to allow (on hw that supports it). For hw that does not, it
3855e743737SRob Clark * should be checked in driver's crtc->atomic_check() vfunc.
3865e743737SRob Clark *
3875e743737SRob Clark * TODO: Add generic modeset state checks once we support those.
3885e743737SRob Clark */
389eab3bbefSDaniel Vetter
390b2432adfSVille Syrjälä if (new_crtc_state->active && !new_crtc_state->enable) {
3916e22dc35SClaudio Suarez drm_dbg_atomic(crtc->dev,
3926e22dc35SClaudio Suarez "[CRTC:%d:%s] active without enabled\n",
393fa3ab4c2SVille Syrjälä crtc->base.id, crtc->name);
394eab3bbefSDaniel Vetter return -EINVAL;
395eab3bbefSDaniel Vetter }
396eab3bbefSDaniel Vetter
39799cf4a29SDaniel Stone /* The state->enable vs. state->mode_blob checks can be WARN_ON,
39899cf4a29SDaniel Stone * as this is a kernel-internal detail that userspace should never
399060726c5SBeatriz Martins de Carvalho * be able to trigger.
400060726c5SBeatriz Martins de Carvalho */
40199cf4a29SDaniel Stone if (drm_core_check_feature(crtc->dev, DRIVER_ATOMIC) &&
402b2432adfSVille Syrjälä WARN_ON(new_crtc_state->enable && !new_crtc_state->mode_blob)) {
4036e22dc35SClaudio Suarez drm_dbg_atomic(crtc->dev,
4046e22dc35SClaudio Suarez "[CRTC:%d:%s] enabled without mode blob\n",
405fa3ab4c2SVille Syrjälä crtc->base.id, crtc->name);
40699cf4a29SDaniel Stone return -EINVAL;
40799cf4a29SDaniel Stone }
40899cf4a29SDaniel Stone
40999cf4a29SDaniel Stone if (drm_core_check_feature(crtc->dev, DRIVER_ATOMIC) &&
410b2432adfSVille Syrjälä WARN_ON(!new_crtc_state->enable && new_crtc_state->mode_blob)) {
4116e22dc35SClaudio Suarez drm_dbg_atomic(crtc->dev,
4126e22dc35SClaudio Suarez "[CRTC:%d:%s] disabled with mode blob\n",
413fa3ab4c2SVille Syrjälä crtc->base.id, crtc->name);
41499cf4a29SDaniel Stone return -EINVAL;
41599cf4a29SDaniel Stone }
41699cf4a29SDaniel Stone
4174cba6850SDaniel Vetter /*
4184cba6850SDaniel Vetter * Reject event generation for when a CRTC is off and stays off.
4194cba6850SDaniel Vetter * It wouldn't be hard to implement this, but userspace has a track
4204cba6850SDaniel Vetter * record of happily burning through 100% cpu (or worse, crash) when the
4214cba6850SDaniel Vetter * display pipe is suspended. To avoid all that fun just reject updates
4224cba6850SDaniel Vetter * that ask for events since likely that indicates a bug in the
4234cba6850SDaniel Vetter * compositor's drawing loop. This is consistent with the vblank IOCTL
4244cba6850SDaniel Vetter * and legacy page_flip IOCTL which also reject service on a disabled
4254cba6850SDaniel Vetter * pipe.
4264cba6850SDaniel Vetter */
427b2432adfSVille Syrjälä if (new_crtc_state->event &&
428b2432adfSVille Syrjälä !new_crtc_state->active && !old_crtc_state->active) {
4296e22dc35SClaudio Suarez drm_dbg_atomic(crtc->dev,
4306e22dc35SClaudio Suarez "[CRTC:%d:%s] requesting event but off\n",
4316ac7c548SRussell King crtc->base.id, crtc->name);
4324cba6850SDaniel Vetter return -EINVAL;
4334cba6850SDaniel Vetter }
4344cba6850SDaniel Vetter
4355e743737SRob Clark return 0;
4365e743737SRob Clark }
4375e743737SRob Clark
drm_atomic_crtc_print_state(struct drm_printer * p,const struct drm_crtc_state * state)438fceffb32SRob Clark static void drm_atomic_crtc_print_state(struct drm_printer *p,
439fceffb32SRob Clark const struct drm_crtc_state *state)
440fceffb32SRob Clark {
441fceffb32SRob Clark struct drm_crtc *crtc = state->crtc;
442fceffb32SRob Clark
443fceffb32SRob Clark drm_printf(p, "crtc[%u]: %s\n", crtc->base.id, crtc->name);
444fceffb32SRob Clark drm_printf(p, "\tenable=%d\n", state->enable);
445fceffb32SRob Clark drm_printf(p, "\tactive=%d\n", state->active);
4461452c25bSSean Paul drm_printf(p, "\tself_refresh_active=%d\n", state->self_refresh_active);
447fceffb32SRob Clark drm_printf(p, "\tplanes_changed=%d\n", state->planes_changed);
448fceffb32SRob Clark drm_printf(p, "\tmode_changed=%d\n", state->mode_changed);
449fceffb32SRob Clark drm_printf(p, "\tactive_changed=%d\n", state->active_changed);
450fceffb32SRob Clark drm_printf(p, "\tconnectors_changed=%d\n", state->connectors_changed);
451fceffb32SRob Clark drm_printf(p, "\tcolor_mgmt_changed=%d\n", state->color_mgmt_changed);
452fceffb32SRob Clark drm_printf(p, "\tplane_mask=%x\n", state->plane_mask);
453fceffb32SRob Clark drm_printf(p, "\tconnector_mask=%x\n", state->connector_mask);
454fceffb32SRob Clark drm_printf(p, "\tencoder_mask=%x\n", state->encoder_mask);
455fceffb32SRob Clark drm_printf(p, "\tmode: " DRM_MODE_FMT "\n", DRM_MODE_ARG(&state->mode));
456fceffb32SRob Clark
457fceffb32SRob Clark if (crtc->funcs->atomic_print_state)
458fceffb32SRob Clark crtc->funcs->atomic_print_state(p, state);
459fceffb32SRob Clark }
460fceffb32SRob Clark
drm_atomic_connector_check(struct drm_connector * connector,struct drm_connector_state * state)461935774cdSBrian Starkey static int drm_atomic_connector_check(struct drm_connector *connector,
462935774cdSBrian Starkey struct drm_connector_state *state)
463935774cdSBrian Starkey {
464935774cdSBrian Starkey struct drm_crtc_state *crtc_state;
465935774cdSBrian Starkey struct drm_writeback_job *writeback_job = state->writeback_job;
46647e22ff1SRadhakrishna Sripada const struct drm_display_info *info = &connector->display_info;
46747e22ff1SRadhakrishna Sripada
46847e22ff1SRadhakrishna Sripada state->max_bpc = info->bpc ? info->bpc : 8;
46947e22ff1SRadhakrishna Sripada if (connector->max_bpc_property)
47047e22ff1SRadhakrishna Sripada state->max_bpc = min(state->max_bpc, state->max_requested_bpc);
471935774cdSBrian Starkey
472935774cdSBrian Starkey if ((connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) || !writeback_job)
473935774cdSBrian Starkey return 0;
474935774cdSBrian Starkey
475935774cdSBrian Starkey if (writeback_job->fb && !state->crtc) {
4766e22dc35SClaudio Suarez drm_dbg_atomic(connector->dev,
4776e22dc35SClaudio Suarez "[CONNECTOR:%d:%s] framebuffer without CRTC\n",
478935774cdSBrian Starkey connector->base.id, connector->name);
479935774cdSBrian Starkey return -EINVAL;
480935774cdSBrian Starkey }
481935774cdSBrian Starkey
482935774cdSBrian Starkey if (state->crtc)
483935774cdSBrian Starkey crtc_state = drm_atomic_get_existing_crtc_state(state->state,
484935774cdSBrian Starkey state->crtc);
485935774cdSBrian Starkey
486935774cdSBrian Starkey if (writeback_job->fb && !crtc_state->active) {
4876e22dc35SClaudio Suarez drm_dbg_atomic(connector->dev,
4886e22dc35SClaudio Suarez "[CONNECTOR:%d:%s] has framebuffer, but [CRTC:%d] is off\n",
489935774cdSBrian Starkey connector->base.id, connector->name,
490935774cdSBrian Starkey state->crtc->base.id);
491935774cdSBrian Starkey return -EINVAL;
492935774cdSBrian Starkey }
493935774cdSBrian Starkey
4948581d510SLowry Li (Arm Technology China) if (!writeback_job->fb) {
4958581d510SLowry Li (Arm Technology China) if (writeback_job->out_fence) {
4966e22dc35SClaudio Suarez drm_dbg_atomic(connector->dev,
4976e22dc35SClaudio Suarez "[CONNECTOR:%d:%s] requesting out-fence without framebuffer\n",
498b13cc8ddSBrian Starkey connector->base.id, connector->name);
499b13cc8ddSBrian Starkey return -EINVAL;
500b13cc8ddSBrian Starkey }
501b13cc8ddSBrian Starkey
5028581d510SLowry Li (Arm Technology China) drm_writeback_cleanup_job(writeback_job);
5038581d510SLowry Li (Arm Technology China) state->writeback_job = NULL;
5048581d510SLowry Li (Arm Technology China) }
5058581d510SLowry Li (Arm Technology China)
506935774cdSBrian Starkey return 0;
507935774cdSBrian Starkey }
508935774cdSBrian Starkey
509935774cdSBrian Starkey /**
510cc4ceb48SDaniel Vetter * drm_atomic_get_plane_state - get plane state
511cc4ceb48SDaniel Vetter * @state: global atomic state object
512cc4ceb48SDaniel Vetter * @plane: plane to get state object for
513cc4ceb48SDaniel Vetter *
514cc4ceb48SDaniel Vetter * This function returns the plane state for the given plane, allocating it if
515cc4ceb48SDaniel Vetter * needed. It will also grab the relevant plane lock to make sure that the state
516cc4ceb48SDaniel Vetter * is consistent.
517cc4ceb48SDaniel Vetter *
518cc4ceb48SDaniel Vetter * Returns:
519cc4ceb48SDaniel Vetter * Either the allocated state or the error code encoded into the pointer. When
520cc4ceb48SDaniel Vetter * the error is EDEADLK then the w/w mutex code has detected a deadlock and the
521cc4ceb48SDaniel Vetter * entire atomic sequence must be restarted. All other errors are fatal.
522cc4ceb48SDaniel Vetter */
523cc4ceb48SDaniel Vetter struct drm_plane_state *
drm_atomic_get_plane_state(struct drm_atomic_state * state,struct drm_plane * plane)524cc4ceb48SDaniel Vetter drm_atomic_get_plane_state(struct drm_atomic_state *state,
525cc4ceb48SDaniel Vetter struct drm_plane *plane)
526cc4ceb48SDaniel Vetter {
5271b26a5e1SMaarten Lankhorst int ret, index = drm_plane_index(plane);
528cc4ceb48SDaniel Vetter struct drm_plane_state *plane_state;
529cc4ceb48SDaniel Vetter
5307f4eaa89SMaarten Lankhorst WARN_ON(!state->acquire_ctx);
5317f4eaa89SMaarten Lankhorst
532e00fb856SVille Syrjälä /* the legacy pointers should never be set */
533e00fb856SVille Syrjälä WARN_ON(plane->fb);
534e00fb856SVille Syrjälä WARN_ON(plane->old_fb);
535e00fb856SVille Syrjälä WARN_ON(plane->crtc);
536e00fb856SVille Syrjälä
5371b26a5e1SMaarten Lankhorst plane_state = drm_atomic_get_existing_plane_state(state, plane);
5381b26a5e1SMaarten Lankhorst if (plane_state)
5391b26a5e1SMaarten Lankhorst return plane_state;
540cc4ceb48SDaniel Vetter
5414d02e2deSDaniel Vetter ret = drm_modeset_lock(&plane->mutex, state->acquire_ctx);
542cc4ceb48SDaniel Vetter if (ret)
543cc4ceb48SDaniel Vetter return ERR_PTR(ret);
544cc4ceb48SDaniel Vetter
545cc4ceb48SDaniel Vetter plane_state = plane->funcs->atomic_duplicate_state(plane);
546cc4ceb48SDaniel Vetter if (!plane_state)
547cc4ceb48SDaniel Vetter return ERR_PTR(-ENOMEM);
548cc4ceb48SDaniel Vetter
549b8b5342bSDaniel Vetter state->planes[index].state = plane_state;
550b8b5342bSDaniel Vetter state->planes[index].ptr = plane;
551581e49feSMaarten Lankhorst state->planes[index].old_state = plane->state;
552581e49feSMaarten Lankhorst state->planes[index].new_state = plane_state;
553cc4ceb48SDaniel Vetter plane_state->state = state;
554cc4ceb48SDaniel Vetter
5556e22dc35SClaudio Suarez drm_dbg_atomic(plane->dev, "Added [PLANE:%d:%s] %p state to %p\n",
5569f4c97a2SVille Syrjälä plane->base.id, plane->name, plane_state, state);
557cc4ceb48SDaniel Vetter
558cc4ceb48SDaniel Vetter if (plane_state->crtc) {
559cc4ceb48SDaniel Vetter struct drm_crtc_state *crtc_state;
560cc4ceb48SDaniel Vetter
561cc4ceb48SDaniel Vetter crtc_state = drm_atomic_get_crtc_state(state,
562cc4ceb48SDaniel Vetter plane_state->crtc);
563cc4ceb48SDaniel Vetter if (IS_ERR(crtc_state))
564cc4ceb48SDaniel Vetter return ERR_CAST(crtc_state);
565cc4ceb48SDaniel Vetter }
566cc4ceb48SDaniel Vetter
567cc4ceb48SDaniel Vetter return plane_state;
568cc4ceb48SDaniel Vetter }
569cc4ceb48SDaniel Vetter EXPORT_SYMBOL(drm_atomic_get_plane_state);
570cc4ceb48SDaniel Vetter
571f8aeb41cSDaniel Vetter static bool
plane_switching_crtc(const struct drm_plane_state * old_plane_state,const struct drm_plane_state * new_plane_state)572d9be05b7SVille Syrjälä plane_switching_crtc(const struct drm_plane_state *old_plane_state,
573d9be05b7SVille Syrjälä const struct drm_plane_state *new_plane_state)
574f8aeb41cSDaniel Vetter {
575d9be05b7SVille Syrjälä if (!old_plane_state->crtc || !new_plane_state->crtc)
576f8aeb41cSDaniel Vetter return false;
577f8aeb41cSDaniel Vetter
578d9be05b7SVille Syrjälä if (old_plane_state->crtc == new_plane_state->crtc)
579f8aeb41cSDaniel Vetter return false;
580f8aeb41cSDaniel Vetter
581f8aeb41cSDaniel Vetter /* This could be refined, but currently there's no helper or driver code
582f8aeb41cSDaniel Vetter * to implement direct switching of active planes nor userspace to take
583f8aeb41cSDaniel Vetter * advantage of more direct plane switching without the intermediate
584f8aeb41cSDaniel Vetter * full OFF state.
585f8aeb41cSDaniel Vetter */
586f8aeb41cSDaniel Vetter return true;
587f8aeb41cSDaniel Vetter }
588f8aeb41cSDaniel Vetter
589ac9c9256SRob Clark /**
5905e743737SRob Clark * drm_atomic_plane_check - check plane state
591d9be05b7SVille Syrjälä * @old_plane_state: old plane state to check
592d9be05b7SVille Syrjälä * @new_plane_state: new plane state to check
5935e743737SRob Clark *
5945e743737SRob Clark * Provides core sanity checks for plane state.
5955e743737SRob Clark *
5965e743737SRob Clark * RETURNS:
5975e743737SRob Clark * Zero on success, error code on failure
5985e743737SRob Clark */
drm_atomic_plane_check(const struct drm_plane_state * old_plane_state,const struct drm_plane_state * new_plane_state)599d9be05b7SVille Syrjälä static int drm_atomic_plane_check(const struct drm_plane_state *old_plane_state,
600d9be05b7SVille Syrjälä const struct drm_plane_state *new_plane_state)
6015e743737SRob Clark {
602d9be05b7SVille Syrjälä struct drm_plane *plane = new_plane_state->plane;
603d9be05b7SVille Syrjälä struct drm_crtc *crtc = new_plane_state->crtc;
6041c0a80f1SDmitry Baryshkov const struct drm_framebuffer *fb = new_plane_state->fb;
605b881ba8fSDmitry Baryshkov unsigned int fb_width, fb_height;
606b881ba8fSDmitry Baryshkov struct drm_mode_rect *clips;
607b881ba8fSDmitry Baryshkov uint32_t num_clips;
6085e743737SRob Clark
6091c0a80f1SDmitry Baryshkov /* either *both* CRTC and FB must be set, or neither */
6101c0a80f1SDmitry Baryshkov if (crtc && !fb) {
6111c0a80f1SDmitry Baryshkov drm_dbg_atomic(plane->dev, "[PLANE:%d:%s] CRTC set but no FB\n",
612b6f690abSVille Syrjälä plane->base.id, plane->name);
6135e743737SRob Clark return -EINVAL;
6141c0a80f1SDmitry Baryshkov } else if (fb && !crtc) {
6151c0a80f1SDmitry Baryshkov drm_dbg_atomic(plane->dev, "[PLANE:%d:%s] FB set but no CRTC\n",
6161c0a80f1SDmitry Baryshkov plane->base.id, plane->name);
6175e743737SRob Clark return -EINVAL;
6185e743737SRob Clark }
6195e743737SRob Clark
6205e743737SRob Clark /* if disabled, we don't care about the rest of the state: */
621d9be05b7SVille Syrjälä if (!crtc)
6225e743737SRob Clark return 0;
6235e743737SRob Clark
6245e743737SRob Clark /* Check whether this plane is usable on this CRTC */
625d9be05b7SVille Syrjälä if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) {
6266e22dc35SClaudio Suarez drm_dbg_atomic(plane->dev,
6276e22dc35SClaudio Suarez "Invalid [CRTC:%d:%s] for [PLANE:%d:%s]\n",
628d9be05b7SVille Syrjälä crtc->base.id, crtc->name,
629b6f690abSVille Syrjälä plane->base.id, plane->name);
6305e743737SRob Clark return -EINVAL;
6315e743737SRob Clark }
6325e743737SRob Clark
633b881ba8fSDmitry Baryshkov /* Check whether this plane supports the fb pixel format. */
634*1d36db2bSVille Syrjälä if (!drm_plane_has_format(plane, fb->format->format, fb->modifier)) {
635b881ba8fSDmitry Baryshkov drm_dbg_atomic(plane->dev,
636b881ba8fSDmitry Baryshkov "[PLANE:%d:%s] invalid pixel format %p4cc, modifier 0x%llx\n",
637b881ba8fSDmitry Baryshkov plane->base.id, plane->name,
638b881ba8fSDmitry Baryshkov &fb->format->format, fb->modifier);
639*1d36db2bSVille Syrjälä return -EINVAL;
640b881ba8fSDmitry Baryshkov }
641b881ba8fSDmitry Baryshkov
6425e743737SRob Clark /* Give drivers some help against integer overflows */
643d9be05b7SVille Syrjälä if (new_plane_state->crtc_w > INT_MAX ||
644d9be05b7SVille Syrjälä new_plane_state->crtc_x > INT_MAX - (int32_t) new_plane_state->crtc_w ||
645d9be05b7SVille Syrjälä new_plane_state->crtc_h > INT_MAX ||
646d9be05b7SVille Syrjälä new_plane_state->crtc_y > INT_MAX - (int32_t) new_plane_state->crtc_h) {
6476e22dc35SClaudio Suarez drm_dbg_atomic(plane->dev,
6486e22dc35SClaudio Suarez "[PLANE:%d:%s] invalid CRTC coordinates %ux%u+%d+%d\n",
649b6f690abSVille Syrjälä plane->base.id, plane->name,
650d9be05b7SVille Syrjälä new_plane_state->crtc_w, new_plane_state->crtc_h,
651d9be05b7SVille Syrjälä new_plane_state->crtc_x, new_plane_state->crtc_y);
6525e743737SRob Clark return -ERANGE;
6535e743737SRob Clark }
6545e743737SRob Clark
655b881ba8fSDmitry Baryshkov fb_width = fb->width << 16;
656b881ba8fSDmitry Baryshkov fb_height = fb->height << 16;
6575e743737SRob Clark
658b881ba8fSDmitry Baryshkov /* Make sure source coordinates are inside the fb. */
659b881ba8fSDmitry Baryshkov if (new_plane_state->src_w > fb_width ||
660b881ba8fSDmitry Baryshkov new_plane_state->src_x > fb_width - new_plane_state->src_w ||
661b881ba8fSDmitry Baryshkov new_plane_state->src_h > fb_height ||
662b881ba8fSDmitry Baryshkov new_plane_state->src_y > fb_height - new_plane_state->src_h) {
663b881ba8fSDmitry Baryshkov drm_dbg_atomic(plane->dev,
664b881ba8fSDmitry Baryshkov "[PLANE:%d:%s] invalid source coordinates "
665b881ba8fSDmitry Baryshkov "%u.%06ux%u.%06u+%u.%06u+%u.%06u (fb %ux%u)\n",
666b881ba8fSDmitry Baryshkov plane->base.id, plane->name,
667b881ba8fSDmitry Baryshkov new_plane_state->src_w >> 16,
668b881ba8fSDmitry Baryshkov ((new_plane_state->src_w & 0xffff) * 15625) >> 10,
669b881ba8fSDmitry Baryshkov new_plane_state->src_h >> 16,
670b881ba8fSDmitry Baryshkov ((new_plane_state->src_h & 0xffff) * 15625) >> 10,
671b881ba8fSDmitry Baryshkov new_plane_state->src_x >> 16,
672b881ba8fSDmitry Baryshkov ((new_plane_state->src_x & 0xffff) * 15625) >> 10,
673b881ba8fSDmitry Baryshkov new_plane_state->src_y >> 16,
674b881ba8fSDmitry Baryshkov ((new_plane_state->src_y & 0xffff) * 15625) >> 10,
675b881ba8fSDmitry Baryshkov fb->width, fb->height);
676b881ba8fSDmitry Baryshkov return -ENOSPC;
677b881ba8fSDmitry Baryshkov }
678b881ba8fSDmitry Baryshkov
679b881ba8fSDmitry Baryshkov clips = __drm_plane_get_damage_clips(new_plane_state);
680b881ba8fSDmitry Baryshkov num_clips = drm_plane_get_damage_clips_count(new_plane_state);
681b881ba8fSDmitry Baryshkov
682b881ba8fSDmitry Baryshkov /* Make sure damage clips are valid and inside the fb. */
683b881ba8fSDmitry Baryshkov while (num_clips > 0) {
684b881ba8fSDmitry Baryshkov if (clips->x1 >= clips->x2 ||
685b881ba8fSDmitry Baryshkov clips->y1 >= clips->y2 ||
686b881ba8fSDmitry Baryshkov clips->x1 < 0 ||
687b881ba8fSDmitry Baryshkov clips->y1 < 0 ||
688b881ba8fSDmitry Baryshkov clips->x2 > fb_width ||
689b881ba8fSDmitry Baryshkov clips->y2 > fb_height) {
690b881ba8fSDmitry Baryshkov drm_dbg_atomic(plane->dev,
691b881ba8fSDmitry Baryshkov "[PLANE:%d:%s] invalid damage clip %d %d %d %d\n",
692b881ba8fSDmitry Baryshkov plane->base.id, plane->name, clips->x1,
693b881ba8fSDmitry Baryshkov clips->y1, clips->x2, clips->y2);
694b881ba8fSDmitry Baryshkov return -EINVAL;
695b881ba8fSDmitry Baryshkov }
696b881ba8fSDmitry Baryshkov clips++;
697b881ba8fSDmitry Baryshkov num_clips--;
698b881ba8fSDmitry Baryshkov }
699d3b21767SLukasz Spintzyk
700d9be05b7SVille Syrjälä if (plane_switching_crtc(old_plane_state, new_plane_state)) {
7016e22dc35SClaudio Suarez drm_dbg_atomic(plane->dev,
7026e22dc35SClaudio Suarez "[PLANE:%d:%s] switching CRTC directly\n",
7039f4c97a2SVille Syrjälä plane->base.id, plane->name);
704f8aeb41cSDaniel Vetter return -EINVAL;
705f8aeb41cSDaniel Vetter }
706f8aeb41cSDaniel Vetter
7075e743737SRob Clark return 0;
7085e743737SRob Clark }
7095e743737SRob Clark
drm_atomic_plane_print_state(struct drm_printer * p,const struct drm_plane_state * state)710fceffb32SRob Clark static void drm_atomic_plane_print_state(struct drm_printer *p,
711fceffb32SRob Clark const struct drm_plane_state *state)
712fceffb32SRob Clark {
713fceffb32SRob Clark struct drm_plane *plane = state->plane;
714fceffb32SRob Clark struct drm_rect src = drm_plane_state_src(state);
715fceffb32SRob Clark struct drm_rect dest = drm_plane_state_dest(state);
716fceffb32SRob Clark
717fceffb32SRob Clark drm_printf(p, "plane[%u]: %s\n", plane->base.id, plane->name);
718fceffb32SRob Clark drm_printf(p, "\tcrtc=%s\n", state->crtc ? state->crtc->name : "(null)");
719fceffb32SRob Clark drm_printf(p, "\tfb=%u\n", state->fb ? state->fb->base.id : 0);
720f02b604bSNoralf Trønnes if (state->fb)
721f02b604bSNoralf Trønnes drm_framebuffer_print_info(p, 2, state->fb);
722fceffb32SRob Clark drm_printf(p, "\tcrtc-pos=" DRM_RECT_FMT "\n", DRM_RECT_ARG(&dest));
723fceffb32SRob Clark drm_printf(p, "\tsrc-pos=" DRM_RECT_FP_FMT "\n", DRM_RECT_FP_ARG(&src));
724fceffb32SRob Clark drm_printf(p, "\trotation=%x\n", state->rotation);
725f8878bb2SBenjamin Gaignard drm_printf(p, "\tnormalized-zpos=%x\n", state->normalized_zpos);
72656dbbaffSVille Syrjälä drm_printf(p, "\tcolor-encoding=%s\n",
72756dbbaffSVille Syrjälä drm_get_color_encoding_name(state->color_encoding));
72856dbbaffSVille Syrjälä drm_printf(p, "\tcolor-range=%s\n",
72956dbbaffSVille Syrjälä drm_get_color_range_name(state->color_range));
73024013b93SMelissa Wen drm_printf(p, "\tcolor_mgmt_changed=%d\n", state->color_mgmt_changed);
731fceffb32SRob Clark
732fceffb32SRob Clark if (plane->funcs->atomic_print_state)
733fceffb32SRob Clark plane->funcs->atomic_print_state(p, state);
734fceffb32SRob Clark }
735fceffb32SRob Clark
7365e743737SRob Clark /**
737da6c0596SDaniel Vetter * DOC: handling driver private state
738da6c0596SDaniel Vetter *
739da6c0596SDaniel Vetter * Very often the DRM objects exposed to userspace in the atomic modeset api
740da6c0596SDaniel Vetter * (&drm_connector, &drm_crtc and &drm_plane) do not map neatly to the
741da6c0596SDaniel Vetter * underlying hardware. Especially for any kind of shared resources (e.g. shared
742da6c0596SDaniel Vetter * clocks, scaler units, bandwidth and fifo limits shared among a group of
743da6c0596SDaniel Vetter * planes or CRTCs, and so on) it makes sense to model these as independent
744da6c0596SDaniel Vetter * objects. Drivers then need to do similar state tracking and commit ordering for
7450ae865efSCai Huoqing * such private (since not exposed to userspace) objects as the atomic core and
746da6c0596SDaniel Vetter * helpers already provide for connectors, planes and CRTCs.
747da6c0596SDaniel Vetter *
748da6c0596SDaniel Vetter * To make this easier on drivers the atomic core provides some support to track
749da6c0596SDaniel Vetter * driver private state objects using struct &drm_private_obj, with the
750da6c0596SDaniel Vetter * associated state struct &drm_private_state.
751da6c0596SDaniel Vetter *
752da6c0596SDaniel Vetter * Similar to userspace-exposed objects, private state structures can be
7530380c684SDaniel Vetter * acquired by calling drm_atomic_get_private_obj_state(). This also takes care
7540380c684SDaniel Vetter * of locking, hence drivers should not have a need to call drm_modeset_lock()
7550380c684SDaniel Vetter * directly. Sequence of the actual hardware state commit is not handled,
7560380c684SDaniel Vetter * drivers might need to keep track of struct drm_crtc_commit within subclassed
7570380c684SDaniel Vetter * structure of &drm_private_state as necessary, e.g. similar to
7580380c684SDaniel Vetter * &drm_plane_state.commit. See also &drm_atomic_state.fake_commit.
759da6c0596SDaniel Vetter *
760da6c0596SDaniel Vetter * All private state structures contained in a &drm_atomic_state update can be
761da6c0596SDaniel Vetter * iterated using for_each_oldnew_private_obj_in_state(),
762da6c0596SDaniel Vetter * for_each_new_private_obj_in_state() and for_each_old_private_obj_in_state().
763da6c0596SDaniel Vetter * Drivers are recommended to wrap these for each type of driver private state
764da6c0596SDaniel Vetter * object they have, filtering on &drm_private_obj.funcs using for_each_if(), at
765da6c0596SDaniel Vetter * least if they want to iterate over all objects of a given type.
766da6c0596SDaniel Vetter *
767da6c0596SDaniel Vetter * An earlier way to handle driver private state was by subclassing struct
768da6c0596SDaniel Vetter * &drm_atomic_state. But since that encourages non-standard ways to implement
769da6c0596SDaniel Vetter * the check/commit split atomic requires (by using e.g. "check and rollback or
770da6c0596SDaniel Vetter * commit instead" of "duplicate state, check, then either commit or release
771da6c0596SDaniel Vetter * duplicated state) it is deprecated in favour of using &drm_private_state.
772da6c0596SDaniel Vetter */
773da6c0596SDaniel Vetter
774da6c0596SDaniel Vetter /**
775a4370c77SVille Syrjälä * drm_atomic_private_obj_init - initialize private object
776b962a120SRob Clark * @dev: DRM device this object will be attached to
777a4370c77SVille Syrjälä * @obj: private object
778a4370c77SVille Syrjälä * @state: initial private object state
779a4370c77SVille Syrjälä * @funcs: pointer to the struct of function pointers that identify the object
780a4370c77SVille Syrjälä * type
781a4370c77SVille Syrjälä *
782a4370c77SVille Syrjälä * Initialize the private object, which can be embedded into any
783a4370c77SVille Syrjälä * driver private object that needs its own atomic state.
784a4370c77SVille Syrjälä */
785a4370c77SVille Syrjälä void
drm_atomic_private_obj_init(struct drm_device * dev,struct drm_private_obj * obj,struct drm_private_state * state,const struct drm_private_state_funcs * funcs)786b962a120SRob Clark drm_atomic_private_obj_init(struct drm_device *dev,
787b962a120SRob Clark struct drm_private_obj *obj,
788a4370c77SVille Syrjälä struct drm_private_state *state,
789a4370c77SVille Syrjälä const struct drm_private_state_funcs *funcs)
790a4370c77SVille Syrjälä {
791a4370c77SVille Syrjälä memset(obj, 0, sizeof(*obj));
792a4370c77SVille Syrjälä
793b962a120SRob Clark drm_modeset_lock_init(&obj->lock);
794b962a120SRob Clark
795a4370c77SVille Syrjälä obj->state = state;
796a4370c77SVille Syrjälä obj->funcs = funcs;
797b962a120SRob Clark list_add_tail(&obj->head, &dev->mode_config.privobj_list);
79897a1f01bSMaxime Ripard
79997a1f01bSMaxime Ripard state->obj = obj;
800a4370c77SVille Syrjälä }
801a4370c77SVille Syrjälä EXPORT_SYMBOL(drm_atomic_private_obj_init);
802a4370c77SVille Syrjälä
803a4370c77SVille Syrjälä /**
804a4370c77SVille Syrjälä * drm_atomic_private_obj_fini - finalize private object
805a4370c77SVille Syrjälä * @obj: private object
806a4370c77SVille Syrjälä *
807a4370c77SVille Syrjälä * Finalize the private object.
808a4370c77SVille Syrjälä */
809a4370c77SVille Syrjälä void
drm_atomic_private_obj_fini(struct drm_private_obj * obj)810a4370c77SVille Syrjälä drm_atomic_private_obj_fini(struct drm_private_obj *obj)
811a4370c77SVille Syrjälä {
812b962a120SRob Clark list_del(&obj->head);
813a4370c77SVille Syrjälä obj->funcs->atomic_destroy_state(obj, obj->state);
814b962a120SRob Clark drm_modeset_lock_fini(&obj->lock);
815a4370c77SVille Syrjälä }
816a4370c77SVille Syrjälä EXPORT_SYMBOL(drm_atomic_private_obj_fini);
817a4370c77SVille Syrjälä
818a4370c77SVille Syrjälä /**
819b430c27aSPandiyan, Dhinakaran * drm_atomic_get_private_obj_state - get private object state
820b430c27aSPandiyan, Dhinakaran * @state: global atomic state
821b430c27aSPandiyan, Dhinakaran * @obj: private object to get the state for
822b430c27aSPandiyan, Dhinakaran *
823b430c27aSPandiyan, Dhinakaran * This function returns the private object state for the given private object,
824b962a120SRob Clark * allocating the state if needed. It will also grab the relevant private
825b962a120SRob Clark * object lock to make sure that the state is consistent.
826b430c27aSPandiyan, Dhinakaran *
827b430c27aSPandiyan, Dhinakaran * RETURNS:
828b430c27aSPandiyan, Dhinakaran * Either the allocated state or the error code encoded into a pointer.
829b430c27aSPandiyan, Dhinakaran */
830a4370c77SVille Syrjälä struct drm_private_state *
drm_atomic_get_private_obj_state(struct drm_atomic_state * state,struct drm_private_obj * obj)831a4370c77SVille Syrjälä drm_atomic_get_private_obj_state(struct drm_atomic_state *state,
832a4370c77SVille Syrjälä struct drm_private_obj *obj)
833b430c27aSPandiyan, Dhinakaran {
834b962a120SRob Clark int index, num_objs, i, ret;
835b430c27aSPandiyan, Dhinakaran size_t size;
836b430c27aSPandiyan, Dhinakaran struct __drm_private_objs_state *arr;
837a4370c77SVille Syrjälä struct drm_private_state *obj_state;
838b430c27aSPandiyan, Dhinakaran
839b430c27aSPandiyan, Dhinakaran for (i = 0; i < state->num_private_objs; i++)
840a4370c77SVille Syrjälä if (obj == state->private_objs[i].ptr)
841a4370c77SVille Syrjälä return state->private_objs[i].state;
842b430c27aSPandiyan, Dhinakaran
843b962a120SRob Clark ret = drm_modeset_lock(&obj->lock, state->acquire_ctx);
844b962a120SRob Clark if (ret)
845b962a120SRob Clark return ERR_PTR(ret);
846b962a120SRob Clark
847b430c27aSPandiyan, Dhinakaran num_objs = state->num_private_objs + 1;
848b430c27aSPandiyan, Dhinakaran size = sizeof(*state->private_objs) * num_objs;
849b430c27aSPandiyan, Dhinakaran arr = krealloc(state->private_objs, size, GFP_KERNEL);
850b430c27aSPandiyan, Dhinakaran if (!arr)
851b430c27aSPandiyan, Dhinakaran return ERR_PTR(-ENOMEM);
852b430c27aSPandiyan, Dhinakaran
853b430c27aSPandiyan, Dhinakaran state->private_objs = arr;
854b430c27aSPandiyan, Dhinakaran index = state->num_private_objs;
855b430c27aSPandiyan, Dhinakaran memset(&state->private_objs[index], 0, sizeof(*state->private_objs));
856b430c27aSPandiyan, Dhinakaran
857a4370c77SVille Syrjälä obj_state = obj->funcs->atomic_duplicate_state(obj);
858a4370c77SVille Syrjälä if (!obj_state)
859b430c27aSPandiyan, Dhinakaran return ERR_PTR(-ENOMEM);
860b430c27aSPandiyan, Dhinakaran
861a4370c77SVille Syrjälä state->private_objs[index].state = obj_state;
862a4370c77SVille Syrjälä state->private_objs[index].old_state = obj->state;
863a4370c77SVille Syrjälä state->private_objs[index].new_state = obj_state;
864a4370c77SVille Syrjälä state->private_objs[index].ptr = obj;
865e89ea355SAlexandru Gheorghe obj_state->state = state;
866a4370c77SVille Syrjälä
867b430c27aSPandiyan, Dhinakaran state->num_private_objs = num_objs;
868b430c27aSPandiyan, Dhinakaran
8696e22dc35SClaudio Suarez drm_dbg_atomic(state->dev,
8706e22dc35SClaudio Suarez "Added new private object %p state %p to %p\n",
871a4370c77SVille Syrjälä obj, obj_state, state);
872b430c27aSPandiyan, Dhinakaran
873a4370c77SVille Syrjälä return obj_state;
874b430c27aSPandiyan, Dhinakaran }
875b430c27aSPandiyan, Dhinakaran EXPORT_SYMBOL(drm_atomic_get_private_obj_state);
876b430c27aSPandiyan, Dhinakaran
877b430c27aSPandiyan, Dhinakaran /**
8789801a7eaSjames qian wang (Arm Technology China) * drm_atomic_get_old_private_obj_state
8799801a7eaSjames qian wang (Arm Technology China) * @state: global atomic state object
8809801a7eaSjames qian wang (Arm Technology China) * @obj: private_obj to grab
8819801a7eaSjames qian wang (Arm Technology China) *
8829801a7eaSjames qian wang (Arm Technology China) * This function returns the old private object state for the given private_obj,
8839801a7eaSjames qian wang (Arm Technology China) * or NULL if the private_obj is not part of the global atomic state.
8849801a7eaSjames qian wang (Arm Technology China) */
8859801a7eaSjames qian wang (Arm Technology China) struct drm_private_state *
drm_atomic_get_old_private_obj_state(const struct drm_atomic_state * state,struct drm_private_obj * obj)8862081bd89SMaxime Ripard drm_atomic_get_old_private_obj_state(const struct drm_atomic_state *state,
8879801a7eaSjames qian wang (Arm Technology China) struct drm_private_obj *obj)
8889801a7eaSjames qian wang (Arm Technology China) {
8899801a7eaSjames qian wang (Arm Technology China) int i;
8909801a7eaSjames qian wang (Arm Technology China)
8919801a7eaSjames qian wang (Arm Technology China) for (i = 0; i < state->num_private_objs; i++)
8929801a7eaSjames qian wang (Arm Technology China) if (obj == state->private_objs[i].ptr)
8939801a7eaSjames qian wang (Arm Technology China) return state->private_objs[i].old_state;
8949801a7eaSjames qian wang (Arm Technology China)
8959801a7eaSjames qian wang (Arm Technology China) return NULL;
8969801a7eaSjames qian wang (Arm Technology China) }
8979801a7eaSjames qian wang (Arm Technology China) EXPORT_SYMBOL(drm_atomic_get_old_private_obj_state);
8989801a7eaSjames qian wang (Arm Technology China)
8999801a7eaSjames qian wang (Arm Technology China) /**
9009801a7eaSjames qian wang (Arm Technology China) * drm_atomic_get_new_private_obj_state
9019801a7eaSjames qian wang (Arm Technology China) * @state: global atomic state object
9029801a7eaSjames qian wang (Arm Technology China) * @obj: private_obj to grab
9039801a7eaSjames qian wang (Arm Technology China) *
9049801a7eaSjames qian wang (Arm Technology China) * This function returns the new private object state for the given private_obj,
9059801a7eaSjames qian wang (Arm Technology China) * or NULL if the private_obj is not part of the global atomic state.
9069801a7eaSjames qian wang (Arm Technology China) */
9079801a7eaSjames qian wang (Arm Technology China) struct drm_private_state *
drm_atomic_get_new_private_obj_state(const struct drm_atomic_state * state,struct drm_private_obj * obj)9082081bd89SMaxime Ripard drm_atomic_get_new_private_obj_state(const struct drm_atomic_state *state,
9099801a7eaSjames qian wang (Arm Technology China) struct drm_private_obj *obj)
9109801a7eaSjames qian wang (Arm Technology China) {
9119801a7eaSjames qian wang (Arm Technology China) int i;
9129801a7eaSjames qian wang (Arm Technology China)
9139801a7eaSjames qian wang (Arm Technology China) for (i = 0; i < state->num_private_objs; i++)
9149801a7eaSjames qian wang (Arm Technology China) if (obj == state->private_objs[i].ptr)
9159801a7eaSjames qian wang (Arm Technology China) return state->private_objs[i].new_state;
9169801a7eaSjames qian wang (Arm Technology China)
9179801a7eaSjames qian wang (Arm Technology China) return NULL;
9189801a7eaSjames qian wang (Arm Technology China) }
9199801a7eaSjames qian wang (Arm Technology China) EXPORT_SYMBOL(drm_atomic_get_new_private_obj_state);
9209801a7eaSjames qian wang (Arm Technology China)
9219801a7eaSjames qian wang (Arm Technology China) /**
9221b27fbddSLaurent Pinchart * drm_atomic_get_old_connector_for_encoder - Get old connector for an encoder
9231b27fbddSLaurent Pinchart * @state: Atomic state
9241b27fbddSLaurent Pinchart * @encoder: The encoder to fetch the connector state for
9251b27fbddSLaurent Pinchart *
9261b27fbddSLaurent Pinchart * This function finds and returns the connector that was connected to @encoder
9271b27fbddSLaurent Pinchart * as specified by the @state.
9281b27fbddSLaurent Pinchart *
9291b27fbddSLaurent Pinchart * If there is no connector in @state which previously had @encoder connected to
9301b27fbddSLaurent Pinchart * it, this function will return NULL. While this may seem like an invalid use
9311b27fbddSLaurent Pinchart * case, it is sometimes useful to differentiate commits which had no prior
9321b27fbddSLaurent Pinchart * connectors attached to @encoder vs ones that did (and to inspect their
9331b27fbddSLaurent Pinchart * state). This is especially true in enable hooks because the pipeline has
9341b27fbddSLaurent Pinchart * changed.
9351b27fbddSLaurent Pinchart *
9361b27fbddSLaurent Pinchart * Returns: The old connector connected to @encoder, or NULL if the encoder is
9371b27fbddSLaurent Pinchart * not connected.
9381b27fbddSLaurent Pinchart */
9391b27fbddSLaurent Pinchart struct drm_connector *
drm_atomic_get_old_connector_for_encoder(const struct drm_atomic_state * state,struct drm_encoder * encoder)9402081bd89SMaxime Ripard drm_atomic_get_old_connector_for_encoder(const struct drm_atomic_state *state,
9411b27fbddSLaurent Pinchart struct drm_encoder *encoder)
9421b27fbddSLaurent Pinchart {
9431b27fbddSLaurent Pinchart struct drm_connector_state *conn_state;
9441b27fbddSLaurent Pinchart struct drm_connector *connector;
9451b27fbddSLaurent Pinchart unsigned int i;
9461b27fbddSLaurent Pinchart
9471b27fbddSLaurent Pinchart for_each_old_connector_in_state(state, connector, conn_state, i) {
9481b27fbddSLaurent Pinchart if (conn_state->best_encoder == encoder)
9491b27fbddSLaurent Pinchart return connector;
9501b27fbddSLaurent Pinchart }
9511b27fbddSLaurent Pinchart
9521b27fbddSLaurent Pinchart return NULL;
9531b27fbddSLaurent Pinchart }
9541b27fbddSLaurent Pinchart EXPORT_SYMBOL(drm_atomic_get_old_connector_for_encoder);
9551b27fbddSLaurent Pinchart
9561b27fbddSLaurent Pinchart /**
9571b27fbddSLaurent Pinchart * drm_atomic_get_new_connector_for_encoder - Get new connector for an encoder
9581b27fbddSLaurent Pinchart * @state: Atomic state
9591b27fbddSLaurent Pinchart * @encoder: The encoder to fetch the connector state for
9601b27fbddSLaurent Pinchart *
9611b27fbddSLaurent Pinchart * This function finds and returns the connector that will be connected to
9621b27fbddSLaurent Pinchart * @encoder as specified by the @state.
9631b27fbddSLaurent Pinchart *
9641b27fbddSLaurent Pinchart * If there is no connector in @state which will have @encoder connected to it,
9651b27fbddSLaurent Pinchart * this function will return NULL. While this may seem like an invalid use case,
9661b27fbddSLaurent Pinchart * it is sometimes useful to differentiate commits which have no connectors
9671b27fbddSLaurent Pinchart * attached to @encoder vs ones that do (and to inspect their state). This is
9681b27fbddSLaurent Pinchart * especially true in disable hooks because the pipeline will change.
9691b27fbddSLaurent Pinchart *
9701b27fbddSLaurent Pinchart * Returns: The new connector connected to @encoder, or NULL if the encoder is
9711b27fbddSLaurent Pinchart * not connected.
9721b27fbddSLaurent Pinchart */
9731b27fbddSLaurent Pinchart struct drm_connector *
drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state * state,struct drm_encoder * encoder)9742081bd89SMaxime Ripard drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
9751b27fbddSLaurent Pinchart struct drm_encoder *encoder)
9761b27fbddSLaurent Pinchart {
9771b27fbddSLaurent Pinchart struct drm_connector_state *conn_state;
9781b27fbddSLaurent Pinchart struct drm_connector *connector;
9791b27fbddSLaurent Pinchart unsigned int i;
9801b27fbddSLaurent Pinchart
9811b27fbddSLaurent Pinchart for_each_new_connector_in_state(state, connector, conn_state, i) {
9821b27fbddSLaurent Pinchart if (conn_state->best_encoder == encoder)
9831b27fbddSLaurent Pinchart return connector;
9841b27fbddSLaurent Pinchart }
9851b27fbddSLaurent Pinchart
9861b27fbddSLaurent Pinchart return NULL;
9871b27fbddSLaurent Pinchart }
9881b27fbddSLaurent Pinchart EXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder);
9891b27fbddSLaurent Pinchart
9901b27fbddSLaurent Pinchart /**
9917b9a9e35SVinod Polimera * drm_atomic_get_old_crtc_for_encoder - Get old crtc for an encoder
9927b9a9e35SVinod Polimera * @state: Atomic state
9937b9a9e35SVinod Polimera * @encoder: The encoder to fetch the crtc state for
9947b9a9e35SVinod Polimera *
9957b9a9e35SVinod Polimera * This function finds and returns the crtc that was connected to @encoder
9967b9a9e35SVinod Polimera * as specified by the @state.
9977b9a9e35SVinod Polimera *
9987b9a9e35SVinod Polimera * Returns: The old crtc connected to @encoder, or NULL if the encoder is
9997b9a9e35SVinod Polimera * not connected.
10007b9a9e35SVinod Polimera */
10017b9a9e35SVinod Polimera struct drm_crtc *
drm_atomic_get_old_crtc_for_encoder(struct drm_atomic_state * state,struct drm_encoder * encoder)10027b9a9e35SVinod Polimera drm_atomic_get_old_crtc_for_encoder(struct drm_atomic_state *state,
10037b9a9e35SVinod Polimera struct drm_encoder *encoder)
10047b9a9e35SVinod Polimera {
10057b9a9e35SVinod Polimera struct drm_connector *connector;
10067b9a9e35SVinod Polimera struct drm_connector_state *conn_state;
10077b9a9e35SVinod Polimera
10087b9a9e35SVinod Polimera connector = drm_atomic_get_old_connector_for_encoder(state, encoder);
10097b9a9e35SVinod Polimera if (!connector)
10107b9a9e35SVinod Polimera return NULL;
10117b9a9e35SVinod Polimera
10127b9a9e35SVinod Polimera conn_state = drm_atomic_get_old_connector_state(state, connector);
10137b9a9e35SVinod Polimera if (!conn_state)
10147b9a9e35SVinod Polimera return NULL;
10157b9a9e35SVinod Polimera
10167b9a9e35SVinod Polimera return conn_state->crtc;
10177b9a9e35SVinod Polimera }
10187b9a9e35SVinod Polimera EXPORT_SYMBOL(drm_atomic_get_old_crtc_for_encoder);
10197b9a9e35SVinod Polimera
10207b9a9e35SVinod Polimera /**
10217b9a9e35SVinod Polimera * drm_atomic_get_new_crtc_for_encoder - Get new crtc for an encoder
10227b9a9e35SVinod Polimera * @state: Atomic state
10237b9a9e35SVinod Polimera * @encoder: The encoder to fetch the crtc state for
10247b9a9e35SVinod Polimera *
10257b9a9e35SVinod Polimera * This function finds and returns the crtc that will be connected to @encoder
10267b9a9e35SVinod Polimera * as specified by the @state.
10277b9a9e35SVinod Polimera *
10287b9a9e35SVinod Polimera * Returns: The new crtc connected to @encoder, or NULL if the encoder is
10297b9a9e35SVinod Polimera * not connected.
10307b9a9e35SVinod Polimera */
10317b9a9e35SVinod Polimera struct drm_crtc *
drm_atomic_get_new_crtc_for_encoder(struct drm_atomic_state * state,struct drm_encoder * encoder)10327b9a9e35SVinod Polimera drm_atomic_get_new_crtc_for_encoder(struct drm_atomic_state *state,
10337b9a9e35SVinod Polimera struct drm_encoder *encoder)
10347b9a9e35SVinod Polimera {
10357b9a9e35SVinod Polimera struct drm_connector *connector;
10367b9a9e35SVinod Polimera struct drm_connector_state *conn_state;
10377b9a9e35SVinod Polimera
10387b9a9e35SVinod Polimera connector = drm_atomic_get_new_connector_for_encoder(state, encoder);
10397b9a9e35SVinod Polimera if (!connector)
10407b9a9e35SVinod Polimera return NULL;
10417b9a9e35SVinod Polimera
10427b9a9e35SVinod Polimera conn_state = drm_atomic_get_new_connector_state(state, connector);
10437b9a9e35SVinod Polimera if (!conn_state)
10447b9a9e35SVinod Polimera return NULL;
10457b9a9e35SVinod Polimera
10467b9a9e35SVinod Polimera return conn_state->crtc;
10477b9a9e35SVinod Polimera }
10487b9a9e35SVinod Polimera EXPORT_SYMBOL(drm_atomic_get_new_crtc_for_encoder);
10497b9a9e35SVinod Polimera
10507b9a9e35SVinod Polimera /**
1051cc4ceb48SDaniel Vetter * drm_atomic_get_connector_state - get connector state
1052cc4ceb48SDaniel Vetter * @state: global atomic state object
1053cc4ceb48SDaniel Vetter * @connector: connector to get state object for
1054cc4ceb48SDaniel Vetter *
1055cc4ceb48SDaniel Vetter * This function returns the connector state for the given connector,
1056cc4ceb48SDaniel Vetter * allocating it if needed. It will also grab the relevant connector lock to
1057cc4ceb48SDaniel Vetter * make sure that the state is consistent.
1058cc4ceb48SDaniel Vetter *
1059cc4ceb48SDaniel Vetter * Returns:
1060cc4ceb48SDaniel Vetter * Either the allocated state or the error code encoded into the pointer. When
1061cc4ceb48SDaniel Vetter * the error is EDEADLK then the w/w mutex code has detected a deadlock and the
1062cc4ceb48SDaniel Vetter * entire atomic sequence must be restarted. All other errors are fatal.
1063cc4ceb48SDaniel Vetter */
1064cc4ceb48SDaniel Vetter struct drm_connector_state *
drm_atomic_get_connector_state(struct drm_atomic_state * state,struct drm_connector * connector)1065cc4ceb48SDaniel Vetter drm_atomic_get_connector_state(struct drm_atomic_state *state,
1066cc4ceb48SDaniel Vetter struct drm_connector *connector)
1067cc4ceb48SDaniel Vetter {
1068cc4ceb48SDaniel Vetter int ret, index;
1069cc4ceb48SDaniel Vetter struct drm_mode_config *config = &connector->dev->mode_config;
1070cc4ceb48SDaniel Vetter struct drm_connector_state *connector_state;
1071cc4ceb48SDaniel Vetter
10727f4eaa89SMaarten Lankhorst WARN_ON(!state->acquire_ctx);
10737f4eaa89SMaarten Lankhorst
1074c7eb76f4SDaniel Vetter ret = drm_modeset_lock(&config->connection_mutex, state->acquire_ctx);
1075c7eb76f4SDaniel Vetter if (ret)
1076c7eb76f4SDaniel Vetter return ERR_PTR(ret);
1077c7eb76f4SDaniel Vetter
1078cc4ceb48SDaniel Vetter index = drm_connector_index(connector);
1079cc4ceb48SDaniel Vetter
1080f52b69f1SDaniel Vetter if (index >= state->num_connector) {
108163e83c1dSDaniel Vetter struct __drm_connnectors_state *c;
10825fff80bbSMaarten Lankhorst int alloc = max(index + 1, config->num_connector);
10835fff80bbSMaarten Lankhorst
108432ce2553SBartosz Golaszewski c = krealloc_array(state->connectors, alloc,
108532ce2553SBartosz Golaszewski sizeof(*state->connectors), GFP_KERNEL);
10865fff80bbSMaarten Lankhorst if (!c)
10875fff80bbSMaarten Lankhorst return ERR_PTR(-ENOMEM);
10885fff80bbSMaarten Lankhorst
10895fff80bbSMaarten Lankhorst state->connectors = c;
10905fff80bbSMaarten Lankhorst memset(&state->connectors[state->num_connector], 0,
10915fff80bbSMaarten Lankhorst sizeof(*state->connectors) * (alloc - state->num_connector));
10925fff80bbSMaarten Lankhorst
10935fff80bbSMaarten Lankhorst state->num_connector = alloc;
1094f52b69f1SDaniel Vetter }
1095f52b69f1SDaniel Vetter
109663e83c1dSDaniel Vetter if (state->connectors[index].state)
109763e83c1dSDaniel Vetter return state->connectors[index].state;
1098cc4ceb48SDaniel Vetter
1099cc4ceb48SDaniel Vetter connector_state = connector->funcs->atomic_duplicate_state(connector);
1100cc4ceb48SDaniel Vetter if (!connector_state)
1101cc4ceb48SDaniel Vetter return ERR_PTR(-ENOMEM);
1102cc4ceb48SDaniel Vetter
1103ad093607SThierry Reding drm_connector_get(connector);
110463e83c1dSDaniel Vetter state->connectors[index].state = connector_state;
1105581e49feSMaarten Lankhorst state->connectors[index].old_state = connector->state;
1106581e49feSMaarten Lankhorst state->connectors[index].new_state = connector_state;
110763e83c1dSDaniel Vetter state->connectors[index].ptr = connector;
1108cc4ceb48SDaniel Vetter connector_state->state = state;
1109cc4ceb48SDaniel Vetter
11106e22dc35SClaudio Suarez drm_dbg_atomic(connector->dev, "Added [CONNECTOR:%d:%s] %p state to %p\n",
11116ac7c548SRussell King connector->base.id, connector->name,
11126ac7c548SRussell King connector_state, state);
1113cc4ceb48SDaniel Vetter
1114cc4ceb48SDaniel Vetter if (connector_state->crtc) {
1115cc4ceb48SDaniel Vetter struct drm_crtc_state *crtc_state;
1116cc4ceb48SDaniel Vetter
1117cc4ceb48SDaniel Vetter crtc_state = drm_atomic_get_crtc_state(state,
1118cc4ceb48SDaniel Vetter connector_state->crtc);
1119cc4ceb48SDaniel Vetter if (IS_ERR(crtc_state))
1120cc4ceb48SDaniel Vetter return ERR_CAST(crtc_state);
1121cc4ceb48SDaniel Vetter }
1122cc4ceb48SDaniel Vetter
1123cc4ceb48SDaniel Vetter return connector_state;
1124cc4ceb48SDaniel Vetter }
1125cc4ceb48SDaniel Vetter EXPORT_SYMBOL(drm_atomic_get_connector_state);
1126cc4ceb48SDaniel Vetter
drm_atomic_connector_print_state(struct drm_printer * p,const struct drm_connector_state * state)1127fceffb32SRob Clark static void drm_atomic_connector_print_state(struct drm_printer *p,
1128fceffb32SRob Clark const struct drm_connector_state *state)
1129fceffb32SRob Clark {
1130fceffb32SRob Clark struct drm_connector *connector = state->connector;
1131fceffb32SRob Clark
1132fceffb32SRob Clark drm_printf(p, "connector[%u]: %s\n", connector->base.id, connector->name);
1133fceffb32SRob Clark drm_printf(p, "\tcrtc=%s\n", state->crtc ? state->crtc->name : "(null)");
11341452c25bSSean Paul drm_printf(p, "\tself_refresh_aware=%d\n", state->self_refresh_aware);
11357d386975SHarry Wentland drm_printf(p, "\tmax_requested_bpc=%d\n", state->max_requested_bpc);
1136035d53e0SHarry Wentland drm_printf(p, "\tcolorspace=%s\n", drm_get_colorspace_name(state->colorspace));
1137fceffb32SRob Clark
1138aadb3e16SMaxime Ripard if (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA ||
1139aadb3e16SMaxime Ripard connector->connector_type == DRM_MODE_CONNECTOR_HDMIB) {
1140ab52af4bSMaxime Ripard drm_printf(p, "\tbroadcast_rgb=%s\n",
1141ab52af4bSMaxime Ripard drm_hdmi_connector_get_broadcast_rgb_name(state->hdmi.broadcast_rgb));
1142027d4359SMaxime Ripard drm_printf(p, "\tis_limited_range=%c\n", state->hdmi.is_limited_range ? 'y' : 'n');
1143aadb3e16SMaxime Ripard drm_printf(p, "\toutput_bpc=%u\n", state->hdmi.output_bpc);
1144948f01d5SMaxime Ripard drm_printf(p, "\toutput_format=%s\n",
1145948f01d5SMaxime Ripard drm_hdmi_connector_get_output_format_name(state->hdmi.output_format));
1146f035f409SMaxime Ripard drm_printf(p, "\ttmds_char_rate=%llu\n", state->hdmi.tmds_char_rate);
1147aadb3e16SMaxime Ripard }
1148aadb3e16SMaxime Ripard
11498cbc5cafSBrian Starkey if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
11508cbc5cafSBrian Starkey if (state->writeback_job && state->writeback_job->fb)
11518cbc5cafSBrian Starkey drm_printf(p, "\tfb=%d\n", state->writeback_job->fb->base.id);
11528cbc5cafSBrian Starkey
1153fceffb32SRob Clark if (connector->funcs->atomic_print_state)
1154fceffb32SRob Clark connector->funcs->atomic_print_state(p, state);
1155fceffb32SRob Clark }
1156fceffb32SRob Clark
1157cc4ceb48SDaniel Vetter /**
115875146591SBoris Brezillon * drm_atomic_get_bridge_state - get bridge state
115975146591SBoris Brezillon * @state: global atomic state object
116075146591SBoris Brezillon * @bridge: bridge to get state object for
116175146591SBoris Brezillon *
116275146591SBoris Brezillon * This function returns the bridge state for the given bridge, allocating it
116375146591SBoris Brezillon * if needed. It will also grab the relevant bridge lock to make sure that the
116475146591SBoris Brezillon * state is consistent.
116575146591SBoris Brezillon *
116675146591SBoris Brezillon * Returns:
116775146591SBoris Brezillon * Either the allocated state or the error code encoded into the pointer. When
116875146591SBoris Brezillon * the error is EDEADLK then the w/w mutex code has detected a deadlock and the
116975146591SBoris Brezillon * entire atomic sequence must be restarted.
117075146591SBoris Brezillon */
117175146591SBoris Brezillon struct drm_bridge_state *
drm_atomic_get_bridge_state(struct drm_atomic_state * state,struct drm_bridge * bridge)117275146591SBoris Brezillon drm_atomic_get_bridge_state(struct drm_atomic_state *state,
117375146591SBoris Brezillon struct drm_bridge *bridge)
117475146591SBoris Brezillon {
117575146591SBoris Brezillon struct drm_private_state *obj_state;
117675146591SBoris Brezillon
117775146591SBoris Brezillon obj_state = drm_atomic_get_private_obj_state(state, &bridge->base);
117875146591SBoris Brezillon if (IS_ERR(obj_state))
117975146591SBoris Brezillon return ERR_CAST(obj_state);
118075146591SBoris Brezillon
118175146591SBoris Brezillon return drm_priv_to_bridge_state(obj_state);
118275146591SBoris Brezillon }
118375146591SBoris Brezillon EXPORT_SYMBOL(drm_atomic_get_bridge_state);
118475146591SBoris Brezillon
118575146591SBoris Brezillon /**
118675146591SBoris Brezillon * drm_atomic_get_old_bridge_state - get old bridge state, if it exists
118775146591SBoris Brezillon * @state: global atomic state object
118875146591SBoris Brezillon * @bridge: bridge to grab
118975146591SBoris Brezillon *
119075146591SBoris Brezillon * This function returns the old bridge state for the given bridge, or NULL if
119175146591SBoris Brezillon * the bridge is not part of the global atomic state.
119275146591SBoris Brezillon */
119375146591SBoris Brezillon struct drm_bridge_state *
drm_atomic_get_old_bridge_state(const struct drm_atomic_state * state,struct drm_bridge * bridge)11942081bd89SMaxime Ripard drm_atomic_get_old_bridge_state(const struct drm_atomic_state *state,
119575146591SBoris Brezillon struct drm_bridge *bridge)
119675146591SBoris Brezillon {
119775146591SBoris Brezillon struct drm_private_state *obj_state;
119875146591SBoris Brezillon
119975146591SBoris Brezillon obj_state = drm_atomic_get_old_private_obj_state(state, &bridge->base);
120075146591SBoris Brezillon if (!obj_state)
120175146591SBoris Brezillon return NULL;
120275146591SBoris Brezillon
120375146591SBoris Brezillon return drm_priv_to_bridge_state(obj_state);
120475146591SBoris Brezillon }
120575146591SBoris Brezillon EXPORT_SYMBOL(drm_atomic_get_old_bridge_state);
120675146591SBoris Brezillon
120775146591SBoris Brezillon /**
120875146591SBoris Brezillon * drm_atomic_get_new_bridge_state - get new bridge state, if it exists
120975146591SBoris Brezillon * @state: global atomic state object
121075146591SBoris Brezillon * @bridge: bridge to grab
121175146591SBoris Brezillon *
121275146591SBoris Brezillon * This function returns the new bridge state for the given bridge, or NULL if
121375146591SBoris Brezillon * the bridge is not part of the global atomic state.
121475146591SBoris Brezillon */
121575146591SBoris Brezillon struct drm_bridge_state *
drm_atomic_get_new_bridge_state(const struct drm_atomic_state * state,struct drm_bridge * bridge)12162081bd89SMaxime Ripard drm_atomic_get_new_bridge_state(const struct drm_atomic_state *state,
121775146591SBoris Brezillon struct drm_bridge *bridge)
121875146591SBoris Brezillon {
121975146591SBoris Brezillon struct drm_private_state *obj_state;
122075146591SBoris Brezillon
122175146591SBoris Brezillon obj_state = drm_atomic_get_new_private_obj_state(state, &bridge->base);
122275146591SBoris Brezillon if (!obj_state)
122375146591SBoris Brezillon return NULL;
122475146591SBoris Brezillon
122575146591SBoris Brezillon return drm_priv_to_bridge_state(obj_state);
122675146591SBoris Brezillon }
122775146591SBoris Brezillon EXPORT_SYMBOL(drm_atomic_get_new_bridge_state);
122875146591SBoris Brezillon
122975146591SBoris Brezillon /**
123075146591SBoris Brezillon * drm_atomic_add_encoder_bridges - add bridges attached to an encoder
123175146591SBoris Brezillon * @state: atomic state
123275146591SBoris Brezillon * @encoder: DRM encoder
123375146591SBoris Brezillon *
123475146591SBoris Brezillon * This function adds all bridges attached to @encoder. This is needed to add
123575146591SBoris Brezillon * bridge states to @state and make them available when
123691ea8330SBoris Brezillon * &drm_bridge_funcs.atomic_check(), &drm_bridge_funcs.atomic_pre_enable(),
123791ea8330SBoris Brezillon * &drm_bridge_funcs.atomic_enable(),
123891ea8330SBoris Brezillon * &drm_bridge_funcs.atomic_disable_post_disable() are called.
123975146591SBoris Brezillon *
124075146591SBoris Brezillon * Returns:
124175146591SBoris Brezillon * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK
124275146591SBoris Brezillon * then the w/w mutex code has detected a deadlock and the entire atomic
124375146591SBoris Brezillon * sequence must be restarted. All other errors are fatal.
124475146591SBoris Brezillon */
124575146591SBoris Brezillon int
drm_atomic_add_encoder_bridges(struct drm_atomic_state * state,struct drm_encoder * encoder)124675146591SBoris Brezillon drm_atomic_add_encoder_bridges(struct drm_atomic_state *state,
124775146591SBoris Brezillon struct drm_encoder *encoder)
124875146591SBoris Brezillon {
124975146591SBoris Brezillon struct drm_bridge_state *bridge_state;
125075146591SBoris Brezillon struct drm_bridge *bridge;
125175146591SBoris Brezillon
125275146591SBoris Brezillon if (!encoder)
125375146591SBoris Brezillon return 0;
125475146591SBoris Brezillon
12556e22dc35SClaudio Suarez drm_dbg_atomic(encoder->dev,
12566e22dc35SClaudio Suarez "Adding all bridges for [encoder:%d:%s] to %p\n",
125775146591SBoris Brezillon encoder->base.id, encoder->name, state);
125875146591SBoris Brezillon
125975146591SBoris Brezillon drm_for_each_bridge_in_chain(encoder, bridge) {
126075146591SBoris Brezillon /* Skip bridges that don't implement the atomic state hooks. */
126175146591SBoris Brezillon if (!bridge->funcs->atomic_duplicate_state)
126275146591SBoris Brezillon continue;
126375146591SBoris Brezillon
126475146591SBoris Brezillon bridge_state = drm_atomic_get_bridge_state(state, bridge);
126575146591SBoris Brezillon if (IS_ERR(bridge_state))
126675146591SBoris Brezillon return PTR_ERR(bridge_state);
126775146591SBoris Brezillon }
126875146591SBoris Brezillon
126975146591SBoris Brezillon return 0;
127075146591SBoris Brezillon }
127175146591SBoris Brezillon EXPORT_SYMBOL(drm_atomic_add_encoder_bridges);
127275146591SBoris Brezillon
127375146591SBoris Brezillon /**
127442240c90SThierry Reding * drm_atomic_add_affected_connectors - add connectors for CRTC
1275cc4ceb48SDaniel Vetter * @state: atomic state
127642240c90SThierry Reding * @crtc: DRM CRTC
1277cc4ceb48SDaniel Vetter *
1278cc4ceb48SDaniel Vetter * This function walks the current configuration and adds all connectors
1279cc4ceb48SDaniel Vetter * currently using @crtc to the atomic configuration @state. Note that this
1280cc4ceb48SDaniel Vetter * function must acquire the connection mutex. This can potentially cause
1281a8a1de90SBhaskar Chowdhury * unneeded serialization if the update is just for the planes on one CRTC. Hence
1282cc4ceb48SDaniel Vetter * drivers and helpers should only call this when really needed (e.g. when a
1283cc4ceb48SDaniel Vetter * full modeset needs to happen due to some change).
1284cc4ceb48SDaniel Vetter *
1285cc4ceb48SDaniel Vetter * Returns:
1286cc4ceb48SDaniel Vetter * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK
1287cc4ceb48SDaniel Vetter * then the w/w mutex code has detected a deadlock and the entire atomic
1288cc4ceb48SDaniel Vetter * sequence must be restarted. All other errors are fatal.
1289cc4ceb48SDaniel Vetter */
1290cc4ceb48SDaniel Vetter int
drm_atomic_add_affected_connectors(struct drm_atomic_state * state,struct drm_crtc * crtc)1291cc4ceb48SDaniel Vetter drm_atomic_add_affected_connectors(struct drm_atomic_state *state,
1292cc4ceb48SDaniel Vetter struct drm_crtc *crtc)
1293cc4ceb48SDaniel Vetter {
1294cc4ceb48SDaniel Vetter struct drm_mode_config *config = &state->dev->mode_config;
1295cc4ceb48SDaniel Vetter struct drm_connector *connector;
1296cc4ceb48SDaniel Vetter struct drm_connector_state *conn_state;
1297613051daSDaniel Vetter struct drm_connector_list_iter conn_iter;
12985351bbddSMaarten Lankhorst struct drm_crtc_state *crtc_state;
1299cc4ceb48SDaniel Vetter int ret;
1300cc4ceb48SDaniel Vetter
13015351bbddSMaarten Lankhorst crtc_state = drm_atomic_get_crtc_state(state, crtc);
13025351bbddSMaarten Lankhorst if (IS_ERR(crtc_state))
13035351bbddSMaarten Lankhorst return PTR_ERR(crtc_state);
13045351bbddSMaarten Lankhorst
1305cc4ceb48SDaniel Vetter ret = drm_modeset_lock(&config->connection_mutex, state->acquire_ctx);
1306cc4ceb48SDaniel Vetter if (ret)
1307cc4ceb48SDaniel Vetter return ret;
1308cc4ceb48SDaniel Vetter
13096e22dc35SClaudio Suarez drm_dbg_atomic(crtc->dev,
13106e22dc35SClaudio Suarez "Adding all current connectors for [CRTC:%d:%s] to %p\n",
1311fa3ab4c2SVille Syrjälä crtc->base.id, crtc->name, state);
1312cc4ceb48SDaniel Vetter
1313cc4ceb48SDaniel Vetter /*
13145351bbddSMaarten Lankhorst * Changed connectors are already in @state, so only need to look
13155351bbddSMaarten Lankhorst * at the connector_mask in crtc_state.
1316cc4ceb48SDaniel Vetter */
1317b982dab1SThierry Reding drm_connector_list_iter_begin(state->dev, &conn_iter);
1318613051daSDaniel Vetter drm_for_each_connector_iter(connector, &conn_iter) {
131973705732SVille Syrjälä if (!(crtc_state->connector_mask & drm_connector_mask(connector)))
1320cc4ceb48SDaniel Vetter continue;
1321cc4ceb48SDaniel Vetter
1322cc4ceb48SDaniel Vetter conn_state = drm_atomic_get_connector_state(state, connector);
1323613051daSDaniel Vetter if (IS_ERR(conn_state)) {
1324b982dab1SThierry Reding drm_connector_list_iter_end(&conn_iter);
1325cc4ceb48SDaniel Vetter return PTR_ERR(conn_state);
1326cc4ceb48SDaniel Vetter }
1327613051daSDaniel Vetter }
1328b982dab1SThierry Reding drm_connector_list_iter_end(&conn_iter);
1329cc4ceb48SDaniel Vetter
1330cc4ceb48SDaniel Vetter return 0;
1331cc4ceb48SDaniel Vetter }
1332cc4ceb48SDaniel Vetter EXPORT_SYMBOL(drm_atomic_add_affected_connectors);
1333cc4ceb48SDaniel Vetter
1334cc4ceb48SDaniel Vetter /**
133542240c90SThierry Reding * drm_atomic_add_affected_planes - add planes for CRTC
1336e01e9f75SMaarten Lankhorst * @state: atomic state
133742240c90SThierry Reding * @crtc: DRM CRTC
1338e01e9f75SMaarten Lankhorst *
1339e01e9f75SMaarten Lankhorst * This function walks the current configuration and adds all planes
1340e01e9f75SMaarten Lankhorst * currently used by @crtc to the atomic configuration @state. This is useful
1341e01e9f75SMaarten Lankhorst * when an atomic commit also needs to check all currently enabled plane on
1342e01e9f75SMaarten Lankhorst * @crtc, e.g. when changing the mode. It's also useful when re-enabling a CRTC
1343e01e9f75SMaarten Lankhorst * to avoid special code to force-enable all planes.
1344e01e9f75SMaarten Lankhorst *
1345e01e9f75SMaarten Lankhorst * Since acquiring a plane state will always also acquire the w/w mutex of the
1346e01e9f75SMaarten Lankhorst * current CRTC for that plane (if there is any) adding all the plane states for
1347a8a1de90SBhaskar Chowdhury * a CRTC will not reduce parallelism of atomic updates.
1348e01e9f75SMaarten Lankhorst *
1349e01e9f75SMaarten Lankhorst * Returns:
1350e01e9f75SMaarten Lankhorst * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK
1351e01e9f75SMaarten Lankhorst * then the w/w mutex code has detected a deadlock and the entire atomic
1352e01e9f75SMaarten Lankhorst * sequence must be restarted. All other errors are fatal.
1353e01e9f75SMaarten Lankhorst */
1354e01e9f75SMaarten Lankhorst int
drm_atomic_add_affected_planes(struct drm_atomic_state * state,struct drm_crtc * crtc)1355e01e9f75SMaarten Lankhorst drm_atomic_add_affected_planes(struct drm_atomic_state *state,
1356e01e9f75SMaarten Lankhorst struct drm_crtc *crtc)
1357e01e9f75SMaarten Lankhorst {
1358534903d6SVille Syrjälä const struct drm_crtc_state *old_crtc_state =
1359534903d6SVille Syrjälä drm_atomic_get_old_crtc_state(state, crtc);
1360e01e9f75SMaarten Lankhorst struct drm_plane *plane;
1361e01e9f75SMaarten Lankhorst
1362b4d93679SMaarten Lankhorst WARN_ON(!drm_atomic_get_new_crtc_state(state, crtc));
1363e01e9f75SMaarten Lankhorst
13646e22dc35SClaudio Suarez drm_dbg_atomic(crtc->dev,
13656e22dc35SClaudio Suarez "Adding all current planes for [CRTC:%d:%s] to %p\n",
1366b6f690abSVille Syrjälä crtc->base.id, crtc->name, state);
1367b6f690abSVille Syrjälä
1368534903d6SVille Syrjälä drm_for_each_plane_mask(plane, state->dev, old_crtc_state->plane_mask) {
1369e01e9f75SMaarten Lankhorst struct drm_plane_state *plane_state =
1370e01e9f75SMaarten Lankhorst drm_atomic_get_plane_state(state, plane);
1371e01e9f75SMaarten Lankhorst
1372e01e9f75SMaarten Lankhorst if (IS_ERR(plane_state))
1373e01e9f75SMaarten Lankhorst return PTR_ERR(plane_state);
1374e01e9f75SMaarten Lankhorst }
1375e01e9f75SMaarten Lankhorst return 0;
1376e01e9f75SMaarten Lankhorst }
1377e01e9f75SMaarten Lankhorst EXPORT_SYMBOL(drm_atomic_add_affected_planes);
1378e01e9f75SMaarten Lankhorst
1379e01e9f75SMaarten Lankhorst /**
1380cc4ceb48SDaniel Vetter * drm_atomic_check_only - check whether a given config would work
1381cc4ceb48SDaniel Vetter * @state: atomic configuration to check
1382cc4ceb48SDaniel Vetter *
1383cc4ceb48SDaniel Vetter * Note that this function can return -EDEADLK if the driver needed to acquire
1384cc4ceb48SDaniel Vetter * more locks but encountered a deadlock. The caller must then do the usual w/w
1385cc4ceb48SDaniel Vetter * backoff dance and restart. All other errors are fatal.
1386cc4ceb48SDaniel Vetter *
1387cc4ceb48SDaniel Vetter * Returns:
1388cc4ceb48SDaniel Vetter * 0 on success, negative error code on failure.
1389cc4ceb48SDaniel Vetter */
drm_atomic_check_only(struct drm_atomic_state * state)1390cc4ceb48SDaniel Vetter int drm_atomic_check_only(struct drm_atomic_state *state)
1391cc4ceb48SDaniel Vetter {
13925e743737SRob Clark struct drm_device *dev = state->dev;
13935e743737SRob Clark struct drm_mode_config *config = &dev->mode_config;
1394df63b999SAnder Conselvan de Oliveira struct drm_plane *plane;
1395d9be05b7SVille Syrjälä struct drm_plane_state *old_plane_state;
1396d9be05b7SVille Syrjälä struct drm_plane_state *new_plane_state;
1397df63b999SAnder Conselvan de Oliveira struct drm_crtc *crtc;
1398b2432adfSVille Syrjälä struct drm_crtc_state *old_crtc_state;
1399b2432adfSVille Syrjälä struct drm_crtc_state *new_crtc_state;
1400935774cdSBrian Starkey struct drm_connector *conn;
1401935774cdSBrian Starkey struct drm_connector_state *conn_state;
14021cdb005dSFabio M. De Francesco unsigned int requested_crtc = 0;
14031cdb005dSFabio M. De Francesco unsigned int affected_crtc = 0;
14045e743737SRob Clark int i, ret = 0;
1405cc4ceb48SDaniel Vetter
14066e22dc35SClaudio Suarez drm_dbg_atomic(dev, "checking %p\n", state);
1407cc4ceb48SDaniel Vetter
14085ec1cebdSManasi Navare for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
14095ec1cebdSManasi Navare if (new_crtc_state->enable)
1410fb6473a4SDaniel Vetter requested_crtc |= drm_crtc_mask(crtc);
14115ec1cebdSManasi Navare }
1412fb6473a4SDaniel Vetter
1413d9be05b7SVille Syrjälä for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {
1414d9be05b7SVille Syrjälä ret = drm_atomic_plane_check(old_plane_state, new_plane_state);
14155e743737SRob Clark if (ret) {
14166e22dc35SClaudio Suarez drm_dbg_atomic(dev, "[PLANE:%d:%s] atomic core check failed\n",
14179f4c97a2SVille Syrjälä plane->base.id, plane->name);
14185e743737SRob Clark return ret;
14195e743737SRob Clark }
14205e743737SRob Clark }
14215e743737SRob Clark
1422b2432adfSVille Syrjälä for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
1423b2432adfSVille Syrjälä ret = drm_atomic_crtc_check(old_crtc_state, new_crtc_state);
14245e743737SRob Clark if (ret) {
14256e22dc35SClaudio Suarez drm_dbg_atomic(dev, "[CRTC:%d:%s] atomic core check failed\n",
1426fa3ab4c2SVille Syrjälä crtc->base.id, crtc->name);
14275e743737SRob Clark return ret;
14285e743737SRob Clark }
14295e743737SRob Clark }
14305e743737SRob Clark
1431935774cdSBrian Starkey for_each_new_connector_in_state(state, conn, conn_state, i) {
1432935774cdSBrian Starkey ret = drm_atomic_connector_check(conn, conn_state);
1433935774cdSBrian Starkey if (ret) {
14346e22dc35SClaudio Suarez drm_dbg_atomic(dev, "[CONNECTOR:%d:%s] atomic core check failed\n",
1435935774cdSBrian Starkey conn->base.id, conn->name);
1436935774cdSBrian Starkey return ret;
1437935774cdSBrian Starkey }
1438935774cdSBrian Starkey }
1439935774cdSBrian Starkey
144014d4e522SLyude Paul if (config->funcs->atomic_check) {
14415e743737SRob Clark ret = config->funcs->atomic_check(state->dev, state);
14425e743737SRob Clark
144314d4e522SLyude Paul if (ret) {
14446e22dc35SClaudio Suarez drm_dbg_atomic(dev, "atomic driver check for %p failed: %d\n",
144514d4e522SLyude Paul state, ret);
1446a0ffc51eSMaarten Lankhorst return ret;
144714d4e522SLyude Paul }
144814d4e522SLyude Paul }
1449a0ffc51eSMaarten Lankhorst
1450d34f20d6SRob Clark if (!state->allow_modeset) {
1451b2432adfSVille Syrjälä for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
1452b2432adfSVille Syrjälä if (drm_atomic_crtc_needs_modeset(new_crtc_state)) {
14536e22dc35SClaudio Suarez drm_dbg_atomic(dev, "[CRTC:%d:%s] requires full modeset\n",
1454fa3ab4c2SVille Syrjälä crtc->base.id, crtc->name);
1455d34f20d6SRob Clark return -EINVAL;
1456d34f20d6SRob Clark }
1457d34f20d6SRob Clark }
1458d34f20d6SRob Clark }
1459d34f20d6SRob Clark
14605ec1cebdSManasi Navare for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
14615ec1cebdSManasi Navare if (new_crtc_state->enable)
1462fb6473a4SDaniel Vetter affected_crtc |= drm_crtc_mask(crtc);
14635ec1cebdSManasi Navare }
1464fb6473a4SDaniel Vetter
1465fb6473a4SDaniel Vetter /*
1466fb6473a4SDaniel Vetter * For commits that allow modesets drivers can add other CRTCs to the
1467fb6473a4SDaniel Vetter * atomic commit, e.g. when they need to reallocate global resources.
1468fb6473a4SDaniel Vetter * This can cause spurious EBUSY, which robs compositors of a very
1469fb6473a4SDaniel Vetter * effective sanity check for their drawing loop. Therefor only allow
1470fb6473a4SDaniel Vetter * drivers to add unrelated CRTC states for modeset commits.
1471fb6473a4SDaniel Vetter *
1472fb6473a4SDaniel Vetter * FIXME: Should add affected_crtc mask to the ATOMIC IOCTL as an output
1473fb6473a4SDaniel Vetter * so compositors know what's going on.
1474fb6473a4SDaniel Vetter */
1475fb6473a4SDaniel Vetter if (affected_crtc != requested_crtc) {
14766e22dc35SClaudio Suarez drm_dbg_atomic(dev,
14776e22dc35SClaudio Suarez "driver added CRTC to commit: requested 0x%x, affected 0x%0x\n",
1478fb6473a4SDaniel Vetter requested_crtc, affected_crtc);
1479fb6473a4SDaniel Vetter WARN(!state->allow_modeset, "adding CRTC not allowed without modesets: requested 0x%x, affected 0x%0x\n",
1480fb6473a4SDaniel Vetter requested_crtc, affected_crtc);
1481fb6473a4SDaniel Vetter }
1482fb6473a4SDaniel Vetter
1483a0ffc51eSMaarten Lankhorst return 0;
1484cc4ceb48SDaniel Vetter }
1485cc4ceb48SDaniel Vetter EXPORT_SYMBOL(drm_atomic_check_only);
1486cc4ceb48SDaniel Vetter
1487cc4ceb48SDaniel Vetter /**
1488cc4ceb48SDaniel Vetter * drm_atomic_commit - commit configuration atomically
1489cc4ceb48SDaniel Vetter * @state: atomic configuration to check
1490cc4ceb48SDaniel Vetter *
1491cc4ceb48SDaniel Vetter * Note that this function can return -EDEADLK if the driver needed to acquire
1492cc4ceb48SDaniel Vetter * more locks but encountered a deadlock. The caller must then do the usual w/w
1493cc4ceb48SDaniel Vetter * backoff dance and restart. All other errors are fatal.
1494cc4ceb48SDaniel Vetter *
149576fede2fSMaarten Lankhorst * This function will take its own reference on @state.
149676fede2fSMaarten Lankhorst * Callers should always release their reference with drm_atomic_state_put().
1497cc4ceb48SDaniel Vetter *
1498cc4ceb48SDaniel Vetter * Returns:
1499cc4ceb48SDaniel Vetter * 0 on success, negative error code on failure.
1500cc4ceb48SDaniel Vetter */
drm_atomic_commit(struct drm_atomic_state * state)1501cc4ceb48SDaniel Vetter int drm_atomic_commit(struct drm_atomic_state *state)
1502cc4ceb48SDaniel Vetter {
1503cc4ceb48SDaniel Vetter struct drm_mode_config *config = &state->dev->mode_config;
1504018ad18fSMaxime Ripard struct drm_printer p = drm_info_printer(state->dev->dev);
1505cc4ceb48SDaniel Vetter int ret;
1506cc4ceb48SDaniel Vetter
1507018ad18fSMaxime Ripard if (drm_debug_enabled(DRM_UT_STATE))
1508018ad18fSMaxime Ripard drm_atomic_print_new_state(state, &p);
1509018ad18fSMaxime Ripard
1510cc4ceb48SDaniel Vetter ret = drm_atomic_check_only(state);
1511cc4ceb48SDaniel Vetter if (ret)
1512cc4ceb48SDaniel Vetter return ret;
1513cc4ceb48SDaniel Vetter
15146e22dc35SClaudio Suarez drm_dbg_atomic(state->dev, "committing %p\n", state);
1515cc4ceb48SDaniel Vetter
1516cc4ceb48SDaniel Vetter return config->funcs->atomic_commit(state->dev, state, false);
1517cc4ceb48SDaniel Vetter }
1518cc4ceb48SDaniel Vetter EXPORT_SYMBOL(drm_atomic_commit);
1519cc4ceb48SDaniel Vetter
1520cc4ceb48SDaniel Vetter /**
1521d574528aSDaniel Vetter * drm_atomic_nonblocking_commit - atomic nonblocking commit
1522cc4ceb48SDaniel Vetter * @state: atomic configuration to check
1523cc4ceb48SDaniel Vetter *
1524cc4ceb48SDaniel Vetter * Note that this function can return -EDEADLK if the driver needed to acquire
1525cc4ceb48SDaniel Vetter * more locks but encountered a deadlock. The caller must then do the usual w/w
1526cc4ceb48SDaniel Vetter * backoff dance and restart. All other errors are fatal.
1527cc4ceb48SDaniel Vetter *
152876fede2fSMaarten Lankhorst * This function will take its own reference on @state.
152976fede2fSMaarten Lankhorst * Callers should always release their reference with drm_atomic_state_put().
1530cc4ceb48SDaniel Vetter *
1531cc4ceb48SDaniel Vetter * Returns:
1532cc4ceb48SDaniel Vetter * 0 on success, negative error code on failure.
1533cc4ceb48SDaniel Vetter */
drm_atomic_nonblocking_commit(struct drm_atomic_state * state)1534b837ba0aSMaarten Lankhorst int drm_atomic_nonblocking_commit(struct drm_atomic_state *state)
1535cc4ceb48SDaniel Vetter {
1536cc4ceb48SDaniel Vetter struct drm_mode_config *config = &state->dev->mode_config;
1537cc4ceb48SDaniel Vetter int ret;
1538cc4ceb48SDaniel Vetter
1539cc4ceb48SDaniel Vetter ret = drm_atomic_check_only(state);
1540cc4ceb48SDaniel Vetter if (ret)
1541cc4ceb48SDaniel Vetter return ret;
1542cc4ceb48SDaniel Vetter
15436e22dc35SClaudio Suarez drm_dbg_atomic(state->dev, "committing %p nonblocking\n", state);
1544cc4ceb48SDaniel Vetter
1545cc4ceb48SDaniel Vetter return config->funcs->atomic_commit(state->dev, state, true);
1546cc4ceb48SDaniel Vetter }
1547b837ba0aSMaarten Lankhorst EXPORT_SYMBOL(drm_atomic_nonblocking_commit);
1548d34f20d6SRob Clark
1549df737895SNoralf Trønnes /* just used from drm-client and atomic-helper: */
__drm_atomic_helper_disable_plane(struct drm_plane * plane,struct drm_plane_state * plane_state)1550df737895SNoralf Trønnes int __drm_atomic_helper_disable_plane(struct drm_plane *plane,
1551df737895SNoralf Trønnes struct drm_plane_state *plane_state)
1552df737895SNoralf Trønnes {
1553df737895SNoralf Trønnes int ret;
1554df737895SNoralf Trønnes
1555df737895SNoralf Trønnes ret = drm_atomic_set_crtc_for_plane(plane_state, NULL);
1556df737895SNoralf Trønnes if (ret != 0)
1557df737895SNoralf Trønnes return ret;
1558df737895SNoralf Trønnes
1559df737895SNoralf Trønnes drm_atomic_set_fb_for_plane(plane_state, NULL);
1560df737895SNoralf Trønnes plane_state->crtc_x = 0;
1561df737895SNoralf Trønnes plane_state->crtc_y = 0;
1562df737895SNoralf Trønnes plane_state->crtc_w = 0;
1563df737895SNoralf Trønnes plane_state->crtc_h = 0;
1564df737895SNoralf Trønnes plane_state->src_x = 0;
1565df737895SNoralf Trønnes plane_state->src_y = 0;
1566df737895SNoralf Trønnes plane_state->src_w = 0;
1567df737895SNoralf Trønnes plane_state->src_h = 0;
1568df737895SNoralf Trønnes
1569df737895SNoralf Trønnes return 0;
1570df737895SNoralf Trønnes }
1571df737895SNoralf Trønnes EXPORT_SYMBOL(__drm_atomic_helper_disable_plane);
1572df737895SNoralf Trønnes
update_output_state(struct drm_atomic_state * state,struct drm_mode_set * set)1573df737895SNoralf Trønnes static int update_output_state(struct drm_atomic_state *state,
1574df737895SNoralf Trønnes struct drm_mode_set *set)
1575df737895SNoralf Trønnes {
1576df737895SNoralf Trønnes struct drm_device *dev = set->crtc->dev;
1577df737895SNoralf Trønnes struct drm_crtc *crtc;
1578df737895SNoralf Trønnes struct drm_crtc_state *new_crtc_state;
1579df737895SNoralf Trønnes struct drm_connector *connector;
1580df737895SNoralf Trønnes struct drm_connector_state *new_conn_state;
1581df737895SNoralf Trønnes int ret, i;
1582df737895SNoralf Trønnes
1583df737895SNoralf Trønnes ret = drm_modeset_lock(&dev->mode_config.connection_mutex,
1584df737895SNoralf Trønnes state->acquire_ctx);
1585df737895SNoralf Trønnes if (ret)
1586df737895SNoralf Trønnes return ret;
1587df737895SNoralf Trønnes
1588df737895SNoralf Trønnes /* First disable all connectors on the target crtc. */
1589df737895SNoralf Trønnes ret = drm_atomic_add_affected_connectors(state, set->crtc);
1590df737895SNoralf Trønnes if (ret)
1591df737895SNoralf Trønnes return ret;
1592df737895SNoralf Trønnes
1593df737895SNoralf Trønnes for_each_new_connector_in_state(state, connector, new_conn_state, i) {
1594df737895SNoralf Trønnes if (new_conn_state->crtc == set->crtc) {
1595df737895SNoralf Trønnes ret = drm_atomic_set_crtc_for_connector(new_conn_state,
1596df737895SNoralf Trønnes NULL);
1597df737895SNoralf Trønnes if (ret)
1598df737895SNoralf Trønnes return ret;
1599df737895SNoralf Trønnes
1600df737895SNoralf Trønnes /* Make sure legacy setCrtc always re-trains */
1601df737895SNoralf Trønnes new_conn_state->link_status = DRM_LINK_STATUS_GOOD;
1602df737895SNoralf Trønnes }
1603df737895SNoralf Trønnes }
1604df737895SNoralf Trønnes
1605df737895SNoralf Trønnes /* Then set all connectors from set->connectors on the target crtc */
1606df737895SNoralf Trønnes for (i = 0; i < set->num_connectors; i++) {
1607df737895SNoralf Trønnes new_conn_state = drm_atomic_get_connector_state(state,
1608df737895SNoralf Trønnes set->connectors[i]);
1609df737895SNoralf Trønnes if (IS_ERR(new_conn_state))
1610df737895SNoralf Trønnes return PTR_ERR(new_conn_state);
1611df737895SNoralf Trønnes
1612df737895SNoralf Trønnes ret = drm_atomic_set_crtc_for_connector(new_conn_state,
1613df737895SNoralf Trønnes set->crtc);
1614df737895SNoralf Trønnes if (ret)
1615df737895SNoralf Trønnes return ret;
1616df737895SNoralf Trønnes }
1617df737895SNoralf Trønnes
1618df737895SNoralf Trønnes for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
1619df737895SNoralf Trønnes /*
1620df737895SNoralf Trønnes * Don't update ->enable for the CRTC in the set_config request,
1621df737895SNoralf Trønnes * since a mismatch would indicate a bug in the upper layers.
1622df737895SNoralf Trønnes * The actual modeset code later on will catch any
1623df737895SNoralf Trønnes * inconsistencies here.
1624df737895SNoralf Trønnes */
1625df737895SNoralf Trønnes if (crtc == set->crtc)
1626df737895SNoralf Trønnes continue;
1627df737895SNoralf Trønnes
1628df737895SNoralf Trønnes if (!new_crtc_state->connector_mask) {
1629df737895SNoralf Trønnes ret = drm_atomic_set_mode_prop_for_crtc(new_crtc_state,
1630df737895SNoralf Trønnes NULL);
1631df737895SNoralf Trønnes if (ret < 0)
1632df737895SNoralf Trønnes return ret;
1633df737895SNoralf Trønnes
1634df737895SNoralf Trønnes new_crtc_state->active = false;
1635df737895SNoralf Trønnes }
1636df737895SNoralf Trønnes }
1637df737895SNoralf Trønnes
1638df737895SNoralf Trønnes return 0;
1639df737895SNoralf Trønnes }
1640df737895SNoralf Trønnes
1641df737895SNoralf Trønnes /* just used from drm-client and atomic-helper: */
__drm_atomic_helper_set_config(struct drm_mode_set * set,struct drm_atomic_state * state)1642df737895SNoralf Trønnes int __drm_atomic_helper_set_config(struct drm_mode_set *set,
1643df737895SNoralf Trønnes struct drm_atomic_state *state)
1644df737895SNoralf Trønnes {
1645df737895SNoralf Trønnes struct drm_crtc_state *crtc_state;
1646df737895SNoralf Trønnes struct drm_plane_state *primary_state;
1647df737895SNoralf Trønnes struct drm_crtc *crtc = set->crtc;
1648df737895SNoralf Trønnes int hdisplay, vdisplay;
1649df737895SNoralf Trønnes int ret;
1650df737895SNoralf Trønnes
1651df737895SNoralf Trønnes crtc_state = drm_atomic_get_crtc_state(state, crtc);
1652df737895SNoralf Trønnes if (IS_ERR(crtc_state))
1653df737895SNoralf Trønnes return PTR_ERR(crtc_state);
1654df737895SNoralf Trønnes
1655df737895SNoralf Trønnes primary_state = drm_atomic_get_plane_state(state, crtc->primary);
1656df737895SNoralf Trønnes if (IS_ERR(primary_state))
1657df737895SNoralf Trønnes return PTR_ERR(primary_state);
1658df737895SNoralf Trønnes
1659df737895SNoralf Trønnes if (!set->mode) {
1660df737895SNoralf Trønnes WARN_ON(set->fb);
1661df737895SNoralf Trønnes WARN_ON(set->num_connectors);
1662df737895SNoralf Trønnes
1663df737895SNoralf Trønnes ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL);
1664df737895SNoralf Trønnes if (ret != 0)
1665df737895SNoralf Trønnes return ret;
1666df737895SNoralf Trønnes
1667df737895SNoralf Trønnes crtc_state->active = false;
1668df737895SNoralf Trønnes
1669df737895SNoralf Trønnes ret = drm_atomic_set_crtc_for_plane(primary_state, NULL);
1670df737895SNoralf Trønnes if (ret != 0)
1671df737895SNoralf Trønnes return ret;
1672df737895SNoralf Trønnes
1673df737895SNoralf Trønnes drm_atomic_set_fb_for_plane(primary_state, NULL);
1674df737895SNoralf Trønnes
1675df737895SNoralf Trønnes goto commit;
1676df737895SNoralf Trønnes }
1677df737895SNoralf Trønnes
1678df737895SNoralf Trønnes WARN_ON(!set->fb);
1679df737895SNoralf Trønnes WARN_ON(!set->num_connectors);
1680df737895SNoralf Trønnes
1681df737895SNoralf Trønnes ret = drm_atomic_set_mode_for_crtc(crtc_state, set->mode);
1682df737895SNoralf Trønnes if (ret != 0)
1683df737895SNoralf Trønnes return ret;
1684df737895SNoralf Trønnes
1685df737895SNoralf Trønnes crtc_state->active = true;
1686df737895SNoralf Trønnes
1687df737895SNoralf Trønnes ret = drm_atomic_set_crtc_for_plane(primary_state, crtc);
1688df737895SNoralf Trønnes if (ret != 0)
1689df737895SNoralf Trønnes return ret;
1690df737895SNoralf Trønnes
1691df737895SNoralf Trønnes drm_mode_get_hv_timing(set->mode, &hdisplay, &vdisplay);
1692df737895SNoralf Trønnes
1693df737895SNoralf Trønnes drm_atomic_set_fb_for_plane(primary_state, set->fb);
1694df737895SNoralf Trønnes primary_state->crtc_x = 0;
1695df737895SNoralf Trønnes primary_state->crtc_y = 0;
1696df737895SNoralf Trønnes primary_state->crtc_w = hdisplay;
1697df737895SNoralf Trønnes primary_state->crtc_h = vdisplay;
1698df737895SNoralf Trønnes primary_state->src_x = set->x << 16;
1699df737895SNoralf Trønnes primary_state->src_y = set->y << 16;
1700df737895SNoralf Trønnes if (drm_rotation_90_or_270(primary_state->rotation)) {
1701df737895SNoralf Trønnes primary_state->src_w = vdisplay << 16;
1702df737895SNoralf Trønnes primary_state->src_h = hdisplay << 16;
1703df737895SNoralf Trønnes } else {
1704df737895SNoralf Trønnes primary_state->src_w = hdisplay << 16;
1705df737895SNoralf Trønnes primary_state->src_h = vdisplay << 16;
1706df737895SNoralf Trønnes }
1707df737895SNoralf Trønnes
1708df737895SNoralf Trønnes commit:
1709df737895SNoralf Trønnes ret = update_output_state(state, set);
1710df737895SNoralf Trønnes if (ret)
1711df737895SNoralf Trønnes return ret;
1712df737895SNoralf Trønnes
1713df737895SNoralf Trønnes return 0;
1714df737895SNoralf Trønnes }
1715df737895SNoralf Trønnes EXPORT_SYMBOL(__drm_atomic_helper_set_config);
1716df737895SNoralf Trønnes
drm_atomic_private_obj_print_state(struct drm_printer * p,const struct drm_private_state * state)171797a1f01bSMaxime Ripard static void drm_atomic_private_obj_print_state(struct drm_printer *p,
171897a1f01bSMaxime Ripard const struct drm_private_state *state)
171997a1f01bSMaxime Ripard {
172097a1f01bSMaxime Ripard struct drm_private_obj *obj = state->obj;
172197a1f01bSMaxime Ripard
172297a1f01bSMaxime Ripard if (obj->funcs->atomic_print_state)
172397a1f01bSMaxime Ripard obj->funcs->atomic_print_state(p, state);
172497a1f01bSMaxime Ripard }
172597a1f01bSMaxime Ripard
1726a4324a7aSAbhinav Kumar /**
1727a4324a7aSAbhinav Kumar * drm_atomic_print_new_state - prints drm atomic state
1728a4324a7aSAbhinav Kumar * @state: atomic configuration to check
1729a4324a7aSAbhinav Kumar * @p: drm printer
1730a4324a7aSAbhinav Kumar *
1731a4324a7aSAbhinav Kumar * This functions prints the drm atomic state snapshot using the drm printer
1732a4324a7aSAbhinav Kumar * which is passed to it. This snapshot can be used for debugging purposes.
1733a4324a7aSAbhinav Kumar *
1734a4324a7aSAbhinav Kumar * Note that this function looks into the new state objects and hence its not
1735a4324a7aSAbhinav Kumar * safe to be used after the call to drm_atomic_helper_commit_hw_done().
1736a4324a7aSAbhinav Kumar */
drm_atomic_print_new_state(const struct drm_atomic_state * state,struct drm_printer * p)1737a4324a7aSAbhinav Kumar void drm_atomic_print_new_state(const struct drm_atomic_state *state,
1738a4324a7aSAbhinav Kumar struct drm_printer *p)
1739fceffb32SRob Clark {
1740fceffb32SRob Clark struct drm_plane *plane;
1741fceffb32SRob Clark struct drm_plane_state *plane_state;
1742fceffb32SRob Clark struct drm_crtc *crtc;
1743fceffb32SRob Clark struct drm_crtc_state *crtc_state;
1744fceffb32SRob Clark struct drm_connector *connector;
1745fceffb32SRob Clark struct drm_connector_state *connector_state;
174697a1f01bSMaxime Ripard struct drm_private_obj *obj;
174797a1f01bSMaxime Ripard struct drm_private_state *obj_state;
1748fceffb32SRob Clark int i;
1749fceffb32SRob Clark
1750a4324a7aSAbhinav Kumar if (!p) {
17516e22dc35SClaudio Suarez drm_err(state->dev, "invalid drm printer\n");
1752a4324a7aSAbhinav Kumar return;
1753a4324a7aSAbhinav Kumar }
1754a4324a7aSAbhinav Kumar
17556e22dc35SClaudio Suarez drm_dbg_atomic(state->dev, "checking %p\n", state);
1756fceffb32SRob Clark
17575721a380SMaarten Lankhorst for_each_new_plane_in_state(state, plane, plane_state, i)
1758a4324a7aSAbhinav Kumar drm_atomic_plane_print_state(p, plane_state);
1759fceffb32SRob Clark
17605721a380SMaarten Lankhorst for_each_new_crtc_in_state(state, crtc, crtc_state, i)
1761a4324a7aSAbhinav Kumar drm_atomic_crtc_print_state(p, crtc_state);
1762fceffb32SRob Clark
17635721a380SMaarten Lankhorst for_each_new_connector_in_state(state, connector, connector_state, i)
1764a4324a7aSAbhinav Kumar drm_atomic_connector_print_state(p, connector_state);
176597a1f01bSMaxime Ripard
176697a1f01bSMaxime Ripard for_each_new_private_obj_in_state(state, obj, obj_state, i)
176797a1f01bSMaxime Ripard drm_atomic_private_obj_print_state(p, obj_state);
1768fceffb32SRob Clark }
1769a4324a7aSAbhinav Kumar EXPORT_SYMBOL(drm_atomic_print_new_state);
1770fceffb32SRob Clark
__drm_state_dump(struct drm_device * dev,struct drm_printer * p,bool take_locks)1771c2d85564SDaniel Vetter static void __drm_state_dump(struct drm_device *dev, struct drm_printer *p,
1772c2d85564SDaniel Vetter bool take_locks)
1773c2d85564SDaniel Vetter {
1774c2d85564SDaniel Vetter struct drm_mode_config *config = &dev->mode_config;
1775c2d85564SDaniel Vetter struct drm_plane *plane;
1776c2d85564SDaniel Vetter struct drm_crtc *crtc;
1777c2d85564SDaniel Vetter struct drm_connector *connector;
1778c2d85564SDaniel Vetter struct drm_connector_list_iter conn_iter;
1779c8fa1cc0SDmitry Baryshkov struct drm_private_obj *obj;
1780c2d85564SDaniel Vetter
17813c499ea0SLyude Paul if (!drm_drv_uses_atomic_modeset(dev))
1782c2d85564SDaniel Vetter return;
1783c2d85564SDaniel Vetter
1784c2d85564SDaniel Vetter list_for_each_entry(plane, &config->plane_list, head) {
1785c2d85564SDaniel Vetter if (take_locks)
1786c2d85564SDaniel Vetter drm_modeset_lock(&plane->mutex, NULL);
1787c2d85564SDaniel Vetter drm_atomic_plane_print_state(p, plane->state);
1788c2d85564SDaniel Vetter if (take_locks)
1789c2d85564SDaniel Vetter drm_modeset_unlock(&plane->mutex);
1790c2d85564SDaniel Vetter }
1791c2d85564SDaniel Vetter
1792c2d85564SDaniel Vetter list_for_each_entry(crtc, &config->crtc_list, head) {
1793c2d85564SDaniel Vetter if (take_locks)
1794c2d85564SDaniel Vetter drm_modeset_lock(&crtc->mutex, NULL);
1795c2d85564SDaniel Vetter drm_atomic_crtc_print_state(p, crtc->state);
1796c2d85564SDaniel Vetter if (take_locks)
1797c2d85564SDaniel Vetter drm_modeset_unlock(&crtc->mutex);
1798c2d85564SDaniel Vetter }
1799c2d85564SDaniel Vetter
1800c2d85564SDaniel Vetter drm_connector_list_iter_begin(dev, &conn_iter);
1801c2d85564SDaniel Vetter if (take_locks)
1802c2d85564SDaniel Vetter drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
1803c2d85564SDaniel Vetter drm_for_each_connector_iter(connector, &conn_iter)
1804c2d85564SDaniel Vetter drm_atomic_connector_print_state(p, connector->state);
1805c2d85564SDaniel Vetter if (take_locks)
1806c2d85564SDaniel Vetter drm_modeset_unlock(&dev->mode_config.connection_mutex);
1807c2d85564SDaniel Vetter drm_connector_list_iter_end(&conn_iter);
1808c8fa1cc0SDmitry Baryshkov
1809c8fa1cc0SDmitry Baryshkov list_for_each_entry(obj, &config->privobj_list, head) {
1810c8fa1cc0SDmitry Baryshkov if (take_locks)
1811c8fa1cc0SDmitry Baryshkov drm_modeset_lock(&obj->lock, NULL);
1812c8fa1cc0SDmitry Baryshkov drm_atomic_private_obj_print_state(p, obj->state);
1813c8fa1cc0SDmitry Baryshkov if (take_locks)
1814c8fa1cc0SDmitry Baryshkov drm_modeset_unlock(&obj->lock);
1815c8fa1cc0SDmitry Baryshkov }
1816c2d85564SDaniel Vetter }
1817c2d85564SDaniel Vetter
18186559c901SRob Clark /**
18196559c901SRob Clark * drm_state_dump - dump entire device atomic state
18206559c901SRob Clark * @dev: the drm device
18216559c901SRob Clark * @p: where to print the state to
18226559c901SRob Clark *
18236559c901SRob Clark * Just for debugging. Drivers might want an option to dump state
18246559c901SRob Clark * to dmesg in case of error irq's. (Hint, you probably want to
18256559c901SRob Clark * ratelimit this!)
18266559c901SRob Clark *
1827bd1fbef7SDaniel Vetter * The caller must wrap this drm_modeset_lock_all_ctx() and
1828bd1fbef7SDaniel Vetter * drm_modeset_drop_locks(). If this is called from error irq handler, it should
1829bd1fbef7SDaniel Vetter * not be enabled by default - if you are debugging errors you might
1830bd1fbef7SDaniel Vetter * not care that this is racey, but calling this without all modeset locks held
1831bd1fbef7SDaniel Vetter * is inherently unsafe.
18326559c901SRob Clark */
drm_state_dump(struct drm_device * dev,struct drm_printer * p)18336559c901SRob Clark void drm_state_dump(struct drm_device *dev, struct drm_printer *p)
18346559c901SRob Clark {
1835c2d85564SDaniel Vetter __drm_state_dump(dev, p, false);
18366559c901SRob Clark }
18376559c901SRob Clark EXPORT_SYMBOL(drm_state_dump);
18386559c901SRob Clark
18396559c901SRob Clark #ifdef CONFIG_DEBUG_FS
drm_state_info(struct seq_file * m,void * data)18406559c901SRob Clark static int drm_state_info(struct seq_file *m, void *data)
18416559c901SRob Clark {
18426fd80729SMaíra Canal struct drm_debugfs_entry *entry = m->private;
18436fd80729SMaíra Canal struct drm_device *dev = entry->dev;
18446559c901SRob Clark struct drm_printer p = drm_seq_file_printer(m);
18456559c901SRob Clark
1846c2d85564SDaniel Vetter __drm_state_dump(dev, &p, true);
18476559c901SRob Clark
18486559c901SRob Clark return 0;
18496559c901SRob Clark }
18506559c901SRob Clark
18516559c901SRob Clark /* any use in debugfs files to dump individual planes/crtc/etc? */
18526fd80729SMaíra Canal static const struct drm_debugfs_info drm_atomic_debugfs_list[] = {
18536559c901SRob Clark {"state", drm_state_info, 0},
18546559c901SRob Clark };
18556559c901SRob Clark
drm_atomic_debugfs_init(struct drm_device * dev)18560b30d57aSChristian König void drm_atomic_debugfs_init(struct drm_device *dev)
18576559c901SRob Clark {
18580b30d57aSChristian König drm_debugfs_add_files(dev, drm_atomic_debugfs_list,
18596fd80729SMaíra Canal ARRAY_SIZE(drm_atomic_debugfs_list));
18606559c901SRob Clark }
18616559c901SRob Clark #endif
1862