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