1c2fcd274SDaniel Vetter /*
2c2fcd274SDaniel Vetter * Copyright (C) 2014 Red Hat
3c2fcd274SDaniel Vetter * Copyright (C) 2014 Intel Corp.
4c2fcd274SDaniel Vetter *
5c2fcd274SDaniel Vetter * Permission is hereby granted, free of charge, to any person obtaining a
6c2fcd274SDaniel Vetter * copy of this software and associated documentation files (the "Software"),
7c2fcd274SDaniel Vetter * to deal in the Software without restriction, including without limitation
8c2fcd274SDaniel Vetter * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9c2fcd274SDaniel Vetter * and/or sell copies of the Software, and to permit persons to whom the
10c2fcd274SDaniel Vetter * Software is furnished to do so, subject to the following conditions:
11c2fcd274SDaniel Vetter *
12c2fcd274SDaniel Vetter * The above copyright notice and this permission notice shall be included in
13c2fcd274SDaniel Vetter * all copies or substantial portions of the Software.
14c2fcd274SDaniel Vetter *
15c2fcd274SDaniel Vetter * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16c2fcd274SDaniel Vetter * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17c2fcd274SDaniel Vetter * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18c2fcd274SDaniel Vetter * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
19c2fcd274SDaniel Vetter * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20c2fcd274SDaniel Vetter * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21c2fcd274SDaniel Vetter * OTHER DEALINGS IN THE SOFTWARE.
22c2fcd274SDaniel Vetter *
23c2fcd274SDaniel Vetter * Authors:
24c2fcd274SDaniel Vetter * Rob Clark <robdclark@gmail.com>
25c2fcd274SDaniel Vetter * Daniel Vetter <daniel.vetter@ffwll.ch>
26c2fcd274SDaniel Vetter */
27c2fcd274SDaniel Vetter
28f54d1867SChris Wilson #include <linux/dma-fence.h>
29d4da4e33SSean Paul #include <linux/ktime.h>
30c2fcd274SDaniel Vetter
310500c04eSSam Ravnborg #include <drm/drm_atomic.h>
320500c04eSSam Ravnborg #include <drm/drm_atomic_helper.h>
330500c04eSSam Ravnborg #include <drm/drm_atomic_uapi.h>
3490bb087fSVille Syrjälä #include <drm/drm_blend.h>
35ee68c743SBoris Brezillon #include <drm/drm_bridge.h>
360500c04eSSam Ravnborg #include <drm/drm_damage_helper.h>
370500c04eSSam Ravnborg #include <drm/drm_device.h>
3877ef3857SDaniel Vetter #include <drm/drm_drv.h>
39720cf96dSVille Syrjälä #include <drm/drm_framebuffer.h>
407d30963fSDaniel Vetter #include <drm/drm_gem_atomic_helper.h>
410500c04eSSam Ravnborg #include <drm/drm_print.h>
421452c25bSSean Paul #include <drm/drm_self_refresh_helper.h>
430500c04eSSam Ravnborg #include <drm/drm_vblank.h>
440500c04eSSam Ravnborg #include <drm/drm_writeback.h>
450500c04eSSam Ravnborg
46faf94a08SJose Abreu #include "drm_crtc_helper_internal.h"
4744d1240dSMarek Szyprowski #include "drm_crtc_internal.h"
4844d1240dSMarek Szyprowski
493150c7d0SDaniel Vetter /**
503150c7d0SDaniel Vetter * DOC: overview
513150c7d0SDaniel Vetter *
523150c7d0SDaniel Vetter * This helper library provides implementations of check and commit functions on
533150c7d0SDaniel Vetter * top of the CRTC modeset helper callbacks and the plane helper callbacks. It
543150c7d0SDaniel Vetter * also provides convenience implementations for the atomic state handling
553150c7d0SDaniel Vetter * callbacks for drivers which don't need to subclass the drm core structures to
563150c7d0SDaniel Vetter * add their own additional internal state.
573150c7d0SDaniel Vetter *
583150c7d0SDaniel Vetter * This library also provides default implementations for the check callback in
5926196f7eSDaniel Vetter * drm_atomic_helper_check() and for the commit callback with
6026196f7eSDaniel Vetter * drm_atomic_helper_commit(). But the individual stages and callbacks are
6126196f7eSDaniel Vetter * exposed to allow drivers to mix and match and e.g. use the plane helpers only
623150c7d0SDaniel Vetter * together with a driver private modeset implementation.
633150c7d0SDaniel Vetter *
643150c7d0SDaniel Vetter * This library also provides implementations for all the legacy driver
6526196f7eSDaniel Vetter * interfaces on top of the atomic interface. See drm_atomic_helper_set_config(),
66ee84c58bSDafna Hirschfeld * drm_atomic_helper_disable_plane(), and the various functions to implement
67ee84c58bSDafna Hirschfeld * set_property callbacks. New drivers must not implement these functions
68ee84c58bSDafna Hirschfeld * themselves but must use the provided helpers.
69092d01daSDaniel Vetter *
70092d01daSDaniel Vetter * The atomic helper uses the same function table structures as all other
71ea0dd85aSDaniel Vetter * modesetting helpers. See the documentation for &struct drm_crtc_helper_funcs,
72ea0dd85aSDaniel Vetter * struct &drm_encoder_helper_funcs and &struct drm_connector_helper_funcs. It
73ea0dd85aSDaniel Vetter * also shares the &struct drm_plane_helper_funcs function table with the plane
74092d01daSDaniel Vetter * helpers.
753150c7d0SDaniel Vetter */
76c2fcd274SDaniel Vetter static void
drm_atomic_helper_plane_changed(struct drm_atomic_state * state,struct drm_plane_state * old_plane_state,struct drm_plane_state * plane_state,struct drm_plane * plane)77c2fcd274SDaniel Vetter drm_atomic_helper_plane_changed(struct drm_atomic_state *state,
78415c3ac3SMaarten Lankhorst struct drm_plane_state *old_plane_state,
79c2fcd274SDaniel Vetter struct drm_plane_state *plane_state,
80c2fcd274SDaniel Vetter struct drm_plane *plane)
81c2fcd274SDaniel Vetter {
82c2fcd274SDaniel Vetter struct drm_crtc_state *crtc_state;
83c2fcd274SDaniel Vetter
84415c3ac3SMaarten Lankhorst if (old_plane_state->crtc) {
85b4d93679SMaarten Lankhorst crtc_state = drm_atomic_get_new_crtc_state(state,
86415c3ac3SMaarten Lankhorst old_plane_state->crtc);
87c2fcd274SDaniel Vetter
88c2fcd274SDaniel Vetter if (WARN_ON(!crtc_state))
89c2fcd274SDaniel Vetter return;
90c2fcd274SDaniel Vetter
91c2fcd274SDaniel Vetter crtc_state->planes_changed = true;
92c2fcd274SDaniel Vetter }
93c2fcd274SDaniel Vetter
94c2fcd274SDaniel Vetter if (plane_state->crtc) {
95b4d93679SMaarten Lankhorst crtc_state = drm_atomic_get_new_crtc_state(state, plane_state->crtc);
96c2fcd274SDaniel Vetter
97c2fcd274SDaniel Vetter if (WARN_ON(!crtc_state))
98c2fcd274SDaniel Vetter return;
99c2fcd274SDaniel Vetter
100c2fcd274SDaniel Vetter crtc_state->planes_changed = true;
101c2fcd274SDaniel Vetter }
102c2fcd274SDaniel Vetter }
103c2fcd274SDaniel Vetter
handle_conflicting_encoders(struct drm_atomic_state * state,bool disable_conflicting_encoders)1048248b65dSMaarten Lankhorst static int handle_conflicting_encoders(struct drm_atomic_state *state,
1058248b65dSMaarten Lankhorst bool disable_conflicting_encoders)
10697ac3204SDaniel Vetter {
107415c3ac3SMaarten Lankhorst struct drm_connector_state *new_conn_state;
108623369e5SDaniel Vetter struct drm_connector *connector;
109c36a3254SDaniel Vetter struct drm_connector_list_iter conn_iter;
11040616a26SMaarten Lankhorst struct drm_encoder *encoder;
1119237ec1fSFabio M. De Francesco unsigned int encoder_mask = 0;
112c36a3254SDaniel Vetter int i, ret = 0;
113623369e5SDaniel Vetter
1148248b65dSMaarten Lankhorst /*
1158248b65dSMaarten Lankhorst * First loop, find all newly assigned encoders from the connectors
1168248b65dSMaarten Lankhorst * part of the state. If the same encoder is assigned to multiple
1178248b65dSMaarten Lankhorst * connectors bail out.
1188248b65dSMaarten Lankhorst */
119415c3ac3SMaarten Lankhorst for_each_new_connector_in_state(state, connector, new_conn_state, i) {
12040616a26SMaarten Lankhorst const struct drm_connector_helper_funcs *funcs = connector->helper_private;
12140616a26SMaarten Lankhorst struct drm_encoder *new_encoder;
122623369e5SDaniel Vetter
123415c3ac3SMaarten Lankhorst if (!new_conn_state->crtc)
124623369e5SDaniel Vetter continue;
125623369e5SDaniel Vetter
12640616a26SMaarten Lankhorst if (funcs->atomic_best_encoder)
127eca22edbSMaxime Ripard new_encoder = funcs->atomic_best_encoder(connector,
128eca22edbSMaxime Ripard state);
129a0909cc5SBoris Brezillon else if (funcs->best_encoder)
13040616a26SMaarten Lankhorst new_encoder = funcs->best_encoder(connector);
131a0909cc5SBoris Brezillon else
132a92462d6SJosé Roberto de Souza new_encoder = drm_connector_get_single_encoder(connector);
13340616a26SMaarten Lankhorst
1348248b65dSMaarten Lankhorst if (new_encoder) {
1356f3be036SVille Syrjälä if (encoder_mask & drm_encoder_mask(new_encoder)) {
1366e22dc35SClaudio Suarez drm_dbg_atomic(connector->dev,
1376e22dc35SClaudio Suarez "[ENCODER:%d:%s] on [CONNECTOR:%d:%s] already assigned\n",
1388248b65dSMaarten Lankhorst new_encoder->base.id, new_encoder->name,
1398248b65dSMaarten Lankhorst connector->base.id, connector->name);
1408248b65dSMaarten Lankhorst
1418248b65dSMaarten Lankhorst return -EINVAL;
142623369e5SDaniel Vetter }
143623369e5SDaniel Vetter
1446f3be036SVille Syrjälä encoder_mask |= drm_encoder_mask(new_encoder);
1458248b65dSMaarten Lankhorst }
1468248b65dSMaarten Lankhorst }
1478248b65dSMaarten Lankhorst
1488248b65dSMaarten Lankhorst if (!encoder_mask)
1498248b65dSMaarten Lankhorst return 0;
1508248b65dSMaarten Lankhorst
1518248b65dSMaarten Lankhorst /*
1528248b65dSMaarten Lankhorst * Second loop, iterate over all connectors not part of the state.
1538248b65dSMaarten Lankhorst *
1548248b65dSMaarten Lankhorst * If a conflicting encoder is found and disable_conflicting_encoders
1558248b65dSMaarten Lankhorst * is not set, an error is returned. Userspace can provide a solution
1568248b65dSMaarten Lankhorst * through the atomic ioctl.
1578248b65dSMaarten Lankhorst *
15842240c90SThierry Reding * If the flag is set conflicting connectors are removed from the CRTC
15942240c90SThierry Reding * and the CRTC is disabled if no encoder is left. This preserves
1608248b65dSMaarten Lankhorst * compatibility with the legacy set_config behavior.
1618248b65dSMaarten Lankhorst */
162b982dab1SThierry Reding drm_connector_list_iter_begin(state->dev, &conn_iter);
163c36a3254SDaniel Vetter drm_for_each_connector_iter(connector, &conn_iter) {
16440616a26SMaarten Lankhorst struct drm_crtc_state *crtc_state;
16540616a26SMaarten Lankhorst
166b4d93679SMaarten Lankhorst if (drm_atomic_get_new_connector_state(state, connector))
16740616a26SMaarten Lankhorst continue;
16840616a26SMaarten Lankhorst
16940616a26SMaarten Lankhorst encoder = connector->state->best_encoder;
1706f3be036SVille Syrjälä if (!encoder || !(encoder_mask & drm_encoder_mask(encoder)))
17140616a26SMaarten Lankhorst continue;
17240616a26SMaarten Lankhorst
1738248b65dSMaarten Lankhorst if (!disable_conflicting_encoders) {
1746e22dc35SClaudio Suarez drm_dbg_atomic(connector->dev,
1756e22dc35SClaudio Suarez "[ENCODER:%d:%s] in use on [CRTC:%d:%s] by [CONNECTOR:%d:%s]\n",
1768248b65dSMaarten Lankhorst encoder->base.id, encoder->name,
1778248b65dSMaarten Lankhorst connector->state->crtc->base.id,
1788248b65dSMaarten Lankhorst connector->state->crtc->name,
1798248b65dSMaarten Lankhorst connector->base.id, connector->name);
180c36a3254SDaniel Vetter ret = -EINVAL;
181c36a3254SDaniel Vetter goto out;
1828248b65dSMaarten Lankhorst }
1838248b65dSMaarten Lankhorst
184415c3ac3SMaarten Lankhorst new_conn_state = drm_atomic_get_connector_state(state, connector);
185415c3ac3SMaarten Lankhorst if (IS_ERR(new_conn_state)) {
186415c3ac3SMaarten Lankhorst ret = PTR_ERR(new_conn_state);
187c36a3254SDaniel Vetter goto out;
188c36a3254SDaniel Vetter }
18940616a26SMaarten Lankhorst
1906e22dc35SClaudio Suarez drm_dbg_atomic(connector->dev,
1916e22dc35SClaudio Suarez "[ENCODER:%d:%s] in use on [CRTC:%d:%s], disabling [CONNECTOR:%d:%s]\n",
19240616a26SMaarten Lankhorst encoder->base.id, encoder->name,
193415c3ac3SMaarten Lankhorst new_conn_state->crtc->base.id, new_conn_state->crtc->name,
19440616a26SMaarten Lankhorst connector->base.id, connector->name);
19540616a26SMaarten Lankhorst
196b4d93679SMaarten Lankhorst crtc_state = drm_atomic_get_new_crtc_state(state, new_conn_state->crtc);
19740616a26SMaarten Lankhorst
198415c3ac3SMaarten Lankhorst ret = drm_atomic_set_crtc_for_connector(new_conn_state, NULL);
19940616a26SMaarten Lankhorst if (ret)
200c36a3254SDaniel Vetter goto out;
20140616a26SMaarten Lankhorst
20240616a26SMaarten Lankhorst if (!crtc_state->connector_mask) {
20340616a26SMaarten Lankhorst ret = drm_atomic_set_mode_prop_for_crtc(crtc_state,
20440616a26SMaarten Lankhorst NULL);
20540616a26SMaarten Lankhorst if (ret < 0)
206c36a3254SDaniel Vetter goto out;
20740616a26SMaarten Lankhorst
20840616a26SMaarten Lankhorst crtc_state->active = false;
20940616a26SMaarten Lankhorst }
21040616a26SMaarten Lankhorst }
211c36a3254SDaniel Vetter out:
212b982dab1SThierry Reding drm_connector_list_iter_end(&conn_iter);
21340616a26SMaarten Lankhorst
214c36a3254SDaniel Vetter return ret;
215623369e5SDaniel Vetter }
216623369e5SDaniel Vetter
217e87a52b3SMaarten Lankhorst static void
set_best_encoder(struct drm_atomic_state * state,struct drm_connector_state * conn_state,struct drm_encoder * encoder)218e87a52b3SMaarten Lankhorst set_best_encoder(struct drm_atomic_state *state,
219e87a52b3SMaarten Lankhorst struct drm_connector_state *conn_state,
220e87a52b3SMaarten Lankhorst struct drm_encoder *encoder)
221e87a52b3SMaarten Lankhorst {
222e87a52b3SMaarten Lankhorst struct drm_crtc_state *crtc_state;
223e87a52b3SMaarten Lankhorst struct drm_crtc *crtc;
224e87a52b3SMaarten Lankhorst
225e87a52b3SMaarten Lankhorst if (conn_state->best_encoder) {
226e87a52b3SMaarten Lankhorst /* Unset the encoder_mask in the old crtc state. */
227e87a52b3SMaarten Lankhorst crtc = conn_state->connector->state->crtc;
228e87a52b3SMaarten Lankhorst
229e87a52b3SMaarten Lankhorst /* A NULL crtc is an error here because we should have
230e87a52b3SMaarten Lankhorst * duplicated a NULL best_encoder when crtc was NULL.
231e87a52b3SMaarten Lankhorst * As an exception restoring duplicated atomic state
232e87a52b3SMaarten Lankhorst * during resume is allowed, so don't warn when
233e87a52b3SMaarten Lankhorst * best_encoder is equal to encoder we intend to set.
234e87a52b3SMaarten Lankhorst */
235e87a52b3SMaarten Lankhorst WARN_ON(!crtc && encoder != conn_state->best_encoder);
236e87a52b3SMaarten Lankhorst if (crtc) {
237b4d93679SMaarten Lankhorst crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
238e87a52b3SMaarten Lankhorst
239e87a52b3SMaarten Lankhorst crtc_state->encoder_mask &=
2406f3be036SVille Syrjälä ~drm_encoder_mask(conn_state->best_encoder);
241e87a52b3SMaarten Lankhorst }
242e87a52b3SMaarten Lankhorst }
243e87a52b3SMaarten Lankhorst
244e87a52b3SMaarten Lankhorst if (encoder) {
245e87a52b3SMaarten Lankhorst crtc = conn_state->crtc;
246e87a52b3SMaarten Lankhorst WARN_ON(!crtc);
247e87a52b3SMaarten Lankhorst if (crtc) {
248b4d93679SMaarten Lankhorst crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
249e87a52b3SMaarten Lankhorst
250e87a52b3SMaarten Lankhorst crtc_state->encoder_mask |=
2516f3be036SVille Syrjälä drm_encoder_mask(encoder);
252e87a52b3SMaarten Lankhorst }
253e87a52b3SMaarten Lankhorst }
254e87a52b3SMaarten Lankhorst
255e87a52b3SMaarten Lankhorst conn_state->best_encoder = encoder;
256e87a52b3SMaarten Lankhorst }
257e87a52b3SMaarten Lankhorst
258ec5aaa58SMaarten Lankhorst static void
steal_encoder(struct drm_atomic_state * state,struct drm_encoder * encoder)259623369e5SDaniel Vetter steal_encoder(struct drm_atomic_state *state,
260ff19b786SMaarten Lankhorst struct drm_encoder *encoder)
261623369e5SDaniel Vetter {
262623369e5SDaniel Vetter struct drm_crtc_state *crtc_state;
263623369e5SDaniel Vetter struct drm_connector *connector;
264415c3ac3SMaarten Lankhorst struct drm_connector_state *old_connector_state, *new_connector_state;
265ec5aaa58SMaarten Lankhorst int i;
266623369e5SDaniel Vetter
267415c3ac3SMaarten Lankhorst for_each_oldnew_connector_in_state(state, connector, old_connector_state, new_connector_state, i) {
268ff19b786SMaarten Lankhorst struct drm_crtc *encoder_crtc;
269623369e5SDaniel Vetter
270415c3ac3SMaarten Lankhorst if (new_connector_state->best_encoder != encoder)
271e87a52b3SMaarten Lankhorst continue;
272e87a52b3SMaarten Lankhorst
273415c3ac3SMaarten Lankhorst encoder_crtc = old_connector_state->crtc;
274623369e5SDaniel Vetter
2756e22dc35SClaudio Suarez drm_dbg_atomic(encoder->dev,
2766e22dc35SClaudio Suarez "[ENCODER:%d:%s] in use on [CRTC:%d:%s], stealing it\n",
277623369e5SDaniel Vetter encoder->base.id, encoder->name,
278fa3ab4c2SVille Syrjälä encoder_crtc->base.id, encoder_crtc->name);
279623369e5SDaniel Vetter
280415c3ac3SMaarten Lankhorst set_best_encoder(state, new_connector_state, NULL);
281623369e5SDaniel Vetter
282b4d93679SMaarten Lankhorst crtc_state = drm_atomic_get_new_crtc_state(state, encoder_crtc);
283fc596660SMaarten Lankhorst crtc_state->connectors_changed = true;
284623369e5SDaniel Vetter
285ec5aaa58SMaarten Lankhorst return;
286623369e5SDaniel Vetter }
287623369e5SDaniel Vetter }
288623369e5SDaniel Vetter
289623369e5SDaniel Vetter static int
update_connector_routing(struct drm_atomic_state * state,struct drm_connector * connector,struct drm_connector_state * old_connector_state,struct drm_connector_state * new_connector_state,bool added_by_user)2909459545bSMaarten Lankhorst update_connector_routing(struct drm_atomic_state *state,
2919459545bSMaarten Lankhorst struct drm_connector *connector,
292415c3ac3SMaarten Lankhorst struct drm_connector_state *old_connector_state,
2932b7947bdSSimon Ser struct drm_connector_state *new_connector_state,
2942b7947bdSSimon Ser bool added_by_user)
295623369e5SDaniel Vetter {
296b5ceff20SVille Syrjälä const struct drm_connector_helper_funcs *funcs;
297623369e5SDaniel Vetter struct drm_encoder *new_encoder;
298623369e5SDaniel Vetter struct drm_crtc_state *crtc_state;
299623369e5SDaniel Vetter
3006e22dc35SClaudio Suarez drm_dbg_atomic(connector->dev, "Updating routing for [CONNECTOR:%d:%s]\n",
3016e22dc35SClaudio Suarez connector->base.id, connector->name);
302623369e5SDaniel Vetter
303415c3ac3SMaarten Lankhorst if (old_connector_state->crtc != new_connector_state->crtc) {
304415c3ac3SMaarten Lankhorst if (old_connector_state->crtc) {
305b4d93679SMaarten Lankhorst crtc_state = drm_atomic_get_new_crtc_state(state, old_connector_state->crtc);
306fc596660SMaarten Lankhorst crtc_state->connectors_changed = true;
307623369e5SDaniel Vetter }
308623369e5SDaniel Vetter
309415c3ac3SMaarten Lankhorst if (new_connector_state->crtc) {
310b4d93679SMaarten Lankhorst crtc_state = drm_atomic_get_new_crtc_state(state, new_connector_state->crtc);
311fc596660SMaarten Lankhorst crtc_state->connectors_changed = true;
312623369e5SDaniel Vetter }
313623369e5SDaniel Vetter }
314623369e5SDaniel Vetter
315415c3ac3SMaarten Lankhorst if (!new_connector_state->crtc) {
3166e22dc35SClaudio Suarez drm_dbg_atomic(connector->dev, "Disabling [CONNECTOR:%d:%s]\n",
3176e22dc35SClaudio Suarez connector->base.id, connector->name);
318623369e5SDaniel Vetter
319415c3ac3SMaarten Lankhorst set_best_encoder(state, new_connector_state, NULL);
320623369e5SDaniel Vetter
321623369e5SDaniel Vetter return 0;
322623369e5SDaniel Vetter }
323623369e5SDaniel Vetter
324de9f8eeaSLyude Paul crtc_state = drm_atomic_get_new_crtc_state(state,
325de9f8eeaSLyude Paul new_connector_state->crtc);
326de9f8eeaSLyude Paul /*
327de9f8eeaSLyude Paul * For compatibility with legacy users, we want to make sure that
328de9f8eeaSLyude Paul * we allow DPMS On->Off modesets on unregistered connectors. Modesets
329de9f8eeaSLyude Paul * which would result in anything else must be considered invalid, to
330de9f8eeaSLyude Paul * avoid turning on new displays on dead connectors.
331de9f8eeaSLyude Paul *
332de9f8eeaSLyude Paul * Since the connector can be unregistered at any point during an
333de9f8eeaSLyude Paul * atomic check or commit, this is racy. But that's OK: all we care
334de9f8eeaSLyude Paul * about is ensuring that userspace can't do anything but shut off the
3351e55a53aSMatt Roper * display on a connector that was destroyed after it's been notified,
336de9f8eeaSLyude Paul * not before.
337022debadSLyude Paul *
338022debadSLyude Paul * Additionally, we also want to ignore connector registration when
339022debadSLyude Paul * we're trying to restore an atomic state during system resume since
340022debadSLyude Paul * there's a chance the connector may have been destroyed during the
341022debadSLyude Paul * process, but it's better to ignore that then cause
342022debadSLyude Paul * drm_atomic_helper_resume() to fail.
3432b7947bdSSimon Ser *
3442b7947bdSSimon Ser * Last, we want to ignore connector registration when the connector
3452b7947bdSSimon Ser * was not pulled in the atomic state by user-space (ie, was pulled
3462b7947bdSSimon Ser * in by the driver, e.g. when updating a DP-MST stream).
347de9f8eeaSLyude Paul */
348022debadSLyude Paul if (!state->duplicated && drm_connector_is_unregistered(connector) &&
3492b7947bdSSimon Ser added_by_user && crtc_state->active) {
3506e22dc35SClaudio Suarez drm_dbg_atomic(connector->dev,
3516e22dc35SClaudio Suarez "[CONNECTOR:%d:%s] is not registered\n",
352de9f8eeaSLyude Paul connector->base.id, connector->name);
353de9f8eeaSLyude Paul return -EINVAL;
354de9f8eeaSLyude Paul }
355de9f8eeaSLyude Paul
356623369e5SDaniel Vetter funcs = connector->helper_private;
3573b8a684bSDaniel Vetter
3583b8a684bSDaniel Vetter if (funcs->atomic_best_encoder)
359eca22edbSMaxime Ripard new_encoder = funcs->atomic_best_encoder(connector, state);
360c61b93feSBoris Brezillon else if (funcs->best_encoder)
361623369e5SDaniel Vetter new_encoder = funcs->best_encoder(connector);
362c61b93feSBoris Brezillon else
363a92462d6SJosé Roberto de Souza new_encoder = drm_connector_get_single_encoder(connector);
364623369e5SDaniel Vetter
365623369e5SDaniel Vetter if (!new_encoder) {
3666e22dc35SClaudio Suarez drm_dbg_atomic(connector->dev,
3676e22dc35SClaudio Suarez "No suitable encoder found for [CONNECTOR:%d:%s]\n",
3686e22dc35SClaudio Suarez connector->base.id, connector->name);
369623369e5SDaniel Vetter return -EINVAL;
370623369e5SDaniel Vetter }
371623369e5SDaniel Vetter
372415c3ac3SMaarten Lankhorst if (!drm_encoder_crtc_ok(new_encoder, new_connector_state->crtc)) {
3736e22dc35SClaudio Suarez drm_dbg_atomic(connector->dev,
3746e22dc35SClaudio Suarez "[ENCODER:%d:%s] incompatible with [CRTC:%d:%s]\n",
3755481c8fbSDaniel Vetter new_encoder->base.id,
3765481c8fbSDaniel Vetter new_encoder->name,
377415c3ac3SMaarten Lankhorst new_connector_state->crtc->base.id,
378415c3ac3SMaarten Lankhorst new_connector_state->crtc->name);
3795481c8fbSDaniel Vetter return -EINVAL;
3805481c8fbSDaniel Vetter }
3815481c8fbSDaniel Vetter
382415c3ac3SMaarten Lankhorst if (new_encoder == new_connector_state->best_encoder) {
383415c3ac3SMaarten Lankhorst set_best_encoder(state, new_connector_state, new_encoder);
384e87a52b3SMaarten Lankhorst
3856e22dc35SClaudio Suarez drm_dbg_atomic(connector->dev,
3866e22dc35SClaudio Suarez "[CONNECTOR:%d:%s] keeps [ENCODER:%d:%s], now on [CRTC:%d:%s]\n",
387623369e5SDaniel Vetter connector->base.id,
388623369e5SDaniel Vetter connector->name,
389623369e5SDaniel Vetter new_encoder->base.id,
390623369e5SDaniel Vetter new_encoder->name,
391415c3ac3SMaarten Lankhorst new_connector_state->crtc->base.id,
392415c3ac3SMaarten Lankhorst new_connector_state->crtc->name);
393623369e5SDaniel Vetter
394623369e5SDaniel Vetter return 0;
395623369e5SDaniel Vetter }
396623369e5SDaniel Vetter
397ec5aaa58SMaarten Lankhorst steal_encoder(state, new_encoder);
3986ea76f3cSDaniel Vetter
399415c3ac3SMaarten Lankhorst set_best_encoder(state, new_connector_state, new_encoder);
400e87a52b3SMaarten Lankhorst
401fc596660SMaarten Lankhorst crtc_state->connectors_changed = true;
402623369e5SDaniel Vetter
4036e22dc35SClaudio Suarez drm_dbg_atomic(connector->dev,
4046e22dc35SClaudio Suarez "[CONNECTOR:%d:%s] using [ENCODER:%d:%s] on [CRTC:%d:%s]\n",
405623369e5SDaniel Vetter connector->base.id,
406623369e5SDaniel Vetter connector->name,
407623369e5SDaniel Vetter new_encoder->base.id,
408623369e5SDaniel Vetter new_encoder->name,
409415c3ac3SMaarten Lankhorst new_connector_state->crtc->base.id,
410415c3ac3SMaarten Lankhorst new_connector_state->crtc->name);
411623369e5SDaniel Vetter
412623369e5SDaniel Vetter return 0;
413623369e5SDaniel Vetter }
414623369e5SDaniel Vetter
415623369e5SDaniel Vetter static int
mode_fixup(struct drm_atomic_state * state)416623369e5SDaniel Vetter mode_fixup(struct drm_atomic_state *state)
417623369e5SDaniel Vetter {
418df63b999SAnder Conselvan de Oliveira struct drm_crtc *crtc;
419415c3ac3SMaarten Lankhorst struct drm_crtc_state *new_crtc_state;
420df63b999SAnder Conselvan de Oliveira struct drm_connector *connector;
421415c3ac3SMaarten Lankhorst struct drm_connector_state *new_conn_state;
422623369e5SDaniel Vetter int i;
423f9ad86e4SDan Carpenter int ret;
424623369e5SDaniel Vetter
425415c3ac3SMaarten Lankhorst for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
426415c3ac3SMaarten Lankhorst if (!new_crtc_state->mode_changed &&
427415c3ac3SMaarten Lankhorst !new_crtc_state->connectors_changed)
428623369e5SDaniel Vetter continue;
429623369e5SDaniel Vetter
430415c3ac3SMaarten Lankhorst drm_mode_copy(&new_crtc_state->adjusted_mode, &new_crtc_state->mode);
431623369e5SDaniel Vetter }
432623369e5SDaniel Vetter
433415c3ac3SMaarten Lankhorst for_each_new_connector_in_state(state, connector, new_conn_state, i) {
434b5ceff20SVille Syrjälä const struct drm_encoder_helper_funcs *funcs;
435623369e5SDaniel Vetter struct drm_encoder *encoder;
43635a61fe9SBoris Brezillon struct drm_bridge *bridge;
437623369e5SDaniel Vetter
438415c3ac3SMaarten Lankhorst WARN_ON(!!new_conn_state->best_encoder != !!new_conn_state->crtc);
439623369e5SDaniel Vetter
440415c3ac3SMaarten Lankhorst if (!new_conn_state->crtc || !new_conn_state->best_encoder)
441623369e5SDaniel Vetter continue;
442623369e5SDaniel Vetter
443415c3ac3SMaarten Lankhorst new_crtc_state =
444b4d93679SMaarten Lankhorst drm_atomic_get_new_crtc_state(state, new_conn_state->crtc);
445623369e5SDaniel Vetter
446623369e5SDaniel Vetter /*
447623369e5SDaniel Vetter * Each encoder has at most one connector (since we always steal
448623369e5SDaniel Vetter * it away), so we won't call ->mode_fixup twice.
449623369e5SDaniel Vetter */
450415c3ac3SMaarten Lankhorst encoder = new_conn_state->best_encoder;
451623369e5SDaniel Vetter funcs = encoder->helper_private;
452623369e5SDaniel Vetter
45335a61fe9SBoris Brezillon bridge = drm_bridge_chain_get_first_bridge(encoder);
4545061b8a9SBoris Brezillon ret = drm_atomic_bridge_chain_check(bridge,
4555061b8a9SBoris Brezillon new_crtc_state,
4565061b8a9SBoris Brezillon new_conn_state);
4575061b8a9SBoris Brezillon if (ret) {
4586e22dc35SClaudio Suarez drm_dbg_atomic(encoder->dev, "Bridge atomic check failed\n");
4595061b8a9SBoris Brezillon return ret;
460623369e5SDaniel Vetter }
461623369e5SDaniel Vetter
4622827635eSNoralf Trønnes if (funcs && funcs->atomic_check) {
463415c3ac3SMaarten Lankhorst ret = funcs->atomic_check(encoder, new_crtc_state,
464415c3ac3SMaarten Lankhorst new_conn_state);
4654cd4df80SThierry Reding if (ret) {
4666e22dc35SClaudio Suarez drm_dbg_atomic(encoder->dev,
4676e22dc35SClaudio Suarez "[ENCODER:%d:%s] check failed\n",
4684cd4df80SThierry Reding encoder->base.id, encoder->name);
4694cd4df80SThierry Reding return ret;
4704cd4df80SThierry Reding }
4712827635eSNoralf Trønnes } else if (funcs && funcs->mode_fixup) {
472415c3ac3SMaarten Lankhorst ret = funcs->mode_fixup(encoder, &new_crtc_state->mode,
473415c3ac3SMaarten Lankhorst &new_crtc_state->adjusted_mode);
474623369e5SDaniel Vetter if (!ret) {
4756e22dc35SClaudio Suarez drm_dbg_atomic(encoder->dev,
4766e22dc35SClaudio Suarez "[ENCODER:%d:%s] fixup failed\n",
477623369e5SDaniel Vetter encoder->base.id, encoder->name);
478623369e5SDaniel Vetter return -EINVAL;
479623369e5SDaniel Vetter }
480623369e5SDaniel Vetter }
4814cd4df80SThierry Reding }
482623369e5SDaniel Vetter
483415c3ac3SMaarten Lankhorst for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
484b5ceff20SVille Syrjälä const struct drm_crtc_helper_funcs *funcs;
485623369e5SDaniel Vetter
486415c3ac3SMaarten Lankhorst if (!new_crtc_state->enable)
487f55f1701SLiu Ying continue;
488f55f1701SLiu Ying
489415c3ac3SMaarten Lankhorst if (!new_crtc_state->mode_changed &&
490415c3ac3SMaarten Lankhorst !new_crtc_state->connectors_changed)
491623369e5SDaniel Vetter continue;
492623369e5SDaniel Vetter
493623369e5SDaniel Vetter funcs = crtc->helper_private;
49426564be5SVille Syrjälä if (!funcs || !funcs->mode_fixup)
495840bfe95SAnder Conselvan de Oliveira continue;
496840bfe95SAnder Conselvan de Oliveira
497415c3ac3SMaarten Lankhorst ret = funcs->mode_fixup(crtc, &new_crtc_state->mode,
498415c3ac3SMaarten Lankhorst &new_crtc_state->adjusted_mode);
499623369e5SDaniel Vetter if (!ret) {
5006e22dc35SClaudio Suarez drm_dbg_atomic(crtc->dev, "[CRTC:%d:%s] fixup failed\n",
501fa3ab4c2SVille Syrjälä crtc->base.id, crtc->name);
502623369e5SDaniel Vetter return -EINVAL;
503623369e5SDaniel Vetter }
504623369e5SDaniel Vetter }
505623369e5SDaniel Vetter
506623369e5SDaniel Vetter return 0;
507623369e5SDaniel Vetter }
508623369e5SDaniel Vetter
mode_valid_path(struct drm_connector * connector,struct drm_encoder * encoder,struct drm_crtc * crtc,const struct drm_display_mode * mode)509faf94a08SJose Abreu static enum drm_mode_status mode_valid_path(struct drm_connector *connector,
510faf94a08SJose Abreu struct drm_encoder *encoder,
511faf94a08SJose Abreu struct drm_crtc *crtc,
5128518f05aSLaurent Pinchart const struct drm_display_mode *mode)
513faf94a08SJose Abreu {
51435a61fe9SBoris Brezillon struct drm_bridge *bridge;
515faf94a08SJose Abreu enum drm_mode_status ret;
516faf94a08SJose Abreu
517faf94a08SJose Abreu ret = drm_encoder_mode_valid(encoder, mode);
518faf94a08SJose Abreu if (ret != MODE_OK) {
5196e22dc35SClaudio Suarez drm_dbg_atomic(encoder->dev,
5206e22dc35SClaudio Suarez "[ENCODER:%d:%s] mode_valid() failed\n",
521faf94a08SJose Abreu encoder->base.id, encoder->name);
522faf94a08SJose Abreu return ret;
523faf94a08SJose Abreu }
524faf94a08SJose Abreu
52535a61fe9SBoris Brezillon bridge = drm_bridge_chain_get_first_bridge(encoder);
52612c683e1SLaurent Pinchart ret = drm_bridge_chain_mode_valid(bridge, &connector->display_info,
52712c683e1SLaurent Pinchart mode);
528faf94a08SJose Abreu if (ret != MODE_OK) {
5296e22dc35SClaudio Suarez drm_dbg_atomic(encoder->dev, "[BRIDGE] mode_valid() failed\n");
530faf94a08SJose Abreu return ret;
531faf94a08SJose Abreu }
532faf94a08SJose Abreu
533faf94a08SJose Abreu ret = drm_crtc_mode_valid(crtc, mode);
534faf94a08SJose Abreu if (ret != MODE_OK) {
5356e22dc35SClaudio Suarez drm_dbg_atomic(encoder->dev, "[CRTC:%d:%s] mode_valid() failed\n",
536faf94a08SJose Abreu crtc->base.id, crtc->name);
537faf94a08SJose Abreu return ret;
538faf94a08SJose Abreu }
539faf94a08SJose Abreu
540faf94a08SJose Abreu return ret;
541faf94a08SJose Abreu }
542faf94a08SJose Abreu
543faf94a08SJose Abreu static int
mode_valid(struct drm_atomic_state * state)544faf94a08SJose Abreu mode_valid(struct drm_atomic_state *state)
545faf94a08SJose Abreu {
546faf94a08SJose Abreu struct drm_connector_state *conn_state;
547faf94a08SJose Abreu struct drm_connector *connector;
548faf94a08SJose Abreu int i;
549faf94a08SJose Abreu
550faf94a08SJose Abreu for_each_new_connector_in_state(state, connector, conn_state, i) {
551faf94a08SJose Abreu struct drm_encoder *encoder = conn_state->best_encoder;
552faf94a08SJose Abreu struct drm_crtc *crtc = conn_state->crtc;
553faf94a08SJose Abreu struct drm_crtc_state *crtc_state;
554faf94a08SJose Abreu enum drm_mode_status mode_status;
5558518f05aSLaurent Pinchart const struct drm_display_mode *mode;
556faf94a08SJose Abreu
557faf94a08SJose Abreu if (!crtc || !encoder)
558faf94a08SJose Abreu continue;
559faf94a08SJose Abreu
560faf94a08SJose Abreu crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
561faf94a08SJose Abreu if (!crtc_state)
562faf94a08SJose Abreu continue;
563faf94a08SJose Abreu if (!crtc_state->mode_changed && !crtc_state->connectors_changed)
564faf94a08SJose Abreu continue;
565faf94a08SJose Abreu
566faf94a08SJose Abreu mode = &crtc_state->mode;
567faf94a08SJose Abreu
568faf94a08SJose Abreu mode_status = mode_valid_path(connector, encoder, crtc, mode);
569faf94a08SJose Abreu if (mode_status != MODE_OK)
570faf94a08SJose Abreu return -EINVAL;
571faf94a08SJose Abreu }
572faf94a08SJose Abreu
573faf94a08SJose Abreu return 0;
574faf94a08SJose Abreu }
575faf94a08SJose Abreu
576d9b13620SDaniel Vetter /**
577f98bd3efSJohn Hunter * drm_atomic_helper_check_modeset - validate state object for modeset changes
578d9b13620SDaniel Vetter * @dev: DRM device
579d9b13620SDaniel Vetter * @state: the driver state object
580d9b13620SDaniel Vetter *
581d9b13620SDaniel Vetter * Check the state object to see if the requested state is physically possible.
58242240c90SThierry Reding * This does all the CRTC and connector related computations for an atomic
583ce09d766SMaarten Lankhorst * update and adds any additional connectors needed for full modesets. It calls
584ce09d766SMaarten Lankhorst * the various per-object callbacks in the follow order:
585ce09d766SMaarten Lankhorst *
586ce09d766SMaarten Lankhorst * 1. &drm_connector_helper_funcs.atomic_best_encoder for determining the new encoder.
587ce09d766SMaarten Lankhorst * 2. &drm_connector_helper_funcs.atomic_check to validate the connector state.
588dbe2d2bfSThierry Reding * 3. If it's determined a modeset is needed then all connectors on the affected
58942240c90SThierry Reding * CRTC are added and &drm_connector_helper_funcs.atomic_check is run on them.
590faf94a08SJose Abreu * 4. &drm_encoder_helper_funcs.mode_valid, &drm_bridge_funcs.mode_valid and
591faf94a08SJose Abreu * &drm_crtc_helper_funcs.mode_valid are called on the affected components.
592faf94a08SJose Abreu * 5. &drm_bridge_funcs.mode_fixup is called on all encoder bridges.
593faf94a08SJose Abreu * 6. &drm_encoder_helper_funcs.atomic_check is called to validate any encoder state.
59442240c90SThierry Reding * This function is only called when the encoder will be part of a configured CRTC,
595ce09d766SMaarten Lankhorst * it must not be used for implementing connector property validation.
596ce09d766SMaarten Lankhorst * If this function is NULL, &drm_atomic_encoder_helper_funcs.mode_fixup is called
597ce09d766SMaarten Lankhorst * instead.
59842240c90SThierry Reding * 7. &drm_crtc_helper_funcs.mode_fixup is called last, to fix up the mode with CRTC constraints.
599fc596660SMaarten Lankhorst *
6006806cdf9SDaniel Vetter * &drm_crtc_state.mode_changed is set when the input mode is changed.
6016806cdf9SDaniel Vetter * &drm_crtc_state.connectors_changed is set when a connector is added or
60242240c90SThierry Reding * removed from the CRTC. &drm_crtc_state.active_changed is set when
6036806cdf9SDaniel Vetter * &drm_crtc_state.active changes, which is used for DPMS.
6047beb691fSThomas Zimmermann * &drm_crtc_state.no_vblank is set from the result of drm_dev_has_vblank().
605d807ed1cSBrian Starkey * See also: drm_atomic_crtc_needs_modeset()
606d9b13620SDaniel Vetter *
607d9b13620SDaniel Vetter * IMPORTANT:
608d9b13620SDaniel Vetter *
6096806cdf9SDaniel Vetter * Drivers which set &drm_crtc_state.mode_changed (e.g. in their
6106806cdf9SDaniel Vetter * &drm_plane_helper_funcs.atomic_check hooks if a plane update can't be done
611ee84c58bSDafna Hirschfeld * without a full modeset) _must_ call this function after that change. It is
612ee84c58bSDafna Hirschfeld * permitted to call this function multiple times for the same update, e.g.
613ee84c58bSDafna Hirschfeld * when the &drm_crtc_helper_funcs.atomic_check functions depend upon the
614ee84c58bSDafna Hirschfeld * adjusted dotclock for fifo space allocation and watermark computation.
615d9b13620SDaniel Vetter *
616c39032a8SDaniel Vetter * RETURNS:
617d9b13620SDaniel Vetter * Zero for success or -errno
618d9b13620SDaniel Vetter */
619d9b13620SDaniel Vetter int
drm_atomic_helper_check_modeset(struct drm_device * dev,struct drm_atomic_state * state)620934ce1c2SRob Clark drm_atomic_helper_check_modeset(struct drm_device *dev,
621623369e5SDaniel Vetter struct drm_atomic_state *state)
622623369e5SDaniel Vetter {
623623369e5SDaniel Vetter struct drm_crtc *crtc;
624415c3ac3SMaarten Lankhorst struct drm_crtc_state *old_crtc_state, *new_crtc_state;
625df63b999SAnder Conselvan de Oliveira struct drm_connector *connector;
626415c3ac3SMaarten Lankhorst struct drm_connector_state *old_connector_state, *new_connector_state;
627623369e5SDaniel Vetter int i, ret;
6282b7947bdSSimon Ser unsigned int connectors_mask = 0, user_connectors_mask = 0;
6292b7947bdSSimon Ser
6302b7947bdSSimon Ser for_each_oldnew_connector_in_state(state, connector, old_connector_state, new_connector_state, i)
6312b7947bdSSimon Ser user_connectors_mask |= BIT(i);
632623369e5SDaniel Vetter
633415c3ac3SMaarten Lankhorst for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
634970ece83SMaarten Lankhorst bool has_connectors =
635970ece83SMaarten Lankhorst !!new_crtc_state->connector_mask;
636970ece83SMaarten Lankhorst
637869e188aSDaniel Vetter WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
638869e188aSDaniel Vetter
639415c3ac3SMaarten Lankhorst if (!drm_mode_equal(&old_crtc_state->mode, &new_crtc_state->mode)) {
6406e22dc35SClaudio Suarez drm_dbg_atomic(dev, "[CRTC:%d:%s] mode changed\n",
641fa3ab4c2SVille Syrjälä crtc->base.id, crtc->name);
642415c3ac3SMaarten Lankhorst new_crtc_state->mode_changed = true;
643623369e5SDaniel Vetter }
644623369e5SDaniel Vetter
645415c3ac3SMaarten Lankhorst if (old_crtc_state->enable != new_crtc_state->enable) {
6466e22dc35SClaudio Suarez drm_dbg_atomic(dev, "[CRTC:%d:%s] enable changed\n",
647fa3ab4c2SVille Syrjälä crtc->base.id, crtc->name);
648fc596660SMaarten Lankhorst
649fc596660SMaarten Lankhorst /*
650fc596660SMaarten Lankhorst * For clarity this assignment is done here, but
651fc596660SMaarten Lankhorst * enable == 0 is only true when there are no
652fc596660SMaarten Lankhorst * connectors and a NULL mode.
653fc596660SMaarten Lankhorst *
654fc596660SMaarten Lankhorst * The other way around is true as well. enable != 0
6550ae865efSCai Huoqing * implies that connectors are attached and a mode is set.
656fc596660SMaarten Lankhorst */
657415c3ac3SMaarten Lankhorst new_crtc_state->mode_changed = true;
658415c3ac3SMaarten Lankhorst new_crtc_state->connectors_changed = true;
659623369e5SDaniel Vetter }
66024d6652cSMaarten Lankhorst
66124d6652cSMaarten Lankhorst if (old_crtc_state->active != new_crtc_state->active) {
6626e22dc35SClaudio Suarez drm_dbg_atomic(dev, "[CRTC:%d:%s] active changed\n",
66324d6652cSMaarten Lankhorst crtc->base.id, crtc->name);
66424d6652cSMaarten Lankhorst new_crtc_state->active_changed = true;
66524d6652cSMaarten Lankhorst }
666970ece83SMaarten Lankhorst
667970ece83SMaarten Lankhorst if (new_crtc_state->enable != has_connectors) {
6686e22dc35SClaudio Suarez drm_dbg_atomic(dev, "[CRTC:%d:%s] enabled/connectors mismatch\n",
669970ece83SMaarten Lankhorst crtc->base.id, crtc->name);
670970ece83SMaarten Lankhorst
671970ece83SMaarten Lankhorst return -EINVAL;
672970ece83SMaarten Lankhorst }
6737beb691fSThomas Zimmermann
6747beb691fSThomas Zimmermann if (drm_dev_has_vblank(dev))
6757beb691fSThomas Zimmermann new_crtc_state->no_vblank = false;
6767beb691fSThomas Zimmermann else
6777beb691fSThomas Zimmermann new_crtc_state->no_vblank = true;
678623369e5SDaniel Vetter }
679623369e5SDaniel Vetter
68044596b8cSMaarten Lankhorst ret = handle_conflicting_encoders(state, false);
68140616a26SMaarten Lankhorst if (ret)
68240616a26SMaarten Lankhorst return ret;
68340616a26SMaarten Lankhorst
684415c3ac3SMaarten Lankhorst for_each_oldnew_connector_in_state(state, connector, old_connector_state, new_connector_state, i) {
685ce09d766SMaarten Lankhorst const struct drm_connector_helper_funcs *funcs = connector->helper_private;
686ce09d766SMaarten Lankhorst
687869e188aSDaniel Vetter WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
688869e188aSDaniel Vetter
689623369e5SDaniel Vetter /*
690d807ed1cSBrian Starkey * This only sets crtc->connectors_changed for routing changes,
691d807ed1cSBrian Starkey * drivers must set crtc->connectors_changed themselves when
692d807ed1cSBrian Starkey * connector properties need to be updated.
693623369e5SDaniel Vetter */
6949459545bSMaarten Lankhorst ret = update_connector_routing(state, connector,
695415c3ac3SMaarten Lankhorst old_connector_state,
6962b7947bdSSimon Ser new_connector_state,
6972b7947bdSSimon Ser BIT(i) & user_connectors_mask);
698623369e5SDaniel Vetter if (ret)
699623369e5SDaniel Vetter return ret;
700415c3ac3SMaarten Lankhorst if (old_connector_state->crtc) {
701b4d93679SMaarten Lankhorst new_crtc_state = drm_atomic_get_new_crtc_state(state,
702415c3ac3SMaarten Lankhorst old_connector_state->crtc);
703415c3ac3SMaarten Lankhorst if (old_connector_state->link_status !=
704415c3ac3SMaarten Lankhorst new_connector_state->link_status)
705415c3ac3SMaarten Lankhorst new_crtc_state->connectors_changed = true;
70647e22ff1SRadhakrishna Sripada
70747e22ff1SRadhakrishna Sripada if (old_connector_state->max_requested_bpc !=
70847e22ff1SRadhakrishna Sripada new_connector_state->max_requested_bpc)
70947e22ff1SRadhakrishna Sripada new_crtc_state->connectors_changed = true;
71040ee6fbeSManasi Navare }
711ce09d766SMaarten Lankhorst
712ce09d766SMaarten Lankhorst if (funcs->atomic_check)
7136f3b6278SSean Paul ret = funcs->atomic_check(connector, state);
7140aedc880SSimon Ser if (ret) {
7150aedc880SSimon Ser drm_dbg_atomic(dev,
7160aedc880SSimon Ser "[CONNECTOR:%d:%s] driver check failed\n",
7170aedc880SSimon Ser connector->base.id, connector->name);
718ce09d766SMaarten Lankhorst return ret;
7190aedc880SSimon Ser }
720ce09d766SMaarten Lankhorst
721ca52bea9SVille Syrjälä connectors_mask |= BIT(i);
722623369e5SDaniel Vetter }
723623369e5SDaniel Vetter
724623369e5SDaniel Vetter /*
725623369e5SDaniel Vetter * After all the routing has been prepared we need to add in any
72642240c90SThierry Reding * connector which is itself unchanged, but whose CRTC changes its
727623369e5SDaniel Vetter * configuration. This must be done before calling mode_fixup in case a
728623369e5SDaniel Vetter * crtc only changed its mode but has the same set of connectors.
729623369e5SDaniel Vetter */
730415c3ac3SMaarten Lankhorst for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
731415c3ac3SMaarten Lankhorst if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
732eab3bbefSDaniel Vetter continue;
733eab3bbefSDaniel Vetter
7346e22dc35SClaudio Suarez drm_dbg_atomic(dev,
7356e22dc35SClaudio Suarez "[CRTC:%d:%s] needs all connectors, enable: %c, active: %c\n",
736fa3ab4c2SVille Syrjälä crtc->base.id, crtc->name,
737415c3ac3SMaarten Lankhorst new_crtc_state->enable ? 'y' : 'n',
738415c3ac3SMaarten Lankhorst new_crtc_state->active ? 'y' : 'n');
739623369e5SDaniel Vetter
740623369e5SDaniel Vetter ret = drm_atomic_add_affected_connectors(state, crtc);
741623369e5SDaniel Vetter if (ret != 0)
742623369e5SDaniel Vetter return ret;
743623369e5SDaniel Vetter
74457744aa7SMaarten Lankhorst ret = drm_atomic_add_affected_planes(state, crtc);
74557744aa7SMaarten Lankhorst if (ret != 0)
74657744aa7SMaarten Lankhorst return ret;
747623369e5SDaniel Vetter }
748623369e5SDaniel Vetter
749ce09d766SMaarten Lankhorst /*
750ce09d766SMaarten Lankhorst * Iterate over all connectors again, to make sure atomic_check()
751ce09d766SMaarten Lankhorst * has been called on them when a modeset is forced.
752ce09d766SMaarten Lankhorst */
753ce09d766SMaarten Lankhorst for_each_oldnew_connector_in_state(state, connector, old_connector_state, new_connector_state, i) {
754ce09d766SMaarten Lankhorst const struct drm_connector_helper_funcs *funcs = connector->helper_private;
755ce09d766SMaarten Lankhorst
756ce09d766SMaarten Lankhorst if (connectors_mask & BIT(i))
757ce09d766SMaarten Lankhorst continue;
758ce09d766SMaarten Lankhorst
759ce09d766SMaarten Lankhorst if (funcs->atomic_check)
7606f3b6278SSean Paul ret = funcs->atomic_check(connector, state);
7610aedc880SSimon Ser if (ret) {
7620aedc880SSimon Ser drm_dbg_atomic(dev,
7630aedc880SSimon Ser "[CONNECTOR:%d:%s] driver check failed\n",
7640aedc880SSimon Ser connector->base.id, connector->name);
765ce09d766SMaarten Lankhorst return ret;
766ce09d766SMaarten Lankhorst }
7670aedc880SSimon Ser }
768ce09d766SMaarten Lankhorst
76975146591SBoris Brezillon /*
77075146591SBoris Brezillon * Iterate over all connectors again, and add all affected bridges to
77175146591SBoris Brezillon * the state.
77275146591SBoris Brezillon */
77375146591SBoris Brezillon for_each_oldnew_connector_in_state(state, connector,
77475146591SBoris Brezillon old_connector_state,
77575146591SBoris Brezillon new_connector_state, i) {
77675146591SBoris Brezillon struct drm_encoder *encoder;
77775146591SBoris Brezillon
77875146591SBoris Brezillon encoder = old_connector_state->best_encoder;
77975146591SBoris Brezillon ret = drm_atomic_add_encoder_bridges(state, encoder);
78075146591SBoris Brezillon if (ret)
78175146591SBoris Brezillon return ret;
78275146591SBoris Brezillon
78375146591SBoris Brezillon encoder = new_connector_state->best_encoder;
78475146591SBoris Brezillon ret = drm_atomic_add_encoder_bridges(state, encoder);
78575146591SBoris Brezillon if (ret)
78675146591SBoris Brezillon return ret;
78775146591SBoris Brezillon }
78875146591SBoris Brezillon
789faf94a08SJose Abreu ret = mode_valid(state);
790faf94a08SJose Abreu if (ret)
791faf94a08SJose Abreu return ret;
792faf94a08SJose Abreu
793623369e5SDaniel Vetter return mode_fixup(state);
794623369e5SDaniel Vetter }
795d9b13620SDaniel Vetter EXPORT_SYMBOL(drm_atomic_helper_check_modeset);
796623369e5SDaniel Vetter
797c2fcd274SDaniel Vetter /**
798ee34b77fSJiapeng Chong * drm_atomic_helper_check_wb_encoder_state() - Check writeback encoder state
799254fe9c1SIgor Torrente * @encoder: encoder state to check
800254fe9c1SIgor Torrente * @conn_state: connector state to check
801254fe9c1SIgor Torrente *
802254fe9c1SIgor Torrente * Checks if the writeback connector state is valid, and returns an error if it
803254fe9c1SIgor Torrente * isn't.
804254fe9c1SIgor Torrente *
805254fe9c1SIgor Torrente * RETURNS:
806254fe9c1SIgor Torrente * Zero for success or -errno
807254fe9c1SIgor Torrente */
808254fe9c1SIgor Torrente int
drm_atomic_helper_check_wb_encoder_state(struct drm_encoder * encoder,struct drm_connector_state * conn_state)809254fe9c1SIgor Torrente drm_atomic_helper_check_wb_encoder_state(struct drm_encoder *encoder,
810254fe9c1SIgor Torrente struct drm_connector_state *conn_state)
811254fe9c1SIgor Torrente {
812254fe9c1SIgor Torrente struct drm_writeback_job *wb_job = conn_state->writeback_job;
813254fe9c1SIgor Torrente struct drm_property_blob *pixel_format_blob;
814254fe9c1SIgor Torrente struct drm_framebuffer *fb;
815254fe9c1SIgor Torrente size_t i, nformats;
816254fe9c1SIgor Torrente u32 *formats;
817254fe9c1SIgor Torrente
818254fe9c1SIgor Torrente if (!wb_job || !wb_job->fb)
819254fe9c1SIgor Torrente return 0;
820254fe9c1SIgor Torrente
821254fe9c1SIgor Torrente pixel_format_blob = wb_job->connector->pixel_formats_blob_ptr;
822254fe9c1SIgor Torrente nformats = pixel_format_blob->length / sizeof(u32);
823254fe9c1SIgor Torrente formats = pixel_format_blob->data;
824254fe9c1SIgor Torrente fb = wb_job->fb;
825254fe9c1SIgor Torrente
826254fe9c1SIgor Torrente for (i = 0; i < nformats; i++)
827254fe9c1SIgor Torrente if (fb->format->format == formats[i])
828254fe9c1SIgor Torrente return 0;
829254fe9c1SIgor Torrente
830254fe9c1SIgor Torrente drm_dbg_kms(encoder->dev, "Invalid pixel format %p4cc\n", &fb->format->format);
831254fe9c1SIgor Torrente
832254fe9c1SIgor Torrente return -EINVAL;
833254fe9c1SIgor Torrente }
834254fe9c1SIgor Torrente EXPORT_SYMBOL(drm_atomic_helper_check_wb_encoder_state);
835254fe9c1SIgor Torrente
836254fe9c1SIgor Torrente /**
837a01cb8baSVille Syrjälä * drm_atomic_helper_check_plane_state() - Check plane state for validity
838a01cb8baSVille Syrjälä * @plane_state: plane state to check
83942240c90SThierry Reding * @crtc_state: CRTC state to check
840a01cb8baSVille Syrjälä * @min_scale: minimum @src:@dest scaling factor in 16.16 fixed point
841a01cb8baSVille Syrjälä * @max_scale: maximum @src:@dest scaling factor in 16.16 fixed point
842a01cb8baSVille Syrjälä * @can_position: is it legal to position the plane such that it
84342240c90SThierry Reding * doesn't cover the entire CRTC? This will generally
844a01cb8baSVille Syrjälä * only be false for primary planes.
84542240c90SThierry Reding * @can_update_disabled: can the plane be updated while the CRTC
846a01cb8baSVille Syrjälä * is disabled?
847a01cb8baSVille Syrjälä *
848a01cb8baSVille Syrjälä * Checks that a desired plane update is valid, and updates various
849a01cb8baSVille Syrjälä * bits of derived state (clipped coordinates etc.). Drivers that provide
850a01cb8baSVille Syrjälä * their own plane handling rather than helper-provided implementations may
851a01cb8baSVille Syrjälä * still wish to call this function to avoid duplication of error checking
852a01cb8baSVille Syrjälä * code.
853a01cb8baSVille Syrjälä *
854a01cb8baSVille Syrjälä * RETURNS:
855a01cb8baSVille Syrjälä * Zero if update appears valid, error code on failure
856a01cb8baSVille Syrjälä */
drm_atomic_helper_check_plane_state(struct drm_plane_state * plane_state,const struct drm_crtc_state * crtc_state,int min_scale,int max_scale,bool can_position,bool can_update_disabled)857a01cb8baSVille Syrjälä int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state,
858a01cb8baSVille Syrjälä const struct drm_crtc_state *crtc_state,
859a01cb8baSVille Syrjälä int min_scale,
860a01cb8baSVille Syrjälä int max_scale,
861a01cb8baSVille Syrjälä bool can_position,
862a01cb8baSVille Syrjälä bool can_update_disabled)
863a01cb8baSVille Syrjälä {
864a01cb8baSVille Syrjälä struct drm_framebuffer *fb = plane_state->fb;
865a01cb8baSVille Syrjälä struct drm_rect *src = &plane_state->src;
866a01cb8baSVille Syrjälä struct drm_rect *dst = &plane_state->dst;
867a01cb8baSVille Syrjälä unsigned int rotation = plane_state->rotation;
86881af63a4SVille Syrjälä struct drm_rect clip = {};
869a01cb8baSVille Syrjälä int hscale, vscale;
870a01cb8baSVille Syrjälä
871a01cb8baSVille Syrjälä WARN_ON(plane_state->crtc && plane_state->crtc != crtc_state->crtc);
872a01cb8baSVille Syrjälä
873a01cb8baSVille Syrjälä *src = drm_plane_state_src(plane_state);
874a01cb8baSVille Syrjälä *dst = drm_plane_state_dest(plane_state);
875a01cb8baSVille Syrjälä
876a01cb8baSVille Syrjälä if (!fb) {
877a01cb8baSVille Syrjälä plane_state->visible = false;
878a01cb8baSVille Syrjälä return 0;
879a01cb8baSVille Syrjälä }
880a01cb8baSVille Syrjälä
881a01cb8baSVille Syrjälä /* crtc should only be NULL when disabling (i.e., !fb) */
882a01cb8baSVille Syrjälä if (WARN_ON(!plane_state->crtc)) {
883a01cb8baSVille Syrjälä plane_state->visible = false;
884a01cb8baSVille Syrjälä return 0;
885a01cb8baSVille Syrjälä }
886a01cb8baSVille Syrjälä
887a01cb8baSVille Syrjälä if (!crtc_state->enable && !can_update_disabled) {
888bd672b75SClaudio Suarez drm_dbg_kms(plane_state->plane->dev,
8896e22dc35SClaudio Suarez "Cannot update plane of a disabled CRTC.\n");
890a01cb8baSVille Syrjälä return -EINVAL;
891a01cb8baSVille Syrjälä }
892a01cb8baSVille Syrjälä
893a01cb8baSVille Syrjälä drm_rect_rotate(src, fb->width << 16, fb->height << 16, rotation);
894a01cb8baSVille Syrjälä
895a01cb8baSVille Syrjälä /* Check scaling */
896a01cb8baSVille Syrjälä hscale = drm_rect_calc_hscale(src, dst, min_scale, max_scale);
897a01cb8baSVille Syrjälä vscale = drm_rect_calc_vscale(src, dst, min_scale, max_scale);
898a01cb8baSVille Syrjälä if (hscale < 0 || vscale < 0) {
899bd672b75SClaudio Suarez drm_dbg_kms(plane_state->plane->dev,
9006e22dc35SClaudio Suarez "Invalid scaling of plane\n");
901a01cb8baSVille Syrjälä drm_rect_debug_print("src: ", &plane_state->src, true);
902a01cb8baSVille Syrjälä drm_rect_debug_print("dst: ", &plane_state->dst, false);
903a01cb8baSVille Syrjälä return -ERANGE;
904a01cb8baSVille Syrjälä }
905a01cb8baSVille Syrjälä
90681af63a4SVille Syrjälä if (crtc_state->enable)
90781af63a4SVille Syrjälä drm_mode_get_hv_timing(&crtc_state->mode, &clip.x2, &clip.y2);
90881af63a4SVille Syrjälä
909f96bdf56SMaarten Lankhorst plane_state->visible = drm_rect_clip_scaled(src, dst, &clip);
910a01cb8baSVille Syrjälä
911a01cb8baSVille Syrjälä drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16, rotation);
912a01cb8baSVille Syrjälä
913a01cb8baSVille Syrjälä if (!plane_state->visible)
914a01cb8baSVille Syrjälä /*
915a01cb8baSVille Syrjälä * Plane isn't visible; some drivers can handle this
916a01cb8baSVille Syrjälä * so we just return success here. Drivers that can't
917a01cb8baSVille Syrjälä * (including those that use the primary plane helper's
918a01cb8baSVille Syrjälä * update function) will return an error from their
919a01cb8baSVille Syrjälä * update_plane handler.
920a01cb8baSVille Syrjälä */
921a01cb8baSVille Syrjälä return 0;
922a01cb8baSVille Syrjälä
92381af63a4SVille Syrjälä if (!can_position && !drm_rect_equals(dst, &clip)) {
924bd672b75SClaudio Suarez drm_dbg_kms(plane_state->plane->dev,
9256e22dc35SClaudio Suarez "Plane must cover entire CRTC\n");
926a01cb8baSVille Syrjälä drm_rect_debug_print("dst: ", dst, false);
92781af63a4SVille Syrjälä drm_rect_debug_print("clip: ", &clip, false);
928a01cb8baSVille Syrjälä return -EINVAL;
929a01cb8baSVille Syrjälä }
930a01cb8baSVille Syrjälä
931a01cb8baSVille Syrjälä return 0;
932a01cb8baSVille Syrjälä }
933a01cb8baSVille Syrjälä EXPORT_SYMBOL(drm_atomic_helper_check_plane_state);
934a01cb8baSVille Syrjälä
935a01cb8baSVille Syrjälä /**
9368f2fd57dSThomas Zimmermann * drm_atomic_helper_check_crtc_primary_plane() - Check CRTC state for primary plane
937d6b9af10SThomas Zimmermann * @crtc_state: CRTC state to check
938d6b9af10SThomas Zimmermann *
9398f2fd57dSThomas Zimmermann * Checks that a CRTC has at least one primary plane attached to it, which is
9408f2fd57dSThomas Zimmermann * a requirement on some hardware. Note that this only involves the CRTC side
9418f2fd57dSThomas Zimmermann * of the test. To test if the primary plane is visible or if it can be updated
9428f2fd57dSThomas Zimmermann * without the CRTC being enabled, use drm_atomic_helper_check_plane_state() in
9438f2fd57dSThomas Zimmermann * the plane's atomic check.
944d6b9af10SThomas Zimmermann *
945d6b9af10SThomas Zimmermann * RETURNS:
9468f2fd57dSThomas Zimmermann * 0 if a primary plane is attached to the CRTC, or an error code otherwise
947d6b9af10SThomas Zimmermann */
drm_atomic_helper_check_crtc_primary_plane(struct drm_crtc_state * crtc_state)9488f2fd57dSThomas Zimmermann int drm_atomic_helper_check_crtc_primary_plane(struct drm_crtc_state *crtc_state)
949d6b9af10SThomas Zimmermann {
9508f2fd57dSThomas Zimmermann struct drm_crtc *crtc = crtc_state->crtc;
9518f2fd57dSThomas Zimmermann struct drm_device *dev = crtc->dev;
952d6b9af10SThomas Zimmermann struct drm_plane *plane;
953d6b9af10SThomas Zimmermann
9548f2fd57dSThomas Zimmermann /* needs at least one primary plane to be enabled */
955d6b9af10SThomas Zimmermann drm_for_each_plane_mask(plane, dev, crtc_state->plane_mask) {
9568f2fd57dSThomas Zimmermann if (plane->type == DRM_PLANE_TYPE_PRIMARY)
957d6b9af10SThomas Zimmermann return 0;
958d6b9af10SThomas Zimmermann }
9598f2fd57dSThomas Zimmermann
9608f2fd57dSThomas Zimmermann drm_dbg_atomic(dev, "[CRTC:%d:%s] primary plane missing\n", crtc->base.id, crtc->name);
9618f2fd57dSThomas Zimmermann
9628f2fd57dSThomas Zimmermann return -EINVAL;
9638f2fd57dSThomas Zimmermann }
9648f2fd57dSThomas Zimmermann EXPORT_SYMBOL(drm_atomic_helper_check_crtc_primary_plane);
965d6b9af10SThomas Zimmermann
966d6b9af10SThomas Zimmermann /**
967f98bd3efSJohn Hunter * drm_atomic_helper_check_planes - validate state object for planes changes
968c2fcd274SDaniel Vetter * @dev: DRM device
969c2fcd274SDaniel Vetter * @state: the driver state object
970c2fcd274SDaniel Vetter *
971c2fcd274SDaniel Vetter * Check the state object to see if the requested state is physically possible.
972d9b13620SDaniel Vetter * This does all the plane update related checks using by calling into the
9736806cdf9SDaniel Vetter * &drm_crtc_helper_funcs.atomic_check and &drm_plane_helper_funcs.atomic_check
9746806cdf9SDaniel Vetter * hooks provided by the driver.
975c2fcd274SDaniel Vetter *
97642240c90SThierry Reding * It also sets &drm_crtc_state.planes_changed to indicate that a CRTC has
977fc596660SMaarten Lankhorst * updated planes.
978fc596660SMaarten Lankhorst *
979c39032a8SDaniel Vetter * RETURNS:
980c2fcd274SDaniel Vetter * Zero for success or -errno
981c2fcd274SDaniel Vetter */
982d9b13620SDaniel Vetter int
drm_atomic_helper_check_planes(struct drm_device * dev,struct drm_atomic_state * state)983d9b13620SDaniel Vetter drm_atomic_helper_check_planes(struct drm_device *dev,
984c2fcd274SDaniel Vetter struct drm_atomic_state *state)
985c2fcd274SDaniel Vetter {
986df63b999SAnder Conselvan de Oliveira struct drm_crtc *crtc;
987415c3ac3SMaarten Lankhorst struct drm_crtc_state *new_crtc_state;
988df63b999SAnder Conselvan de Oliveira struct drm_plane *plane;
989415c3ac3SMaarten Lankhorst struct drm_plane_state *new_plane_state, *old_plane_state;
990c2fcd274SDaniel Vetter int i, ret = 0;
991c2fcd274SDaniel Vetter
992415c3ac3SMaarten Lankhorst for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {
993b5ceff20SVille Syrjälä const struct drm_plane_helper_funcs *funcs;
994c2fcd274SDaniel Vetter
995869e188aSDaniel Vetter WARN_ON(!drm_modeset_is_locked(&plane->mutex));
996869e188aSDaniel Vetter
997c2fcd274SDaniel Vetter funcs = plane->helper_private;
998c2fcd274SDaniel Vetter
999415c3ac3SMaarten Lankhorst drm_atomic_helper_plane_changed(state, old_plane_state, new_plane_state, plane);
1000c2fcd274SDaniel Vetter
1001d9778b40SDeepak Rawat drm_atomic_helper_check_plane_damage(state, new_plane_state);
1002d9778b40SDeepak Rawat
1003c2fcd274SDaniel Vetter if (!funcs || !funcs->atomic_check)
1004c2fcd274SDaniel Vetter continue;
1005c2fcd274SDaniel Vetter
10067c11b99aSMaxime Ripard ret = funcs->atomic_check(plane, state);
1007c2fcd274SDaniel Vetter if (ret) {
10086e22dc35SClaudio Suarez drm_dbg_atomic(plane->dev,
10096e22dc35SClaudio Suarez "[PLANE:%d:%s] atomic driver check failed\n",
10109f4c97a2SVille Syrjälä plane->base.id, plane->name);
1011c2fcd274SDaniel Vetter return ret;
1012c2fcd274SDaniel Vetter }
1013c2fcd274SDaniel Vetter }
1014c2fcd274SDaniel Vetter
1015415c3ac3SMaarten Lankhorst for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
1016b5ceff20SVille Syrjälä const struct drm_crtc_helper_funcs *funcs;
1017c2fcd274SDaniel Vetter
1018c2fcd274SDaniel Vetter funcs = crtc->helper_private;
1019c2fcd274SDaniel Vetter
1020c2fcd274SDaniel Vetter if (!funcs || !funcs->atomic_check)
1021c2fcd274SDaniel Vetter continue;
1022c2fcd274SDaniel Vetter
102329b77ad7SMaxime Ripard ret = funcs->atomic_check(crtc, state);
1024c2fcd274SDaniel Vetter if (ret) {
10256e22dc35SClaudio Suarez drm_dbg_atomic(crtc->dev,
10266e22dc35SClaudio Suarez "[CRTC:%d:%s] atomic driver check failed\n",
1027fa3ab4c2SVille Syrjälä crtc->base.id, crtc->name);
1028c2fcd274SDaniel Vetter return ret;
1029c2fcd274SDaniel Vetter }
1030c2fcd274SDaniel Vetter }
1031c2fcd274SDaniel Vetter
1032d9b13620SDaniel Vetter return ret;
1033d9b13620SDaniel Vetter }
1034d9b13620SDaniel Vetter EXPORT_SYMBOL(drm_atomic_helper_check_planes);
1035d9b13620SDaniel Vetter
1036d9b13620SDaniel Vetter /**
1037d9b13620SDaniel Vetter * drm_atomic_helper_check - validate state object
1038d9b13620SDaniel Vetter * @dev: DRM device
1039d9b13620SDaniel Vetter * @state: the driver state object
1040d9b13620SDaniel Vetter *
1041d9b13620SDaniel Vetter * Check the state object to see if the requested state is physically possible.
104242240c90SThierry Reding * Only CRTCs and planes have check callbacks, so for any additional (global)
1043d9b13620SDaniel Vetter * checking that a driver needs it can simply wrap that around this function.
10446806cdf9SDaniel Vetter * Drivers without such needs can directly use this as their
10456806cdf9SDaniel Vetter * &drm_mode_config_funcs.atomic_check callback.
1046d9b13620SDaniel Vetter *
1047b4274fbeSDaniel Vetter * This just wraps the two parts of the state checking for planes and modeset
1048b4274fbeSDaniel Vetter * state in the default order: First it calls drm_atomic_helper_check_modeset()
1049b4274fbeSDaniel Vetter * and then drm_atomic_helper_check_planes(). The assumption is that the
10506806cdf9SDaniel Vetter * @drm_plane_helper_funcs.atomic_check and @drm_crtc_helper_funcs.atomic_check
10516806cdf9SDaniel Vetter * functions depend upon an updated adjusted_mode.clock to e.g. properly compute
10526806cdf9SDaniel Vetter * watermarks.
1053b4274fbeSDaniel Vetter *
105449efffc7SPeter Ujfalusi * Note that zpos normalization will add all enable planes to the state which
105549efffc7SPeter Ujfalusi * might not desired for some drivers.
105649efffc7SPeter Ujfalusi * For example enable/disable of a cursor plane which have fixed zpos value
105749efffc7SPeter Ujfalusi * would trigger all other enabled planes to be forced to the state change.
105849efffc7SPeter Ujfalusi *
1059c39032a8SDaniel Vetter * RETURNS:
1060d9b13620SDaniel Vetter * Zero for success or -errno
1061d9b13620SDaniel Vetter */
drm_atomic_helper_check(struct drm_device * dev,struct drm_atomic_state * state)1062d9b13620SDaniel Vetter int drm_atomic_helper_check(struct drm_device *dev,
1063d9b13620SDaniel Vetter struct drm_atomic_state *state)
1064d9b13620SDaniel Vetter {
1065d9b13620SDaniel Vetter int ret;
1066d9b13620SDaniel Vetter
1067b4274fbeSDaniel Vetter ret = drm_atomic_helper_check_modeset(dev, state);
1068d9b13620SDaniel Vetter if (ret)
1069d9b13620SDaniel Vetter return ret;
1070d9b13620SDaniel Vetter
107149efffc7SPeter Ujfalusi if (dev->mode_config.normalize_zpos) {
107249efffc7SPeter Ujfalusi ret = drm_atomic_normalize_zpos(dev, state);
107349efffc7SPeter Ujfalusi if (ret)
107449efffc7SPeter Ujfalusi return ret;
107549efffc7SPeter Ujfalusi }
107649efffc7SPeter Ujfalusi
1077b4274fbeSDaniel Vetter ret = drm_atomic_helper_check_planes(dev, state);
1078934ce1c2SRob Clark if (ret)
1079934ce1c2SRob Clark return ret;
1080934ce1c2SRob Clark
1081fef9df8bSGustavo Padovan if (state->legacy_cursor_update)
1082fef9df8bSGustavo Padovan state->async_update = !drm_atomic_helper_async_check(dev, state);
1083fef9df8bSGustavo Padovan
10841452c25bSSean Paul drm_self_refresh_helper_alter_state(state);
10851452c25bSSean Paul
1086c2fcd274SDaniel Vetter return ret;
1087c2fcd274SDaniel Vetter }
1088c2fcd274SDaniel Vetter EXPORT_SYMBOL(drm_atomic_helper_check);
1089c2fcd274SDaniel Vetter
10901452c25bSSean Paul static bool
crtc_needs_disable(struct drm_crtc_state * old_state,struct drm_crtc_state * new_state)10911452c25bSSean Paul crtc_needs_disable(struct drm_crtc_state *old_state,
10921452c25bSSean Paul struct drm_crtc_state *new_state)
10931452c25bSSean Paul {
10941452c25bSSean Paul /*
109542240c90SThierry Reding * No new_state means the CRTC is off, so the only criteria is whether
10961452c25bSSean Paul * it's currently active or in self refresh mode.
10971452c25bSSean Paul */
10981452c25bSSean Paul if (!new_state)
10991452c25bSSean Paul return drm_atomic_crtc_effectively_active(old_state);
11001452c25bSSean Paul
11011452c25bSSean Paul /*
1102e54a4424SBrian Norris * We need to disable bridge(s) and CRTC if we're transitioning out of
1103e54a4424SBrian Norris * self-refresh and changing CRTCs at the same time, because the
1104e54a4424SBrian Norris * bridge tracks self-refresh status via CRTC state.
1105e54a4424SBrian Norris */
1106e54a4424SBrian Norris if (old_state->self_refresh_active &&
1107e54a4424SBrian Norris old_state->crtc != new_state->crtc)
1108e54a4424SBrian Norris return true;
1109e54a4424SBrian Norris
1110e54a4424SBrian Norris /*
1111e54a4424SBrian Norris * We also need to run through the crtc_funcs->disable() function if
1112e54a4424SBrian Norris * the CRTC is currently on, if it's transitioning to self refresh
1113e54a4424SBrian Norris * mode, or if it's in self refresh mode and needs to be fully
1114e54a4424SBrian Norris * disabled.
11151452c25bSSean Paul */
11161452c25bSSean Paul return old_state->active ||
111769e63001SLiu Ying (old_state->self_refresh_active && !new_state->active) ||
11181452c25bSSean Paul new_state->self_refresh_active;
11191452c25bSSean Paul }
11201452c25bSSean Paul
1121623369e5SDaniel Vetter static void
disable_outputs(struct drm_device * dev,struct drm_atomic_state * old_state)1122623369e5SDaniel Vetter disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
1123623369e5SDaniel Vetter {
1124df63b999SAnder Conselvan de Oliveira struct drm_connector *connector;
1125415c3ac3SMaarten Lankhorst struct drm_connector_state *old_conn_state, *new_conn_state;
1126df63b999SAnder Conselvan de Oliveira struct drm_crtc *crtc;
1127415c3ac3SMaarten Lankhorst struct drm_crtc_state *old_crtc_state, *new_crtc_state;
1128623369e5SDaniel Vetter int i;
1129623369e5SDaniel Vetter
1130415c3ac3SMaarten Lankhorst for_each_oldnew_connector_in_state(old_state, connector, old_conn_state, new_conn_state, i) {
1131b5ceff20SVille Syrjälä const struct drm_encoder_helper_funcs *funcs;
1132623369e5SDaniel Vetter struct drm_encoder *encoder;
113335a61fe9SBoris Brezillon struct drm_bridge *bridge;
1134623369e5SDaniel Vetter
11351758f403SFabio M. De Francesco /*
11361758f403SFabio M. De Francesco * Shut down everything that's in the changeset and currently
11371758f403SFabio M. De Francesco * still on. So need to check the old, saved state.
11381758f403SFabio M. De Francesco */
1139df63b999SAnder Conselvan de Oliveira if (!old_conn_state->crtc)
1140623369e5SDaniel Vetter continue;
1141623369e5SDaniel Vetter
1142b4d93679SMaarten Lankhorst old_crtc_state = drm_atomic_get_old_crtc_state(old_state, old_conn_state->crtc);
1143eab3bbefSDaniel Vetter
11441452c25bSSean Paul if (new_conn_state->crtc)
11451452c25bSSean Paul new_crtc_state = drm_atomic_get_new_crtc_state(
11461452c25bSSean Paul old_state,
11471452c25bSSean Paul new_conn_state->crtc);
11481452c25bSSean Paul else
11491452c25bSSean Paul new_crtc_state = NULL;
11501452c25bSSean Paul
11511452c25bSSean Paul if (!crtc_needs_disable(old_crtc_state, new_crtc_state) ||
11522465ff62SDaniel Vetter !drm_atomic_crtc_needs_modeset(old_conn_state->crtc->state))
1153eab3bbefSDaniel Vetter continue;
1154eab3bbefSDaniel Vetter
115546df9adbSRob Clark encoder = old_conn_state->best_encoder;
1156623369e5SDaniel Vetter
115746df9adbSRob Clark /* We shouldn't get this far if we didn't previously have
115846df9adbSRob Clark * an encoder.. but WARN_ON() rather than explode.
115946df9adbSRob Clark */
116046df9adbSRob Clark if (WARN_ON(!encoder))
1161623369e5SDaniel Vetter continue;
1162623369e5SDaniel Vetter
1163623369e5SDaniel Vetter funcs = encoder->helper_private;
1164623369e5SDaniel Vetter
11656e22dc35SClaudio Suarez drm_dbg_atomic(dev, "disabling [ENCODER:%d:%s]\n",
116695d6eb3bSDaniel Vetter encoder->base.id, encoder->name);
116795d6eb3bSDaniel Vetter
1168623369e5SDaniel Vetter /*
1169623369e5SDaniel Vetter * Each encoder has at most one connector (since we always steal
1170f98bd3efSJohn Hunter * it away), so we won't call disable hooks twice.
1171623369e5SDaniel Vetter */
117235a61fe9SBoris Brezillon bridge = drm_bridge_chain_get_first_bridge(encoder);
117335a61fe9SBoris Brezillon drm_atomic_bridge_chain_disable(bridge, old_state);
1174623369e5SDaniel Vetter
1175623369e5SDaniel Vetter /* Right function depends upon target state. */
11762827635eSNoralf Trønnes if (funcs) {
117743c76d72SSean Paul if (funcs->atomic_disable)
117843c76d72SSean Paul funcs->atomic_disable(encoder, old_state);
117943c76d72SSean Paul else if (new_conn_state->crtc && funcs->prepare)
1180623369e5SDaniel Vetter funcs->prepare(encoder);
1181623369e5SDaniel Vetter else if (funcs->disable)
1182623369e5SDaniel Vetter funcs->disable(encoder);
118375229ecaSNoralf Trønnes else if (funcs->dpms)
1184623369e5SDaniel Vetter funcs->dpms(encoder, DRM_MODE_DPMS_OFF);
11852827635eSNoralf Trønnes }
1186623369e5SDaniel Vetter
118735a61fe9SBoris Brezillon drm_atomic_bridge_chain_post_disable(bridge, old_state);
1188623369e5SDaniel Vetter }
1189623369e5SDaniel Vetter
1190415c3ac3SMaarten Lankhorst for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) {
1191b5ceff20SVille Syrjälä const struct drm_crtc_helper_funcs *funcs;
119284014b0aSDaniel Vetter int ret;
1193623369e5SDaniel Vetter
1194623369e5SDaniel Vetter /* Shut down everything that needs a full modeset. */
1195415c3ac3SMaarten Lankhorst if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
1196eab3bbefSDaniel Vetter continue;
1197eab3bbefSDaniel Vetter
11981452c25bSSean Paul if (!crtc_needs_disable(old_crtc_state, new_crtc_state))
1199623369e5SDaniel Vetter continue;
1200623369e5SDaniel Vetter
1201623369e5SDaniel Vetter funcs = crtc->helper_private;
1202623369e5SDaniel Vetter
12036e22dc35SClaudio Suarez drm_dbg_atomic(dev, "disabling [CRTC:%d:%s]\n",
1204fa3ab4c2SVille Syrjälä crtc->base.id, crtc->name);
120595d6eb3bSDaniel Vetter
120695d6eb3bSDaniel Vetter
1207623369e5SDaniel Vetter /* Right function depends upon target state. */
1208415c3ac3SMaarten Lankhorst if (new_crtc_state->enable && funcs->prepare)
1209623369e5SDaniel Vetter funcs->prepare(crtc);
1210c9ac8b4cSLiu Ying else if (funcs->atomic_disable)
1211351f950dSMaxime Ripard funcs->atomic_disable(crtc, old_state);
1212623369e5SDaniel Vetter else if (funcs->disable)
1213623369e5SDaniel Vetter funcs->disable(crtc);
1214fe616928SRodrigo Siqueira else if (funcs->dpms)
1215623369e5SDaniel Vetter funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
121684014b0aSDaniel Vetter
12176015002eSDaniel Vetter if (!drm_dev_has_vblank(dev))
121884014b0aSDaniel Vetter continue;
121984014b0aSDaniel Vetter
122084014b0aSDaniel Vetter ret = drm_crtc_vblank_get(crtc);
12219d0e3cacSBrian Norris /*
12229d0e3cacSBrian Norris * Self-refresh is not a true "disable"; ensure vblank remains
12239d0e3cacSBrian Norris * enabled.
12249d0e3cacSBrian Norris */
12259d0e3cacSBrian Norris if (new_crtc_state->self_refresh_active)
12269d0e3cacSBrian Norris WARN_ONCE(ret != 0,
12279d0e3cacSBrian Norris "driver disabled vblank in self-refresh\n");
12289d0e3cacSBrian Norris else
12299d0e3cacSBrian Norris WARN_ONCE(ret != -EINVAL,
12309d0e3cacSBrian Norris "driver forgot to call drm_crtc_vblank_off()\n");
123184014b0aSDaniel Vetter if (ret == 0)
123284014b0aSDaniel Vetter drm_crtc_vblank_put(crtc);
1233623369e5SDaniel Vetter }
1234623369e5SDaniel Vetter }
1235623369e5SDaniel Vetter
12364c18d301SDaniel Vetter /**
12374c18d301SDaniel Vetter * drm_atomic_helper_update_legacy_modeset_state - update legacy modeset state
12384c18d301SDaniel Vetter * @dev: DRM device
12394c18d301SDaniel Vetter * @old_state: atomic state object with old state structures
12404c18d301SDaniel Vetter *
12414c18d301SDaniel Vetter * This function updates all the various legacy modeset state pointers in
1242441959ebSVille Syrjälä * connectors, encoders and CRTCs.
12434c18d301SDaniel Vetter *
12444c18d301SDaniel Vetter * Drivers can use this for building their own atomic commit if they don't have
12454c18d301SDaniel Vetter * a pure helper-based modeset implementation.
12462e2b96efSDaniel Vetter *
12472e2b96efSDaniel Vetter * Since these updates are not synchronized with lockings, only code paths
12482e2b96efSDaniel Vetter * called from &drm_mode_config_helper_funcs.atomic_commit_tail can look at the
12492e2b96efSDaniel Vetter * legacy state filled out by this helper. Defacto this means this helper and
12502e2b96efSDaniel Vetter * the legacy state pointers are only really useful for transitioning an
12512e2b96efSDaniel Vetter * existing driver to the atomic world.
12524c18d301SDaniel Vetter */
12534c18d301SDaniel Vetter void
drm_atomic_helper_update_legacy_modeset_state(struct drm_device * dev,struct drm_atomic_state * old_state)12544c18d301SDaniel Vetter drm_atomic_helper_update_legacy_modeset_state(struct drm_device *dev,
12554c18d301SDaniel Vetter struct drm_atomic_state *old_state)
1256623369e5SDaniel Vetter {
1257df63b999SAnder Conselvan de Oliveira struct drm_connector *connector;
1258415c3ac3SMaarten Lankhorst struct drm_connector_state *old_conn_state, *new_conn_state;
1259df63b999SAnder Conselvan de Oliveira struct drm_crtc *crtc;
1260415c3ac3SMaarten Lankhorst struct drm_crtc_state *new_crtc_state;
1261623369e5SDaniel Vetter int i;
1262623369e5SDaniel Vetter
12638c10342cSMaarten Lankhorst /* clear out existing links and update dpms */
1264415c3ac3SMaarten Lankhorst for_each_oldnew_connector_in_state(old_state, connector, old_conn_state, new_conn_state, i) {
12658c10342cSMaarten Lankhorst if (connector->encoder) {
1266623369e5SDaniel Vetter WARN_ON(!connector->encoder->crtc);
1267623369e5SDaniel Vetter
1268623369e5SDaniel Vetter connector->encoder->crtc = NULL;
1269623369e5SDaniel Vetter connector->encoder = NULL;
1270623369e5SDaniel Vetter }
1271623369e5SDaniel Vetter
1272415c3ac3SMaarten Lankhorst crtc = new_conn_state->crtc;
12738c10342cSMaarten Lankhorst if ((!crtc && old_conn_state->crtc) ||
12748c10342cSMaarten Lankhorst (crtc && drm_atomic_crtc_needs_modeset(crtc->state))) {
12758c10342cSMaarten Lankhorst int mode = DRM_MODE_DPMS_OFF;
12768c10342cSMaarten Lankhorst
12778c10342cSMaarten Lankhorst if (crtc && crtc->state->active)
12788c10342cSMaarten Lankhorst mode = DRM_MODE_DPMS_ON;
12798c10342cSMaarten Lankhorst
12808c10342cSMaarten Lankhorst connector->dpms = mode;
12818c10342cSMaarten Lankhorst }
12828c10342cSMaarten Lankhorst }
12838c10342cSMaarten Lankhorst
1284623369e5SDaniel Vetter /* set new links */
1285415c3ac3SMaarten Lankhorst for_each_new_connector_in_state(old_state, connector, new_conn_state, i) {
1286415c3ac3SMaarten Lankhorst if (!new_conn_state->crtc)
1287623369e5SDaniel Vetter continue;
1288623369e5SDaniel Vetter
1289415c3ac3SMaarten Lankhorst if (WARN_ON(!new_conn_state->best_encoder))
1290623369e5SDaniel Vetter continue;
1291623369e5SDaniel Vetter
1292415c3ac3SMaarten Lankhorst connector->encoder = new_conn_state->best_encoder;
1293415c3ac3SMaarten Lankhorst connector->encoder->crtc = new_conn_state->crtc;
1294623369e5SDaniel Vetter }
1295623369e5SDaniel Vetter
1296623369e5SDaniel Vetter /* set legacy state in the crtc structure */
1297415c3ac3SMaarten Lankhorst for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i) {
12982660801fSMaarten Lankhorst struct drm_plane *primary = crtc->primary;
1299b4d93679SMaarten Lankhorst struct drm_plane_state *new_plane_state;
13002660801fSMaarten Lankhorst
1301415c3ac3SMaarten Lankhorst crtc->mode = new_crtc_state->mode;
1302415c3ac3SMaarten Lankhorst crtc->enabled = new_crtc_state->enable;
13032660801fSMaarten Lankhorst
1304b4d93679SMaarten Lankhorst new_plane_state =
1305b4d93679SMaarten Lankhorst drm_atomic_get_new_plane_state(old_state, primary);
1306b4d93679SMaarten Lankhorst
1307b4d93679SMaarten Lankhorst if (new_plane_state && new_plane_state->crtc == crtc) {
1308b4d93679SMaarten Lankhorst crtc->x = new_plane_state->src_x >> 16;
1309b4d93679SMaarten Lankhorst crtc->y = new_plane_state->src_y >> 16;
13102660801fSMaarten Lankhorst }
13114b31a9c7SVille Syrjälä }
13124b31a9c7SVille Syrjälä }
13134b31a9c7SVille Syrjälä EXPORT_SYMBOL(drm_atomic_helper_update_legacy_modeset_state);
13144b31a9c7SVille Syrjälä
13154b31a9c7SVille Syrjälä /**
13164b31a9c7SVille Syrjälä * drm_atomic_helper_calc_timestamping_constants - update vblank timestamping constants
13174b31a9c7SVille Syrjälä * @state: atomic state object
13184b31a9c7SVille Syrjälä *
13194b31a9c7SVille Syrjälä * Updates the timestamping constants used for precise vblank timestamps
13204b31a9c7SVille Syrjälä * by calling drm_calc_timestamping_constants() for all enabled crtcs in @state.
13214b31a9c7SVille Syrjälä */
drm_atomic_helper_calc_timestamping_constants(struct drm_atomic_state * state)13224b31a9c7SVille Syrjälä void drm_atomic_helper_calc_timestamping_constants(struct drm_atomic_state *state)
13234b31a9c7SVille Syrjälä {
13244b31a9c7SVille Syrjälä struct drm_crtc_state *new_crtc_state;
13254b31a9c7SVille Syrjälä struct drm_crtc *crtc;
13264b31a9c7SVille Syrjälä int i;
13274b31a9c7SVille Syrjälä
13284b31a9c7SVille Syrjälä for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
1329415c3ac3SMaarten Lankhorst if (new_crtc_state->enable)
13303d51d2d2SDaniel Vetter drm_calc_timestamping_constants(crtc,
1331415c3ac3SMaarten Lankhorst &new_crtc_state->adjusted_mode);
1332623369e5SDaniel Vetter }
1333623369e5SDaniel Vetter }
13344b31a9c7SVille Syrjälä EXPORT_SYMBOL(drm_atomic_helper_calc_timestamping_constants);
1335623369e5SDaniel Vetter
1336623369e5SDaniel Vetter static void
crtc_set_mode(struct drm_device * dev,struct drm_atomic_state * old_state)1337623369e5SDaniel Vetter crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)
1338623369e5SDaniel Vetter {
1339df63b999SAnder Conselvan de Oliveira struct drm_crtc *crtc;
1340415c3ac3SMaarten Lankhorst struct drm_crtc_state *new_crtc_state;
1341df63b999SAnder Conselvan de Oliveira struct drm_connector *connector;
1342415c3ac3SMaarten Lankhorst struct drm_connector_state *new_conn_state;
1343623369e5SDaniel Vetter int i;
1344623369e5SDaniel Vetter
1345415c3ac3SMaarten Lankhorst for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i) {
1346b5ceff20SVille Syrjälä const struct drm_crtc_helper_funcs *funcs;
1347623369e5SDaniel Vetter
1348415c3ac3SMaarten Lankhorst if (!new_crtc_state->mode_changed)
1349623369e5SDaniel Vetter continue;
1350623369e5SDaniel Vetter
1351623369e5SDaniel Vetter funcs = crtc->helper_private;
1352623369e5SDaniel Vetter
1353415c3ac3SMaarten Lankhorst if (new_crtc_state->enable && funcs->mode_set_nofb) {
13546e22dc35SClaudio Suarez drm_dbg_atomic(dev, "modeset on [CRTC:%d:%s]\n",
1355fa3ab4c2SVille Syrjälä crtc->base.id, crtc->name);
135695d6eb3bSDaniel Vetter
1357623369e5SDaniel Vetter funcs->mode_set_nofb(crtc);
1358623369e5SDaniel Vetter }
135995d6eb3bSDaniel Vetter }
1360623369e5SDaniel Vetter
1361415c3ac3SMaarten Lankhorst for_each_new_connector_in_state(old_state, connector, new_conn_state, i) {
1362b5ceff20SVille Syrjälä const struct drm_encoder_helper_funcs *funcs;
1363623369e5SDaniel Vetter struct drm_encoder *encoder;
1364623369e5SDaniel Vetter struct drm_display_mode *mode, *adjusted_mode;
136535a61fe9SBoris Brezillon struct drm_bridge *bridge;
1366623369e5SDaniel Vetter
1367415c3ac3SMaarten Lankhorst if (!new_conn_state->best_encoder)
1368623369e5SDaniel Vetter continue;
1369623369e5SDaniel Vetter
1370415c3ac3SMaarten Lankhorst encoder = new_conn_state->best_encoder;
1371623369e5SDaniel Vetter funcs = encoder->helper_private;
1372415c3ac3SMaarten Lankhorst new_crtc_state = new_conn_state->crtc->state;
1373623369e5SDaniel Vetter mode = &new_crtc_state->mode;
1374623369e5SDaniel Vetter adjusted_mode = &new_crtc_state->adjusted_mode;
1375623369e5SDaniel Vetter
1376eab3bbefSDaniel Vetter if (!new_crtc_state->mode_changed)
1377eab3bbefSDaniel Vetter continue;
1378eab3bbefSDaniel Vetter
13796e22dc35SClaudio Suarez drm_dbg_atomic(dev, "modeset on [ENCODER:%d:%s]\n",
138095d6eb3bSDaniel Vetter encoder->base.id, encoder->name);
138195d6eb3bSDaniel Vetter
1382623369e5SDaniel Vetter /*
1383623369e5SDaniel Vetter * Each encoder has at most one connector (since we always steal
1384f98bd3efSJohn Hunter * it away), so we won't call mode_set hooks twice.
1385623369e5SDaniel Vetter */
1386fe4a11c9SPhilipp Zabel if (funcs && funcs->atomic_mode_set) {
1387fe4a11c9SPhilipp Zabel funcs->atomic_mode_set(encoder, new_crtc_state,
1388415c3ac3SMaarten Lankhorst new_conn_state);
1389fe4a11c9SPhilipp Zabel } else if (funcs && funcs->mode_set) {
1390623369e5SDaniel Vetter funcs->mode_set(encoder, mode, adjusted_mode);
1391fe4a11c9SPhilipp Zabel }
1392623369e5SDaniel Vetter
139335a61fe9SBoris Brezillon bridge = drm_bridge_chain_get_first_bridge(encoder);
139435a61fe9SBoris Brezillon drm_bridge_chain_mode_set(bridge, mode, adjusted_mode);
1395623369e5SDaniel Vetter }
1396623369e5SDaniel Vetter }
1397623369e5SDaniel Vetter
1398623369e5SDaniel Vetter /**
13991af434a9SDaniel Vetter * drm_atomic_helper_commit_modeset_disables - modeset commit to disable outputs
1400623369e5SDaniel Vetter * @dev: DRM device
1401a072f809SLaurent Pinchart * @old_state: atomic state object with old state structures
1402623369e5SDaniel Vetter *
14031af434a9SDaniel Vetter * This function shuts down all the outputs that need to be shut down and
1404623369e5SDaniel Vetter * prepares them (if required) with the new mode.
14051af434a9SDaniel Vetter *
140642240c90SThierry Reding * For compatibility with legacy CRTC helpers this should be called before
14071af434a9SDaniel Vetter * drm_atomic_helper_commit_planes(), which is what the default commit function
14081af434a9SDaniel Vetter * does. But drivers with different needs can group the modeset commits together
14091af434a9SDaniel Vetter * and do the plane commits at the end. This is useful for drivers doing runtime
14101af434a9SDaniel Vetter * PM since planes updates then only happen when the CRTC is actually enabled.
1411623369e5SDaniel Vetter */
drm_atomic_helper_commit_modeset_disables(struct drm_device * dev,struct drm_atomic_state * old_state)14121af434a9SDaniel Vetter void drm_atomic_helper_commit_modeset_disables(struct drm_device *dev,
1413a072f809SLaurent Pinchart struct drm_atomic_state *old_state)
1414623369e5SDaniel Vetter {
1415a072f809SLaurent Pinchart disable_outputs(dev, old_state);
14164c18d301SDaniel Vetter
14174c18d301SDaniel Vetter drm_atomic_helper_update_legacy_modeset_state(dev, old_state);
1418441959ebSVille Syrjälä drm_atomic_helper_calc_timestamping_constants(old_state);
14194c18d301SDaniel Vetter
1420a072f809SLaurent Pinchart crtc_set_mode(dev, old_state);
1421623369e5SDaniel Vetter }
14221af434a9SDaniel Vetter EXPORT_SYMBOL(drm_atomic_helper_commit_modeset_disables);
1423623369e5SDaniel Vetter
drm_atomic_helper_commit_writebacks(struct drm_device * dev,struct drm_atomic_state * old_state)1424935774cdSBrian Starkey static void drm_atomic_helper_commit_writebacks(struct drm_device *dev,
1425935774cdSBrian Starkey struct drm_atomic_state *old_state)
1426935774cdSBrian Starkey {
1427935774cdSBrian Starkey struct drm_connector *connector;
1428935774cdSBrian Starkey struct drm_connector_state *new_conn_state;
1429935774cdSBrian Starkey int i;
1430935774cdSBrian Starkey
1431935774cdSBrian Starkey for_each_new_connector_in_state(old_state, connector, new_conn_state, i) {
1432935774cdSBrian Starkey const struct drm_connector_helper_funcs *funcs;
1433935774cdSBrian Starkey
1434935774cdSBrian Starkey funcs = connector->helper_private;
1435814bde99SBoris Brezillon if (!funcs->atomic_commit)
1436814bde99SBoris Brezillon continue;
1437935774cdSBrian Starkey
1438935774cdSBrian Starkey if (new_conn_state->writeback_job && new_conn_state->writeback_job->fb) {
1439935774cdSBrian Starkey WARN_ON(connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK);
1440eca22edbSMaxime Ripard funcs->atomic_commit(connector, old_state);
1441935774cdSBrian Starkey }
1442935774cdSBrian Starkey }
1443935774cdSBrian Starkey }
1444935774cdSBrian Starkey
1445623369e5SDaniel Vetter /**
14461af434a9SDaniel Vetter * drm_atomic_helper_commit_modeset_enables - modeset commit to enable outputs
1447623369e5SDaniel Vetter * @dev: DRM device
1448623369e5SDaniel Vetter * @old_state: atomic state object with old state structures
1449623369e5SDaniel Vetter *
14501af434a9SDaniel Vetter * This function enables all the outputs with the new configuration which had to
14511af434a9SDaniel Vetter * be turned off for the update.
14521af434a9SDaniel Vetter *
145342240c90SThierry Reding * For compatibility with legacy CRTC helpers this should be called after
14541af434a9SDaniel Vetter * drm_atomic_helper_commit_planes(), which is what the default commit function
14551af434a9SDaniel Vetter * does. But drivers with different needs can group the modeset commits together
14561af434a9SDaniel Vetter * and do the plane commits at the end. This is useful for drivers doing runtime
14571af434a9SDaniel Vetter * PM since planes updates then only happen when the CRTC is actually enabled.
1458623369e5SDaniel Vetter */
drm_atomic_helper_commit_modeset_enables(struct drm_device * dev,struct drm_atomic_state * old_state)14591af434a9SDaniel Vetter void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
1460623369e5SDaniel Vetter struct drm_atomic_state *old_state)
1461623369e5SDaniel Vetter {
1462df63b999SAnder Conselvan de Oliveira struct drm_crtc *crtc;
14630b20a0f8SLaurent Pinchart struct drm_crtc_state *old_crtc_state;
1464415c3ac3SMaarten Lankhorst struct drm_crtc_state *new_crtc_state;
1465df63b999SAnder Conselvan de Oliveira struct drm_connector *connector;
1466415c3ac3SMaarten Lankhorst struct drm_connector_state *new_conn_state;
1467623369e5SDaniel Vetter int i;
1468623369e5SDaniel Vetter
14690b20a0f8SLaurent Pinchart for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) {
1470b5ceff20SVille Syrjälä const struct drm_crtc_helper_funcs *funcs;
1471623369e5SDaniel Vetter
1472623369e5SDaniel Vetter /* Need to filter out CRTCs where only planes change. */
1473415c3ac3SMaarten Lankhorst if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
1474eab3bbefSDaniel Vetter continue;
1475eab3bbefSDaniel Vetter
1476415c3ac3SMaarten Lankhorst if (!new_crtc_state->active)
1477623369e5SDaniel Vetter continue;
1478623369e5SDaniel Vetter
1479623369e5SDaniel Vetter funcs = crtc->helper_private;
1480623369e5SDaniel Vetter
1481415c3ac3SMaarten Lankhorst if (new_crtc_state->enable) {
14826e22dc35SClaudio Suarez drm_dbg_atomic(dev, "enabling [CRTC:%d:%s]\n",
1483fa3ab4c2SVille Syrjälä crtc->base.id, crtc->name);
14840b20a0f8SLaurent Pinchart if (funcs->atomic_enable)
1485351f950dSMaxime Ripard funcs->atomic_enable(crtc, old_state);
1486fe616928SRodrigo Siqueira else if (funcs->commit)
1487623369e5SDaniel Vetter funcs->commit(crtc);
1488623369e5SDaniel Vetter }
1489ee0a89cfSDaniel Vetter }
1490623369e5SDaniel Vetter
1491415c3ac3SMaarten Lankhorst for_each_new_connector_in_state(old_state, connector, new_conn_state, i) {
1492b5ceff20SVille Syrjälä const struct drm_encoder_helper_funcs *funcs;
1493623369e5SDaniel Vetter struct drm_encoder *encoder;
149435a61fe9SBoris Brezillon struct drm_bridge *bridge;
1495623369e5SDaniel Vetter
1496415c3ac3SMaarten Lankhorst if (!new_conn_state->best_encoder)
1497623369e5SDaniel Vetter continue;
1498623369e5SDaniel Vetter
1499415c3ac3SMaarten Lankhorst if (!new_conn_state->crtc->state->active ||
1500415c3ac3SMaarten Lankhorst !drm_atomic_crtc_needs_modeset(new_conn_state->crtc->state))
1501eab3bbefSDaniel Vetter continue;
1502eab3bbefSDaniel Vetter
1503415c3ac3SMaarten Lankhorst encoder = new_conn_state->best_encoder;
1504623369e5SDaniel Vetter funcs = encoder->helper_private;
1505623369e5SDaniel Vetter
15066e22dc35SClaudio Suarez drm_dbg_atomic(dev, "enabling [ENCODER:%d:%s]\n",
150795d6eb3bSDaniel Vetter encoder->base.id, encoder->name);
150895d6eb3bSDaniel Vetter
1509623369e5SDaniel Vetter /*
1510623369e5SDaniel Vetter * Each encoder has at most one connector (since we always steal
1511f98bd3efSJohn Hunter * it away), so we won't call enable hooks twice.
1512623369e5SDaniel Vetter */
151335a61fe9SBoris Brezillon bridge = drm_bridge_chain_get_first_bridge(encoder);
151435a61fe9SBoris Brezillon drm_atomic_bridge_chain_pre_enable(bridge, old_state);
1515623369e5SDaniel Vetter
15162827635eSNoralf Trønnes if (funcs) {
151743c76d72SSean Paul if (funcs->atomic_enable)
151843c76d72SSean Paul funcs->atomic_enable(encoder, old_state);
151943c76d72SSean Paul else if (funcs->enable)
1520ee0a89cfSDaniel Vetter funcs->enable(encoder);
152175229ecaSNoralf Trønnes else if (funcs->commit)
1522623369e5SDaniel Vetter funcs->commit(encoder);
15232827635eSNoralf Trønnes }
1524623369e5SDaniel Vetter
152535a61fe9SBoris Brezillon drm_atomic_bridge_chain_enable(bridge, old_state);
1526623369e5SDaniel Vetter }
1527935774cdSBrian Starkey
1528935774cdSBrian Starkey drm_atomic_helper_commit_writebacks(dev, old_state);
1529623369e5SDaniel Vetter }
15301af434a9SDaniel Vetter EXPORT_SYMBOL(drm_atomic_helper_commit_modeset_enables);
1531623369e5SDaniel Vetter
1532d39e48caSRob Clark /*
1533d39e48caSRob Clark * For atomic updates which touch just a single CRTC, calculate the time of the
1534d39e48caSRob Clark * next vblank, and inform all the fences of the deadline.
1535d39e48caSRob Clark */
set_fence_deadline(struct drm_device * dev,struct drm_atomic_state * state)1536d39e48caSRob Clark static void set_fence_deadline(struct drm_device *dev,
1537d39e48caSRob Clark struct drm_atomic_state *state)
1538d39e48caSRob Clark {
1539d39e48caSRob Clark struct drm_crtc *crtc;
1540d39e48caSRob Clark struct drm_crtc_state *new_crtc_state;
1541d39e48caSRob Clark struct drm_plane *plane;
1542d39e48caSRob Clark struct drm_plane_state *new_plane_state;
1543d39e48caSRob Clark ktime_t vbltime = 0;
1544d39e48caSRob Clark int i;
1545d39e48caSRob Clark
1546d39e48caSRob Clark for_each_new_crtc_in_state (state, crtc, new_crtc_state, i) {
1547d39e48caSRob Clark ktime_t v;
1548d39e48caSRob Clark
1549f2c7ca89SDaniel Vetter if (drm_atomic_crtc_needs_modeset(new_crtc_state))
1550f2c7ca89SDaniel Vetter continue;
1551f2c7ca89SDaniel Vetter
1552f2c7ca89SDaniel Vetter if (!new_crtc_state->active)
1553f2c7ca89SDaniel Vetter continue;
1554f2c7ca89SDaniel Vetter
1555d39e48caSRob Clark if (drm_crtc_next_vblank_start(crtc, &v))
1556d39e48caSRob Clark continue;
1557d39e48caSRob Clark
1558d39e48caSRob Clark if (!vbltime || ktime_before(v, vbltime))
1559d39e48caSRob Clark vbltime = v;
1560d39e48caSRob Clark }
1561d39e48caSRob Clark
1562d39e48caSRob Clark /* If no CRTCs updated, then nothing to do: */
1563d39e48caSRob Clark if (!vbltime)
1564d39e48caSRob Clark return;
1565d39e48caSRob Clark
1566d39e48caSRob Clark for_each_new_plane_in_state (state, plane, new_plane_state, i) {
1567d39e48caSRob Clark if (!new_plane_state->fence)
1568d39e48caSRob Clark continue;
1569d39e48caSRob Clark dma_fence_set_deadline(new_plane_state->fence, vbltime);
1570d39e48caSRob Clark }
1571d39e48caSRob Clark }
1572d39e48caSRob Clark
15734c5b7f3aSRob Clark /**
15744c5b7f3aSRob Clark * drm_atomic_helper_wait_for_fences - wait for fences stashed in plane state
15754c5b7f3aSRob Clark * @dev: DRM device
15764c5b7f3aSRob Clark * @state: atomic state object with old state structures
15771ea0c02eSDaniel Vetter * @pre_swap: If true, do an interruptible wait, and @state is the new state.
15781ea0c02eSDaniel Vetter * Otherwise @state is the old state.
15794c5b7f3aSRob Clark *
15804c5b7f3aSRob Clark * For implicit sync, driver should fish the exclusive fence out from the
15814c5b7f3aSRob Clark * incoming fb's and stash it in the drm_plane_state. This is called after
15824c5b7f3aSRob Clark * drm_atomic_helper_swap_state() so it uses the current plane state (and
15834c5b7f3aSRob Clark * just uses the atomic state to find the changed planes)
1584f6ce410aSGustavo Padovan *
15851ea0c02eSDaniel Vetter * Note that @pre_swap is needed since the point where we block for fences moves
15861ea0c02eSDaniel Vetter * around depending upon whether an atomic commit is blocking or
158742590372SGustavo Padovan * non-blocking. For non-blocking commit all waiting needs to happen after
158842590372SGustavo Padovan * drm_atomic_helper_swap_state() is called, but for blocking commits we want
15891ea0c02eSDaniel Vetter * to wait **before** we do anything that can't be easily rolled back. That is
15901ea0c02eSDaniel Vetter * before we call drm_atomic_helper_swap_state().
15911ea0c02eSDaniel Vetter *
1592f54d1867SChris Wilson * Returns zero if success or < 0 if dma_fence_wait() fails.
15934c5b7f3aSRob Clark */
drm_atomic_helper_wait_for_fences(struct drm_device * dev,struct drm_atomic_state * state,bool pre_swap)1594f6ce410aSGustavo Padovan int drm_atomic_helper_wait_for_fences(struct drm_device *dev,
1595f6ce410aSGustavo Padovan struct drm_atomic_state *state,
1596f6ce410aSGustavo Padovan bool pre_swap)
1597e2330f07SDaniel Vetter {
1598df63b999SAnder Conselvan de Oliveira struct drm_plane *plane;
1599415c3ac3SMaarten Lankhorst struct drm_plane_state *new_plane_state;
1600f6ce410aSGustavo Padovan int i, ret;
1601e2330f07SDaniel Vetter
1602d39e48caSRob Clark set_fence_deadline(dev, state);
1603d39e48caSRob Clark
1604415c3ac3SMaarten Lankhorst for_each_new_plane_in_state(state, plane, new_plane_state, i) {
1605415c3ac3SMaarten Lankhorst if (!new_plane_state->fence)
1606e2330f07SDaniel Vetter continue;
1607e2330f07SDaniel Vetter
1608415c3ac3SMaarten Lankhorst WARN_ON(!new_plane_state->fb);
1609e2330f07SDaniel Vetter
1610f6ce410aSGustavo Padovan /*
1611f6ce410aSGustavo Padovan * If waiting for fences pre-swap (ie: nonblock), userspace can
1612f6ce410aSGustavo Padovan * still interrupt the operation. Instead of blocking until the
1613f6ce410aSGustavo Padovan * timer expires, make the wait interruptible.
1614f6ce410aSGustavo Padovan */
1615415c3ac3SMaarten Lankhorst ret = dma_fence_wait(new_plane_state->fence, pre_swap);
1616f6ce410aSGustavo Padovan if (ret)
1617f6ce410aSGustavo Padovan return ret;
1618f6ce410aSGustavo Padovan
1619415c3ac3SMaarten Lankhorst dma_fence_put(new_plane_state->fence);
1620415c3ac3SMaarten Lankhorst new_plane_state->fence = NULL;
1621e2330f07SDaniel Vetter }
1622f6ce410aSGustavo Padovan
1623f6ce410aSGustavo Padovan return 0;
1624e2330f07SDaniel Vetter }
16254c5b7f3aSRob Clark EXPORT_SYMBOL(drm_atomic_helper_wait_for_fences);
1626e2330f07SDaniel Vetter
1627c240906dSJohn Keeping /**
162842240c90SThierry Reding * drm_atomic_helper_wait_for_vblanks - wait for vblank on CRTCs
16295ee3229cSRob Clark * @dev: DRM device
16305ee3229cSRob Clark * @old_state: atomic state object with old state structures
16315ee3229cSRob Clark *
1632dbe2d2bfSThierry Reding * Helper to, after atomic commit, wait for vblanks on all affected
163342240c90SThierry Reding * CRTCs (ie. before cleaning up old framebuffers using
163401086487SBoris Brezillon * drm_atomic_helper_cleanup_planes()). It will only wait on CRTCs where the
1635ab58e338SDaniel Vetter * framebuffers have actually changed to optimize for the legacy cursor and
1636ab58e338SDaniel Vetter * plane update use-case.
163701086487SBoris Brezillon *
163801086487SBoris Brezillon * Drivers using the nonblocking commit tracking support initialized by calling
163901086487SBoris Brezillon * drm_atomic_helper_setup_commit() should look at
164001086487SBoris Brezillon * drm_atomic_helper_wait_for_flip_done() as an alternative.
16415ee3229cSRob Clark */
16425ee3229cSRob Clark void
drm_atomic_helper_wait_for_vblanks(struct drm_device * dev,struct drm_atomic_state * old_state)16435ee3229cSRob Clark drm_atomic_helper_wait_for_vblanks(struct drm_device *dev,
16445ee3229cSRob Clark struct drm_atomic_state *old_state)
1645623369e5SDaniel Vetter {
1646623369e5SDaniel Vetter struct drm_crtc *crtc;
1647415c3ac3SMaarten Lankhorst struct drm_crtc_state *old_crtc_state, *new_crtc_state;
1648623369e5SDaniel Vetter int i, ret;
16499237ec1fSFabio M. De Francesco unsigned int crtc_mask = 0;
1650bdc57146SMaarten Lankhorst
1651bdc57146SMaarten Lankhorst /*
1652bdc57146SMaarten Lankhorst * Legacy cursor ioctls are completely unsynced, and userspace
1653bdc57146SMaarten Lankhorst * relies on that (by doing tons of cursor updates).
1654bdc57146SMaarten Lankhorst */
1655bdc57146SMaarten Lankhorst if (old_state->legacy_cursor_update)
1656bdc57146SMaarten Lankhorst return;
1657623369e5SDaniel Vetter
1658415c3ac3SMaarten Lankhorst for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) {
1659a76dfe35SLucas Stach if (!new_crtc_state->active)
1660ab58e338SDaniel Vetter continue;
1661ab58e338SDaniel Vetter
1662623369e5SDaniel Vetter ret = drm_crtc_vblank_get(crtc);
1663623369e5SDaniel Vetter if (ret != 0)
1664623369e5SDaniel Vetter continue;
1665623369e5SDaniel Vetter
1666bdc57146SMaarten Lankhorst crtc_mask |= drm_crtc_mask(crtc);
1667bdc57146SMaarten Lankhorst old_state->crtcs[i].last_vblank_count = drm_crtc_vblank_count(crtc);
1668623369e5SDaniel Vetter }
1669623369e5SDaniel Vetter
1670415c3ac3SMaarten Lankhorst for_each_old_crtc_in_state(old_state, crtc, old_crtc_state, i) {
1671bdc57146SMaarten Lankhorst if (!(crtc_mask & drm_crtc_mask(crtc)))
1672623369e5SDaniel Vetter continue;
1673623369e5SDaniel Vetter
1674623369e5SDaniel Vetter ret = wait_event_timeout(dev->vblank[i].queue,
1675bdc57146SMaarten Lankhorst old_state->crtcs[i].last_vblank_count !=
1676d4853630SThierry Reding drm_crtc_vblank_count(crtc),
1677b3198c38SLinus Walleij msecs_to_jiffies(100));
1678623369e5SDaniel Vetter
16796ac7c548SRussell King WARN(!ret, "[CRTC:%d:%s] vblank wait timed out\n",
16806ac7c548SRussell King crtc->base.id, crtc->name);
16818d4d0d70SVille Syrjälä
1682623369e5SDaniel Vetter drm_crtc_vblank_put(crtc);
1683623369e5SDaniel Vetter }
1684623369e5SDaniel Vetter }
16855ee3229cSRob Clark EXPORT_SYMBOL(drm_atomic_helper_wait_for_vblanks);
1686623369e5SDaniel Vetter
1687623369e5SDaniel Vetter /**
168801086487SBoris Brezillon * drm_atomic_helper_wait_for_flip_done - wait for all page flips to be done
168901086487SBoris Brezillon * @dev: DRM device
169001086487SBoris Brezillon * @old_state: atomic state object with old state structures
169101086487SBoris Brezillon *
1692dbe2d2bfSThierry Reding * Helper to, after atomic commit, wait for page flips on all affected
169301086487SBoris Brezillon * crtcs (ie. before cleaning up old framebuffers using
169401086487SBoris Brezillon * drm_atomic_helper_cleanup_planes()). Compared to
1695dbe2d2bfSThierry Reding * drm_atomic_helper_wait_for_vblanks() this waits for the completion on all
169601086487SBoris Brezillon * CRTCs, assuming that cursors-only updates are signalling their completion
169701086487SBoris Brezillon * immediately (or using a different path).
169801086487SBoris Brezillon *
169901086487SBoris Brezillon * This requires that drivers use the nonblocking commit tracking support
170001086487SBoris Brezillon * initialized using drm_atomic_helper_setup_commit().
170101086487SBoris Brezillon */
drm_atomic_helper_wait_for_flip_done(struct drm_device * dev,struct drm_atomic_state * old_state)170201086487SBoris Brezillon void drm_atomic_helper_wait_for_flip_done(struct drm_device *dev,
170301086487SBoris Brezillon struct drm_atomic_state *old_state)
170401086487SBoris Brezillon {
170501086487SBoris Brezillon struct drm_crtc *crtc;
170601086487SBoris Brezillon int i;
170701086487SBoris Brezillon
17084364bcb2SLeo Li for (i = 0; i < dev->mode_config.num_crtc; i++) {
17094364bcb2SLeo Li struct drm_crtc_commit *commit = old_state->crtcs[i].commit;
171001086487SBoris Brezillon int ret;
171101086487SBoris Brezillon
17124364bcb2SLeo Li crtc = old_state->crtcs[i].ptr;
17134364bcb2SLeo Li
17144364bcb2SLeo Li if (!crtc || !commit)
171501086487SBoris Brezillon continue;
171601086487SBoris Brezillon
171701086487SBoris Brezillon ret = wait_for_completion_timeout(&commit->flip_done, 10 * HZ);
171801086487SBoris Brezillon if (ret == 0)
17196e22dc35SClaudio Suarez drm_err(dev, "[CRTC:%d:%s] flip_done timed out\n",
172001086487SBoris Brezillon crtc->base.id, crtc->name);
172101086487SBoris Brezillon }
17222de42f79SVille Syrjälä
17232de42f79SVille Syrjälä if (old_state->fake_commit)
17242de42f79SVille Syrjälä complete_all(&old_state->fake_commit->flip_done);
172501086487SBoris Brezillon }
172601086487SBoris Brezillon EXPORT_SYMBOL(drm_atomic_helper_wait_for_flip_done);
172701086487SBoris Brezillon
172801086487SBoris Brezillon /**
17299f2a7950SDaniel Vetter * drm_atomic_helper_commit_tail - commit atomic update to hardware
17301ea0c02eSDaniel Vetter * @old_state: atomic state object with old state structures
1731623369e5SDaniel Vetter *
17326806cdf9SDaniel Vetter * This is the default implementation for the
173381a099acSMaxime Ripard * &drm_mode_config_helper_funcs.atomic_commit_tail hook, for drivers
173481a099acSMaxime Ripard * that do not support runtime_pm or do not need the CRTC to be
173581a099acSMaxime Ripard * enabled to perform a commit. Otherwise, see
173681a099acSMaxime Ripard * drm_atomic_helper_commit_tail_rpm().
1737623369e5SDaniel Vetter *
17389f2a7950SDaniel Vetter * Note that the default ordering of how the various stages are called is to
173981a099acSMaxime Ripard * match the legacy modeset helper library closest.
17409f2a7950SDaniel Vetter */
drm_atomic_helper_commit_tail(struct drm_atomic_state * old_state)17411ea0c02eSDaniel Vetter void drm_atomic_helper_commit_tail(struct drm_atomic_state *old_state)
17429f2a7950SDaniel Vetter {
17431ea0c02eSDaniel Vetter struct drm_device *dev = old_state->dev;
17449f2a7950SDaniel Vetter
17451ea0c02eSDaniel Vetter drm_atomic_helper_commit_modeset_disables(dev, old_state);
17469f2a7950SDaniel Vetter
17471ea0c02eSDaniel Vetter drm_atomic_helper_commit_planes(dev, old_state, 0);
17489f2a7950SDaniel Vetter
17491ea0c02eSDaniel Vetter drm_atomic_helper_commit_modeset_enables(dev, old_state);
17509f2a7950SDaniel Vetter
17516fb42b66SBoris Brezillon drm_atomic_helper_fake_vblank(old_state);
17526fb42b66SBoris Brezillon
17531ea0c02eSDaniel Vetter drm_atomic_helper_commit_hw_done(old_state);
17549f2a7950SDaniel Vetter
17551ea0c02eSDaniel Vetter drm_atomic_helper_wait_for_vblanks(dev, old_state);
17569f2a7950SDaniel Vetter
17571ea0c02eSDaniel Vetter drm_atomic_helper_cleanup_planes(dev, old_state);
17589f2a7950SDaniel Vetter }
17599f2a7950SDaniel Vetter EXPORT_SYMBOL(drm_atomic_helper_commit_tail);
17609f2a7950SDaniel Vetter
176181a099acSMaxime Ripard /**
176281a099acSMaxime Ripard * drm_atomic_helper_commit_tail_rpm - commit atomic update to hardware
176381a099acSMaxime Ripard * @old_state: new modeset state to be committed
176481a099acSMaxime Ripard *
176581a099acSMaxime Ripard * This is an alternative implementation for the
176681a099acSMaxime Ripard * &drm_mode_config_helper_funcs.atomic_commit_tail hook, for drivers
176781a099acSMaxime Ripard * that support runtime_pm or need the CRTC to be enabled to perform a
176881a099acSMaxime Ripard * commit. Otherwise, one should use the default implementation
176981a099acSMaxime Ripard * drm_atomic_helper_commit_tail().
177081a099acSMaxime Ripard */
drm_atomic_helper_commit_tail_rpm(struct drm_atomic_state * old_state)177181a099acSMaxime Ripard void drm_atomic_helper_commit_tail_rpm(struct drm_atomic_state *old_state)
177281a099acSMaxime Ripard {
177381a099acSMaxime Ripard struct drm_device *dev = old_state->dev;
177481a099acSMaxime Ripard
177581a099acSMaxime Ripard drm_atomic_helper_commit_modeset_disables(dev, old_state);
177681a099acSMaxime Ripard
177781a099acSMaxime Ripard drm_atomic_helper_commit_modeset_enables(dev, old_state);
177881a099acSMaxime Ripard
177981a099acSMaxime Ripard drm_atomic_helper_commit_planes(dev, old_state,
178081a099acSMaxime Ripard DRM_PLANE_COMMIT_ACTIVE_ONLY);
178181a099acSMaxime Ripard
17826fb42b66SBoris Brezillon drm_atomic_helper_fake_vblank(old_state);
17836fb42b66SBoris Brezillon
178481a099acSMaxime Ripard drm_atomic_helper_commit_hw_done(old_state);
178581a099acSMaxime Ripard
178681a099acSMaxime Ripard drm_atomic_helper_wait_for_vblanks(dev, old_state);
178781a099acSMaxime Ripard
178881a099acSMaxime Ripard drm_atomic_helper_cleanup_planes(dev, old_state);
178981a099acSMaxime Ripard }
179081a099acSMaxime Ripard EXPORT_SYMBOL(drm_atomic_helper_commit_tail_rpm);
179181a099acSMaxime Ripard
commit_tail(struct drm_atomic_state * old_state)17921ea0c02eSDaniel Vetter static void commit_tail(struct drm_atomic_state *old_state)
17939f2a7950SDaniel Vetter {
17941ea0c02eSDaniel Vetter struct drm_device *dev = old_state->dev;
1795a4b10cceSLaurent Pinchart const struct drm_mode_config_helper_funcs *funcs;
179686de88cfSRob Clark struct drm_crtc_state *new_crtc_state;
179786de88cfSRob Clark struct drm_crtc *crtc;
1798d4da4e33SSean Paul ktime_t start;
1799d4da4e33SSean Paul s64 commit_time_ms;
180086de88cfSRob Clark unsigned int i, new_self_refresh_mask = 0;
18019f2a7950SDaniel Vetter
18029f2a7950SDaniel Vetter funcs = dev->mode_config.helper_private;
18039f2a7950SDaniel Vetter
1804d4da4e33SSean Paul /*
1805d4da4e33SSean Paul * We're measuring the _entire_ commit, so the time will vary depending
1806d4da4e33SSean Paul * on how many fences and objects are involved. For the purposes of self
1807d4da4e33SSean Paul * refresh, this is desirable since it'll give us an idea of how
1808d4da4e33SSean Paul * congested things are. This will inform our decision on how often we
1809d4da4e33SSean Paul * should enter self refresh after idle.
1810d4da4e33SSean Paul *
1811d4da4e33SSean Paul * These times will be averaged out in the self refresh helpers to avoid
1812d4da4e33SSean Paul * overreacting over one outlier frame
1813d4da4e33SSean Paul */
1814d4da4e33SSean Paul start = ktime_get();
1815d4da4e33SSean Paul
18161ea0c02eSDaniel Vetter drm_atomic_helper_wait_for_fences(dev, old_state, false);
18179f2a7950SDaniel Vetter
18181ea0c02eSDaniel Vetter drm_atomic_helper_wait_for_dependencies(old_state);
18199f2a7950SDaniel Vetter
182086de88cfSRob Clark /*
182186de88cfSRob Clark * We cannot safely access new_crtc_state after
182286de88cfSRob Clark * drm_atomic_helper_commit_hw_done() so figure out which crtc's have
182386de88cfSRob Clark * self-refresh active beforehand:
182486de88cfSRob Clark */
182586de88cfSRob Clark for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i)
182686de88cfSRob Clark if (new_crtc_state->self_refresh_active)
182786de88cfSRob Clark new_self_refresh_mask |= BIT(i);
182886de88cfSRob Clark
18299f2a7950SDaniel Vetter if (funcs && funcs->atomic_commit_tail)
18301ea0c02eSDaniel Vetter funcs->atomic_commit_tail(old_state);
18319f2a7950SDaniel Vetter else
18321ea0c02eSDaniel Vetter drm_atomic_helper_commit_tail(old_state);
18339f2a7950SDaniel Vetter
1834d4da4e33SSean Paul commit_time_ms = ktime_ms_delta(ktime_get(), start);
1835d4da4e33SSean Paul if (commit_time_ms > 0)
1836d4da4e33SSean Paul drm_self_refresh_helper_update_avg_times(old_state,
183786de88cfSRob Clark (unsigned long)commit_time_ms,
183886de88cfSRob Clark new_self_refresh_mask);
1839d4da4e33SSean Paul
18401ea0c02eSDaniel Vetter drm_atomic_helper_commit_cleanup_done(old_state);
18419f2a7950SDaniel Vetter
18421ea0c02eSDaniel Vetter drm_atomic_state_put(old_state);
18439f2a7950SDaniel Vetter }
18449f2a7950SDaniel Vetter
commit_work(struct work_struct * work)18459f2a7950SDaniel Vetter static void commit_work(struct work_struct *work)
18469f2a7950SDaniel Vetter {
18479f2a7950SDaniel Vetter struct drm_atomic_state *state = container_of(work,
18489f2a7950SDaniel Vetter struct drm_atomic_state,
18499f2a7950SDaniel Vetter commit_work);
18509f2a7950SDaniel Vetter commit_tail(state);
18519f2a7950SDaniel Vetter }
18529f2a7950SDaniel Vetter
18539f2a7950SDaniel Vetter /**
18540ae865efSCai Huoqing * drm_atomic_helper_async_check - check if state can be committed asynchronously
1855fef9df8bSGustavo Padovan * @dev: DRM device
1856fef9df8bSGustavo Padovan * @state: the driver state object
1857fef9df8bSGustavo Padovan *
1858fef9df8bSGustavo Padovan * This helper will check if it is possible to commit the state asynchronously.
1859fef9df8bSGustavo Padovan * Async commits are not supposed to swap the states like normal sync commits
1860fef9df8bSGustavo Padovan * but just do in-place changes on the current state.
1861fef9df8bSGustavo Padovan *
1862fef9df8bSGustavo Padovan * It will return 0 if the commit can happen in an asynchronous fashion or error
18630ae865efSCai Huoqing * if not. Note that error just mean it can't be committed asynchronously, if it
1864fef9df8bSGustavo Padovan * fails the commit should be treated like a normal synchronous commit.
1865fef9df8bSGustavo Padovan */
drm_atomic_helper_async_check(struct drm_device * dev,struct drm_atomic_state * state)1866fef9df8bSGustavo Padovan int drm_atomic_helper_async_check(struct drm_device *dev,
1867fef9df8bSGustavo Padovan struct drm_atomic_state *state)
1868fef9df8bSGustavo Padovan {
1869fef9df8bSGustavo Padovan struct drm_crtc *crtc;
1870fef9df8bSGustavo Padovan struct drm_crtc_state *crtc_state;
1871de2d8db3SBoris Brezillon struct drm_plane *plane = NULL;
1872de2d8db3SBoris Brezillon struct drm_plane_state *old_plane_state = NULL;
1873de2d8db3SBoris Brezillon struct drm_plane_state *new_plane_state = NULL;
1874fef9df8bSGustavo Padovan const struct drm_plane_helper_funcs *funcs;
18758fe444ebSSimon Ser int i, ret, n_planes = 0;
1876fef9df8bSGustavo Padovan
1877fef9df8bSGustavo Padovan for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
1878fef9df8bSGustavo Padovan if (drm_atomic_crtc_needs_modeset(crtc_state))
1879fef9df8bSGustavo Padovan return -EINVAL;
1880fef9df8bSGustavo Padovan }
1881fef9df8bSGustavo Padovan
1882669c9215SMaarten Lankhorst for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i)
1883fef9df8bSGustavo Padovan n_planes++;
1884fef9df8bSGustavo Padovan
1885fef9df8bSGustavo Padovan /* FIXME: we support only single plane updates for now */
18868fe444ebSSimon Ser if (n_planes != 1) {
18878fe444ebSSimon Ser drm_dbg_atomic(dev,
18888fe444ebSSimon Ser "only single plane async updates are supported\n");
1889fef9df8bSGustavo Padovan return -EINVAL;
18908fe444ebSSimon Ser }
1891fef9df8bSGustavo Padovan
1892603ba2dfSBoris Brezillon if (!new_plane_state->crtc ||
18938fe444ebSSimon Ser old_plane_state->crtc != new_plane_state->crtc) {
18948fe444ebSSimon Ser drm_dbg_atomic(dev,
18958fe444ebSSimon Ser "[PLANE:%d:%s] async update cannot change CRTC\n",
18968fe444ebSSimon Ser plane->base.id, plane->name);
1897fef9df8bSGustavo Padovan return -EINVAL;
18988fe444ebSSimon Ser }
1899fef9df8bSGustavo Padovan
1900fef9df8bSGustavo Padovan funcs = plane->helper_private;
19018fe444ebSSimon Ser if (!funcs->atomic_async_update) {
19028fe444ebSSimon Ser drm_dbg_atomic(dev,
19038fe444ebSSimon Ser "[PLANE:%d:%s] driver does not support async updates\n",
19048fe444ebSSimon Ser plane->base.id, plane->name);
1905fef9df8bSGustavo Padovan return -EINVAL;
19068fe444ebSSimon Ser }
1907fef9df8bSGustavo Padovan
19088fe444ebSSimon Ser if (new_plane_state->fence) {
19098fe444ebSSimon Ser drm_dbg_atomic(dev,
19108fe444ebSSimon Ser "[PLANE:%d:%s] missing fence for async update\n",
19118fe444ebSSimon Ser plane->base.id, plane->name);
1912fef9df8bSGustavo Padovan return -EINVAL;
19138fe444ebSSimon Ser }
1914fef9df8bSGustavo Padovan
1915fef9df8bSGustavo Padovan /*
1916fef9df8bSGustavo Padovan * Don't do an async update if there is an outstanding commit modifying
1917fef9df8bSGustavo Padovan * the plane. This prevents our async update's changes from getting
1918fef9df8bSGustavo Padovan * overridden by a previous synchronous update's state.
1919fef9df8bSGustavo Padovan */
1920669c9215SMaarten Lankhorst if (old_plane_state->commit &&
19219073d4edSDaniel Vetter !try_wait_for_completion(&old_plane_state->commit->hw_done)) {
19226e22dc35SClaudio Suarez drm_dbg_atomic(dev,
19236e22dc35SClaudio Suarez "[PLANE:%d:%s] inflight previous commit preventing async commit\n",
19249073d4edSDaniel Vetter plane->base.id, plane->name);
1925669c9215SMaarten Lankhorst return -EBUSY;
19269073d4edSDaniel Vetter }
1927fef9df8bSGustavo Padovan
19288fe444ebSSimon Ser ret = funcs->atomic_async_check(plane, state);
19298fe444ebSSimon Ser if (ret != 0)
19308fe444ebSSimon Ser drm_dbg_atomic(dev,
19318fe444ebSSimon Ser "[PLANE:%d:%s] driver async check failed\n",
19328fe444ebSSimon Ser plane->base.id, plane->name);
19338fe444ebSSimon Ser return ret;
1934fef9df8bSGustavo Padovan }
1935fef9df8bSGustavo Padovan EXPORT_SYMBOL(drm_atomic_helper_async_check);
1936fef9df8bSGustavo Padovan
1937fef9df8bSGustavo Padovan /**
1938fef9df8bSGustavo Padovan * drm_atomic_helper_async_commit - commit state asynchronously
1939fef9df8bSGustavo Padovan * @dev: DRM device
1940fef9df8bSGustavo Padovan * @state: the driver state object
1941fef9df8bSGustavo Padovan *
1942fef9df8bSGustavo Padovan * This function commits a state asynchronously, i.e., not vblank
1943fef9df8bSGustavo Padovan * synchronized. It should be used on a state only when
1944fef9df8bSGustavo Padovan * drm_atomic_async_check() succeeds. Async commits are not supposed to swap
1945fef9df8bSGustavo Padovan * the states like normal sync commits, but just do in-place changes on the
1946fef9df8bSGustavo Padovan * current state.
194789a4aac0SHelen Koike *
194889a4aac0SHelen Koike * TODO: Implement full swap instead of doing in-place changes.
1949fef9df8bSGustavo Padovan */
drm_atomic_helper_async_commit(struct drm_device * dev,struct drm_atomic_state * state)1950fef9df8bSGustavo Padovan void drm_atomic_helper_async_commit(struct drm_device *dev,
1951fef9df8bSGustavo Padovan struct drm_atomic_state *state)
1952fef9df8bSGustavo Padovan {
1953fef9df8bSGustavo Padovan struct drm_plane *plane;
1954fef9df8bSGustavo Padovan struct drm_plane_state *plane_state;
1955fef9df8bSGustavo Padovan const struct drm_plane_helper_funcs *funcs;
1956fef9df8bSGustavo Padovan int i;
1957fef9df8bSGustavo Padovan
1958fef9df8bSGustavo Padovan for_each_new_plane_in_state(state, plane, plane_state, i) {
195989a4aac0SHelen Koike struct drm_framebuffer *new_fb = plane_state->fb;
196089a4aac0SHelen Koike struct drm_framebuffer *old_fb = plane->state->fb;
196189a4aac0SHelen Koike
1962fef9df8bSGustavo Padovan funcs = plane->helper_private;
19635ddb0bd4SMaxime Ripard funcs->atomic_async_update(plane, state);
196402edfd9cSBoris Brezillon
196502edfd9cSBoris Brezillon /*
196602edfd9cSBoris Brezillon * ->atomic_async_update() is supposed to update the
196702edfd9cSBoris Brezillon * plane->state in-place, make sure at least common
196802edfd9cSBoris Brezillon * properties have been properly updated.
196902edfd9cSBoris Brezillon */
197089a4aac0SHelen Koike WARN_ON_ONCE(plane->state->fb != new_fb);
197102edfd9cSBoris Brezillon WARN_ON_ONCE(plane->state->crtc_x != plane_state->crtc_x);
197202edfd9cSBoris Brezillon WARN_ON_ONCE(plane->state->crtc_y != plane_state->crtc_y);
197302edfd9cSBoris Brezillon WARN_ON_ONCE(plane->state->src_x != plane_state->src_x);
197402edfd9cSBoris Brezillon WARN_ON_ONCE(plane->state->src_y != plane_state->src_y);
197589a4aac0SHelen Koike
197689a4aac0SHelen Koike /*
197789a4aac0SHelen Koike * Make sure the FBs have been swapped so that cleanups in the
197889a4aac0SHelen Koike * new_state performs a cleanup in the old FB.
197989a4aac0SHelen Koike */
198089a4aac0SHelen Koike WARN_ON_ONCE(plane_state->fb != old_fb);
1981fef9df8bSGustavo Padovan }
1982fef9df8bSGustavo Padovan }
1983fef9df8bSGustavo Padovan EXPORT_SYMBOL(drm_atomic_helper_async_commit);
1984fef9df8bSGustavo Padovan
1985fef9df8bSGustavo Padovan /**
19869f2a7950SDaniel Vetter * drm_atomic_helper_commit - commit validated state object
19879f2a7950SDaniel Vetter * @dev: DRM device
19889f2a7950SDaniel Vetter * @state: the driver state object
19899f2a7950SDaniel Vetter * @nonblock: whether nonblocking behavior is requested.
19909f2a7950SDaniel Vetter *
19919f2a7950SDaniel Vetter * This function commits a with drm_atomic_helper_check() pre-validated state
19929f2a7950SDaniel Vetter * object. This can still fail when e.g. the framebuffer reservation fails. This
19939f2a7950SDaniel Vetter * function implements nonblocking commits, using
19949f2a7950SDaniel Vetter * drm_atomic_helper_setup_commit() and related functions.
19959f2a7950SDaniel Vetter *
19969f2a7950SDaniel Vetter * Committing the actual hardware state is done through the
19971e55a53aSMatt Roper * &drm_mode_config_helper_funcs.atomic_commit_tail callback, or its default
19986806cdf9SDaniel Vetter * implementation drm_atomic_helper_commit_tail().
19996e48ae32SDaniel Vetter *
2000c39032a8SDaniel Vetter * RETURNS:
2001623369e5SDaniel Vetter * Zero for success or -errno.
2002623369e5SDaniel Vetter */
drm_atomic_helper_commit(struct drm_device * dev,struct drm_atomic_state * state,bool nonblock)2003623369e5SDaniel Vetter int drm_atomic_helper_commit(struct drm_device *dev,
2004623369e5SDaniel Vetter struct drm_atomic_state *state,
2005286dbb8dSMaarten Lankhorst bool nonblock)
2006623369e5SDaniel Vetter {
2007623369e5SDaniel Vetter int ret;
2008623369e5SDaniel Vetter
2009fef9df8bSGustavo Padovan if (state->async_update) {
2010fef9df8bSGustavo Padovan ret = drm_atomic_helper_prepare_planes(dev, state);
2011fef9df8bSGustavo Padovan if (ret)
2012fef9df8bSGustavo Padovan return ret;
2013fef9df8bSGustavo Padovan
2014fef9df8bSGustavo Padovan drm_atomic_helper_async_commit(dev, state);
2015*02650b3bSThomas Zimmermann drm_atomic_helper_unprepare_planes(dev, state);
2016fef9df8bSGustavo Padovan
2017fef9df8bSGustavo Padovan return 0;
2018fef9df8bSGustavo Padovan }
2019fef9df8bSGustavo Padovan
2020a095caa7SDaniel Vetter ret = drm_atomic_helper_setup_commit(state, nonblock);
2021a095caa7SDaniel Vetter if (ret)
2022a095caa7SDaniel Vetter return ret;
2023a095caa7SDaniel Vetter
20249f2a7950SDaniel Vetter INIT_WORK(&state->commit_work, commit_work);
20259f2a7950SDaniel Vetter
2026623369e5SDaniel Vetter ret = drm_atomic_helper_prepare_planes(dev, state);
2027623369e5SDaniel Vetter if (ret)
2028623369e5SDaniel Vetter return ret;
2029623369e5SDaniel Vetter
2030f6ce410aSGustavo Padovan if (!nonblock) {
2031f6ce410aSGustavo Padovan ret = drm_atomic_helper_wait_for_fences(dev, state, true);
2032c066d231SMaarten Lankhorst if (ret)
2033c066d231SMaarten Lankhorst goto err;
2034aebe55c2SLaurent Pinchart }
2035f6ce410aSGustavo Padovan
2036623369e5SDaniel Vetter /*
2037623369e5SDaniel Vetter * This is the point of no return - everything below never fails except
2038623369e5SDaniel Vetter * when the hw goes bonghits. Which means we can commit the new state on
2039623369e5SDaniel Vetter * the software side now.
2040623369e5SDaniel Vetter */
2041623369e5SDaniel Vetter
2042c066d231SMaarten Lankhorst ret = drm_atomic_helper_swap_state(state, true);
2043c066d231SMaarten Lankhorst if (ret)
2044c066d231SMaarten Lankhorst goto err;
2045623369e5SDaniel Vetter
2046623369e5SDaniel Vetter /*
2047623369e5SDaniel Vetter * Everything below can be run asynchronously without the need to grab
2048f98bd3efSJohn Hunter * any modeset locks at all under one condition: It must be guaranteed
2049623369e5SDaniel Vetter * that the asynchronous work has either been cancelled (if the driver
2050623369e5SDaniel Vetter * supports it, which at least requires that the framebuffers get
2051623369e5SDaniel Vetter * cleaned up with drm_atomic_helper_cleanup_planes()) or completed
2052623369e5SDaniel Vetter * before the new state gets committed on the software side with
2053623369e5SDaniel Vetter * drm_atomic_helper_swap_state().
2054623369e5SDaniel Vetter *
2055623369e5SDaniel Vetter * This scheme allows new atomic state updates to be prepared and
2056623369e5SDaniel Vetter * checked in parallel to the asynchronous completion of the previous
2057623369e5SDaniel Vetter * update. Which is important since compositors need to figure out the
2058623369e5SDaniel Vetter * composition of the next frame right after having submitted the
2059623369e5SDaniel Vetter * current layout.
20609f2a7950SDaniel Vetter *
20619f2a7950SDaniel Vetter * NOTE: Commit work has multiple phases, first hardware commit, then
20629f2a7950SDaniel Vetter * cleanup. We want them to overlap, hence need system_unbound_wq to
2063a0689e34SKieran Bingham * make sure work items don't artificially stall on each another.
2064623369e5SDaniel Vetter */
2065623369e5SDaniel Vetter
20660853695cSChris Wilson drm_atomic_state_get(state);
20679f2a7950SDaniel Vetter if (nonblock)
20689f2a7950SDaniel Vetter queue_work(system_unbound_wq, &state->commit_work);
20699f2a7950SDaniel Vetter else
20709f2a7950SDaniel Vetter commit_tail(state);
2071623369e5SDaniel Vetter
2072623369e5SDaniel Vetter return 0;
2073c066d231SMaarten Lankhorst
2074c066d231SMaarten Lankhorst err:
2075*02650b3bSThomas Zimmermann drm_atomic_helper_unprepare_planes(dev, state);
2076c066d231SMaarten Lankhorst return ret;
2077623369e5SDaniel Vetter }
2078623369e5SDaniel Vetter EXPORT_SYMBOL(drm_atomic_helper_commit);
2079623369e5SDaniel Vetter
2080c2fcd274SDaniel Vetter /**
2081286dbb8dSMaarten Lankhorst * DOC: implementing nonblocking commit
2082e8c833a7SDaniel Vetter *
20830380c684SDaniel Vetter * Nonblocking atomic commits should use struct &drm_crtc_commit to sequence
20840380c684SDaniel Vetter * different operations against each another. Locks, especially struct
20850380c684SDaniel Vetter * &drm_modeset_lock, should not be held in worker threads or any other
20860380c684SDaniel Vetter * asynchronous context used to commit the hardware state.
2087e8c833a7SDaniel Vetter *
20880380c684SDaniel Vetter * drm_atomic_helper_commit() implements the recommended sequence for
20890380c684SDaniel Vetter * nonblocking commits, using drm_atomic_helper_setup_commit() internally:
20900380c684SDaniel Vetter *
20910380c684SDaniel Vetter * 1. Run drm_atomic_helper_prepare_planes(). Since this can fail and we
20920380c684SDaniel Vetter * need to propagate out of memory/VRAM errors to userspace, it must be called
2093e8c833a7SDaniel Vetter * synchronously.
2094e8c833a7SDaniel Vetter *
2095286dbb8dSMaarten Lankhorst * 2. Synchronize with any outstanding nonblocking commit worker threads which
20960380c684SDaniel Vetter * might be affected by the new state update. This is handled by
20970380c684SDaniel Vetter * drm_atomic_helper_setup_commit().
2098e8c833a7SDaniel Vetter *
20999f2a7950SDaniel Vetter * Asynchronous workers need to have sufficient parallelism to be able to run
21009f2a7950SDaniel Vetter * different atomic commits on different CRTCs in parallel. The simplest way to
2101a0689e34SKieran Bingham * achieve this is by running them on the &system_unbound_wq work queue. Note
21029f2a7950SDaniel Vetter * that drivers are not required to split up atomic commits and run an
21039f2a7950SDaniel Vetter * individual commit in parallel - userspace is supposed to do that if it cares.
21049f2a7950SDaniel Vetter * But it might be beneficial to do that for modesets, since those necessarily
21059f2a7950SDaniel Vetter * must be done as one global operation, and enabling or disabling a CRTC can
21069f2a7950SDaniel Vetter * take a long time. But even that is not required.
2107e8c833a7SDaniel Vetter *
21080380c684SDaniel Vetter * IMPORTANT: A &drm_atomic_state update for multiple CRTCs is sequenced
21090380c684SDaniel Vetter * against all CRTCs therein. Therefore for atomic state updates which only flip
21100380c684SDaniel Vetter * planes the driver must not get the struct &drm_crtc_state of unrelated CRTCs
21110380c684SDaniel Vetter * in its atomic check code: This would prevent committing of atomic updates to
21120380c684SDaniel Vetter * multiple CRTCs in parallel. In general, adding additional state structures
21130380c684SDaniel Vetter * should be avoided as much as possible, because this reduces parallelism in
21140380c684SDaniel Vetter * (nonblocking) commits, both due to locking and due to commit sequencing
21150380c684SDaniel Vetter * requirements.
21160380c684SDaniel Vetter *
2117e8c833a7SDaniel Vetter * 3. The software state is updated synchronously with
211826196f7eSDaniel Vetter * drm_atomic_helper_swap_state(). Doing this under the protection of all modeset
21190380c684SDaniel Vetter * locks means concurrent callers never see inconsistent state. Note that commit
21200380c684SDaniel Vetter * workers do not hold any locks; their access is only coordinated through
21210380c684SDaniel Vetter * ordering. If workers would access state only through the pointers in the
21220380c684SDaniel Vetter * free-standing state objects (currently not the case for any driver) then even
21230380c684SDaniel Vetter * multiple pending commits could be in-flight at the same time.
2124e8c833a7SDaniel Vetter *
2125e8c833a7SDaniel Vetter * 4. Schedule a work item to do all subsequent steps, using the split-out
2126e8c833a7SDaniel Vetter * commit helpers: a) pre-plane commit b) plane commit c) post-plane commit and
2127e8c833a7SDaniel Vetter * then cleaning up the framebuffers after the old framebuffer is no longer
21280380c684SDaniel Vetter * being displayed. The scheduled work should synchronize against other workers
21290380c684SDaniel Vetter * using the &drm_crtc_commit infrastructure as needed. See
21300380c684SDaniel Vetter * drm_atomic_helper_setup_commit() for more details.
2131e8c833a7SDaniel Vetter */
2132e8c833a7SDaniel Vetter
stall_checks(struct drm_crtc * crtc,bool nonblock)2133a095caa7SDaniel Vetter static int stall_checks(struct drm_crtc *crtc, bool nonblock)
2134a095caa7SDaniel Vetter {
2135a095caa7SDaniel Vetter struct drm_crtc_commit *commit, *stall_commit = NULL;
2136a095caa7SDaniel Vetter bool completed = true;
2137a095caa7SDaniel Vetter int i;
2138a095caa7SDaniel Vetter long ret = 0;
2139a095caa7SDaniel Vetter
2140a095caa7SDaniel Vetter spin_lock(&crtc->commit_lock);
2141a095caa7SDaniel Vetter i = 0;
2142a095caa7SDaniel Vetter list_for_each_entry(commit, &crtc->commit_list, commit_entry) {
2143a095caa7SDaniel Vetter if (i == 0) {
2144a095caa7SDaniel Vetter completed = try_wait_for_completion(&commit->flip_done);
21451758f403SFabio M. De Francesco /*
21461758f403SFabio M. De Francesco * Userspace is not allowed to get ahead of the previous
21471758f403SFabio M. De Francesco * commit with nonblocking ones.
21481758f403SFabio M. De Francesco */
2149a095caa7SDaniel Vetter if (!completed && nonblock) {
2150a095caa7SDaniel Vetter spin_unlock(&crtc->commit_lock);
21516e22dc35SClaudio Suarez drm_dbg_atomic(crtc->dev,
21526e22dc35SClaudio Suarez "[CRTC:%d:%s] busy with a previous commit\n",
21539073d4edSDaniel Vetter crtc->base.id, crtc->name);
21549073d4edSDaniel Vetter
2155a095caa7SDaniel Vetter return -EBUSY;
2156a095caa7SDaniel Vetter }
2157a095caa7SDaniel Vetter } else if (i == 1) {
2158f46640b9SMaarten Lankhorst stall_commit = drm_crtc_commit_get(commit);
2159a095caa7SDaniel Vetter break;
2160723c3e55SDaniel Vetter }
2161a095caa7SDaniel Vetter
2162a095caa7SDaniel Vetter i++;
2163a095caa7SDaniel Vetter }
2164a095caa7SDaniel Vetter spin_unlock(&crtc->commit_lock);
2165a095caa7SDaniel Vetter
2166a095caa7SDaniel Vetter if (!stall_commit)
2167a095caa7SDaniel Vetter return 0;
2168a095caa7SDaniel Vetter
2169a095caa7SDaniel Vetter /* We don't want to let commits get ahead of cleanup work too much,
2170a095caa7SDaniel Vetter * stalling on 2nd previous commit means triple-buffer won't ever stall.
2171a095caa7SDaniel Vetter */
2172723c3e55SDaniel Vetter ret = wait_for_completion_interruptible_timeout(&stall_commit->cleanup_done,
2173a095caa7SDaniel Vetter 10*HZ);
2174a095caa7SDaniel Vetter if (ret == 0)
21756e22dc35SClaudio Suarez drm_err(crtc->dev, "[CRTC:%d:%s] cleanup_done timed out\n",
2176a095caa7SDaniel Vetter crtc->base.id, crtc->name);
2177a095caa7SDaniel Vetter
2178a095caa7SDaniel Vetter drm_crtc_commit_put(stall_commit);
2179a095caa7SDaniel Vetter
2180a095caa7SDaniel Vetter return ret < 0 ? ret : 0;
2181a095caa7SDaniel Vetter }
2182a095caa7SDaniel Vetter
release_crtc_commit(struct completion * completion)2183899cc5f1SWei Yongjun static void release_crtc_commit(struct completion *completion)
218424835e44SDaniel Vetter {
218524835e44SDaniel Vetter struct drm_crtc_commit *commit = container_of(completion,
218624835e44SDaniel Vetter typeof(*commit),
218724835e44SDaniel Vetter flip_done);
218824835e44SDaniel Vetter
218924835e44SDaniel Vetter drm_crtc_commit_put(commit);
219024835e44SDaniel Vetter }
219124835e44SDaniel Vetter
init_commit(struct drm_crtc_commit * commit,struct drm_crtc * crtc)219221a01abbSMaarten Lankhorst static void init_commit(struct drm_crtc_commit *commit, struct drm_crtc *crtc)
219321a01abbSMaarten Lankhorst {
219421a01abbSMaarten Lankhorst init_completion(&commit->flip_done);
219521a01abbSMaarten Lankhorst init_completion(&commit->hw_done);
219621a01abbSMaarten Lankhorst init_completion(&commit->cleanup_done);
219721a01abbSMaarten Lankhorst INIT_LIST_HEAD(&commit->commit_entry);
219821a01abbSMaarten Lankhorst kref_init(&commit->ref);
219921a01abbSMaarten Lankhorst commit->crtc = crtc;
220021a01abbSMaarten Lankhorst }
220121a01abbSMaarten Lankhorst
220221a01abbSMaarten Lankhorst static struct drm_crtc_commit *
crtc_or_fake_commit(struct drm_atomic_state * state,struct drm_crtc * crtc)220321a01abbSMaarten Lankhorst crtc_or_fake_commit(struct drm_atomic_state *state, struct drm_crtc *crtc)
220421a01abbSMaarten Lankhorst {
220521a01abbSMaarten Lankhorst if (crtc) {
220621a01abbSMaarten Lankhorst struct drm_crtc_state *new_crtc_state;
220721a01abbSMaarten Lankhorst
220821a01abbSMaarten Lankhorst new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
220921a01abbSMaarten Lankhorst
221021a01abbSMaarten Lankhorst return new_crtc_state->commit;
221121a01abbSMaarten Lankhorst }
221221a01abbSMaarten Lankhorst
221321a01abbSMaarten Lankhorst if (!state->fake_commit) {
221421a01abbSMaarten Lankhorst state->fake_commit = kzalloc(sizeof(*state->fake_commit), GFP_KERNEL);
221521a01abbSMaarten Lankhorst if (!state->fake_commit)
221621a01abbSMaarten Lankhorst return NULL;
221721a01abbSMaarten Lankhorst
221821a01abbSMaarten Lankhorst init_commit(state->fake_commit, NULL);
221921a01abbSMaarten Lankhorst }
222021a01abbSMaarten Lankhorst
222121a01abbSMaarten Lankhorst return state->fake_commit;
222221a01abbSMaarten Lankhorst }
222321a01abbSMaarten Lankhorst
2224a095caa7SDaniel Vetter /**
2225a095caa7SDaniel Vetter * drm_atomic_helper_setup_commit - setup possibly nonblocking commit
2226a095caa7SDaniel Vetter * @state: new modeset state to be committed
2227a095caa7SDaniel Vetter * @nonblock: whether nonblocking behavior is requested.
2228a095caa7SDaniel Vetter *
2229a095caa7SDaniel Vetter * This function prepares @state to be used by the atomic helper's support for
2230a095caa7SDaniel Vetter * nonblocking commits. Drivers using the nonblocking commit infrastructure
22316806cdf9SDaniel Vetter * should always call this function from their
22326806cdf9SDaniel Vetter * &drm_mode_config_funcs.atomic_commit hook.
2233a095caa7SDaniel Vetter *
2234ddadd408SMaxime Ripard * Drivers that need to extend the commit setup to private objects can use the
2235ddadd408SMaxime Ripard * &drm_mode_config_helper_funcs.atomic_commit_setup hook.
2236ddadd408SMaxime Ripard *
2237a095caa7SDaniel Vetter * To be able to use this support drivers need to use a few more helper
2238a095caa7SDaniel Vetter * functions. drm_atomic_helper_wait_for_dependencies() must be called before
2239a095caa7SDaniel Vetter * actually committing the hardware state, and for nonblocking commits this call
2240a095caa7SDaniel Vetter * must be placed in the async worker. See also drm_atomic_helper_swap_state()
22411e55a53aSMatt Roper * and its stall parameter, for when a driver's commit hooks look at the
22426806cdf9SDaniel Vetter * &drm_crtc.state, &drm_plane.state or &drm_connector.state pointer directly.
2243a095caa7SDaniel Vetter *
2244a095caa7SDaniel Vetter * Completion of the hardware commit step must be signalled using
2245a095caa7SDaniel Vetter * drm_atomic_helper_commit_hw_done(). After this step the driver is not allowed
2246a095caa7SDaniel Vetter * to read or change any permanent software or hardware modeset state. The only
2247a095caa7SDaniel Vetter * exception is state protected by other means than &drm_modeset_lock locks.
2248a095caa7SDaniel Vetter * Only the free standing @state with pointers to the old state structures can
2249a095caa7SDaniel Vetter * be inspected, e.g. to clean up old buffers using
2250a095caa7SDaniel Vetter * drm_atomic_helper_cleanup_planes().
2251a095caa7SDaniel Vetter *
2252a095caa7SDaniel Vetter * At the very end, before cleaning up @state drivers must call
2253a095caa7SDaniel Vetter * drm_atomic_helper_commit_cleanup_done().
2254a095caa7SDaniel Vetter *
2255a095caa7SDaniel Vetter * This is all implemented by in drm_atomic_helper_commit(), giving drivers a
22569ac07815SThierry Reding * complete and easy-to-use default implementation of the atomic_commit() hook.
2257a095caa7SDaniel Vetter *
2258a095caa7SDaniel Vetter * The tracking of asynchronously executed and still pending commits is done
2259a095caa7SDaniel Vetter * using the core structure &drm_crtc_commit.
2260a095caa7SDaniel Vetter *
2261a095caa7SDaniel Vetter * By default there's no need to clean up resources allocated by this function
2262a095caa7SDaniel Vetter * explicitly: drm_atomic_state_default_clear() will take care of that
2263a095caa7SDaniel Vetter * automatically.
2264a095caa7SDaniel Vetter *
2265a095caa7SDaniel Vetter * Returns:
2266a095caa7SDaniel Vetter *
2267a095caa7SDaniel Vetter * 0 on success. -EBUSY when userspace schedules nonblocking commits too fast,
2268a095caa7SDaniel Vetter * -ENOMEM on allocation failures and -EINTR when a signal is pending.
2269a095caa7SDaniel Vetter */
drm_atomic_helper_setup_commit(struct drm_atomic_state * state,bool nonblock)2270a095caa7SDaniel Vetter int drm_atomic_helper_setup_commit(struct drm_atomic_state *state,
2271a095caa7SDaniel Vetter bool nonblock)
2272a095caa7SDaniel Vetter {
2273a095caa7SDaniel Vetter struct drm_crtc *crtc;
2274415c3ac3SMaarten Lankhorst struct drm_crtc_state *old_crtc_state, *new_crtc_state;
227521a01abbSMaarten Lankhorst struct drm_connector *conn;
227621a01abbSMaarten Lankhorst struct drm_connector_state *old_conn_state, *new_conn_state;
227721a01abbSMaarten Lankhorst struct drm_plane *plane;
227821a01abbSMaarten Lankhorst struct drm_plane_state *old_plane_state, *new_plane_state;
2279a095caa7SDaniel Vetter struct drm_crtc_commit *commit;
2280ddadd408SMaxime Ripard const struct drm_mode_config_helper_funcs *funcs;
2281a095caa7SDaniel Vetter int i, ret;
2282a095caa7SDaniel Vetter
2283ddadd408SMaxime Ripard funcs = state->dev->mode_config.helper_private;
2284ddadd408SMaxime Ripard
2285415c3ac3SMaarten Lankhorst for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
2286a095caa7SDaniel Vetter commit = kzalloc(sizeof(*commit), GFP_KERNEL);
2287a095caa7SDaniel Vetter if (!commit)
2288a095caa7SDaniel Vetter return -ENOMEM;
2289a095caa7SDaniel Vetter
229021a01abbSMaarten Lankhorst init_commit(commit, crtc);
2291a095caa7SDaniel Vetter
2292163bcc2cSMaarten Lankhorst new_crtc_state->commit = commit;
2293a095caa7SDaniel Vetter
2294a095caa7SDaniel Vetter ret = stall_checks(crtc, nonblock);
2295a095caa7SDaniel Vetter if (ret)
2296a095caa7SDaniel Vetter return ret;
2297a095caa7SDaniel Vetter
22981758f403SFabio M. De Francesco /*
22991758f403SFabio M. De Francesco * Drivers only send out events when at least either current or
2300a095caa7SDaniel Vetter * new CRTC state is active. Complete right away if everything
23011758f403SFabio M. De Francesco * stays off.
23021758f403SFabio M. De Francesco */
2303415c3ac3SMaarten Lankhorst if (!old_crtc_state->active && !new_crtc_state->active) {
2304a095caa7SDaniel Vetter complete_all(&commit->flip_done);
2305a095caa7SDaniel Vetter continue;
2306a095caa7SDaniel Vetter }
2307a095caa7SDaniel Vetter
2308a095caa7SDaniel Vetter /* Legacy cursor updates are fully unsynced. */
2309a095caa7SDaniel Vetter if (state->legacy_cursor_update) {
2310a095caa7SDaniel Vetter complete_all(&commit->flip_done);
2311a095caa7SDaniel Vetter continue;
2312a095caa7SDaniel Vetter }
2313a095caa7SDaniel Vetter
2314415c3ac3SMaarten Lankhorst if (!new_crtc_state->event) {
2315a095caa7SDaniel Vetter commit->event = kzalloc(sizeof(*commit->event),
2316a095caa7SDaniel Vetter GFP_KERNEL);
2317a095caa7SDaniel Vetter if (!commit->event)
2318a095caa7SDaniel Vetter return -ENOMEM;
2319a095caa7SDaniel Vetter
2320415c3ac3SMaarten Lankhorst new_crtc_state->event = commit->event;
2321a095caa7SDaniel Vetter }
2322a095caa7SDaniel Vetter
2323415c3ac3SMaarten Lankhorst new_crtc_state->event->base.completion = &commit->flip_done;
2324415c3ac3SMaarten Lankhorst new_crtc_state->event->base.completion_release = release_crtc_commit;
232524835e44SDaniel Vetter drm_crtc_commit_get(commit);
23261c6ceeeeSLeo (Sunpeng) Li
23271c6ceeeeSLeo (Sunpeng) Li commit->abort_completion = true;
23284364bcb2SLeo Li
23294364bcb2SLeo Li state->crtcs[i].commit = commit;
23304364bcb2SLeo Li drm_crtc_commit_get(commit);
2331a095caa7SDaniel Vetter }
2332a095caa7SDaniel Vetter
233321a01abbSMaarten Lankhorst for_each_oldnew_connector_in_state(state, conn, old_conn_state, new_conn_state, i) {
23341758f403SFabio M. De Francesco /*
23351758f403SFabio M. De Francesco * Userspace is not allowed to get ahead of the previous
23361758f403SFabio M. De Francesco * commit with nonblocking ones.
23371758f403SFabio M. De Francesco */
233821a01abbSMaarten Lankhorst if (nonblock && old_conn_state->commit &&
23399073d4edSDaniel Vetter !try_wait_for_completion(&old_conn_state->commit->flip_done)) {
23406e22dc35SClaudio Suarez drm_dbg_atomic(conn->dev,
23416e22dc35SClaudio Suarez "[CONNECTOR:%d:%s] busy with a previous commit\n",
23429073d4edSDaniel Vetter conn->base.id, conn->name);
23439073d4edSDaniel Vetter
234421a01abbSMaarten Lankhorst return -EBUSY;
23459073d4edSDaniel Vetter }
234621a01abbSMaarten Lankhorst
23471f2d9bdcSDaniel Vetter /* Always track connectors explicitly for e.g. link retraining. */
23481f2d9bdcSDaniel Vetter commit = crtc_or_fake_commit(state, new_conn_state->crtc ?: old_conn_state->crtc);
234921a01abbSMaarten Lankhorst if (!commit)
235021a01abbSMaarten Lankhorst return -ENOMEM;
235121a01abbSMaarten Lankhorst
235221a01abbSMaarten Lankhorst new_conn_state->commit = drm_crtc_commit_get(commit);
235321a01abbSMaarten Lankhorst }
235421a01abbSMaarten Lankhorst
235521a01abbSMaarten Lankhorst for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {
23561758f403SFabio M. De Francesco /*
23571758f403SFabio M. De Francesco * Userspace is not allowed to get ahead of the previous
23581758f403SFabio M. De Francesco * commit with nonblocking ones.
23591758f403SFabio M. De Francesco */
236021a01abbSMaarten Lankhorst if (nonblock && old_plane_state->commit &&
23619073d4edSDaniel Vetter !try_wait_for_completion(&old_plane_state->commit->flip_done)) {
23626e22dc35SClaudio Suarez drm_dbg_atomic(plane->dev,
23636e22dc35SClaudio Suarez "[PLANE:%d:%s] busy with a previous commit\n",
23649073d4edSDaniel Vetter plane->base.id, plane->name);
23659073d4edSDaniel Vetter
236621a01abbSMaarten Lankhorst return -EBUSY;
23679073d4edSDaniel Vetter }
236821a01abbSMaarten Lankhorst
23691f2d9bdcSDaniel Vetter /* Always track planes explicitly for async pageflip support. */
23704edd6084SMaarten Lankhorst commit = crtc_or_fake_commit(state, new_plane_state->crtc ?: old_plane_state->crtc);
237121a01abbSMaarten Lankhorst if (!commit)
237221a01abbSMaarten Lankhorst return -ENOMEM;
237321a01abbSMaarten Lankhorst
237421a01abbSMaarten Lankhorst new_plane_state->commit = drm_crtc_commit_get(commit);
237521a01abbSMaarten Lankhorst }
237621a01abbSMaarten Lankhorst
2377ddadd408SMaxime Ripard if (funcs && funcs->atomic_commit_setup)
2378ddadd408SMaxime Ripard return funcs->atomic_commit_setup(state);
2379ddadd408SMaxime Ripard
2380a095caa7SDaniel Vetter return 0;
2381a095caa7SDaniel Vetter }
2382a095caa7SDaniel Vetter EXPORT_SYMBOL(drm_atomic_helper_setup_commit);
2383a095caa7SDaniel Vetter
2384a095caa7SDaniel Vetter /**
2385a095caa7SDaniel Vetter * drm_atomic_helper_wait_for_dependencies - wait for required preceeding commits
23861ea0c02eSDaniel Vetter * @old_state: atomic state object with old state structures
2387a095caa7SDaniel Vetter *
2388a095caa7SDaniel Vetter * This function waits for all preceeding commits that touch the same CRTC as
23891ea0c02eSDaniel Vetter * @old_state to both be committed to the hardware (as signalled by
23900380c684SDaniel Vetter * drm_atomic_helper_commit_hw_done()) and executed by the hardware (as signalled
2391277b09cfSThierry Reding * by calling drm_crtc_send_vblank_event() on the &drm_crtc_state.event).
2392a095caa7SDaniel Vetter *
2393a095caa7SDaniel Vetter * This is part of the atomic helper support for nonblocking commits, see
2394a095caa7SDaniel Vetter * drm_atomic_helper_setup_commit() for an overview.
2395a095caa7SDaniel Vetter */
drm_atomic_helper_wait_for_dependencies(struct drm_atomic_state * old_state)23961ea0c02eSDaniel Vetter void drm_atomic_helper_wait_for_dependencies(struct drm_atomic_state *old_state)
2397a095caa7SDaniel Vetter {
2398a095caa7SDaniel Vetter struct drm_crtc *crtc;
2399163bcc2cSMaarten Lankhorst struct drm_crtc_state *old_crtc_state;
240021a01abbSMaarten Lankhorst struct drm_plane *plane;
240121a01abbSMaarten Lankhorst struct drm_plane_state *old_plane_state;
240221a01abbSMaarten Lankhorst struct drm_connector *conn;
240321a01abbSMaarten Lankhorst struct drm_connector_state *old_conn_state;
2404a095caa7SDaniel Vetter int i;
2405a095caa7SDaniel Vetter long ret;
2406a095caa7SDaniel Vetter
2407163bcc2cSMaarten Lankhorst for_each_old_crtc_in_state(old_state, crtc, old_crtc_state, i) {
2408b99c2c95SMaxime Ripard ret = drm_crtc_commit_wait(old_crtc_state->commit);
2409b99c2c95SMaxime Ripard if (ret)
24106e22dc35SClaudio Suarez drm_err(crtc->dev,
24116e22dc35SClaudio Suarez "[CRTC:%d:%s] commit wait timed out\n",
2412a095caa7SDaniel Vetter crtc->base.id, crtc->name);
2413a095caa7SDaniel Vetter }
2414a095caa7SDaniel Vetter
241521a01abbSMaarten Lankhorst for_each_old_connector_in_state(old_state, conn, old_conn_state, i) {
2416b99c2c95SMaxime Ripard ret = drm_crtc_commit_wait(old_conn_state->commit);
2417b99c2c95SMaxime Ripard if (ret)
24186e22dc35SClaudio Suarez drm_err(conn->dev,
24196e22dc35SClaudio Suarez "[CONNECTOR:%d:%s] commit wait timed out\n",
242021a01abbSMaarten Lankhorst conn->base.id, conn->name);
242121a01abbSMaarten Lankhorst }
242221a01abbSMaarten Lankhorst
242321a01abbSMaarten Lankhorst for_each_old_plane_in_state(old_state, plane, old_plane_state, i) {
2424b99c2c95SMaxime Ripard ret = drm_crtc_commit_wait(old_plane_state->commit);
2425b99c2c95SMaxime Ripard if (ret)
24266e22dc35SClaudio Suarez drm_err(plane->dev,
24276e22dc35SClaudio Suarez "[PLANE:%d:%s] commit wait timed out\n",
242821a01abbSMaarten Lankhorst plane->base.id, plane->name);
2429a095caa7SDaniel Vetter }
2430a095caa7SDaniel Vetter }
2431a095caa7SDaniel Vetter EXPORT_SYMBOL(drm_atomic_helper_wait_for_dependencies);
2432a095caa7SDaniel Vetter
2433a095caa7SDaniel Vetter /**
2434b25c60afSBoris Brezillon * drm_atomic_helper_fake_vblank - fake VBLANK events if needed
2435b25c60afSBoris Brezillon * @old_state: atomic state object with old state structures
2436b25c60afSBoris Brezillon *
2437dbe2d2bfSThierry Reding * This function walks all CRTCs and fakes VBLANK events on those with
2438b25c60afSBoris Brezillon * &drm_crtc_state.no_vblank set to true and &drm_crtc_state.event != NULL.
2439b25c60afSBoris Brezillon * The primary use of this function is writeback connectors working in oneshot
2440b25c60afSBoris Brezillon * mode and faking VBLANK events. In this case they only fake the VBLANK event
2441b25c60afSBoris Brezillon * when a job is queued, and any change to the pipeline that does not touch the
2442b25c60afSBoris Brezillon * connector is leading to timeouts when calling
2443b25c60afSBoris Brezillon * drm_atomic_helper_wait_for_vblanks() or
24447beb691fSThomas Zimmermann * drm_atomic_helper_wait_for_flip_done(). In addition to writeback
24457beb691fSThomas Zimmermann * connectors, this function can also fake VBLANK events for CRTCs without
24467beb691fSThomas Zimmermann * VBLANK interrupt.
2447b25c60afSBoris Brezillon *
2448b25c60afSBoris Brezillon * This is part of the atomic helper support for nonblocking commits, see
2449b25c60afSBoris Brezillon * drm_atomic_helper_setup_commit() for an overview.
2450b25c60afSBoris Brezillon */
drm_atomic_helper_fake_vblank(struct drm_atomic_state * old_state)2451b25c60afSBoris Brezillon void drm_atomic_helper_fake_vblank(struct drm_atomic_state *old_state)
2452b25c60afSBoris Brezillon {
2453b25c60afSBoris Brezillon struct drm_crtc_state *new_crtc_state;
2454b25c60afSBoris Brezillon struct drm_crtc *crtc;
2455b25c60afSBoris Brezillon int i;
2456b25c60afSBoris Brezillon
2457b25c60afSBoris Brezillon for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i) {
2458b25c60afSBoris Brezillon unsigned long flags;
2459b25c60afSBoris Brezillon
2460b25c60afSBoris Brezillon if (!new_crtc_state->no_vblank)
2461b25c60afSBoris Brezillon continue;
2462b25c60afSBoris Brezillon
2463b25c60afSBoris Brezillon spin_lock_irqsave(&old_state->dev->event_lock, flags);
2464b25c60afSBoris Brezillon if (new_crtc_state->event) {
2465b25c60afSBoris Brezillon drm_crtc_send_vblank_event(crtc,
2466b25c60afSBoris Brezillon new_crtc_state->event);
2467b25c60afSBoris Brezillon new_crtc_state->event = NULL;
2468b25c60afSBoris Brezillon }
2469b25c60afSBoris Brezillon spin_unlock_irqrestore(&old_state->dev->event_lock, flags);
2470b25c60afSBoris Brezillon }
2471b25c60afSBoris Brezillon }
2472b25c60afSBoris Brezillon EXPORT_SYMBOL(drm_atomic_helper_fake_vblank);
2473b25c60afSBoris Brezillon
2474b25c60afSBoris Brezillon /**
2475a095caa7SDaniel Vetter * drm_atomic_helper_commit_hw_done - setup possible nonblocking commit
24761ea0c02eSDaniel Vetter * @old_state: atomic state object with old state structures
2477a095caa7SDaniel Vetter *
2478a095caa7SDaniel Vetter * This function is used to signal completion of the hardware commit step. After
2479a095caa7SDaniel Vetter * this step the driver is not allowed to read or change any permanent software
2480a095caa7SDaniel Vetter * or hardware modeset state. The only exception is state protected by other
2481a095caa7SDaniel Vetter * means than &drm_modeset_lock locks.
2482a095caa7SDaniel Vetter *
2483a095caa7SDaniel Vetter * Drivers should try to postpone any expensive or delayed cleanup work after
2484a095caa7SDaniel Vetter * this function is called.
2485a095caa7SDaniel Vetter *
2486a095caa7SDaniel Vetter * This is part of the atomic helper support for nonblocking commits, see
2487a095caa7SDaniel Vetter * drm_atomic_helper_setup_commit() for an overview.
2488a095caa7SDaniel Vetter */
drm_atomic_helper_commit_hw_done(struct drm_atomic_state * old_state)24891ea0c02eSDaniel Vetter void drm_atomic_helper_commit_hw_done(struct drm_atomic_state *old_state)
2490a095caa7SDaniel Vetter {
2491a095caa7SDaniel Vetter struct drm_crtc *crtc;
2492163bcc2cSMaarten Lankhorst struct drm_crtc_state *old_crtc_state, *new_crtc_state;
2493a095caa7SDaniel Vetter struct drm_crtc_commit *commit;
2494a095caa7SDaniel Vetter int i;
2495a095caa7SDaniel Vetter
2496163bcc2cSMaarten Lankhorst for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) {
2497163bcc2cSMaarten Lankhorst commit = new_crtc_state->commit;
2498a095caa7SDaniel Vetter if (!commit)
2499a095caa7SDaniel Vetter continue;
2500a095caa7SDaniel Vetter
2501163bcc2cSMaarten Lankhorst /*
2502163bcc2cSMaarten Lankhorst * copy new_crtc_state->commit to old_crtc_state->commit,
2503163bcc2cSMaarten Lankhorst * it's unsafe to touch new_crtc_state after hw_done,
2504163bcc2cSMaarten Lankhorst * but we still need to do so in cleanup_done().
2505163bcc2cSMaarten Lankhorst */
2506163bcc2cSMaarten Lankhorst if (old_crtc_state->commit)
2507163bcc2cSMaarten Lankhorst drm_crtc_commit_put(old_crtc_state->commit);
2508163bcc2cSMaarten Lankhorst
2509163bcc2cSMaarten Lankhorst old_crtc_state->commit = drm_crtc_commit_get(commit);
2510163bcc2cSMaarten Lankhorst
2511a095caa7SDaniel Vetter /* backend must have consumed any event by now */
2512415c3ac3SMaarten Lankhorst WARN_ON(new_crtc_state->event);
2513a095caa7SDaniel Vetter complete_all(&commit->hw_done);
2514a095caa7SDaniel Vetter }
251521a01abbSMaarten Lankhorst
251621a01abbSMaarten Lankhorst if (old_state->fake_commit) {
251721a01abbSMaarten Lankhorst complete_all(&old_state->fake_commit->hw_done);
251821a01abbSMaarten Lankhorst complete_all(&old_state->fake_commit->flip_done);
251921a01abbSMaarten Lankhorst }
2520a095caa7SDaniel Vetter }
2521a095caa7SDaniel Vetter EXPORT_SYMBOL(drm_atomic_helper_commit_hw_done);
2522a095caa7SDaniel Vetter
2523a095caa7SDaniel Vetter /**
2524a095caa7SDaniel Vetter * drm_atomic_helper_commit_cleanup_done - signal completion of commit
25251ea0c02eSDaniel Vetter * @old_state: atomic state object with old state structures
2526a095caa7SDaniel Vetter *
25271ea0c02eSDaniel Vetter * This signals completion of the atomic update @old_state, including any
25281ea0c02eSDaniel Vetter * cleanup work. If used, it must be called right before calling
25290853695cSChris Wilson * drm_atomic_state_put().
2530a095caa7SDaniel Vetter *
2531a095caa7SDaniel Vetter * This is part of the atomic helper support for nonblocking commits, see
2532a095caa7SDaniel Vetter * drm_atomic_helper_setup_commit() for an overview.
2533a095caa7SDaniel Vetter */
drm_atomic_helper_commit_cleanup_done(struct drm_atomic_state * old_state)25341ea0c02eSDaniel Vetter void drm_atomic_helper_commit_cleanup_done(struct drm_atomic_state *old_state)
2535a095caa7SDaniel Vetter {
2536a095caa7SDaniel Vetter struct drm_crtc *crtc;
2537163bcc2cSMaarten Lankhorst struct drm_crtc_state *old_crtc_state;
2538a095caa7SDaniel Vetter struct drm_crtc_commit *commit;
2539a095caa7SDaniel Vetter int i;
2540a095caa7SDaniel Vetter
2541163bcc2cSMaarten Lankhorst for_each_old_crtc_in_state(old_state, crtc, old_crtc_state, i) {
2542163bcc2cSMaarten Lankhorst commit = old_crtc_state->commit;
2543a095caa7SDaniel Vetter if (WARN_ON(!commit))
2544a095caa7SDaniel Vetter continue;
2545a095caa7SDaniel Vetter
2546a095caa7SDaniel Vetter complete_all(&commit->cleanup_done);
2547a095caa7SDaniel Vetter WARN_ON(!try_wait_for_completion(&commit->hw_done));
2548a095caa7SDaniel Vetter
25497141fd3eSDaniel Vetter spin_lock(&crtc->commit_lock);
2550a095caa7SDaniel Vetter list_del(&commit->commit_entry);
2551a095caa7SDaniel Vetter spin_unlock(&crtc->commit_lock);
2552a095caa7SDaniel Vetter }
255321a01abbSMaarten Lankhorst
255410a599faSVille Syrjälä if (old_state->fake_commit) {
255521a01abbSMaarten Lankhorst complete_all(&old_state->fake_commit->cleanup_done);
255610a599faSVille Syrjälä WARN_ON(!try_wait_for_completion(&old_state->fake_commit->hw_done));
255710a599faSVille Syrjälä }
2558a095caa7SDaniel Vetter }
2559a095caa7SDaniel Vetter EXPORT_SYMBOL(drm_atomic_helper_commit_cleanup_done);
2560a095caa7SDaniel Vetter
2561e8c833a7SDaniel Vetter /**
25622e3afd47SDaniel Vetter * drm_atomic_helper_prepare_planes - prepare plane resources before commit
2563c2fcd274SDaniel Vetter * @dev: DRM device
25642e3afd47SDaniel Vetter * @state: atomic state object with new state structures
2565c2fcd274SDaniel Vetter *
2566c2fcd274SDaniel Vetter * This function prepares plane state, specifically framebuffers, for the new
25676806cdf9SDaniel Vetter * configuration, by calling &drm_plane_helper_funcs.prepare_fb. If any failure
25686806cdf9SDaniel Vetter * is encountered this function will call &drm_plane_helper_funcs.cleanup_fb on
25696806cdf9SDaniel Vetter * any already successfully prepared framebuffer.
2570c2fcd274SDaniel Vetter *
2571c2fcd274SDaniel Vetter * Returns:
2572c2fcd274SDaniel Vetter * 0 on success, negative error code on failure.
2573c2fcd274SDaniel Vetter */
drm_atomic_helper_prepare_planes(struct drm_device * dev,struct drm_atomic_state * state)2574c2fcd274SDaniel Vetter int drm_atomic_helper_prepare_planes(struct drm_device *dev,
2575c2fcd274SDaniel Vetter struct drm_atomic_state *state)
2576c2fcd274SDaniel Vetter {
25779d2230dcSLaurent Pinchart struct drm_connector *connector;
25789d2230dcSLaurent Pinchart struct drm_connector_state *new_conn_state;
2579be9174a4SDaniel Vetter struct drm_plane *plane;
2580415c3ac3SMaarten Lankhorst struct drm_plane_state *new_plane_state;
2581be9174a4SDaniel Vetter int ret, i, j;
2582c2fcd274SDaniel Vetter
25839d2230dcSLaurent Pinchart for_each_new_connector_in_state(state, connector, new_conn_state, i) {
25849d2230dcSLaurent Pinchart if (!new_conn_state->writeback_job)
25859d2230dcSLaurent Pinchart continue;
25869d2230dcSLaurent Pinchart
25879d2230dcSLaurent Pinchart ret = drm_writeback_prepare_job(new_conn_state->writeback_job);
25889d2230dcSLaurent Pinchart if (ret < 0)
25899d2230dcSLaurent Pinchart return ret;
25909d2230dcSLaurent Pinchart }
25919d2230dcSLaurent Pinchart
2592415c3ac3SMaarten Lankhorst for_each_new_plane_in_state(state, plane, new_plane_state, i) {
2593b5ceff20SVille Syrjälä const struct drm_plane_helper_funcs *funcs;
2594c2fcd274SDaniel Vetter
2595c2fcd274SDaniel Vetter funcs = plane->helper_private;
2596c2fcd274SDaniel Vetter
2597844f9111SMaarten Lankhorst if (funcs->prepare_fb) {
2598415c3ac3SMaarten Lankhorst ret = funcs->prepare_fb(plane, new_plane_state);
2599c2fcd274SDaniel Vetter if (ret)
260094d879eaSThomas Zimmermann goto fail_prepare_fb;
26017d30963fSDaniel Vetter } else {
26027d30963fSDaniel Vetter WARN_ON_ONCE(funcs->cleanup_fb);
26037d30963fSDaniel Vetter
26047d30963fSDaniel Vetter if (!drm_core_check_feature(dev, DRIVER_GEM))
26057d30963fSDaniel Vetter continue;
26067d30963fSDaniel Vetter
26077d30963fSDaniel Vetter ret = drm_gem_plane_helper_prepare_fb(plane, new_plane_state);
26087d30963fSDaniel Vetter if (ret)
260994d879eaSThomas Zimmermann goto fail_prepare_fb;
261094d879eaSThomas Zimmermann }
261194d879eaSThomas Zimmermann }
261294d879eaSThomas Zimmermann
261394d879eaSThomas Zimmermann for_each_new_plane_in_state(state, plane, new_plane_state, i) {
261494d879eaSThomas Zimmermann const struct drm_plane_helper_funcs *funcs = plane->helper_private;
261594d879eaSThomas Zimmermann
261694d879eaSThomas Zimmermann if (funcs->begin_fb_access) {
261794d879eaSThomas Zimmermann ret = funcs->begin_fb_access(plane, new_plane_state);
261894d879eaSThomas Zimmermann if (ret)
261994d879eaSThomas Zimmermann goto fail_begin_fb_access;
2620c2fcd274SDaniel Vetter }
2621c2fcd274SDaniel Vetter }
2622c2fcd274SDaniel Vetter
2623c2fcd274SDaniel Vetter return 0;
2624c2fcd274SDaniel Vetter
262594d879eaSThomas Zimmermann fail_begin_fb_access:
262694d879eaSThomas Zimmermann for_each_new_plane_in_state(state, plane, new_plane_state, j) {
262794d879eaSThomas Zimmermann const struct drm_plane_helper_funcs *funcs = plane->helper_private;
262894d879eaSThomas Zimmermann
262994d879eaSThomas Zimmermann if (j >= i)
263094d879eaSThomas Zimmermann continue;
263194d879eaSThomas Zimmermann
263294d879eaSThomas Zimmermann if (funcs->end_fb_access)
263394d879eaSThomas Zimmermann funcs->end_fb_access(plane, new_plane_state);
263494d879eaSThomas Zimmermann }
263594d879eaSThomas Zimmermann i = j; /* set i to upper limit to cleanup all planes */
263694d879eaSThomas Zimmermann fail_prepare_fb:
2637415c3ac3SMaarten Lankhorst for_each_new_plane_in_state(state, plane, new_plane_state, j) {
2638b5ceff20SVille Syrjälä const struct drm_plane_helper_funcs *funcs;
2639c2fcd274SDaniel Vetter
2640be9174a4SDaniel Vetter if (j >= i)
2641c2fcd274SDaniel Vetter continue;
2642c2fcd274SDaniel Vetter
2643c2fcd274SDaniel Vetter funcs = plane->helper_private;
2644c2fcd274SDaniel Vetter
2645844f9111SMaarten Lankhorst if (funcs->cleanup_fb)
2646415c3ac3SMaarten Lankhorst funcs->cleanup_fb(plane, new_plane_state);
2647c2fcd274SDaniel Vetter }
2648c2fcd274SDaniel Vetter
2649c2fcd274SDaniel Vetter return ret;
2650c2fcd274SDaniel Vetter }
2651c2fcd274SDaniel Vetter EXPORT_SYMBOL(drm_atomic_helper_prepare_planes);
2652c2fcd274SDaniel Vetter
2653*02650b3bSThomas Zimmermann /**
2654*02650b3bSThomas Zimmermann * drm_atomic_helper_unprepare_planes - release plane resources on aborts
2655*02650b3bSThomas Zimmermann * @dev: DRM device
2656*02650b3bSThomas Zimmermann * @state: atomic state object with old state structures
2657*02650b3bSThomas Zimmermann *
2658*02650b3bSThomas Zimmermann * This function cleans up plane state, specifically framebuffers, from the
2659*02650b3bSThomas Zimmermann * atomic state. It undoes the effects of drm_atomic_helper_prepare_planes()
2660*02650b3bSThomas Zimmermann * when aborting an atomic commit. For cleaning up after a successful commit
2661*02650b3bSThomas Zimmermann * use drm_atomic_helper_cleanup_planes().
2662*02650b3bSThomas Zimmermann */
drm_atomic_helper_unprepare_planes(struct drm_device * dev,struct drm_atomic_state * state)2663*02650b3bSThomas Zimmermann void drm_atomic_helper_unprepare_planes(struct drm_device *dev,
2664*02650b3bSThomas Zimmermann struct drm_atomic_state *state)
2665*02650b3bSThomas Zimmermann {
2666*02650b3bSThomas Zimmermann struct drm_plane *plane;
2667*02650b3bSThomas Zimmermann struct drm_plane_state *new_plane_state;
2668*02650b3bSThomas Zimmermann int i;
2669*02650b3bSThomas Zimmermann
2670*02650b3bSThomas Zimmermann for_each_new_plane_in_state(state, plane, new_plane_state, i) {
2671*02650b3bSThomas Zimmermann const struct drm_plane_helper_funcs *funcs = plane->helper_private;
2672*02650b3bSThomas Zimmermann
2673*02650b3bSThomas Zimmermann if (funcs->end_fb_access)
2674*02650b3bSThomas Zimmermann funcs->end_fb_access(plane, new_plane_state);
2675*02650b3bSThomas Zimmermann }
2676*02650b3bSThomas Zimmermann
2677*02650b3bSThomas Zimmermann for_each_new_plane_in_state(state, plane, new_plane_state, i) {
2678*02650b3bSThomas Zimmermann const struct drm_plane_helper_funcs *funcs = plane->helper_private;
2679*02650b3bSThomas Zimmermann
2680*02650b3bSThomas Zimmermann if (funcs->cleanup_fb)
2681*02650b3bSThomas Zimmermann funcs->cleanup_fb(plane, new_plane_state);
2682*02650b3bSThomas Zimmermann }
2683*02650b3bSThomas Zimmermann }
2684*02650b3bSThomas Zimmermann EXPORT_SYMBOL(drm_atomic_helper_unprepare_planes);
2685*02650b3bSThomas Zimmermann
plane_crtc_active(const struct drm_plane_state * state)26867135ac54SVille Syrjälä static bool plane_crtc_active(const struct drm_plane_state *state)
2687aef9dbb8SDaniel Vetter {
2688aef9dbb8SDaniel Vetter return state->crtc && state->crtc->state->active;
2689aef9dbb8SDaniel Vetter }
2690aef9dbb8SDaniel Vetter
2691c2fcd274SDaniel Vetter /**
2692c2fcd274SDaniel Vetter * drm_atomic_helper_commit_planes - commit plane state
2693c2fcd274SDaniel Vetter * @dev: DRM device
2694b0fcfc89SDaniel Vetter * @old_state: atomic state object with old state structures
26952b58e98dSLiu Ying * @flags: flags for committing plane state
2696c2fcd274SDaniel Vetter *
2697c2fcd274SDaniel Vetter * This function commits the new plane state using the plane and atomic helper
269842240c90SThierry Reding * functions for planes and CRTCs. It assumes that the atomic state has already
2699c2fcd274SDaniel Vetter * been pushed into the relevant object state pointers, since this step can no
2700c2fcd274SDaniel Vetter * longer fail.
2701c2fcd274SDaniel Vetter *
2702b0fcfc89SDaniel Vetter * It still requires the global state object @old_state to know which planes and
2703c2fcd274SDaniel Vetter * crtcs need to be updated though.
2704de28d021SMaarten Lankhorst *
2705de28d021SMaarten Lankhorst * Note that this function does all plane updates across all CRTCs in one step.
2706de28d021SMaarten Lankhorst * If the hardware can't support this approach look at
2707de28d021SMaarten Lankhorst * drm_atomic_helper_commit_planes_on_crtc() instead.
27086e48ae32SDaniel Vetter *
27096e48ae32SDaniel Vetter * Plane parameters can be updated by applications while the associated CRTC is
27106e48ae32SDaniel Vetter * disabled. The DRM/KMS core will store the parameters in the plane state,
27116e48ae32SDaniel Vetter * which will be available to the driver when the CRTC is turned on. As a result
27126e48ae32SDaniel Vetter * most drivers don't need to be immediately notified of plane updates for a
27136e48ae32SDaniel Vetter * disabled CRTC.
27146e48ae32SDaniel Vetter *
27152b58e98dSLiu Ying * Unless otherwise needed, drivers are advised to set the ACTIVE_ONLY flag in
27162b58e98dSLiu Ying * @flags in order not to receive plane update notifications related to a
27172b58e98dSLiu Ying * disabled CRTC. This avoids the need to manually ignore plane updates in
27186e48ae32SDaniel Vetter * driver code when the driver and/or hardware can't or just don't need to deal
27196e48ae32SDaniel Vetter * with updates on disabled CRTCs, for example when supporting runtime PM.
27206e48ae32SDaniel Vetter *
27212b58e98dSLiu Ying * Drivers may set the NO_DISABLE_AFTER_MODESET flag in @flags if the relevant
27222b58e98dSLiu Ying * display controllers require to disable a CRTC's planes when the CRTC is
27236806cdf9SDaniel Vetter * disabled. This function would skip the &drm_plane_helper_funcs.atomic_disable
27246806cdf9SDaniel Vetter * call for a plane if the CRTC of the old plane state needs a modesetting
27256806cdf9SDaniel Vetter * operation. Of course, the drivers need to disable the planes in their CRTC
27266806cdf9SDaniel Vetter * disable callbacks since no one else would do that.
27272b58e98dSLiu Ying *
27282b58e98dSLiu Ying * The drm_atomic_helper_commit() default implementation doesn't set the
27292b58e98dSLiu Ying * ACTIVE_ONLY flag to most closely match the behaviour of the legacy helpers.
27302b58e98dSLiu Ying * This should not be copied blindly by drivers.
2731c2fcd274SDaniel Vetter */
drm_atomic_helper_commit_planes(struct drm_device * dev,struct drm_atomic_state * old_state,uint32_t flags)2732c2fcd274SDaniel Vetter void drm_atomic_helper_commit_planes(struct drm_device *dev,
2733aef9dbb8SDaniel Vetter struct drm_atomic_state *old_state,
27342b58e98dSLiu Ying uint32_t flags)
2735c2fcd274SDaniel Vetter {
2736df63b999SAnder Conselvan de Oliveira struct drm_crtc *crtc;
2737415c3ac3SMaarten Lankhorst struct drm_crtc_state *old_crtc_state, *new_crtc_state;
2738df63b999SAnder Conselvan de Oliveira struct drm_plane *plane;
2739415c3ac3SMaarten Lankhorst struct drm_plane_state *old_plane_state, *new_plane_state;
2740c2fcd274SDaniel Vetter int i;
27412b58e98dSLiu Ying bool active_only = flags & DRM_PLANE_COMMIT_ACTIVE_ONLY;
27422b58e98dSLiu Ying bool no_disable = flags & DRM_PLANE_COMMIT_NO_DISABLE_AFTER_MODESET;
2743c2fcd274SDaniel Vetter
2744415c3ac3SMaarten Lankhorst for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) {
2745b5ceff20SVille Syrjälä const struct drm_crtc_helper_funcs *funcs;
2746c2fcd274SDaniel Vetter
2747c2fcd274SDaniel Vetter funcs = crtc->helper_private;
2748c2fcd274SDaniel Vetter
2749c2fcd274SDaniel Vetter if (!funcs || !funcs->atomic_begin)
2750c2fcd274SDaniel Vetter continue;
2751c2fcd274SDaniel Vetter
2752415c3ac3SMaarten Lankhorst if (active_only && !new_crtc_state->active)
2753aef9dbb8SDaniel Vetter continue;
2754aef9dbb8SDaniel Vetter
2755f6ebe9f9SMaxime Ripard funcs->atomic_begin(crtc, old_state);
2756c2fcd274SDaniel Vetter }
2757c2fcd274SDaniel Vetter
2758415c3ac3SMaarten Lankhorst for_each_oldnew_plane_in_state(old_state, plane, old_plane_state, new_plane_state, i) {
2759b5ceff20SVille Syrjälä const struct drm_plane_helper_funcs *funcs;
2760216c59d6SLaurent Pinchart bool disabling;
2761c2fcd274SDaniel Vetter
2762c2fcd274SDaniel Vetter funcs = plane->helper_private;
2763c2fcd274SDaniel Vetter
27643cad4b68SThierry Reding if (!funcs)
2765c2fcd274SDaniel Vetter continue;
2766c2fcd274SDaniel Vetter
276751ffa12dSMaarten Lankhorst disabling = drm_atomic_plane_disabling(old_plane_state,
276851ffa12dSMaarten Lankhorst new_plane_state);
2769216c59d6SLaurent Pinchart
2770216c59d6SLaurent Pinchart if (active_only) {
2771216c59d6SLaurent Pinchart /*
2772216c59d6SLaurent Pinchart * Skip planes related to inactive CRTCs. If the plane
2773216c59d6SLaurent Pinchart * is enabled use the state of the current CRTC. If the
2774216c59d6SLaurent Pinchart * plane is being disabled use the state of the old
2775216c59d6SLaurent Pinchart * CRTC to avoid skipping planes being disabled on an
2776216c59d6SLaurent Pinchart * active CRTC.
2777216c59d6SLaurent Pinchart */
2778415c3ac3SMaarten Lankhorst if (!disabling && !plane_crtc_active(new_plane_state))
2779aef9dbb8SDaniel Vetter continue;
2780216c59d6SLaurent Pinchart if (disabling && !plane_crtc_active(old_plane_state))
2781216c59d6SLaurent Pinchart continue;
2782216c59d6SLaurent Pinchart }
2783aef9dbb8SDaniel Vetter
2784407b8bd9SThierry Reding /*
2785407b8bd9SThierry Reding * Special-case disabling the plane if drivers support it.
2786407b8bd9SThierry Reding */
27872b58e98dSLiu Ying if (disabling && funcs->atomic_disable) {
27882b58e98dSLiu Ying struct drm_crtc_state *crtc_state;
27892b58e98dSLiu Ying
27902b58e98dSLiu Ying crtc_state = old_plane_state->crtc->state;
27912b58e98dSLiu Ying
27922b58e98dSLiu Ying if (drm_atomic_crtc_needs_modeset(crtc_state) &&
27932b58e98dSLiu Ying no_disable)
27942b58e98dSLiu Ying continue;
27952b58e98dSLiu Ying
2796977697e2SMaxime Ripard funcs->atomic_disable(plane, old_state);
2797415c3ac3SMaarten Lankhorst } else if (new_plane_state->crtc || disabling) {
2798977697e2SMaxime Ripard funcs->atomic_update(plane, old_state);
2799169b9182SThomas Zimmermann
2800169b9182SThomas Zimmermann if (!disabling && funcs->atomic_enable) {
2801169b9182SThomas Zimmermann if (drm_atomic_plane_enabling(old_plane_state, new_plane_state))
2802169b9182SThomas Zimmermann funcs->atomic_enable(plane, old_state);
2803169b9182SThomas Zimmermann }
2804c2fcd274SDaniel Vetter }
28052b58e98dSLiu Ying }
2806c2fcd274SDaniel Vetter
2807415c3ac3SMaarten Lankhorst for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) {
2808b5ceff20SVille Syrjälä const struct drm_crtc_helper_funcs *funcs;
2809c2fcd274SDaniel Vetter
2810c2fcd274SDaniel Vetter funcs = crtc->helper_private;
2811c2fcd274SDaniel Vetter
2812c2fcd274SDaniel Vetter if (!funcs || !funcs->atomic_flush)
2813c2fcd274SDaniel Vetter continue;
2814c2fcd274SDaniel Vetter
2815415c3ac3SMaarten Lankhorst if (active_only && !new_crtc_state->active)
2816aef9dbb8SDaniel Vetter continue;
2817aef9dbb8SDaniel Vetter
2818f6ebe9f9SMaxime Ripard funcs->atomic_flush(crtc, old_state);
2819c2fcd274SDaniel Vetter }
2820*02650b3bSThomas Zimmermann
2821*02650b3bSThomas Zimmermann /*
2822*02650b3bSThomas Zimmermann * Signal end of framebuffer access here before hw_done. After hw_done,
2823*02650b3bSThomas Zimmermann * a later commit might have already released the plane state.
2824*02650b3bSThomas Zimmermann */
2825*02650b3bSThomas Zimmermann for_each_old_plane_in_state(old_state, plane, old_plane_state, i) {
2826*02650b3bSThomas Zimmermann const struct drm_plane_helper_funcs *funcs = plane->helper_private;
2827*02650b3bSThomas Zimmermann
2828*02650b3bSThomas Zimmermann if (funcs->end_fb_access)
2829*02650b3bSThomas Zimmermann funcs->end_fb_access(plane, old_plane_state);
2830*02650b3bSThomas Zimmermann }
2831c2fcd274SDaniel Vetter }
2832c2fcd274SDaniel Vetter EXPORT_SYMBOL(drm_atomic_helper_commit_planes);
2833c2fcd274SDaniel Vetter
2834c2fcd274SDaniel Vetter /**
283542240c90SThierry Reding * drm_atomic_helper_commit_planes_on_crtc - commit plane state for a CRTC
283642240c90SThierry Reding * @old_crtc_state: atomic state object with the old CRTC state
2837de28d021SMaarten Lankhorst *
2838de28d021SMaarten Lankhorst * This function commits the new plane state using the plane and atomic helper
283942240c90SThierry Reding * functions for planes on the specific CRTC. It assumes that the atomic state
2840de28d021SMaarten Lankhorst * has already been pushed into the relevant object state pointers, since this
2841de28d021SMaarten Lankhorst * step can no longer fail.
2842de28d021SMaarten Lankhorst *
284342240c90SThierry Reding * This function is useful when plane updates should be done CRTC-by-CRTC
2844de28d021SMaarten Lankhorst * instead of one global step like drm_atomic_helper_commit_planes() does.
2845de28d021SMaarten Lankhorst *
2846de28d021SMaarten Lankhorst * This function can only be savely used when planes are not allowed to move
2847de28d021SMaarten Lankhorst * between different CRTCs because this function doesn't handle inter-CRTC
28480ae865efSCai Huoqing * dependencies. Callers need to ensure that either no such dependencies exist,
2849de28d021SMaarten Lankhorst * resolve them through ordering of commit calls or through some other means.
2850de28d021SMaarten Lankhorst */
2851de28d021SMaarten Lankhorst void
drm_atomic_helper_commit_planes_on_crtc(struct drm_crtc_state * old_crtc_state)2852de28d021SMaarten Lankhorst drm_atomic_helper_commit_planes_on_crtc(struct drm_crtc_state *old_crtc_state)
2853de28d021SMaarten Lankhorst {
2854de28d021SMaarten Lankhorst const struct drm_crtc_helper_funcs *crtc_funcs;
2855de28d021SMaarten Lankhorst struct drm_crtc *crtc = old_crtc_state->crtc;
2856de28d021SMaarten Lankhorst struct drm_atomic_state *old_state = old_crtc_state->state;
2857e35a2f9aSVille Syrjälä struct drm_crtc_state *new_crtc_state =
2858e35a2f9aSVille Syrjälä drm_atomic_get_new_crtc_state(old_state, crtc);
2859de28d021SMaarten Lankhorst struct drm_plane *plane;
28609237ec1fSFabio M. De Francesco unsigned int plane_mask;
2861de28d021SMaarten Lankhorst
2862de28d021SMaarten Lankhorst plane_mask = old_crtc_state->plane_mask;
2863e35a2f9aSVille Syrjälä plane_mask |= new_crtc_state->plane_mask;
2864de28d021SMaarten Lankhorst
2865de28d021SMaarten Lankhorst crtc_funcs = crtc->helper_private;
2866de28d021SMaarten Lankhorst if (crtc_funcs && crtc_funcs->atomic_begin)
2867f6ebe9f9SMaxime Ripard crtc_funcs->atomic_begin(crtc, old_state);
2868de28d021SMaarten Lankhorst
2869de28d021SMaarten Lankhorst drm_for_each_plane_mask(plane, crtc->dev, plane_mask) {
2870de28d021SMaarten Lankhorst struct drm_plane_state *old_plane_state =
2871b4d93679SMaarten Lankhorst drm_atomic_get_old_plane_state(old_state, plane);
2872e35a2f9aSVille Syrjälä struct drm_plane_state *new_plane_state =
2873e35a2f9aSVille Syrjälä drm_atomic_get_new_plane_state(old_state, plane);
2874de28d021SMaarten Lankhorst const struct drm_plane_helper_funcs *plane_funcs;
2875169b9182SThomas Zimmermann bool disabling;
2876de28d021SMaarten Lankhorst
2877de28d021SMaarten Lankhorst plane_funcs = plane->helper_private;
2878de28d021SMaarten Lankhorst
2879de28d021SMaarten Lankhorst if (!old_plane_state || !plane_funcs)
2880de28d021SMaarten Lankhorst continue;
2881de28d021SMaarten Lankhorst
2882e35a2f9aSVille Syrjälä WARN_ON(new_plane_state->crtc &&
2883e35a2f9aSVille Syrjälä new_plane_state->crtc != crtc);
2884de28d021SMaarten Lankhorst
2885169b9182SThomas Zimmermann disabling = drm_atomic_plane_disabling(old_plane_state, new_plane_state);
2886169b9182SThomas Zimmermann
2887169b9182SThomas Zimmermann if (disabling && plane_funcs->atomic_disable) {
2888977697e2SMaxime Ripard plane_funcs->atomic_disable(plane, old_state);
2889169b9182SThomas Zimmermann } else if (new_plane_state->crtc || disabling) {
2890977697e2SMaxime Ripard plane_funcs->atomic_update(plane, old_state);
2891169b9182SThomas Zimmermann
2892169b9182SThomas Zimmermann if (!disabling && plane_funcs->atomic_enable) {
2893169b9182SThomas Zimmermann if (drm_atomic_plane_enabling(old_plane_state, new_plane_state))
2894169b9182SThomas Zimmermann plane_funcs->atomic_enable(plane, old_state);
2895169b9182SThomas Zimmermann }
2896169b9182SThomas Zimmermann }
2897de28d021SMaarten Lankhorst }
2898de28d021SMaarten Lankhorst
2899de28d021SMaarten Lankhorst if (crtc_funcs && crtc_funcs->atomic_flush)
2900f6ebe9f9SMaxime Ripard crtc_funcs->atomic_flush(crtc, old_state);
2901de28d021SMaarten Lankhorst }
2902de28d021SMaarten Lankhorst EXPORT_SYMBOL(drm_atomic_helper_commit_planes_on_crtc);
2903de28d021SMaarten Lankhorst
2904de28d021SMaarten Lankhorst /**
29056753ba97SJyri Sarha * drm_atomic_helper_disable_planes_on_crtc - helper to disable CRTC's planes
290628500291SLiu Ying * @old_crtc_state: atomic state object with the old CRTC state
29076753ba97SJyri Sarha * @atomic: if set, synchronize with CRTC's atomic_begin/flush hooks
29086753ba97SJyri Sarha *
29096753ba97SJyri Sarha * Disables all planes associated with the given CRTC. This can be
291028500291SLiu Ying * used for instance in the CRTC helper atomic_disable callback to disable
291128500291SLiu Ying * all planes.
29126753ba97SJyri Sarha *
29136753ba97SJyri Sarha * If the atomic-parameter is set the function calls the CRTC's
29146753ba97SJyri Sarha * atomic_begin hook before and atomic_flush hook after disabling the
29156753ba97SJyri Sarha * planes.
29166753ba97SJyri Sarha *
29176753ba97SJyri Sarha * It is a bug to call this function without having implemented the
29186806cdf9SDaniel Vetter * &drm_plane_helper_funcs.atomic_disable plane hook.
29196753ba97SJyri Sarha */
292028500291SLiu Ying void
drm_atomic_helper_disable_planes_on_crtc(struct drm_crtc_state * old_crtc_state,bool atomic)292128500291SLiu Ying drm_atomic_helper_disable_planes_on_crtc(struct drm_crtc_state *old_crtc_state,
29226753ba97SJyri Sarha bool atomic)
29236753ba97SJyri Sarha {
292428500291SLiu Ying struct drm_crtc *crtc = old_crtc_state->crtc;
29256753ba97SJyri Sarha const struct drm_crtc_helper_funcs *crtc_funcs =
29266753ba97SJyri Sarha crtc->helper_private;
29276753ba97SJyri Sarha struct drm_plane *plane;
29286753ba97SJyri Sarha
29296753ba97SJyri Sarha if (atomic && crtc_funcs && crtc_funcs->atomic_begin)
29306753ba97SJyri Sarha crtc_funcs->atomic_begin(crtc, NULL);
29316753ba97SJyri Sarha
293228500291SLiu Ying drm_atomic_crtc_state_for_each_plane(plane, old_crtc_state) {
29336753ba97SJyri Sarha const struct drm_plane_helper_funcs *plane_funcs =
29346753ba97SJyri Sarha plane->helper_private;
29356753ba97SJyri Sarha
293628500291SLiu Ying if (!plane_funcs)
29376753ba97SJyri Sarha continue;
29386753ba97SJyri Sarha
29396753ba97SJyri Sarha WARN_ON(!plane_funcs->atomic_disable);
29406753ba97SJyri Sarha if (plane_funcs->atomic_disable)
29416753ba97SJyri Sarha plane_funcs->atomic_disable(plane, NULL);
29426753ba97SJyri Sarha }
29436753ba97SJyri Sarha
29446753ba97SJyri Sarha if (atomic && crtc_funcs && crtc_funcs->atomic_flush)
29456753ba97SJyri Sarha crtc_funcs->atomic_flush(crtc, NULL);
29466753ba97SJyri Sarha }
29476753ba97SJyri Sarha EXPORT_SYMBOL(drm_atomic_helper_disable_planes_on_crtc);
29486753ba97SJyri Sarha
29496753ba97SJyri Sarha /**
2950c2fcd274SDaniel Vetter * drm_atomic_helper_cleanup_planes - cleanup plane resources after commit
2951c2fcd274SDaniel Vetter * @dev: DRM device
2952c2fcd274SDaniel Vetter * @old_state: atomic state object with old state structures
2953c2fcd274SDaniel Vetter *
2954c2fcd274SDaniel Vetter * This function cleans up plane state, specifically framebuffers, from the old
2955c2fcd274SDaniel Vetter * configuration. Hence the old configuration must be perserved in @old_state to
2956c2fcd274SDaniel Vetter * be able to call this function.
2957c2fcd274SDaniel Vetter *
2958*02650b3bSThomas Zimmermann * This function may not be called on the new state when the atomic update
2959*02650b3bSThomas Zimmermann * fails at any point after calling drm_atomic_helper_prepare_planes(). Use
2960*02650b3bSThomas Zimmermann * drm_atomic_helper_unprepare_planes() in this case.
2961c2fcd274SDaniel Vetter */
drm_atomic_helper_cleanup_planes(struct drm_device * dev,struct drm_atomic_state * old_state)2962c2fcd274SDaniel Vetter void drm_atomic_helper_cleanup_planes(struct drm_device *dev,
2963c2fcd274SDaniel Vetter struct drm_atomic_state *old_state)
2964c2fcd274SDaniel Vetter {
2965df63b999SAnder Conselvan de Oliveira struct drm_plane *plane;
2966*02650b3bSThomas Zimmermann struct drm_plane_state *old_plane_state;
2967c2fcd274SDaniel Vetter int i;
2968c2fcd274SDaniel Vetter
2969*02650b3bSThomas Zimmermann for_each_old_plane_in_state(old_state, plane, old_plane_state, i) {
297094d879eaSThomas Zimmermann const struct drm_plane_helper_funcs *funcs = plane->helper_private;
297194d879eaSThomas Zimmermann
2972844f9111SMaarten Lankhorst if (funcs->cleanup_fb)
2973*02650b3bSThomas Zimmermann funcs->cleanup_fb(plane, old_plane_state);
2974c2fcd274SDaniel Vetter }
2975c2fcd274SDaniel Vetter }
2976c2fcd274SDaniel Vetter EXPORT_SYMBOL(drm_atomic_helper_cleanup_planes);
2977c2fcd274SDaniel Vetter
2978c2fcd274SDaniel Vetter /**
2979c2fcd274SDaniel Vetter * drm_atomic_helper_swap_state - store atomic state into current sw state
2980c2fcd274SDaniel Vetter * @state: atomic state
29810ae865efSCai Huoqing * @stall: stall for preceding commits
2982c2fcd274SDaniel Vetter *
2983c2fcd274SDaniel Vetter * This function stores the atomic state into the current state pointers in all
2984c2fcd274SDaniel Vetter * driver objects. It should be called after all failing steps have been done
2985c2fcd274SDaniel Vetter * and succeeded, but before the actual hardware state is committed.
2986c2fcd274SDaniel Vetter *
2987c2fcd274SDaniel Vetter * For cleanup and error recovery the current state for all changed objects will
2988c066d231SMaarten Lankhorst * be swapped into @state.
2989c2fcd274SDaniel Vetter *
2990c2fcd274SDaniel Vetter * With that sequence it fits perfectly into the plane prepare/cleanup sequence:
2991c2fcd274SDaniel Vetter *
2992c2fcd274SDaniel Vetter * 1. Call drm_atomic_helper_prepare_planes() with the staged atomic state.
2993c2fcd274SDaniel Vetter *
2994c2fcd274SDaniel Vetter * 2. Do any other steps that might fail.
2995c2fcd274SDaniel Vetter *
2996c2fcd274SDaniel Vetter * 3. Put the staged state into the current state pointers with this function.
2997c2fcd274SDaniel Vetter *
2998c2fcd274SDaniel Vetter * 4. Actually commit the hardware state.
2999c2fcd274SDaniel Vetter *
300026196f7eSDaniel Vetter * 5. Call drm_atomic_helper_cleanup_planes() with @state, which since step 3
3001c2fcd274SDaniel Vetter * contains the old state. Also do any other cleanup required with that state.
3002a095caa7SDaniel Vetter *
3003a095caa7SDaniel Vetter * @stall must be set when nonblocking commits for this driver directly access
30046806cdf9SDaniel Vetter * the &drm_plane.state, &drm_crtc.state or &drm_connector.state pointer. With
30056806cdf9SDaniel Vetter * the current atomic helpers this is almost always the case, since the helpers
3006a095caa7SDaniel Vetter * don't pass the right state structures to the callbacks.
3007c066d231SMaarten Lankhorst *
3008c066d231SMaarten Lankhorst * Returns:
3009c066d231SMaarten Lankhorst *
3010c4bbb735SMaarten Lankhorst * Returns 0 on success. Can return -ERESTARTSYS when @stall is true and the
3011c4bbb735SMaarten Lankhorst * waiting for the previous commits has been interrupted.
3012c2fcd274SDaniel Vetter */
drm_atomic_helper_swap_state(struct drm_atomic_state * state,bool stall)3013c066d231SMaarten Lankhorst int drm_atomic_helper_swap_state(struct drm_atomic_state *state,
30145e84c269SDaniel Vetter bool stall)
3015c2fcd274SDaniel Vetter {
3016c4bbb735SMaarten Lankhorst int i, ret;
3017be9174a4SDaniel Vetter struct drm_connector *connector;
3018415c3ac3SMaarten Lankhorst struct drm_connector_state *old_conn_state, *new_conn_state;
3019be9174a4SDaniel Vetter struct drm_crtc *crtc;
3020415c3ac3SMaarten Lankhorst struct drm_crtc_state *old_crtc_state, *new_crtc_state;
3021be9174a4SDaniel Vetter struct drm_plane *plane;
3022415c3ac3SMaarten Lankhorst struct drm_plane_state *old_plane_state, *new_plane_state;
3023a095caa7SDaniel Vetter struct drm_crtc_commit *commit;
3024a4370c77SVille Syrjälä struct drm_private_obj *obj;
3025a4370c77SVille Syrjälä struct drm_private_state *old_obj_state, *new_obj_state;
3026a095caa7SDaniel Vetter
3027a095caa7SDaniel Vetter if (stall) {
302821a01abbSMaarten Lankhorst /*
302921a01abbSMaarten Lankhorst * We have to stall for hw_done here before
303021a01abbSMaarten Lankhorst * drm_atomic_helper_wait_for_dependencies() because flip
303121a01abbSMaarten Lankhorst * depth > 1 is not yet supported by all drivers. As long as
303221a01abbSMaarten Lankhorst * obj->state is directly dereferenced anywhere in the drivers
303321a01abbSMaarten Lankhorst * atomic_commit_tail function, then it's unsafe to swap state
303421a01abbSMaarten Lankhorst * before drm_atomic_helper_commit_hw_done() is called.
303521a01abbSMaarten Lankhorst */
303621a01abbSMaarten Lankhorst
3037163bcc2cSMaarten Lankhorst for_each_old_crtc_in_state(state, crtc, old_crtc_state, i) {
3038163bcc2cSMaarten Lankhorst commit = old_crtc_state->commit;
3039a095caa7SDaniel Vetter
3040a095caa7SDaniel Vetter if (!commit)
3041a095caa7SDaniel Vetter continue;
3042a095caa7SDaniel Vetter
3043c4bbb735SMaarten Lankhorst ret = wait_for_completion_interruptible(&commit->hw_done);
3044c4bbb735SMaarten Lankhorst if (ret)
3045c4bbb735SMaarten Lankhorst return ret;
3046a095caa7SDaniel Vetter }
3047a095caa7SDaniel Vetter
304821a01abbSMaarten Lankhorst for_each_old_connector_in_state(state, connector, old_conn_state, i) {
304921a01abbSMaarten Lankhorst commit = old_conn_state->commit;
305021a01abbSMaarten Lankhorst
305121a01abbSMaarten Lankhorst if (!commit)
305221a01abbSMaarten Lankhorst continue;
305321a01abbSMaarten Lankhorst
305421a01abbSMaarten Lankhorst ret = wait_for_completion_interruptible(&commit->hw_done);
305521a01abbSMaarten Lankhorst if (ret)
305621a01abbSMaarten Lankhorst return ret;
305721a01abbSMaarten Lankhorst }
305821a01abbSMaarten Lankhorst
305921a01abbSMaarten Lankhorst for_each_old_plane_in_state(state, plane, old_plane_state, i) {
306021a01abbSMaarten Lankhorst commit = old_plane_state->commit;
306121a01abbSMaarten Lankhorst
306221a01abbSMaarten Lankhorst if (!commit)
306321a01abbSMaarten Lankhorst continue;
306421a01abbSMaarten Lankhorst
306521a01abbSMaarten Lankhorst ret = wait_for_completion_interruptible(&commit->hw_done);
3066a095caa7SDaniel Vetter if (ret)
3067a095caa7SDaniel Vetter return ret;
3068a095caa7SDaniel Vetter }
3069a095caa7SDaniel Vetter }
3070c2fcd274SDaniel Vetter
3071415c3ac3SMaarten Lankhorst for_each_oldnew_connector_in_state(state, connector, old_conn_state, new_conn_state, i) {
3072581e49feSMaarten Lankhorst WARN_ON(connector->state != old_conn_state);
3073581e49feSMaarten Lankhorst
3074415c3ac3SMaarten Lankhorst old_conn_state->state = state;
3075415c3ac3SMaarten Lankhorst new_conn_state->state = NULL;
3076415c3ac3SMaarten Lankhorst
3077415c3ac3SMaarten Lankhorst state->connectors[i].state = old_conn_state;
3078415c3ac3SMaarten Lankhorst connector->state = new_conn_state;
3079c2fcd274SDaniel Vetter }
3080c2fcd274SDaniel Vetter
3081415c3ac3SMaarten Lankhorst for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
3082581e49feSMaarten Lankhorst WARN_ON(crtc->state != old_crtc_state);
3083581e49feSMaarten Lankhorst
3084415c3ac3SMaarten Lankhorst old_crtc_state->state = state;
3085415c3ac3SMaarten Lankhorst new_crtc_state->state = NULL;
3086415c3ac3SMaarten Lankhorst
3087415c3ac3SMaarten Lankhorst state->crtcs[i].state = old_crtc_state;
3088415c3ac3SMaarten Lankhorst crtc->state = new_crtc_state;
3089a095caa7SDaniel Vetter
3090163bcc2cSMaarten Lankhorst if (new_crtc_state->commit) {
3091a095caa7SDaniel Vetter spin_lock(&crtc->commit_lock);
3092163bcc2cSMaarten Lankhorst list_add(&new_crtc_state->commit->commit_entry,
3093a095caa7SDaniel Vetter &crtc->commit_list);
3094a095caa7SDaniel Vetter spin_unlock(&crtc->commit_lock);
3095a095caa7SDaniel Vetter
3096163bcc2cSMaarten Lankhorst new_crtc_state->commit->event = NULL;
3097a095caa7SDaniel Vetter }
3098c2fcd274SDaniel Vetter }
3099c2fcd274SDaniel Vetter
3100415c3ac3SMaarten Lankhorst for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {
3101581e49feSMaarten Lankhorst WARN_ON(plane->state != old_plane_state);
3102581e49feSMaarten Lankhorst
3103415c3ac3SMaarten Lankhorst old_plane_state->state = state;
3104415c3ac3SMaarten Lankhorst new_plane_state->state = NULL;
3105415c3ac3SMaarten Lankhorst
3106415c3ac3SMaarten Lankhorst state->planes[i].state = old_plane_state;
3107415c3ac3SMaarten Lankhorst plane->state = new_plane_state;
3108c2fcd274SDaniel Vetter }
3109b430c27aSPandiyan, Dhinakaran
3110a4370c77SVille Syrjälä for_each_oldnew_private_obj_in_state(state, obj, old_obj_state, new_obj_state, i) {
3111a4370c77SVille Syrjälä WARN_ON(obj->state != old_obj_state);
3112a4370c77SVille Syrjälä
3113a4370c77SVille Syrjälä old_obj_state->state = state;
3114a4370c77SVille Syrjälä new_obj_state->state = NULL;
3115a4370c77SVille Syrjälä
3116a4370c77SVille Syrjälä state->private_objs[i].state = old_obj_state;
3117a4370c77SVille Syrjälä obj->state = new_obj_state;
3118a4370c77SVille Syrjälä }
3119c066d231SMaarten Lankhorst
3120c066d231SMaarten Lankhorst return 0;
3121c2fcd274SDaniel Vetter }
3122c2fcd274SDaniel Vetter EXPORT_SYMBOL(drm_atomic_helper_swap_state);
3123042652edSDaniel Vetter
3124042652edSDaniel Vetter /**
3125042652edSDaniel Vetter * drm_atomic_helper_update_plane - Helper for primary plane update using atomic
3126042652edSDaniel Vetter * @plane: plane object to update
3127042652edSDaniel Vetter * @crtc: owning CRTC of owning plane
3128042652edSDaniel Vetter * @fb: framebuffer to flip onto plane
312942240c90SThierry Reding * @crtc_x: x offset of primary plane on @crtc
313042240c90SThierry Reding * @crtc_y: y offset of primary plane on @crtc
313142240c90SThierry Reding * @crtc_w: width of primary plane rectangle on @crtc
313242240c90SThierry Reding * @crtc_h: height of primary plane rectangle on @crtc
3133042652edSDaniel Vetter * @src_x: x offset of @fb for panning
3134042652edSDaniel Vetter * @src_y: y offset of @fb for panning
3135042652edSDaniel Vetter * @src_w: width of source rectangle in @fb
3136042652edSDaniel Vetter * @src_h: height of source rectangle in @fb
313734a2ab5eSDaniel Vetter * @ctx: lock acquire context
3138042652edSDaniel Vetter *
3139042652edSDaniel Vetter * Provides a default plane update handler using the atomic driver interface.
3140042652edSDaniel Vetter *
3141042652edSDaniel Vetter * RETURNS:
3142042652edSDaniel Vetter * Zero on success, error code on failure
3143042652edSDaniel Vetter */
drm_atomic_helper_update_plane(struct drm_plane * plane,struct drm_crtc * crtc,struct drm_framebuffer * fb,int crtc_x,int crtc_y,unsigned int crtc_w,unsigned int crtc_h,uint32_t src_x,uint32_t src_y,uint32_t src_w,uint32_t src_h,struct drm_modeset_acquire_ctx * ctx)3144042652edSDaniel Vetter int drm_atomic_helper_update_plane(struct drm_plane *plane,
3145042652edSDaniel Vetter struct drm_crtc *crtc,
3146042652edSDaniel Vetter struct drm_framebuffer *fb,
3147042652edSDaniel Vetter int crtc_x, int crtc_y,
3148042652edSDaniel Vetter unsigned int crtc_w, unsigned int crtc_h,
3149042652edSDaniel Vetter uint32_t src_x, uint32_t src_y,
315034a2ab5eSDaniel Vetter uint32_t src_w, uint32_t src_h,
315134a2ab5eSDaniel Vetter struct drm_modeset_acquire_ctx *ctx)
3152042652edSDaniel Vetter {
3153042652edSDaniel Vetter struct drm_atomic_state *state;
3154042652edSDaniel Vetter struct drm_plane_state *plane_state;
3155042652edSDaniel Vetter int ret = 0;
3156042652edSDaniel Vetter
3157042652edSDaniel Vetter state = drm_atomic_state_alloc(plane->dev);
3158042652edSDaniel Vetter if (!state)
3159042652edSDaniel Vetter return -ENOMEM;
3160042652edSDaniel Vetter
3161d26f96c7SDaniel Vetter state->acquire_ctx = ctx;
3162042652edSDaniel Vetter plane_state = drm_atomic_get_plane_state(state, plane);
3163042652edSDaniel Vetter if (IS_ERR(plane_state)) {
3164042652edSDaniel Vetter ret = PTR_ERR(plane_state);
3165042652edSDaniel Vetter goto fail;
3166042652edSDaniel Vetter }
3167042652edSDaniel Vetter
316807cc0ef6SDaniel Vetter ret = drm_atomic_set_crtc_for_plane(plane_state, crtc);
3169042652edSDaniel Vetter if (ret != 0)
3170042652edSDaniel Vetter goto fail;
3171321ebf04SDaniel Vetter drm_atomic_set_fb_for_plane(plane_state, fb);
3172042652edSDaniel Vetter plane_state->crtc_x = crtc_x;
3173042652edSDaniel Vetter plane_state->crtc_y = crtc_y;
3174042652edSDaniel Vetter plane_state->crtc_w = crtc_w;
317502e6f379SVille Syrjälä plane_state->crtc_h = crtc_h;
3176042652edSDaniel Vetter plane_state->src_x = src_x;
3177042652edSDaniel Vetter plane_state->src_y = src_y;
3178042652edSDaniel Vetter plane_state->src_w = src_w;
317902e6f379SVille Syrjälä plane_state->src_h = src_h;
3180042652edSDaniel Vetter
31813671c580SDaniel Vetter if (plane == crtc->cursor)
31823671c580SDaniel Vetter state->legacy_cursor_update = true;
31833671c580SDaniel Vetter
3184042652edSDaniel Vetter ret = drm_atomic_commit(state);
3185042652edSDaniel Vetter fail:
31860853695cSChris Wilson drm_atomic_state_put(state);
3187042652edSDaniel Vetter return ret;
3188042652edSDaniel Vetter }
3189042652edSDaniel Vetter EXPORT_SYMBOL(drm_atomic_helper_update_plane);
3190042652edSDaniel Vetter
3191042652edSDaniel Vetter /**
3192788557fbSSui Jingfeng * drm_atomic_helper_disable_plane - Helper for primary plane disable using atomic
3193042652edSDaniel Vetter * @plane: plane to disable
319419315294SDaniel Vetter * @ctx: lock acquire context
3195042652edSDaniel Vetter *
3196042652edSDaniel Vetter * Provides a default plane disable handler using the atomic driver interface.
3197042652edSDaniel Vetter *
3198042652edSDaniel Vetter * RETURNS:
3199042652edSDaniel Vetter * Zero on success, error code on failure
3200042652edSDaniel Vetter */
drm_atomic_helper_disable_plane(struct drm_plane * plane,struct drm_modeset_acquire_ctx * ctx)320119315294SDaniel Vetter int drm_atomic_helper_disable_plane(struct drm_plane *plane,
320219315294SDaniel Vetter struct drm_modeset_acquire_ctx *ctx)
3203042652edSDaniel Vetter {
3204042652edSDaniel Vetter struct drm_atomic_state *state;
3205042652edSDaniel Vetter struct drm_plane_state *plane_state;
3206042652edSDaniel Vetter int ret = 0;
3207042652edSDaniel Vetter
3208042652edSDaniel Vetter state = drm_atomic_state_alloc(plane->dev);
3209042652edSDaniel Vetter if (!state)
3210042652edSDaniel Vetter return -ENOMEM;
3211042652edSDaniel Vetter
3212d26f96c7SDaniel Vetter state->acquire_ctx = ctx;
3213042652edSDaniel Vetter plane_state = drm_atomic_get_plane_state(state, plane);
3214042652edSDaniel Vetter if (IS_ERR(plane_state)) {
3215042652edSDaniel Vetter ret = PTR_ERR(plane_state);
3216042652edSDaniel Vetter goto fail;
3217042652edSDaniel Vetter }
3218042652edSDaniel Vetter
3219a36c027dSVille Syrjälä if (plane_state->crtc && plane_state->crtc->cursor == plane)
322024e79d0dSMaarten Lankhorst plane_state->state->legacy_cursor_update = true;
322124e79d0dSMaarten Lankhorst
3222bbb1e524SRob Clark ret = __drm_atomic_helper_disable_plane(plane, plane_state);
3223042652edSDaniel Vetter if (ret != 0)
3224042652edSDaniel Vetter goto fail;
3225f02ad907SDaniel Vetter
3226042652edSDaniel Vetter ret = drm_atomic_commit(state);
3227042652edSDaniel Vetter fail:
32280853695cSChris Wilson drm_atomic_state_put(state);
3229042652edSDaniel Vetter return ret;
3230042652edSDaniel Vetter }
3231042652edSDaniel Vetter EXPORT_SYMBOL(drm_atomic_helper_disable_plane);
3232042652edSDaniel Vetter
3233042652edSDaniel Vetter /**
3234042652edSDaniel Vetter * drm_atomic_helper_set_config - set a new config from userspace
3235042652edSDaniel Vetter * @set: mode set configuration
3236a4eff9aaSDaniel Vetter * @ctx: lock acquisition context
3237042652edSDaniel Vetter *
323842240c90SThierry Reding * Provides a default CRTC set_config handler using the atomic driver interface.
3239042652edSDaniel Vetter *
324040ee6fbeSManasi Navare * NOTE: For backwards compatibility with old userspace this automatically
324140ee6fbeSManasi Navare * resets the "link-status" property to GOOD, to force any link
324240ee6fbeSManasi Navare * re-training. The SETCRTC ioctl does not define whether an update does
324340ee6fbeSManasi Navare * need a full modeset or just a plane update, hence we're allowed to do
324497e14fbeSDaniel Vetter * that. See also drm_connector_set_link_status_property().
324540ee6fbeSManasi Navare *
3246042652edSDaniel Vetter * Returns:
3247042652edSDaniel Vetter * Returns 0 on success, negative errno numbers on failure.
3248042652edSDaniel Vetter */
drm_atomic_helper_set_config(struct drm_mode_set * set,struct drm_modeset_acquire_ctx * ctx)3249a4eff9aaSDaniel Vetter int drm_atomic_helper_set_config(struct drm_mode_set *set,
3250a4eff9aaSDaniel Vetter struct drm_modeset_acquire_ctx *ctx)
3251042652edSDaniel Vetter {
3252042652edSDaniel Vetter struct drm_atomic_state *state;
3253042652edSDaniel Vetter struct drm_crtc *crtc = set->crtc;
3254042652edSDaniel Vetter int ret = 0;
3255042652edSDaniel Vetter
3256042652edSDaniel Vetter state = drm_atomic_state_alloc(crtc->dev);
3257042652edSDaniel Vetter if (!state)
3258042652edSDaniel Vetter return -ENOMEM;
3259042652edSDaniel Vetter
326038b6441eSDaniel Vetter state->acquire_ctx = ctx;
3261bbb1e524SRob Clark ret = __drm_atomic_helper_set_config(set, state);
3262819364daSDaniel Stone if (ret != 0)
32631fa4da04SDaniel Vetter goto fail;
3264819364daSDaniel Stone
326544596b8cSMaarten Lankhorst ret = handle_conflicting_encoders(state, true);
326644596b8cSMaarten Lankhorst if (ret)
326743b67309SPan Bian goto fail;
326844596b8cSMaarten Lankhorst
3269042652edSDaniel Vetter ret = drm_atomic_commit(state);
3270042652edSDaniel Vetter
32711fa4da04SDaniel Vetter fail:
32720853695cSChris Wilson drm_atomic_state_put(state);
3273042652edSDaniel Vetter return ret;
3274042652edSDaniel Vetter }
3275042652edSDaniel Vetter EXPORT_SYMBOL(drm_atomic_helper_set_config);
3276042652edSDaniel Vetter
327737406a60SSean Paul /**
327837406a60SSean Paul * drm_atomic_helper_disable_all - disable all currently active outputs
327937406a60SSean Paul * @dev: DRM device
328037406a60SSean Paul * @ctx: lock acquisition context
328137406a60SSean Paul *
328237406a60SSean Paul * Loops through all connectors, finding those that aren't turned off and then
328337406a60SSean Paul * turns them off by setting their DPMS mode to OFF and deactivating the CRTC
328437406a60SSean Paul * that they are connected to.
328537406a60SSean Paul *
328637406a60SSean Paul * This is used for example in suspend/resume to disable all currently active
328737406a60SSean Paul * functions when suspending. If you just want to shut down everything at e.g.
328837406a60SSean Paul * driver unload, look at drm_atomic_helper_shutdown().
328937406a60SSean Paul *
329037406a60SSean Paul * Note that if callers haven't already acquired all modeset locks this might
329137406a60SSean Paul * return -EDEADLK, which must be handled by calling drm_modeset_backoff().
329237406a60SSean Paul *
329337406a60SSean Paul * Returns:
329437406a60SSean Paul * 0 on success or a negative error code on failure.
329537406a60SSean Paul *
329637406a60SSean Paul * See also:
329737406a60SSean Paul * drm_atomic_helper_suspend(), drm_atomic_helper_resume() and
329837406a60SSean Paul * drm_atomic_helper_shutdown().
329937406a60SSean Paul */
drm_atomic_helper_disable_all(struct drm_device * dev,struct drm_modeset_acquire_ctx * ctx)330037406a60SSean Paul int drm_atomic_helper_disable_all(struct drm_device *dev,
330137406a60SSean Paul struct drm_modeset_acquire_ctx *ctx)
330214942760SThierry Reding {
330314942760SThierry Reding struct drm_atomic_state *state;
33049b2104f4SMaarten Lankhorst struct drm_connector_state *conn_state;
330514942760SThierry Reding struct drm_connector *conn;
33069b2104f4SMaarten Lankhorst struct drm_plane_state *plane_state;
33079b2104f4SMaarten Lankhorst struct drm_plane *plane;
33089b2104f4SMaarten Lankhorst struct drm_crtc_state *crtc_state;
33099b2104f4SMaarten Lankhorst struct drm_crtc *crtc;
33109b2104f4SMaarten Lankhorst int ret, i;
331114942760SThierry Reding
331214942760SThierry Reding state = drm_atomic_state_alloc(dev);
331314942760SThierry Reding if (!state)
331414942760SThierry Reding return -ENOMEM;
331514942760SThierry Reding
331614942760SThierry Reding state->acquire_ctx = ctx;
331714942760SThierry Reding
33189b2104f4SMaarten Lankhorst drm_for_each_crtc(crtc, dev) {
331914942760SThierry Reding crtc_state = drm_atomic_get_crtc_state(state, crtc);
332014942760SThierry Reding if (IS_ERR(crtc_state)) {
33219b2104f4SMaarten Lankhorst ret = PTR_ERR(crtc_state);
332214942760SThierry Reding goto free;
332314942760SThierry Reding }
332414942760SThierry Reding
332514942760SThierry Reding crtc_state->active = false;
33269b2104f4SMaarten Lankhorst
33279b2104f4SMaarten Lankhorst ret = drm_atomic_set_mode_prop_for_crtc(crtc_state, NULL);
33289b2104f4SMaarten Lankhorst if (ret < 0)
33299b2104f4SMaarten Lankhorst goto free;
33309b2104f4SMaarten Lankhorst
33319b2104f4SMaarten Lankhorst ret = drm_atomic_add_affected_planes(state, crtc);
33329b2104f4SMaarten Lankhorst if (ret < 0)
33339b2104f4SMaarten Lankhorst goto free;
33349b2104f4SMaarten Lankhorst
33359b2104f4SMaarten Lankhorst ret = drm_atomic_add_affected_connectors(state, crtc);
33369b2104f4SMaarten Lankhorst if (ret < 0)
33379b2104f4SMaarten Lankhorst goto free;
333814942760SThierry Reding }
333914942760SThierry Reding
3340dfb8bb3bSMaarten Lankhorst for_each_new_connector_in_state(state, conn, conn_state, i) {
33419b2104f4SMaarten Lankhorst ret = drm_atomic_set_crtc_for_connector(conn_state, NULL);
33429b2104f4SMaarten Lankhorst if (ret < 0)
33439b2104f4SMaarten Lankhorst goto free;
334414942760SThierry Reding }
33459b2104f4SMaarten Lankhorst
3346dfb8bb3bSMaarten Lankhorst for_each_new_plane_in_state(state, plane, plane_state, i) {
33479b2104f4SMaarten Lankhorst ret = drm_atomic_set_crtc_for_plane(plane_state, NULL);
33489b2104f4SMaarten Lankhorst if (ret < 0)
33499b2104f4SMaarten Lankhorst goto free;
33509b2104f4SMaarten Lankhorst
33519b2104f4SMaarten Lankhorst drm_atomic_set_fb_for_plane(plane_state, NULL);
33529b2104f4SMaarten Lankhorst }
33539b2104f4SMaarten Lankhorst
33549b2104f4SMaarten Lankhorst ret = drm_atomic_commit(state);
33559b2104f4SMaarten Lankhorst free:
33569b2104f4SMaarten Lankhorst drm_atomic_state_put(state);
33579b2104f4SMaarten Lankhorst return ret;
33589b2104f4SMaarten Lankhorst }
335914942760SThierry Reding EXPORT_SYMBOL(drm_atomic_helper_disable_all);
336014942760SThierry Reding
336114942760SThierry Reding /**
336218dddadcSDaniel Vetter * drm_atomic_helper_shutdown - shutdown all CRTC
336318dddadcSDaniel Vetter * @dev: DRM device
336418dddadcSDaniel Vetter *
336518dddadcSDaniel Vetter * This shuts down all CRTC, which is useful for driver unloading. Shutdown on
336618dddadcSDaniel Vetter * suspend should instead be handled with drm_atomic_helper_suspend(), since
336718dddadcSDaniel Vetter * that also takes a snapshot of the modeset state to be restored on resume.
336818dddadcSDaniel Vetter *
336918dddadcSDaniel Vetter * This is just a convenience wrapper around drm_atomic_helper_disable_all(),
33705d408ce8SGeert Uytterhoeven * and it is the atomic version of drm_helper_force_disable_all().
337118dddadcSDaniel Vetter */
drm_atomic_helper_shutdown(struct drm_device * dev)337218dddadcSDaniel Vetter void drm_atomic_helper_shutdown(struct drm_device *dev)
337318dddadcSDaniel Vetter {
337418dddadcSDaniel Vetter struct drm_modeset_acquire_ctx ctx;
337518dddadcSDaniel Vetter int ret;
337618dddadcSDaniel Vetter
3377b7ea04d2SSean Paul DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret);
3378b7ea04d2SSean Paul
337937406a60SSean Paul ret = drm_atomic_helper_disable_all(dev, &ctx);
338018dddadcSDaniel Vetter if (ret)
33816e22dc35SClaudio Suarez drm_err(dev,
33826e22dc35SClaudio Suarez "Disabling all crtc's during unload failed with %i\n",
33836e22dc35SClaudio Suarez ret);
338418dddadcSDaniel Vetter
338577ef3857SDaniel Vetter DRM_MODESET_LOCK_ALL_END(dev, ctx, ret);
338618dddadcSDaniel Vetter }
338718dddadcSDaniel Vetter EXPORT_SYMBOL(drm_atomic_helper_shutdown);
338818dddadcSDaniel Vetter
338918dddadcSDaniel Vetter /**
33901d8224e7SDaniel Vetter * drm_atomic_helper_duplicate_state - duplicate an atomic state object
33911d8224e7SDaniel Vetter * @dev: DRM device
33921d8224e7SDaniel Vetter * @ctx: lock acquisition context
33931d8224e7SDaniel Vetter *
33941d8224e7SDaniel Vetter * Makes a copy of the current atomic state by looping over all objects and
33951d8224e7SDaniel Vetter * duplicating their respective states. This is used for example by suspend/
33961d8224e7SDaniel Vetter * resume support code to save the state prior to suspend such that it can
33971d8224e7SDaniel Vetter * be restored upon resume.
33981d8224e7SDaniel Vetter *
33991d8224e7SDaniel Vetter * Note that this treats atomic state as persistent between save and restore.
34001d8224e7SDaniel Vetter * Drivers must make sure that this is possible and won't result in confusion
34011d8224e7SDaniel Vetter * or erroneous behaviour.
34021d8224e7SDaniel Vetter *
34031d8224e7SDaniel Vetter * Note that if callers haven't already acquired all modeset locks this might
34041d8224e7SDaniel Vetter * return -EDEADLK, which must be handled by calling drm_modeset_backoff().
34051d8224e7SDaniel Vetter *
34061d8224e7SDaniel Vetter * Returns:
34071d8224e7SDaniel Vetter * A pointer to the copy of the atomic state object on success or an
34081d8224e7SDaniel Vetter * ERR_PTR()-encoded error code on failure.
34091d8224e7SDaniel Vetter *
34101d8224e7SDaniel Vetter * See also:
34111d8224e7SDaniel Vetter * drm_atomic_helper_suspend(), drm_atomic_helper_resume()
34121d8224e7SDaniel Vetter */
34131d8224e7SDaniel Vetter struct drm_atomic_state *
drm_atomic_helper_duplicate_state(struct drm_device * dev,struct drm_modeset_acquire_ctx * ctx)34141d8224e7SDaniel Vetter drm_atomic_helper_duplicate_state(struct drm_device *dev,
34151d8224e7SDaniel Vetter struct drm_modeset_acquire_ctx *ctx)
34161d8224e7SDaniel Vetter {
34171d8224e7SDaniel Vetter struct drm_atomic_state *state;
34181d8224e7SDaniel Vetter struct drm_connector *conn;
34191d8224e7SDaniel Vetter struct drm_connector_list_iter conn_iter;
34201d8224e7SDaniel Vetter struct drm_plane *plane;
34211d8224e7SDaniel Vetter struct drm_crtc *crtc;
34221d8224e7SDaniel Vetter int err = 0;
34231d8224e7SDaniel Vetter
34241d8224e7SDaniel Vetter state = drm_atomic_state_alloc(dev);
34251d8224e7SDaniel Vetter if (!state)
34261d8224e7SDaniel Vetter return ERR_PTR(-ENOMEM);
34271d8224e7SDaniel Vetter
34281d8224e7SDaniel Vetter state->acquire_ctx = ctx;
3429022debadSLyude Paul state->duplicated = true;
34301d8224e7SDaniel Vetter
34311d8224e7SDaniel Vetter drm_for_each_crtc(crtc, dev) {
34321d8224e7SDaniel Vetter struct drm_crtc_state *crtc_state;
34331d8224e7SDaniel Vetter
34341d8224e7SDaniel Vetter crtc_state = drm_atomic_get_crtc_state(state, crtc);
34351d8224e7SDaniel Vetter if (IS_ERR(crtc_state)) {
34361d8224e7SDaniel Vetter err = PTR_ERR(crtc_state);
34371d8224e7SDaniel Vetter goto free;
34381d8224e7SDaniel Vetter }
34391d8224e7SDaniel Vetter }
34401d8224e7SDaniel Vetter
34411d8224e7SDaniel Vetter drm_for_each_plane(plane, dev) {
34421d8224e7SDaniel Vetter struct drm_plane_state *plane_state;
34431d8224e7SDaniel Vetter
34441d8224e7SDaniel Vetter plane_state = drm_atomic_get_plane_state(state, plane);
34451d8224e7SDaniel Vetter if (IS_ERR(plane_state)) {
34461d8224e7SDaniel Vetter err = PTR_ERR(plane_state);
34471d8224e7SDaniel Vetter goto free;
34481d8224e7SDaniel Vetter }
34491d8224e7SDaniel Vetter }
34501d8224e7SDaniel Vetter
34511d8224e7SDaniel Vetter drm_connector_list_iter_begin(dev, &conn_iter);
34521d8224e7SDaniel Vetter drm_for_each_connector_iter(conn, &conn_iter) {
34531d8224e7SDaniel Vetter struct drm_connector_state *conn_state;
34541d8224e7SDaniel Vetter
34551d8224e7SDaniel Vetter conn_state = drm_atomic_get_connector_state(state, conn);
34561d8224e7SDaniel Vetter if (IS_ERR(conn_state)) {
34571d8224e7SDaniel Vetter err = PTR_ERR(conn_state);
34581d8224e7SDaniel Vetter drm_connector_list_iter_end(&conn_iter);
34591d8224e7SDaniel Vetter goto free;
34601d8224e7SDaniel Vetter }
34611d8224e7SDaniel Vetter }
34621d8224e7SDaniel Vetter drm_connector_list_iter_end(&conn_iter);
34631d8224e7SDaniel Vetter
34641d8224e7SDaniel Vetter /* clear the acquire context so that it isn't accidentally reused */
34651d8224e7SDaniel Vetter state->acquire_ctx = NULL;
34661d8224e7SDaniel Vetter
34671d8224e7SDaniel Vetter free:
34681d8224e7SDaniel Vetter if (err < 0) {
34691d8224e7SDaniel Vetter drm_atomic_state_put(state);
34701d8224e7SDaniel Vetter state = ERR_PTR(err);
34711d8224e7SDaniel Vetter }
34721d8224e7SDaniel Vetter
34731d8224e7SDaniel Vetter return state;
34741d8224e7SDaniel Vetter }
34751d8224e7SDaniel Vetter EXPORT_SYMBOL(drm_atomic_helper_duplicate_state);
34761d8224e7SDaniel Vetter
34771d8224e7SDaniel Vetter /**
347814942760SThierry Reding * drm_atomic_helper_suspend - subsystem-level suspend helper
347914942760SThierry Reding * @dev: DRM device
348014942760SThierry Reding *
348114942760SThierry Reding * Duplicates the current atomic state, disables all active outputs and then
348214942760SThierry Reding * returns a pointer to the original atomic state to the caller. Drivers can
348314942760SThierry Reding * pass this pointer to the drm_atomic_helper_resume() helper upon resume to
348414942760SThierry Reding * restore the output configuration that was active at the time the system
348514942760SThierry Reding * entered suspend.
348614942760SThierry Reding *
348714942760SThierry Reding * Note that it is potentially unsafe to use this. The atomic state object
348814942760SThierry Reding * returned by this function is assumed to be persistent. Drivers must ensure
348914942760SThierry Reding * that this holds true. Before calling this function, drivers must make sure
349014942760SThierry Reding * to suspend fbdev emulation so that nothing can be using the device.
349114942760SThierry Reding *
349214942760SThierry Reding * Returns:
349314942760SThierry Reding * A pointer to a copy of the state before suspend on success or an ERR_PTR()-
349414942760SThierry Reding * encoded error code on failure. Drivers should store the returned atomic
349514942760SThierry Reding * state object and pass it to the drm_atomic_helper_resume() helper upon
349614942760SThierry Reding * resume.
349714942760SThierry Reding *
349814942760SThierry Reding * See also:
349914942760SThierry Reding * drm_atomic_helper_duplicate_state(), drm_atomic_helper_disable_all(),
3500581e49feSMaarten Lankhorst * drm_atomic_helper_resume(), drm_atomic_helper_commit_duplicated_state()
350114942760SThierry Reding */
drm_atomic_helper_suspend(struct drm_device * dev)350214942760SThierry Reding struct drm_atomic_state *drm_atomic_helper_suspend(struct drm_device *dev)
350314942760SThierry Reding {
350414942760SThierry Reding struct drm_modeset_acquire_ctx ctx;
350514942760SThierry Reding struct drm_atomic_state *state;
350614942760SThierry Reding int err;
350714942760SThierry Reding
3508615aa3d9SSean Paul /* This can never be returned, but it makes the compiler happy */
3509615aa3d9SSean Paul state = ERR_PTR(-EINVAL);
351014942760SThierry Reding
3511b7ea04d2SSean Paul DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, err);
351214942760SThierry Reding
351314942760SThierry Reding state = drm_atomic_helper_duplicate_state(dev, &ctx);
351414942760SThierry Reding if (IS_ERR(state))
351514942760SThierry Reding goto unlock;
351614942760SThierry Reding
351714942760SThierry Reding err = drm_atomic_helper_disable_all(dev, &ctx);
351814942760SThierry Reding if (err < 0) {
35190853695cSChris Wilson drm_atomic_state_put(state);
352014942760SThierry Reding state = ERR_PTR(err);
352114942760SThierry Reding goto unlock;
352214942760SThierry Reding }
352314942760SThierry Reding
352414942760SThierry Reding unlock:
352577ef3857SDaniel Vetter DRM_MODESET_LOCK_ALL_END(dev, ctx, err);
3526b7ea04d2SSean Paul if (err)
3527b7ea04d2SSean Paul return ERR_PTR(err);
352814942760SThierry Reding
352914942760SThierry Reding return state;
353014942760SThierry Reding }
353114942760SThierry Reding EXPORT_SYMBOL(drm_atomic_helper_suspend);
353214942760SThierry Reding
353314942760SThierry Reding /**
3534581e49feSMaarten Lankhorst * drm_atomic_helper_commit_duplicated_state - commit duplicated state
3535581e49feSMaarten Lankhorst * @state: duplicated atomic state to commit
3536581e49feSMaarten Lankhorst * @ctx: pointer to acquire_ctx to use for commit.
3537581e49feSMaarten Lankhorst *
3538581e49feSMaarten Lankhorst * The state returned by drm_atomic_helper_duplicate_state() and
3539581e49feSMaarten Lankhorst * drm_atomic_helper_suspend() is partially invalid, and needs to
3540581e49feSMaarten Lankhorst * be fixed up before commit.
3541581e49feSMaarten Lankhorst *
3542581e49feSMaarten Lankhorst * Returns:
3543581e49feSMaarten Lankhorst * 0 on success or a negative error code on failure.
3544581e49feSMaarten Lankhorst *
3545581e49feSMaarten Lankhorst * See also:
3546581e49feSMaarten Lankhorst * drm_atomic_helper_suspend()
3547581e49feSMaarten Lankhorst */
drm_atomic_helper_commit_duplicated_state(struct drm_atomic_state * state,struct drm_modeset_acquire_ctx * ctx)3548581e49feSMaarten Lankhorst int drm_atomic_helper_commit_duplicated_state(struct drm_atomic_state *state,
3549581e49feSMaarten Lankhorst struct drm_modeset_acquire_ctx *ctx)
3550581e49feSMaarten Lankhorst {
3551aa394b0dSSean Paul int i, ret;
3552581e49feSMaarten Lankhorst struct drm_plane *plane;
3553415c3ac3SMaarten Lankhorst struct drm_plane_state *new_plane_state;
3554581e49feSMaarten Lankhorst struct drm_connector *connector;
3555415c3ac3SMaarten Lankhorst struct drm_connector_state *new_conn_state;
3556581e49feSMaarten Lankhorst struct drm_crtc *crtc;
3557415c3ac3SMaarten Lankhorst struct drm_crtc_state *new_crtc_state;
3558581e49feSMaarten Lankhorst
3559581e49feSMaarten Lankhorst state->acquire_ctx = ctx;
3560581e49feSMaarten Lankhorst
3561e00fb856SVille Syrjälä for_each_new_plane_in_state(state, plane, new_plane_state, i)
3562581e49feSMaarten Lankhorst state->planes[i].old_state = plane->state;
3563581e49feSMaarten Lankhorst
3564415c3ac3SMaarten Lankhorst for_each_new_crtc_in_state(state, crtc, new_crtc_state, i)
3565581e49feSMaarten Lankhorst state->crtcs[i].old_state = crtc->state;
3566581e49feSMaarten Lankhorst
3567415c3ac3SMaarten Lankhorst for_each_new_connector_in_state(state, connector, new_conn_state, i)
3568581e49feSMaarten Lankhorst state->connectors[i].old_state = connector->state;
3569581e49feSMaarten Lankhorst
3570aa394b0dSSean Paul ret = drm_atomic_commit(state);
3571aa394b0dSSean Paul
3572aa394b0dSSean Paul state->acquire_ctx = NULL;
3573aa394b0dSSean Paul
3574aa394b0dSSean Paul return ret;
3575581e49feSMaarten Lankhorst }
3576581e49feSMaarten Lankhorst EXPORT_SYMBOL(drm_atomic_helper_commit_duplicated_state);
3577581e49feSMaarten Lankhorst
3578581e49feSMaarten Lankhorst /**
357914942760SThierry Reding * drm_atomic_helper_resume - subsystem-level resume helper
358014942760SThierry Reding * @dev: DRM device
358114942760SThierry Reding * @state: atomic state to resume to
358214942760SThierry Reding *
358314942760SThierry Reding * Calls drm_mode_config_reset() to synchronize hardware and software states,
358414942760SThierry Reding * grabs all modeset locks and commits the atomic state object. This can be
358514942760SThierry Reding * used in conjunction with the drm_atomic_helper_suspend() helper to
358614942760SThierry Reding * implement suspend/resume for drivers that support atomic mode-setting.
358714942760SThierry Reding *
358814942760SThierry Reding * Returns:
358914942760SThierry Reding * 0 on success or a negative error code on failure.
359014942760SThierry Reding *
359114942760SThierry Reding * See also:
359214942760SThierry Reding * drm_atomic_helper_suspend()
359314942760SThierry Reding */
drm_atomic_helper_resume(struct drm_device * dev,struct drm_atomic_state * state)359414942760SThierry Reding int drm_atomic_helper_resume(struct drm_device *dev,
359514942760SThierry Reding struct drm_atomic_state *state)
359614942760SThierry Reding {
3597a5b8444eSDaniel Vetter struct drm_modeset_acquire_ctx ctx;
359814942760SThierry Reding int err;
359914942760SThierry Reding
360014942760SThierry Reding drm_mode_config_reset(dev);
3601581e49feSMaarten Lankhorst
3602b7ea04d2SSean Paul DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, err);
3603869e188aSDaniel Vetter
3604a5b8444eSDaniel Vetter err = drm_atomic_helper_commit_duplicated_state(state, &ctx);
3605a5b8444eSDaniel Vetter
360677ef3857SDaniel Vetter DRM_MODESET_LOCK_ALL_END(dev, ctx, err);
36076d281b1fSJeffy Chen drm_atomic_state_put(state);
360814942760SThierry Reding
360914942760SThierry Reding return err;
361014942760SThierry Reding }
361114942760SThierry Reding EXPORT_SYMBOL(drm_atomic_helper_resume);
361214942760SThierry Reding
page_flip_common(struct drm_atomic_state * state,struct drm_crtc * crtc,struct drm_framebuffer * fb,struct drm_pending_vblank_event * event,uint32_t flags)36138c3a8181SDaniel Vetter static int page_flip_common(struct drm_atomic_state *state,
3614f869a6ecSAndrey Grodzovsky struct drm_crtc *crtc,
3615f869a6ecSAndrey Grodzovsky struct drm_framebuffer *fb,
36166cbe5c46SAndrey Grodzovsky struct drm_pending_vblank_event *event,
36176cbe5c46SAndrey Grodzovsky uint32_t flags)
3618f869a6ecSAndrey Grodzovsky {
3619f869a6ecSAndrey Grodzovsky struct drm_plane *plane = crtc->primary;
3620f869a6ecSAndrey Grodzovsky struct drm_plane_state *plane_state;
3621f869a6ecSAndrey Grodzovsky struct drm_crtc_state *crtc_state;
3622f869a6ecSAndrey Grodzovsky int ret = 0;
3623f869a6ecSAndrey Grodzovsky
3624f869a6ecSAndrey Grodzovsky crtc_state = drm_atomic_get_crtc_state(state, crtc);
3625f869a6ecSAndrey Grodzovsky if (IS_ERR(crtc_state))
3626f869a6ecSAndrey Grodzovsky return PTR_ERR(crtc_state);
3627f869a6ecSAndrey Grodzovsky
3628f869a6ecSAndrey Grodzovsky crtc_state->event = event;
36294d85f45cSDaniel Vetter crtc_state->async_flip = flags & DRM_MODE_PAGE_FLIP_ASYNC;
3630f869a6ecSAndrey Grodzovsky
3631f869a6ecSAndrey Grodzovsky plane_state = drm_atomic_get_plane_state(state, plane);
3632f869a6ecSAndrey Grodzovsky if (IS_ERR(plane_state))
3633f869a6ecSAndrey Grodzovsky return PTR_ERR(plane_state);
3634f869a6ecSAndrey Grodzovsky
3635f869a6ecSAndrey Grodzovsky ret = drm_atomic_set_crtc_for_plane(plane_state, crtc);
3636f869a6ecSAndrey Grodzovsky if (ret != 0)
3637f869a6ecSAndrey Grodzovsky return ret;
3638f869a6ecSAndrey Grodzovsky drm_atomic_set_fb_for_plane(plane_state, fb);
3639f869a6ecSAndrey Grodzovsky
3640f869a6ecSAndrey Grodzovsky /* Make sure we don't accidentally do a full modeset. */
3641f869a6ecSAndrey Grodzovsky state->allow_modeset = false;
3642f869a6ecSAndrey Grodzovsky if (!crtc_state->active) {
36436e22dc35SClaudio Suarez drm_dbg_atomic(crtc->dev,
36446e22dc35SClaudio Suarez "[CRTC:%d:%s] disabled, rejecting legacy flip\n",
36456ac7c548SRussell King crtc->base.id, crtc->name);
3646f869a6ecSAndrey Grodzovsky return -EINVAL;
3647f869a6ecSAndrey Grodzovsky }
3648f869a6ecSAndrey Grodzovsky
3649f869a6ecSAndrey Grodzovsky return ret;
3650f869a6ecSAndrey Grodzovsky }
3651f869a6ecSAndrey Grodzovsky
36528bc0f312SDaniel Vetter /**
36538bc0f312SDaniel Vetter * drm_atomic_helper_page_flip - execute a legacy page flip
365442240c90SThierry Reding * @crtc: DRM CRTC
36558bc0f312SDaniel Vetter * @fb: DRM framebuffer
36568bc0f312SDaniel Vetter * @event: optional DRM event to signal upon completion
36578bc0f312SDaniel Vetter * @flags: flip flags for non-vblank sync'ed updates
365841292b1fSDaniel Vetter * @ctx: lock acquisition context
36598bc0f312SDaniel Vetter *
3660f869a6ecSAndrey Grodzovsky * Provides a default &drm_crtc_funcs.page_flip implementation
3661f869a6ecSAndrey Grodzovsky * using the atomic driver interface.
36628bc0f312SDaniel Vetter *
36638bc0f312SDaniel Vetter * Returns:
36648bc0f312SDaniel Vetter * Returns 0 on success, negative errno numbers on failure.
3665f869a6ecSAndrey Grodzovsky *
3666f869a6ecSAndrey Grodzovsky * See also:
3667f869a6ecSAndrey Grodzovsky * drm_atomic_helper_page_flip_target()
36688bc0f312SDaniel Vetter */
drm_atomic_helper_page_flip(struct drm_crtc * crtc,struct drm_framebuffer * fb,struct drm_pending_vblank_event * event,uint32_t flags,struct drm_modeset_acquire_ctx * ctx)36698bc0f312SDaniel Vetter int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
36708bc0f312SDaniel Vetter struct drm_framebuffer *fb,
36718bc0f312SDaniel Vetter struct drm_pending_vblank_event *event,
367241292b1fSDaniel Vetter uint32_t flags,
367341292b1fSDaniel Vetter struct drm_modeset_acquire_ctx *ctx)
36748bc0f312SDaniel Vetter {
36758bc0f312SDaniel Vetter struct drm_plane *plane = crtc->primary;
36768bc0f312SDaniel Vetter struct drm_atomic_state *state;
36778bc0f312SDaniel Vetter int ret = 0;
36788bc0f312SDaniel Vetter
36798bc0f312SDaniel Vetter state = drm_atomic_state_alloc(plane->dev);
36808bc0f312SDaniel Vetter if (!state)
36818bc0f312SDaniel Vetter return -ENOMEM;
36828bc0f312SDaniel Vetter
3683043e7fb6SDaniel Vetter state->acquire_ctx = ctx;
3684f869a6ecSAndrey Grodzovsky
36856cbe5c46SAndrey Grodzovsky ret = page_flip_common(state, crtc, fb, event, flags);
36868bc0f312SDaniel Vetter if (ret != 0)
36878bc0f312SDaniel Vetter goto fail;
36884cba6850SDaniel Vetter
3689b837ba0aSMaarten Lankhorst ret = drm_atomic_nonblocking_commit(state);
36908bc0f312SDaniel Vetter fail:
36910853695cSChris Wilson drm_atomic_state_put(state);
36928bc0f312SDaniel Vetter return ret;
36938bc0f312SDaniel Vetter }
36948bc0f312SDaniel Vetter EXPORT_SYMBOL(drm_atomic_helper_page_flip);
3695d461701cSDaniel Vetter
3696d461701cSDaniel Vetter /**
3697f869a6ecSAndrey Grodzovsky * drm_atomic_helper_page_flip_target - do page flip on target vblank period.
369842240c90SThierry Reding * @crtc: DRM CRTC
3699f869a6ecSAndrey Grodzovsky * @fb: DRM framebuffer
3700f869a6ecSAndrey Grodzovsky * @event: optional DRM event to signal upon completion
3701f869a6ecSAndrey Grodzovsky * @flags: flip flags for non-vblank sync'ed updates
3702f869a6ecSAndrey Grodzovsky * @target: specifying the target vblank period when the flip to take effect
370341292b1fSDaniel Vetter * @ctx: lock acquisition context
3704f869a6ecSAndrey Grodzovsky *
3705f869a6ecSAndrey Grodzovsky * Provides a default &drm_crtc_funcs.page_flip_target implementation.
3706f869a6ecSAndrey Grodzovsky * Similar to drm_atomic_helper_page_flip() with extra parameter to specify
3707f869a6ecSAndrey Grodzovsky * target vblank period to flip.
3708f869a6ecSAndrey Grodzovsky *
3709f869a6ecSAndrey Grodzovsky * Returns:
3710f869a6ecSAndrey Grodzovsky * Returns 0 on success, negative errno numbers on failure.
3711f869a6ecSAndrey Grodzovsky */
drm_atomic_helper_page_flip_target(struct drm_crtc * crtc,struct drm_framebuffer * fb,struct drm_pending_vblank_event * event,uint32_t flags,uint32_t target,struct drm_modeset_acquire_ctx * ctx)37128c3a8181SDaniel Vetter int drm_atomic_helper_page_flip_target(struct drm_crtc *crtc,
3713f869a6ecSAndrey Grodzovsky struct drm_framebuffer *fb,
3714f869a6ecSAndrey Grodzovsky struct drm_pending_vblank_event *event,
3715f869a6ecSAndrey Grodzovsky uint32_t flags,
371641292b1fSDaniel Vetter uint32_t target,
371741292b1fSDaniel Vetter struct drm_modeset_acquire_ctx *ctx)
3718f869a6ecSAndrey Grodzovsky {
3719f869a6ecSAndrey Grodzovsky struct drm_plane *plane = crtc->primary;
3720f869a6ecSAndrey Grodzovsky struct drm_atomic_state *state;
3721f869a6ecSAndrey Grodzovsky struct drm_crtc_state *crtc_state;
3722f869a6ecSAndrey Grodzovsky int ret = 0;
3723f869a6ecSAndrey Grodzovsky
3724f869a6ecSAndrey Grodzovsky state = drm_atomic_state_alloc(plane->dev);
3725f869a6ecSAndrey Grodzovsky if (!state)
3726f869a6ecSAndrey Grodzovsky return -ENOMEM;
3727f869a6ecSAndrey Grodzovsky
3728043e7fb6SDaniel Vetter state->acquire_ctx = ctx;
3729f869a6ecSAndrey Grodzovsky
37306cbe5c46SAndrey Grodzovsky ret = page_flip_common(state, crtc, fb, event, flags);
3731f869a6ecSAndrey Grodzovsky if (ret != 0)
3732f869a6ecSAndrey Grodzovsky goto fail;
3733f869a6ecSAndrey Grodzovsky
3734b4d93679SMaarten Lankhorst crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
3735f869a6ecSAndrey Grodzovsky if (WARN_ON(!crtc_state)) {
3736f869a6ecSAndrey Grodzovsky ret = -EINVAL;
3737f869a6ecSAndrey Grodzovsky goto fail;
3738f869a6ecSAndrey Grodzovsky }
3739f869a6ecSAndrey Grodzovsky crtc_state->target_vblank = target;
3740f869a6ecSAndrey Grodzovsky
3741f869a6ecSAndrey Grodzovsky ret = drm_atomic_nonblocking_commit(state);
3742f869a6ecSAndrey Grodzovsky fail:
3743f869a6ecSAndrey Grodzovsky drm_atomic_state_put(state);
3744f869a6ecSAndrey Grodzovsky return ret;
3745f869a6ecSAndrey Grodzovsky }
3746f869a6ecSAndrey Grodzovsky EXPORT_SYMBOL(drm_atomic_helper_page_flip_target);
37471d8224e7SDaniel Vetter
37481d8224e7SDaniel Vetter /**
3749f32df58aSBoris Brezillon * drm_atomic_helper_bridge_propagate_bus_fmt() - Propagate output format to
3750f32df58aSBoris Brezillon * the input end of a bridge
3751f32df58aSBoris Brezillon * @bridge: bridge control structure
3752f32df58aSBoris Brezillon * @bridge_state: new bridge state
3753f32df58aSBoris Brezillon * @crtc_state: new CRTC state
3754f32df58aSBoris Brezillon * @conn_state: new connector state
3755f32df58aSBoris Brezillon * @output_fmt: tested output bus format
3756f32df58aSBoris Brezillon * @num_input_fmts: will contain the size of the returned array
3757f32df58aSBoris Brezillon *
3758f32df58aSBoris Brezillon * This helper is a pluggable implementation of the
3759f32df58aSBoris Brezillon * &drm_bridge_funcs.atomic_get_input_bus_fmts operation for bridges that don't
3760f32df58aSBoris Brezillon * modify the bus configuration between their input and their output. It
3761f32df58aSBoris Brezillon * returns an array of input formats with a single element set to @output_fmt.
3762f32df58aSBoris Brezillon *
3763f32df58aSBoris Brezillon * RETURNS:
3764f32df58aSBoris Brezillon * a valid format array of size @num_input_fmts, or NULL if the allocation
3765f32df58aSBoris Brezillon * failed
3766f32df58aSBoris Brezillon */
3767f32df58aSBoris Brezillon u32 *
drm_atomic_helper_bridge_propagate_bus_fmt(struct drm_bridge * bridge,struct drm_bridge_state * bridge_state,struct drm_crtc_state * crtc_state,struct drm_connector_state * conn_state,u32 output_fmt,unsigned int * num_input_fmts)3768f32df58aSBoris Brezillon drm_atomic_helper_bridge_propagate_bus_fmt(struct drm_bridge *bridge,
3769f32df58aSBoris Brezillon struct drm_bridge_state *bridge_state,
3770f32df58aSBoris Brezillon struct drm_crtc_state *crtc_state,
3771f32df58aSBoris Brezillon struct drm_connector_state *conn_state,
3772f32df58aSBoris Brezillon u32 output_fmt,
3773f32df58aSBoris Brezillon unsigned int *num_input_fmts)
3774f32df58aSBoris Brezillon {
3775f32df58aSBoris Brezillon u32 *input_fmts;
3776f32df58aSBoris Brezillon
3777f32df58aSBoris Brezillon input_fmts = kzalloc(sizeof(*input_fmts), GFP_KERNEL);
3778f32df58aSBoris Brezillon if (!input_fmts) {
3779f32df58aSBoris Brezillon *num_input_fmts = 0;
3780f32df58aSBoris Brezillon return NULL;
3781f32df58aSBoris Brezillon }
3782f32df58aSBoris Brezillon
3783f32df58aSBoris Brezillon *num_input_fmts = 1;
3784f32df58aSBoris Brezillon input_fmts[0] = output_fmt;
3785f32df58aSBoris Brezillon return input_fmts;
3786f32df58aSBoris Brezillon }
3787f32df58aSBoris Brezillon EXPORT_SYMBOL(drm_atomic_helper_bridge_propagate_bus_fmt);
3788