18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (C) 2014 Red Hat
38c2ecf20Sopenharmony_ci * Copyright (C) 2014 Intel Corp.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
68c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
78c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation
88c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
98c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
108c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included in
138c2ecf20Sopenharmony_ci * all copies or substantial portions of the Software.
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
168c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
178c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
188c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
198c2ecf20Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
208c2ecf20Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
218c2ecf20Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
228c2ecf20Sopenharmony_ci *
238c2ecf20Sopenharmony_ci * Authors:
248c2ecf20Sopenharmony_ci * Rob Clark <robdclark@gmail.com>
258c2ecf20Sopenharmony_ci * Daniel Vetter <daniel.vetter@ffwll.ch>
268c2ecf20Sopenharmony_ci */
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#include <linux/dma-fence.h>
298c2ecf20Sopenharmony_ci#include <linux/ktime.h>
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#include <drm/drm_atomic.h>
328c2ecf20Sopenharmony_ci#include <drm/drm_atomic_helper.h>
338c2ecf20Sopenharmony_ci#include <drm/drm_atomic_uapi.h>
348c2ecf20Sopenharmony_ci#include <drm/drm_bridge.h>
358c2ecf20Sopenharmony_ci#include <drm/drm_damage_helper.h>
368c2ecf20Sopenharmony_ci#include <drm/drm_device.h>
378c2ecf20Sopenharmony_ci#include <drm/drm_drv.h>
388c2ecf20Sopenharmony_ci#include <drm/drm_plane_helper.h>
398c2ecf20Sopenharmony_ci#include <drm/drm_print.h>
408c2ecf20Sopenharmony_ci#include <drm/drm_self_refresh_helper.h>
418c2ecf20Sopenharmony_ci#include <drm/drm_vblank.h>
428c2ecf20Sopenharmony_ci#include <drm/drm_writeback.h>
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci#include "drm_crtc_helper_internal.h"
458c2ecf20Sopenharmony_ci#include "drm_crtc_internal.h"
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci/**
488c2ecf20Sopenharmony_ci * DOC: overview
498c2ecf20Sopenharmony_ci *
508c2ecf20Sopenharmony_ci * This helper library provides implementations of check and commit functions on
518c2ecf20Sopenharmony_ci * top of the CRTC modeset helper callbacks and the plane helper callbacks. It
528c2ecf20Sopenharmony_ci * also provides convenience implementations for the atomic state handling
538c2ecf20Sopenharmony_ci * callbacks for drivers which don't need to subclass the drm core structures to
548c2ecf20Sopenharmony_ci * add their own additional internal state.
558c2ecf20Sopenharmony_ci *
568c2ecf20Sopenharmony_ci * This library also provides default implementations for the check callback in
578c2ecf20Sopenharmony_ci * drm_atomic_helper_check() and for the commit callback with
588c2ecf20Sopenharmony_ci * drm_atomic_helper_commit(). But the individual stages and callbacks are
598c2ecf20Sopenharmony_ci * exposed to allow drivers to mix and match and e.g. use the plane helpers only
608c2ecf20Sopenharmony_ci * together with a driver private modeset implementation.
618c2ecf20Sopenharmony_ci *
628c2ecf20Sopenharmony_ci * This library also provides implementations for all the legacy driver
638c2ecf20Sopenharmony_ci * interfaces on top of the atomic interface. See drm_atomic_helper_set_config(),
648c2ecf20Sopenharmony_ci * drm_atomic_helper_disable_plane(), drm_atomic_helper_disable_plane() and the
658c2ecf20Sopenharmony_ci * various functions to implement set_property callbacks. New drivers must not
668c2ecf20Sopenharmony_ci * implement these functions themselves but must use the provided helpers.
678c2ecf20Sopenharmony_ci *
688c2ecf20Sopenharmony_ci * The atomic helper uses the same function table structures as all other
698c2ecf20Sopenharmony_ci * modesetting helpers. See the documentation for &struct drm_crtc_helper_funcs,
708c2ecf20Sopenharmony_ci * struct &drm_encoder_helper_funcs and &struct drm_connector_helper_funcs. It
718c2ecf20Sopenharmony_ci * also shares the &struct drm_plane_helper_funcs function table with the plane
728c2ecf20Sopenharmony_ci * helpers.
738c2ecf20Sopenharmony_ci */
748c2ecf20Sopenharmony_cistatic void
758c2ecf20Sopenharmony_cidrm_atomic_helper_plane_changed(struct drm_atomic_state *state,
768c2ecf20Sopenharmony_ci				struct drm_plane_state *old_plane_state,
778c2ecf20Sopenharmony_ci				struct drm_plane_state *plane_state,
788c2ecf20Sopenharmony_ci				struct drm_plane *plane)
798c2ecf20Sopenharmony_ci{
808c2ecf20Sopenharmony_ci	struct drm_crtc_state *crtc_state;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	if (old_plane_state->crtc) {
838c2ecf20Sopenharmony_ci		crtc_state = drm_atomic_get_new_crtc_state(state,
848c2ecf20Sopenharmony_ci							   old_plane_state->crtc);
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci		if (WARN_ON(!crtc_state))
878c2ecf20Sopenharmony_ci			return;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci		crtc_state->planes_changed = true;
908c2ecf20Sopenharmony_ci	}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	if (plane_state->crtc) {
938c2ecf20Sopenharmony_ci		crtc_state = drm_atomic_get_new_crtc_state(state, plane_state->crtc);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci		if (WARN_ON(!crtc_state))
968c2ecf20Sopenharmony_ci			return;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci		crtc_state->planes_changed = true;
998c2ecf20Sopenharmony_ci	}
1008c2ecf20Sopenharmony_ci}
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_cistatic int handle_conflicting_encoders(struct drm_atomic_state *state,
1038c2ecf20Sopenharmony_ci				       bool disable_conflicting_encoders)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	struct drm_connector_state *new_conn_state;
1068c2ecf20Sopenharmony_ci	struct drm_connector *connector;
1078c2ecf20Sopenharmony_ci	struct drm_connector_list_iter conn_iter;
1088c2ecf20Sopenharmony_ci	struct drm_encoder *encoder;
1098c2ecf20Sopenharmony_ci	unsigned encoder_mask = 0;
1108c2ecf20Sopenharmony_ci	int i, ret = 0;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	/*
1138c2ecf20Sopenharmony_ci	 * First loop, find all newly assigned encoders from the connectors
1148c2ecf20Sopenharmony_ci	 * part of the state. If the same encoder is assigned to multiple
1158c2ecf20Sopenharmony_ci	 * connectors bail out.
1168c2ecf20Sopenharmony_ci	 */
1178c2ecf20Sopenharmony_ci	for_each_new_connector_in_state(state, connector, new_conn_state, i) {
1188c2ecf20Sopenharmony_ci		const struct drm_connector_helper_funcs *funcs = connector->helper_private;
1198c2ecf20Sopenharmony_ci		struct drm_encoder *new_encoder;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci		if (!new_conn_state->crtc)
1228c2ecf20Sopenharmony_ci			continue;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci		if (funcs->atomic_best_encoder)
1258c2ecf20Sopenharmony_ci			new_encoder = funcs->atomic_best_encoder(connector, new_conn_state);
1268c2ecf20Sopenharmony_ci		else if (funcs->best_encoder)
1278c2ecf20Sopenharmony_ci			new_encoder = funcs->best_encoder(connector);
1288c2ecf20Sopenharmony_ci		else
1298c2ecf20Sopenharmony_ci			new_encoder = drm_connector_get_single_encoder(connector);
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci		if (new_encoder) {
1328c2ecf20Sopenharmony_ci			if (encoder_mask & drm_encoder_mask(new_encoder)) {
1338c2ecf20Sopenharmony_ci				DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] on [CONNECTOR:%d:%s] already assigned\n",
1348c2ecf20Sopenharmony_ci					new_encoder->base.id, new_encoder->name,
1358c2ecf20Sopenharmony_ci					connector->base.id, connector->name);
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci				return -EINVAL;
1388c2ecf20Sopenharmony_ci			}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci			encoder_mask |= drm_encoder_mask(new_encoder);
1418c2ecf20Sopenharmony_ci		}
1428c2ecf20Sopenharmony_ci	}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	if (!encoder_mask)
1458c2ecf20Sopenharmony_ci		return 0;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	/*
1488c2ecf20Sopenharmony_ci	 * Second loop, iterate over all connectors not part of the state.
1498c2ecf20Sopenharmony_ci	 *
1508c2ecf20Sopenharmony_ci	 * If a conflicting encoder is found and disable_conflicting_encoders
1518c2ecf20Sopenharmony_ci	 * is not set, an error is returned. Userspace can provide a solution
1528c2ecf20Sopenharmony_ci	 * through the atomic ioctl.
1538c2ecf20Sopenharmony_ci	 *
1548c2ecf20Sopenharmony_ci	 * If the flag is set conflicting connectors are removed from the CRTC
1558c2ecf20Sopenharmony_ci	 * and the CRTC is disabled if no encoder is left. This preserves
1568c2ecf20Sopenharmony_ci	 * compatibility with the legacy set_config behavior.
1578c2ecf20Sopenharmony_ci	 */
1588c2ecf20Sopenharmony_ci	drm_connector_list_iter_begin(state->dev, &conn_iter);
1598c2ecf20Sopenharmony_ci	drm_for_each_connector_iter(connector, &conn_iter) {
1608c2ecf20Sopenharmony_ci		struct drm_crtc_state *crtc_state;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci		if (drm_atomic_get_new_connector_state(state, connector))
1638c2ecf20Sopenharmony_ci			continue;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci		encoder = connector->state->best_encoder;
1668c2ecf20Sopenharmony_ci		if (!encoder || !(encoder_mask & drm_encoder_mask(encoder)))
1678c2ecf20Sopenharmony_ci			continue;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci		if (!disable_conflicting_encoders) {
1708c2ecf20Sopenharmony_ci			DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] in use on [CRTC:%d:%s] by [CONNECTOR:%d:%s]\n",
1718c2ecf20Sopenharmony_ci					 encoder->base.id, encoder->name,
1728c2ecf20Sopenharmony_ci					 connector->state->crtc->base.id,
1738c2ecf20Sopenharmony_ci					 connector->state->crtc->name,
1748c2ecf20Sopenharmony_ci					 connector->base.id, connector->name);
1758c2ecf20Sopenharmony_ci			ret = -EINVAL;
1768c2ecf20Sopenharmony_ci			goto out;
1778c2ecf20Sopenharmony_ci		}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci		new_conn_state = drm_atomic_get_connector_state(state, connector);
1808c2ecf20Sopenharmony_ci		if (IS_ERR(new_conn_state)) {
1818c2ecf20Sopenharmony_ci			ret = PTR_ERR(new_conn_state);
1828c2ecf20Sopenharmony_ci			goto out;
1838c2ecf20Sopenharmony_ci		}
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci		DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] in use on [CRTC:%d:%s], disabling [CONNECTOR:%d:%s]\n",
1868c2ecf20Sopenharmony_ci				 encoder->base.id, encoder->name,
1878c2ecf20Sopenharmony_ci				 new_conn_state->crtc->base.id, new_conn_state->crtc->name,
1888c2ecf20Sopenharmony_ci				 connector->base.id, connector->name);
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci		crtc_state = drm_atomic_get_new_crtc_state(state, new_conn_state->crtc);
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci		ret = drm_atomic_set_crtc_for_connector(new_conn_state, NULL);
1938c2ecf20Sopenharmony_ci		if (ret)
1948c2ecf20Sopenharmony_ci			goto out;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci		if (!crtc_state->connector_mask) {
1978c2ecf20Sopenharmony_ci			ret = drm_atomic_set_mode_prop_for_crtc(crtc_state,
1988c2ecf20Sopenharmony_ci								NULL);
1998c2ecf20Sopenharmony_ci			if (ret < 0)
2008c2ecf20Sopenharmony_ci				goto out;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci			crtc_state->active = false;
2038c2ecf20Sopenharmony_ci		}
2048c2ecf20Sopenharmony_ci	}
2058c2ecf20Sopenharmony_ciout:
2068c2ecf20Sopenharmony_ci	drm_connector_list_iter_end(&conn_iter);
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	return ret;
2098c2ecf20Sopenharmony_ci}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_cistatic void
2128c2ecf20Sopenharmony_ciset_best_encoder(struct drm_atomic_state *state,
2138c2ecf20Sopenharmony_ci		 struct drm_connector_state *conn_state,
2148c2ecf20Sopenharmony_ci		 struct drm_encoder *encoder)
2158c2ecf20Sopenharmony_ci{
2168c2ecf20Sopenharmony_ci	struct drm_crtc_state *crtc_state;
2178c2ecf20Sopenharmony_ci	struct drm_crtc *crtc;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	if (conn_state->best_encoder) {
2208c2ecf20Sopenharmony_ci		/* Unset the encoder_mask in the old crtc state. */
2218c2ecf20Sopenharmony_ci		crtc = conn_state->connector->state->crtc;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci		/* A NULL crtc is an error here because we should have
2248c2ecf20Sopenharmony_ci		 * duplicated a NULL best_encoder when crtc was NULL.
2258c2ecf20Sopenharmony_ci		 * As an exception restoring duplicated atomic state
2268c2ecf20Sopenharmony_ci		 * during resume is allowed, so don't warn when
2278c2ecf20Sopenharmony_ci		 * best_encoder is equal to encoder we intend to set.
2288c2ecf20Sopenharmony_ci		 */
2298c2ecf20Sopenharmony_ci		WARN_ON(!crtc && encoder != conn_state->best_encoder);
2308c2ecf20Sopenharmony_ci		if (crtc) {
2318c2ecf20Sopenharmony_ci			crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci			crtc_state->encoder_mask &=
2348c2ecf20Sopenharmony_ci				~drm_encoder_mask(conn_state->best_encoder);
2358c2ecf20Sopenharmony_ci		}
2368c2ecf20Sopenharmony_ci	}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	if (encoder) {
2398c2ecf20Sopenharmony_ci		crtc = conn_state->crtc;
2408c2ecf20Sopenharmony_ci		WARN_ON(!crtc);
2418c2ecf20Sopenharmony_ci		if (crtc) {
2428c2ecf20Sopenharmony_ci			crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci			crtc_state->encoder_mask |=
2458c2ecf20Sopenharmony_ci				drm_encoder_mask(encoder);
2468c2ecf20Sopenharmony_ci		}
2478c2ecf20Sopenharmony_ci	}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	conn_state->best_encoder = encoder;
2508c2ecf20Sopenharmony_ci}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_cistatic void
2538c2ecf20Sopenharmony_cisteal_encoder(struct drm_atomic_state *state,
2548c2ecf20Sopenharmony_ci	      struct drm_encoder *encoder)
2558c2ecf20Sopenharmony_ci{
2568c2ecf20Sopenharmony_ci	struct drm_crtc_state *crtc_state;
2578c2ecf20Sopenharmony_ci	struct drm_connector *connector;
2588c2ecf20Sopenharmony_ci	struct drm_connector_state *old_connector_state, *new_connector_state;
2598c2ecf20Sopenharmony_ci	int i;
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	for_each_oldnew_connector_in_state(state, connector, old_connector_state, new_connector_state, i) {
2628c2ecf20Sopenharmony_ci		struct drm_crtc *encoder_crtc;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci		if (new_connector_state->best_encoder != encoder)
2658c2ecf20Sopenharmony_ci			continue;
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci		encoder_crtc = old_connector_state->crtc;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci		DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] in use on [CRTC:%d:%s], stealing it\n",
2708c2ecf20Sopenharmony_ci				 encoder->base.id, encoder->name,
2718c2ecf20Sopenharmony_ci				 encoder_crtc->base.id, encoder_crtc->name);
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci		set_best_encoder(state, new_connector_state, NULL);
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci		crtc_state = drm_atomic_get_new_crtc_state(state, encoder_crtc);
2768c2ecf20Sopenharmony_ci		crtc_state->connectors_changed = true;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci		return;
2798c2ecf20Sopenharmony_ci	}
2808c2ecf20Sopenharmony_ci}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_cistatic int
2838c2ecf20Sopenharmony_ciupdate_connector_routing(struct drm_atomic_state *state,
2848c2ecf20Sopenharmony_ci			 struct drm_connector *connector,
2858c2ecf20Sopenharmony_ci			 struct drm_connector_state *old_connector_state,
2868c2ecf20Sopenharmony_ci			 struct drm_connector_state *new_connector_state)
2878c2ecf20Sopenharmony_ci{
2888c2ecf20Sopenharmony_ci	const struct drm_connector_helper_funcs *funcs;
2898c2ecf20Sopenharmony_ci	struct drm_encoder *new_encoder;
2908c2ecf20Sopenharmony_ci	struct drm_crtc_state *crtc_state;
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	DRM_DEBUG_ATOMIC("Updating routing for [CONNECTOR:%d:%s]\n",
2938c2ecf20Sopenharmony_ci			 connector->base.id,
2948c2ecf20Sopenharmony_ci			 connector->name);
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	if (old_connector_state->crtc != new_connector_state->crtc) {
2978c2ecf20Sopenharmony_ci		if (old_connector_state->crtc) {
2988c2ecf20Sopenharmony_ci			crtc_state = drm_atomic_get_new_crtc_state(state, old_connector_state->crtc);
2998c2ecf20Sopenharmony_ci			crtc_state->connectors_changed = true;
3008c2ecf20Sopenharmony_ci		}
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci		if (new_connector_state->crtc) {
3038c2ecf20Sopenharmony_ci			crtc_state = drm_atomic_get_new_crtc_state(state, new_connector_state->crtc);
3048c2ecf20Sopenharmony_ci			crtc_state->connectors_changed = true;
3058c2ecf20Sopenharmony_ci		}
3068c2ecf20Sopenharmony_ci	}
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	if (!new_connector_state->crtc) {
3098c2ecf20Sopenharmony_ci		DRM_DEBUG_ATOMIC("Disabling [CONNECTOR:%d:%s]\n",
3108c2ecf20Sopenharmony_ci				connector->base.id,
3118c2ecf20Sopenharmony_ci				connector->name);
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci		set_best_encoder(state, new_connector_state, NULL);
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci		return 0;
3168c2ecf20Sopenharmony_ci	}
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	crtc_state = drm_atomic_get_new_crtc_state(state,
3198c2ecf20Sopenharmony_ci						   new_connector_state->crtc);
3208c2ecf20Sopenharmony_ci	/*
3218c2ecf20Sopenharmony_ci	 * For compatibility with legacy users, we want to make sure that
3228c2ecf20Sopenharmony_ci	 * we allow DPMS On->Off modesets on unregistered connectors. Modesets
3238c2ecf20Sopenharmony_ci	 * which would result in anything else must be considered invalid, to
3248c2ecf20Sopenharmony_ci	 * avoid turning on new displays on dead connectors.
3258c2ecf20Sopenharmony_ci	 *
3268c2ecf20Sopenharmony_ci	 * Since the connector can be unregistered at any point during an
3278c2ecf20Sopenharmony_ci	 * atomic check or commit, this is racy. But that's OK: all we care
3288c2ecf20Sopenharmony_ci	 * about is ensuring that userspace can't do anything but shut off the
3298c2ecf20Sopenharmony_ci	 * display on a connector that was destroyed after it's been notified,
3308c2ecf20Sopenharmony_ci	 * not before.
3318c2ecf20Sopenharmony_ci	 *
3328c2ecf20Sopenharmony_ci	 * Additionally, we also want to ignore connector registration when
3338c2ecf20Sopenharmony_ci	 * we're trying to restore an atomic state during system resume since
3348c2ecf20Sopenharmony_ci	 * there's a chance the connector may have been destroyed during the
3358c2ecf20Sopenharmony_ci	 * process, but it's better to ignore that then cause
3368c2ecf20Sopenharmony_ci	 * drm_atomic_helper_resume() to fail.
3378c2ecf20Sopenharmony_ci	 */
3388c2ecf20Sopenharmony_ci	if (!state->duplicated && drm_connector_is_unregistered(connector) &&
3398c2ecf20Sopenharmony_ci	    crtc_state->active) {
3408c2ecf20Sopenharmony_ci		DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] is not registered\n",
3418c2ecf20Sopenharmony_ci				 connector->base.id, connector->name);
3428c2ecf20Sopenharmony_ci		return -EINVAL;
3438c2ecf20Sopenharmony_ci	}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	funcs = connector->helper_private;
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	if (funcs->atomic_best_encoder)
3488c2ecf20Sopenharmony_ci		new_encoder = funcs->atomic_best_encoder(connector,
3498c2ecf20Sopenharmony_ci							 new_connector_state);
3508c2ecf20Sopenharmony_ci	else if (funcs->best_encoder)
3518c2ecf20Sopenharmony_ci		new_encoder = funcs->best_encoder(connector);
3528c2ecf20Sopenharmony_ci	else
3538c2ecf20Sopenharmony_ci		new_encoder = drm_connector_get_single_encoder(connector);
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	if (!new_encoder) {
3568c2ecf20Sopenharmony_ci		DRM_DEBUG_ATOMIC("No suitable encoder found for [CONNECTOR:%d:%s]\n",
3578c2ecf20Sopenharmony_ci				 connector->base.id,
3588c2ecf20Sopenharmony_ci				 connector->name);
3598c2ecf20Sopenharmony_ci		return -EINVAL;
3608c2ecf20Sopenharmony_ci	}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	if (!drm_encoder_crtc_ok(new_encoder, new_connector_state->crtc)) {
3638c2ecf20Sopenharmony_ci		DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] incompatible with [CRTC:%d:%s]\n",
3648c2ecf20Sopenharmony_ci				 new_encoder->base.id,
3658c2ecf20Sopenharmony_ci				 new_encoder->name,
3668c2ecf20Sopenharmony_ci				 new_connector_state->crtc->base.id,
3678c2ecf20Sopenharmony_ci				 new_connector_state->crtc->name);
3688c2ecf20Sopenharmony_ci		return -EINVAL;
3698c2ecf20Sopenharmony_ci	}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	if (new_encoder == new_connector_state->best_encoder) {
3728c2ecf20Sopenharmony_ci		set_best_encoder(state, new_connector_state, new_encoder);
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci		DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] keeps [ENCODER:%d:%s], now on [CRTC:%d:%s]\n",
3758c2ecf20Sopenharmony_ci				 connector->base.id,
3768c2ecf20Sopenharmony_ci				 connector->name,
3778c2ecf20Sopenharmony_ci				 new_encoder->base.id,
3788c2ecf20Sopenharmony_ci				 new_encoder->name,
3798c2ecf20Sopenharmony_ci				 new_connector_state->crtc->base.id,
3808c2ecf20Sopenharmony_ci				 new_connector_state->crtc->name);
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci		return 0;
3838c2ecf20Sopenharmony_ci	}
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	steal_encoder(state, new_encoder);
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	set_best_encoder(state, new_connector_state, new_encoder);
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	crtc_state->connectors_changed = true;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] using [ENCODER:%d:%s] on [CRTC:%d:%s]\n",
3928c2ecf20Sopenharmony_ci			 connector->base.id,
3938c2ecf20Sopenharmony_ci			 connector->name,
3948c2ecf20Sopenharmony_ci			 new_encoder->base.id,
3958c2ecf20Sopenharmony_ci			 new_encoder->name,
3968c2ecf20Sopenharmony_ci			 new_connector_state->crtc->base.id,
3978c2ecf20Sopenharmony_ci			 new_connector_state->crtc->name);
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	return 0;
4008c2ecf20Sopenharmony_ci}
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_cistatic int
4038c2ecf20Sopenharmony_cimode_fixup(struct drm_atomic_state *state)
4048c2ecf20Sopenharmony_ci{
4058c2ecf20Sopenharmony_ci	struct drm_crtc *crtc;
4068c2ecf20Sopenharmony_ci	struct drm_crtc_state *new_crtc_state;
4078c2ecf20Sopenharmony_ci	struct drm_connector *connector;
4088c2ecf20Sopenharmony_ci	struct drm_connector_state *new_conn_state;
4098c2ecf20Sopenharmony_ci	int i;
4108c2ecf20Sopenharmony_ci	int ret;
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
4138c2ecf20Sopenharmony_ci		if (!new_crtc_state->mode_changed &&
4148c2ecf20Sopenharmony_ci		    !new_crtc_state->connectors_changed)
4158c2ecf20Sopenharmony_ci			continue;
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci		drm_mode_copy(&new_crtc_state->adjusted_mode, &new_crtc_state->mode);
4188c2ecf20Sopenharmony_ci	}
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	for_each_new_connector_in_state(state, connector, new_conn_state, i) {
4218c2ecf20Sopenharmony_ci		const struct drm_encoder_helper_funcs *funcs;
4228c2ecf20Sopenharmony_ci		struct drm_encoder *encoder;
4238c2ecf20Sopenharmony_ci		struct drm_bridge *bridge;
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci		WARN_ON(!!new_conn_state->best_encoder != !!new_conn_state->crtc);
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci		if (!new_conn_state->crtc || !new_conn_state->best_encoder)
4288c2ecf20Sopenharmony_ci			continue;
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci		new_crtc_state =
4318c2ecf20Sopenharmony_ci			drm_atomic_get_new_crtc_state(state, new_conn_state->crtc);
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci		/*
4348c2ecf20Sopenharmony_ci		 * Each encoder has at most one connector (since we always steal
4358c2ecf20Sopenharmony_ci		 * it away), so we won't call ->mode_fixup twice.
4368c2ecf20Sopenharmony_ci		 */
4378c2ecf20Sopenharmony_ci		encoder = new_conn_state->best_encoder;
4388c2ecf20Sopenharmony_ci		funcs = encoder->helper_private;
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci		bridge = drm_bridge_chain_get_first_bridge(encoder);
4418c2ecf20Sopenharmony_ci		ret = drm_atomic_bridge_chain_check(bridge,
4428c2ecf20Sopenharmony_ci						    new_crtc_state,
4438c2ecf20Sopenharmony_ci						    new_conn_state);
4448c2ecf20Sopenharmony_ci		if (ret) {
4458c2ecf20Sopenharmony_ci			DRM_DEBUG_ATOMIC("Bridge atomic check failed\n");
4468c2ecf20Sopenharmony_ci			return ret;
4478c2ecf20Sopenharmony_ci		}
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci		if (funcs && funcs->atomic_check) {
4508c2ecf20Sopenharmony_ci			ret = funcs->atomic_check(encoder, new_crtc_state,
4518c2ecf20Sopenharmony_ci						  new_conn_state);
4528c2ecf20Sopenharmony_ci			if (ret) {
4538c2ecf20Sopenharmony_ci				DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] check failed\n",
4548c2ecf20Sopenharmony_ci						 encoder->base.id, encoder->name);
4558c2ecf20Sopenharmony_ci				return ret;
4568c2ecf20Sopenharmony_ci			}
4578c2ecf20Sopenharmony_ci		} else if (funcs && funcs->mode_fixup) {
4588c2ecf20Sopenharmony_ci			ret = funcs->mode_fixup(encoder, &new_crtc_state->mode,
4598c2ecf20Sopenharmony_ci						&new_crtc_state->adjusted_mode);
4608c2ecf20Sopenharmony_ci			if (!ret) {
4618c2ecf20Sopenharmony_ci				DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] fixup failed\n",
4628c2ecf20Sopenharmony_ci						 encoder->base.id, encoder->name);
4638c2ecf20Sopenharmony_ci				return -EINVAL;
4648c2ecf20Sopenharmony_ci			}
4658c2ecf20Sopenharmony_ci		}
4668c2ecf20Sopenharmony_ci	}
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
4698c2ecf20Sopenharmony_ci		const struct drm_crtc_helper_funcs *funcs;
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci		if (!new_crtc_state->enable)
4728c2ecf20Sopenharmony_ci			continue;
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci		if (!new_crtc_state->mode_changed &&
4758c2ecf20Sopenharmony_ci		    !new_crtc_state->connectors_changed)
4768c2ecf20Sopenharmony_ci			continue;
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci		funcs = crtc->helper_private;
4798c2ecf20Sopenharmony_ci		if (!funcs || !funcs->mode_fixup)
4808c2ecf20Sopenharmony_ci			continue;
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci		ret = funcs->mode_fixup(crtc, &new_crtc_state->mode,
4838c2ecf20Sopenharmony_ci					&new_crtc_state->adjusted_mode);
4848c2ecf20Sopenharmony_ci		if (!ret) {
4858c2ecf20Sopenharmony_ci			DRM_DEBUG_ATOMIC("[CRTC:%d:%s] fixup failed\n",
4868c2ecf20Sopenharmony_ci					 crtc->base.id, crtc->name);
4878c2ecf20Sopenharmony_ci			return -EINVAL;
4888c2ecf20Sopenharmony_ci		}
4898c2ecf20Sopenharmony_ci	}
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	return 0;
4928c2ecf20Sopenharmony_ci}
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_cistatic enum drm_mode_status mode_valid_path(struct drm_connector *connector,
4958c2ecf20Sopenharmony_ci					    struct drm_encoder *encoder,
4968c2ecf20Sopenharmony_ci					    struct drm_crtc *crtc,
4978c2ecf20Sopenharmony_ci					    const struct drm_display_mode *mode)
4988c2ecf20Sopenharmony_ci{
4998c2ecf20Sopenharmony_ci	struct drm_bridge *bridge;
5008c2ecf20Sopenharmony_ci	enum drm_mode_status ret;
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	ret = drm_encoder_mode_valid(encoder, mode);
5038c2ecf20Sopenharmony_ci	if (ret != MODE_OK) {
5048c2ecf20Sopenharmony_ci		DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] mode_valid() failed\n",
5058c2ecf20Sopenharmony_ci				encoder->base.id, encoder->name);
5068c2ecf20Sopenharmony_ci		return ret;
5078c2ecf20Sopenharmony_ci	}
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	bridge = drm_bridge_chain_get_first_bridge(encoder);
5108c2ecf20Sopenharmony_ci	ret = drm_bridge_chain_mode_valid(bridge, &connector->display_info,
5118c2ecf20Sopenharmony_ci					  mode);
5128c2ecf20Sopenharmony_ci	if (ret != MODE_OK) {
5138c2ecf20Sopenharmony_ci		DRM_DEBUG_ATOMIC("[BRIDGE] mode_valid() failed\n");
5148c2ecf20Sopenharmony_ci		return ret;
5158c2ecf20Sopenharmony_ci	}
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	ret = drm_crtc_mode_valid(crtc, mode);
5188c2ecf20Sopenharmony_ci	if (ret != MODE_OK) {
5198c2ecf20Sopenharmony_ci		DRM_DEBUG_ATOMIC("[CRTC:%d:%s] mode_valid() failed\n",
5208c2ecf20Sopenharmony_ci				crtc->base.id, crtc->name);
5218c2ecf20Sopenharmony_ci		return ret;
5228c2ecf20Sopenharmony_ci	}
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	return ret;
5258c2ecf20Sopenharmony_ci}
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_cistatic int
5288c2ecf20Sopenharmony_cimode_valid(struct drm_atomic_state *state)
5298c2ecf20Sopenharmony_ci{
5308c2ecf20Sopenharmony_ci	struct drm_connector_state *conn_state;
5318c2ecf20Sopenharmony_ci	struct drm_connector *connector;
5328c2ecf20Sopenharmony_ci	int i;
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	for_each_new_connector_in_state(state, connector, conn_state, i) {
5358c2ecf20Sopenharmony_ci		struct drm_encoder *encoder = conn_state->best_encoder;
5368c2ecf20Sopenharmony_ci		struct drm_crtc *crtc = conn_state->crtc;
5378c2ecf20Sopenharmony_ci		struct drm_crtc_state *crtc_state;
5388c2ecf20Sopenharmony_ci		enum drm_mode_status mode_status;
5398c2ecf20Sopenharmony_ci		const struct drm_display_mode *mode;
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci		if (!crtc || !encoder)
5428c2ecf20Sopenharmony_ci			continue;
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci		crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
5458c2ecf20Sopenharmony_ci		if (!crtc_state)
5468c2ecf20Sopenharmony_ci			continue;
5478c2ecf20Sopenharmony_ci		if (!crtc_state->mode_changed && !crtc_state->connectors_changed)
5488c2ecf20Sopenharmony_ci			continue;
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci		mode = &crtc_state->mode;
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci		mode_status = mode_valid_path(connector, encoder, crtc, mode);
5538c2ecf20Sopenharmony_ci		if (mode_status != MODE_OK)
5548c2ecf20Sopenharmony_ci			return -EINVAL;
5558c2ecf20Sopenharmony_ci	}
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	return 0;
5588c2ecf20Sopenharmony_ci}
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci/**
5618c2ecf20Sopenharmony_ci * drm_atomic_helper_check_modeset - validate state object for modeset changes
5628c2ecf20Sopenharmony_ci * @dev: DRM device
5638c2ecf20Sopenharmony_ci * @state: the driver state object
5648c2ecf20Sopenharmony_ci *
5658c2ecf20Sopenharmony_ci * Check the state object to see if the requested state is physically possible.
5668c2ecf20Sopenharmony_ci * This does all the CRTC and connector related computations for an atomic
5678c2ecf20Sopenharmony_ci * update and adds any additional connectors needed for full modesets. It calls
5688c2ecf20Sopenharmony_ci * the various per-object callbacks in the follow order:
5698c2ecf20Sopenharmony_ci *
5708c2ecf20Sopenharmony_ci * 1. &drm_connector_helper_funcs.atomic_best_encoder for determining the new encoder.
5718c2ecf20Sopenharmony_ci * 2. &drm_connector_helper_funcs.atomic_check to validate the connector state.
5728c2ecf20Sopenharmony_ci * 3. If it's determined a modeset is needed then all connectors on the affected
5738c2ecf20Sopenharmony_ci *    CRTC are added and &drm_connector_helper_funcs.atomic_check is run on them.
5748c2ecf20Sopenharmony_ci * 4. &drm_encoder_helper_funcs.mode_valid, &drm_bridge_funcs.mode_valid and
5758c2ecf20Sopenharmony_ci *    &drm_crtc_helper_funcs.mode_valid are called on the affected components.
5768c2ecf20Sopenharmony_ci * 5. &drm_bridge_funcs.mode_fixup is called on all encoder bridges.
5778c2ecf20Sopenharmony_ci * 6. &drm_encoder_helper_funcs.atomic_check is called to validate any encoder state.
5788c2ecf20Sopenharmony_ci *    This function is only called when the encoder will be part of a configured CRTC,
5798c2ecf20Sopenharmony_ci *    it must not be used for implementing connector property validation.
5808c2ecf20Sopenharmony_ci *    If this function is NULL, &drm_atomic_encoder_helper_funcs.mode_fixup is called
5818c2ecf20Sopenharmony_ci *    instead.
5828c2ecf20Sopenharmony_ci * 7. &drm_crtc_helper_funcs.mode_fixup is called last, to fix up the mode with CRTC constraints.
5838c2ecf20Sopenharmony_ci *
5848c2ecf20Sopenharmony_ci * &drm_crtc_state.mode_changed is set when the input mode is changed.
5858c2ecf20Sopenharmony_ci * &drm_crtc_state.connectors_changed is set when a connector is added or
5868c2ecf20Sopenharmony_ci * removed from the CRTC.  &drm_crtc_state.active_changed is set when
5878c2ecf20Sopenharmony_ci * &drm_crtc_state.active changes, which is used for DPMS.
5888c2ecf20Sopenharmony_ci * &drm_crtc_state.no_vblank is set from the result of drm_dev_has_vblank().
5898c2ecf20Sopenharmony_ci * See also: drm_atomic_crtc_needs_modeset()
5908c2ecf20Sopenharmony_ci *
5918c2ecf20Sopenharmony_ci * IMPORTANT:
5928c2ecf20Sopenharmony_ci *
5938c2ecf20Sopenharmony_ci * Drivers which set &drm_crtc_state.mode_changed (e.g. in their
5948c2ecf20Sopenharmony_ci * &drm_plane_helper_funcs.atomic_check hooks if a plane update can't be done
5958c2ecf20Sopenharmony_ci * without a full modeset) _must_ call this function afterwards after that
5968c2ecf20Sopenharmony_ci * change. It is permitted to call this function multiple times for the same
5978c2ecf20Sopenharmony_ci * update, e.g. when the &drm_crtc_helper_funcs.atomic_check functions depend
5988c2ecf20Sopenharmony_ci * upon the adjusted dotclock for fifo space allocation and watermark
5998c2ecf20Sopenharmony_ci * computation.
6008c2ecf20Sopenharmony_ci *
6018c2ecf20Sopenharmony_ci * RETURNS:
6028c2ecf20Sopenharmony_ci * Zero for success or -errno
6038c2ecf20Sopenharmony_ci */
6048c2ecf20Sopenharmony_ciint
6058c2ecf20Sopenharmony_cidrm_atomic_helper_check_modeset(struct drm_device *dev,
6068c2ecf20Sopenharmony_ci				struct drm_atomic_state *state)
6078c2ecf20Sopenharmony_ci{
6088c2ecf20Sopenharmony_ci	struct drm_crtc *crtc;
6098c2ecf20Sopenharmony_ci	struct drm_crtc_state *old_crtc_state, *new_crtc_state;
6108c2ecf20Sopenharmony_ci	struct drm_connector *connector;
6118c2ecf20Sopenharmony_ci	struct drm_connector_state *old_connector_state, *new_connector_state;
6128c2ecf20Sopenharmony_ci	int i, ret;
6138c2ecf20Sopenharmony_ci	unsigned connectors_mask = 0;
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
6168c2ecf20Sopenharmony_ci		bool has_connectors =
6178c2ecf20Sopenharmony_ci			!!new_crtc_state->connector_mask;
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci		WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci		if (!drm_mode_equal(&old_crtc_state->mode, &new_crtc_state->mode)) {
6228c2ecf20Sopenharmony_ci			DRM_DEBUG_ATOMIC("[CRTC:%d:%s] mode changed\n",
6238c2ecf20Sopenharmony_ci					 crtc->base.id, crtc->name);
6248c2ecf20Sopenharmony_ci			new_crtc_state->mode_changed = true;
6258c2ecf20Sopenharmony_ci		}
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci		if (old_crtc_state->enable != new_crtc_state->enable) {
6288c2ecf20Sopenharmony_ci			DRM_DEBUG_ATOMIC("[CRTC:%d:%s] enable changed\n",
6298c2ecf20Sopenharmony_ci					 crtc->base.id, crtc->name);
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci			/*
6328c2ecf20Sopenharmony_ci			 * For clarity this assignment is done here, but
6338c2ecf20Sopenharmony_ci			 * enable == 0 is only true when there are no
6348c2ecf20Sopenharmony_ci			 * connectors and a NULL mode.
6358c2ecf20Sopenharmony_ci			 *
6368c2ecf20Sopenharmony_ci			 * The other way around is true as well. enable != 0
6378c2ecf20Sopenharmony_ci			 * iff connectors are attached and a mode is set.
6388c2ecf20Sopenharmony_ci			 */
6398c2ecf20Sopenharmony_ci			new_crtc_state->mode_changed = true;
6408c2ecf20Sopenharmony_ci			new_crtc_state->connectors_changed = true;
6418c2ecf20Sopenharmony_ci		}
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci		if (old_crtc_state->active != new_crtc_state->active) {
6448c2ecf20Sopenharmony_ci			DRM_DEBUG_ATOMIC("[CRTC:%d:%s] active changed\n",
6458c2ecf20Sopenharmony_ci					 crtc->base.id, crtc->name);
6468c2ecf20Sopenharmony_ci			new_crtc_state->active_changed = true;
6478c2ecf20Sopenharmony_ci		}
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci		if (new_crtc_state->enable != has_connectors) {
6508c2ecf20Sopenharmony_ci			DRM_DEBUG_ATOMIC("[CRTC:%d:%s] enabled/connectors mismatch\n",
6518c2ecf20Sopenharmony_ci					 crtc->base.id, crtc->name);
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci			return -EINVAL;
6548c2ecf20Sopenharmony_ci		}
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci		if (drm_dev_has_vblank(dev))
6578c2ecf20Sopenharmony_ci			new_crtc_state->no_vblank = false;
6588c2ecf20Sopenharmony_ci		else
6598c2ecf20Sopenharmony_ci			new_crtc_state->no_vblank = true;
6608c2ecf20Sopenharmony_ci	}
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci	ret = handle_conflicting_encoders(state, false);
6638c2ecf20Sopenharmony_ci	if (ret)
6648c2ecf20Sopenharmony_ci		return ret;
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci	for_each_oldnew_connector_in_state(state, connector, old_connector_state, new_connector_state, i) {
6678c2ecf20Sopenharmony_ci		const struct drm_connector_helper_funcs *funcs = connector->helper_private;
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci		WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci		/*
6728c2ecf20Sopenharmony_ci		 * This only sets crtc->connectors_changed for routing changes,
6738c2ecf20Sopenharmony_ci		 * drivers must set crtc->connectors_changed themselves when
6748c2ecf20Sopenharmony_ci		 * connector properties need to be updated.
6758c2ecf20Sopenharmony_ci		 */
6768c2ecf20Sopenharmony_ci		ret = update_connector_routing(state, connector,
6778c2ecf20Sopenharmony_ci					       old_connector_state,
6788c2ecf20Sopenharmony_ci					       new_connector_state);
6798c2ecf20Sopenharmony_ci		if (ret)
6808c2ecf20Sopenharmony_ci			return ret;
6818c2ecf20Sopenharmony_ci		if (old_connector_state->crtc) {
6828c2ecf20Sopenharmony_ci			new_crtc_state = drm_atomic_get_new_crtc_state(state,
6838c2ecf20Sopenharmony_ci								       old_connector_state->crtc);
6848c2ecf20Sopenharmony_ci			if (old_connector_state->link_status !=
6858c2ecf20Sopenharmony_ci			    new_connector_state->link_status)
6868c2ecf20Sopenharmony_ci				new_crtc_state->connectors_changed = true;
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci			if (old_connector_state->max_requested_bpc !=
6898c2ecf20Sopenharmony_ci			    new_connector_state->max_requested_bpc)
6908c2ecf20Sopenharmony_ci				new_crtc_state->connectors_changed = true;
6918c2ecf20Sopenharmony_ci		}
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci		if (funcs->atomic_check)
6948c2ecf20Sopenharmony_ci			ret = funcs->atomic_check(connector, state);
6958c2ecf20Sopenharmony_ci		if (ret)
6968c2ecf20Sopenharmony_ci			return ret;
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci		connectors_mask |= BIT(i);
6998c2ecf20Sopenharmony_ci	}
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	/*
7028c2ecf20Sopenharmony_ci	 * After all the routing has been prepared we need to add in any
7038c2ecf20Sopenharmony_ci	 * connector which is itself unchanged, but whose CRTC changes its
7048c2ecf20Sopenharmony_ci	 * configuration. This must be done before calling mode_fixup in case a
7058c2ecf20Sopenharmony_ci	 * crtc only changed its mode but has the same set of connectors.
7068c2ecf20Sopenharmony_ci	 */
7078c2ecf20Sopenharmony_ci	for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
7088c2ecf20Sopenharmony_ci		if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
7098c2ecf20Sopenharmony_ci			continue;
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci		DRM_DEBUG_ATOMIC("[CRTC:%d:%s] needs all connectors, enable: %c, active: %c\n",
7128c2ecf20Sopenharmony_ci				 crtc->base.id, crtc->name,
7138c2ecf20Sopenharmony_ci				 new_crtc_state->enable ? 'y' : 'n',
7148c2ecf20Sopenharmony_ci				 new_crtc_state->active ? 'y' : 'n');
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci		ret = drm_atomic_add_affected_connectors(state, crtc);
7178c2ecf20Sopenharmony_ci		if (ret != 0)
7188c2ecf20Sopenharmony_ci			return ret;
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci		ret = drm_atomic_add_affected_planes(state, crtc);
7218c2ecf20Sopenharmony_ci		if (ret != 0)
7228c2ecf20Sopenharmony_ci			return ret;
7238c2ecf20Sopenharmony_ci	}
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	/*
7268c2ecf20Sopenharmony_ci	 * Iterate over all connectors again, to make sure atomic_check()
7278c2ecf20Sopenharmony_ci	 * has been called on them when a modeset is forced.
7288c2ecf20Sopenharmony_ci	 */
7298c2ecf20Sopenharmony_ci	for_each_oldnew_connector_in_state(state, connector, old_connector_state, new_connector_state, i) {
7308c2ecf20Sopenharmony_ci		const struct drm_connector_helper_funcs *funcs = connector->helper_private;
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci		if (connectors_mask & BIT(i))
7338c2ecf20Sopenharmony_ci			continue;
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci		if (funcs->atomic_check)
7368c2ecf20Sopenharmony_ci			ret = funcs->atomic_check(connector, state);
7378c2ecf20Sopenharmony_ci		if (ret)
7388c2ecf20Sopenharmony_ci			return ret;
7398c2ecf20Sopenharmony_ci	}
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci	/*
7428c2ecf20Sopenharmony_ci	 * Iterate over all connectors again, and add all affected bridges to
7438c2ecf20Sopenharmony_ci	 * the state.
7448c2ecf20Sopenharmony_ci	 */
7458c2ecf20Sopenharmony_ci	for_each_oldnew_connector_in_state(state, connector,
7468c2ecf20Sopenharmony_ci					   old_connector_state,
7478c2ecf20Sopenharmony_ci					   new_connector_state, i) {
7488c2ecf20Sopenharmony_ci		struct drm_encoder *encoder;
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci		encoder = old_connector_state->best_encoder;
7518c2ecf20Sopenharmony_ci		ret = drm_atomic_add_encoder_bridges(state, encoder);
7528c2ecf20Sopenharmony_ci		if (ret)
7538c2ecf20Sopenharmony_ci			return ret;
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci		encoder = new_connector_state->best_encoder;
7568c2ecf20Sopenharmony_ci		ret = drm_atomic_add_encoder_bridges(state, encoder);
7578c2ecf20Sopenharmony_ci		if (ret)
7588c2ecf20Sopenharmony_ci			return ret;
7598c2ecf20Sopenharmony_ci	}
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	ret = mode_valid(state);
7628c2ecf20Sopenharmony_ci	if (ret)
7638c2ecf20Sopenharmony_ci		return ret;
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci	return mode_fixup(state);
7668c2ecf20Sopenharmony_ci}
7678c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_check_modeset);
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci/**
7708c2ecf20Sopenharmony_ci * drm_atomic_helper_check_plane_state() - Check plane state for validity
7718c2ecf20Sopenharmony_ci * @plane_state: plane state to check
7728c2ecf20Sopenharmony_ci * @crtc_state: CRTC state to check
7738c2ecf20Sopenharmony_ci * @min_scale: minimum @src:@dest scaling factor in 16.16 fixed point
7748c2ecf20Sopenharmony_ci * @max_scale: maximum @src:@dest scaling factor in 16.16 fixed point
7758c2ecf20Sopenharmony_ci * @can_position: is it legal to position the plane such that it
7768c2ecf20Sopenharmony_ci *                doesn't cover the entire CRTC?  This will generally
7778c2ecf20Sopenharmony_ci *                only be false for primary planes.
7788c2ecf20Sopenharmony_ci * @can_update_disabled: can the plane be updated while the CRTC
7798c2ecf20Sopenharmony_ci *                       is disabled?
7808c2ecf20Sopenharmony_ci *
7818c2ecf20Sopenharmony_ci * Checks that a desired plane update is valid, and updates various
7828c2ecf20Sopenharmony_ci * bits of derived state (clipped coordinates etc.). Drivers that provide
7838c2ecf20Sopenharmony_ci * their own plane handling rather than helper-provided implementations may
7848c2ecf20Sopenharmony_ci * still wish to call this function to avoid duplication of error checking
7858c2ecf20Sopenharmony_ci * code.
7868c2ecf20Sopenharmony_ci *
7878c2ecf20Sopenharmony_ci * RETURNS:
7888c2ecf20Sopenharmony_ci * Zero if update appears valid, error code on failure
7898c2ecf20Sopenharmony_ci */
7908c2ecf20Sopenharmony_ciint drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state,
7918c2ecf20Sopenharmony_ci					const struct drm_crtc_state *crtc_state,
7928c2ecf20Sopenharmony_ci					int min_scale,
7938c2ecf20Sopenharmony_ci					int max_scale,
7948c2ecf20Sopenharmony_ci					bool can_position,
7958c2ecf20Sopenharmony_ci					bool can_update_disabled)
7968c2ecf20Sopenharmony_ci{
7978c2ecf20Sopenharmony_ci	struct drm_framebuffer *fb = plane_state->fb;
7988c2ecf20Sopenharmony_ci	struct drm_rect *src = &plane_state->src;
7998c2ecf20Sopenharmony_ci	struct drm_rect *dst = &plane_state->dst;
8008c2ecf20Sopenharmony_ci	unsigned int rotation = plane_state->rotation;
8018c2ecf20Sopenharmony_ci	struct drm_rect clip = {};
8028c2ecf20Sopenharmony_ci	int hscale, vscale;
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci	WARN_ON(plane_state->crtc && plane_state->crtc != crtc_state->crtc);
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci	*src = drm_plane_state_src(plane_state);
8078c2ecf20Sopenharmony_ci	*dst = drm_plane_state_dest(plane_state);
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci	if (!fb) {
8108c2ecf20Sopenharmony_ci		plane_state->visible = false;
8118c2ecf20Sopenharmony_ci		return 0;
8128c2ecf20Sopenharmony_ci	}
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	/* crtc should only be NULL when disabling (i.e., !fb) */
8158c2ecf20Sopenharmony_ci	if (WARN_ON(!plane_state->crtc)) {
8168c2ecf20Sopenharmony_ci		plane_state->visible = false;
8178c2ecf20Sopenharmony_ci		return 0;
8188c2ecf20Sopenharmony_ci	}
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci	if (!crtc_state->enable && !can_update_disabled) {
8218c2ecf20Sopenharmony_ci		DRM_DEBUG_KMS("Cannot update plane of a disabled CRTC.\n");
8228c2ecf20Sopenharmony_ci		return -EINVAL;
8238c2ecf20Sopenharmony_ci	}
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	drm_rect_rotate(src, fb->width << 16, fb->height << 16, rotation);
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci	/* Check scaling */
8288c2ecf20Sopenharmony_ci	hscale = drm_rect_calc_hscale(src, dst, min_scale, max_scale);
8298c2ecf20Sopenharmony_ci	vscale = drm_rect_calc_vscale(src, dst, min_scale, max_scale);
8308c2ecf20Sopenharmony_ci	if (hscale < 0 || vscale < 0) {
8318c2ecf20Sopenharmony_ci		DRM_DEBUG_KMS("Invalid scaling of plane\n");
8328c2ecf20Sopenharmony_ci		drm_rect_debug_print("src: ", &plane_state->src, true);
8338c2ecf20Sopenharmony_ci		drm_rect_debug_print("dst: ", &plane_state->dst, false);
8348c2ecf20Sopenharmony_ci		return -ERANGE;
8358c2ecf20Sopenharmony_ci	}
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	if (crtc_state->enable)
8388c2ecf20Sopenharmony_ci		drm_mode_get_hv_timing(&crtc_state->mode, &clip.x2, &clip.y2);
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci	plane_state->visible = drm_rect_clip_scaled(src, dst, &clip);
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci	drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16, rotation);
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci	if (!plane_state->visible)
8458c2ecf20Sopenharmony_ci		/*
8468c2ecf20Sopenharmony_ci		 * Plane isn't visible; some drivers can handle this
8478c2ecf20Sopenharmony_ci		 * so we just return success here.  Drivers that can't
8488c2ecf20Sopenharmony_ci		 * (including those that use the primary plane helper's
8498c2ecf20Sopenharmony_ci		 * update function) will return an error from their
8508c2ecf20Sopenharmony_ci		 * update_plane handler.
8518c2ecf20Sopenharmony_ci		 */
8528c2ecf20Sopenharmony_ci		return 0;
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci	if (!can_position && !drm_rect_equals(dst, &clip)) {
8558c2ecf20Sopenharmony_ci		DRM_DEBUG_KMS("Plane must cover entire CRTC\n");
8568c2ecf20Sopenharmony_ci		drm_rect_debug_print("dst: ", dst, false);
8578c2ecf20Sopenharmony_ci		drm_rect_debug_print("clip: ", &clip, false);
8588c2ecf20Sopenharmony_ci		return -EINVAL;
8598c2ecf20Sopenharmony_ci	}
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci	return 0;
8628c2ecf20Sopenharmony_ci}
8638c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_check_plane_state);
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci/**
8668c2ecf20Sopenharmony_ci * drm_atomic_helper_check_planes - validate state object for planes changes
8678c2ecf20Sopenharmony_ci * @dev: DRM device
8688c2ecf20Sopenharmony_ci * @state: the driver state object
8698c2ecf20Sopenharmony_ci *
8708c2ecf20Sopenharmony_ci * Check the state object to see if the requested state is physically possible.
8718c2ecf20Sopenharmony_ci * This does all the plane update related checks using by calling into the
8728c2ecf20Sopenharmony_ci * &drm_crtc_helper_funcs.atomic_check and &drm_plane_helper_funcs.atomic_check
8738c2ecf20Sopenharmony_ci * hooks provided by the driver.
8748c2ecf20Sopenharmony_ci *
8758c2ecf20Sopenharmony_ci * It also sets &drm_crtc_state.planes_changed to indicate that a CRTC has
8768c2ecf20Sopenharmony_ci * updated planes.
8778c2ecf20Sopenharmony_ci *
8788c2ecf20Sopenharmony_ci * RETURNS:
8798c2ecf20Sopenharmony_ci * Zero for success or -errno
8808c2ecf20Sopenharmony_ci */
8818c2ecf20Sopenharmony_ciint
8828c2ecf20Sopenharmony_cidrm_atomic_helper_check_planes(struct drm_device *dev,
8838c2ecf20Sopenharmony_ci			       struct drm_atomic_state *state)
8848c2ecf20Sopenharmony_ci{
8858c2ecf20Sopenharmony_ci	struct drm_crtc *crtc;
8868c2ecf20Sopenharmony_ci	struct drm_crtc_state *new_crtc_state;
8878c2ecf20Sopenharmony_ci	struct drm_plane *plane;
8888c2ecf20Sopenharmony_ci	struct drm_plane_state *new_plane_state, *old_plane_state;
8898c2ecf20Sopenharmony_ci	int i, ret = 0;
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_ci	for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {
8928c2ecf20Sopenharmony_ci		const struct drm_plane_helper_funcs *funcs;
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci		WARN_ON(!drm_modeset_is_locked(&plane->mutex));
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci		funcs = plane->helper_private;
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci		drm_atomic_helper_plane_changed(state, old_plane_state, new_plane_state, plane);
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci		drm_atomic_helper_check_plane_damage(state, new_plane_state);
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci		if (!funcs || !funcs->atomic_check)
9038c2ecf20Sopenharmony_ci			continue;
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci		ret = funcs->atomic_check(plane, new_plane_state);
9068c2ecf20Sopenharmony_ci		if (ret) {
9078c2ecf20Sopenharmony_ci			DRM_DEBUG_ATOMIC("[PLANE:%d:%s] atomic driver check failed\n",
9088c2ecf20Sopenharmony_ci					 plane->base.id, plane->name);
9098c2ecf20Sopenharmony_ci			return ret;
9108c2ecf20Sopenharmony_ci		}
9118c2ecf20Sopenharmony_ci	}
9128c2ecf20Sopenharmony_ci
9138c2ecf20Sopenharmony_ci	for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
9148c2ecf20Sopenharmony_ci		const struct drm_crtc_helper_funcs *funcs;
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci		funcs = crtc->helper_private;
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci		if (!funcs || !funcs->atomic_check)
9198c2ecf20Sopenharmony_ci			continue;
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci		ret = funcs->atomic_check(crtc, new_crtc_state);
9228c2ecf20Sopenharmony_ci		if (ret) {
9238c2ecf20Sopenharmony_ci			DRM_DEBUG_ATOMIC("[CRTC:%d:%s] atomic driver check failed\n",
9248c2ecf20Sopenharmony_ci					 crtc->base.id, crtc->name);
9258c2ecf20Sopenharmony_ci			return ret;
9268c2ecf20Sopenharmony_ci		}
9278c2ecf20Sopenharmony_ci	}
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_ci	return ret;
9308c2ecf20Sopenharmony_ci}
9318c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_check_planes);
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci/**
9348c2ecf20Sopenharmony_ci * drm_atomic_helper_check - validate state object
9358c2ecf20Sopenharmony_ci * @dev: DRM device
9368c2ecf20Sopenharmony_ci * @state: the driver state object
9378c2ecf20Sopenharmony_ci *
9388c2ecf20Sopenharmony_ci * Check the state object to see if the requested state is physically possible.
9398c2ecf20Sopenharmony_ci * Only CRTCs and planes have check callbacks, so for any additional (global)
9408c2ecf20Sopenharmony_ci * checking that a driver needs it can simply wrap that around this function.
9418c2ecf20Sopenharmony_ci * Drivers without such needs can directly use this as their
9428c2ecf20Sopenharmony_ci * &drm_mode_config_funcs.atomic_check callback.
9438c2ecf20Sopenharmony_ci *
9448c2ecf20Sopenharmony_ci * This just wraps the two parts of the state checking for planes and modeset
9458c2ecf20Sopenharmony_ci * state in the default order: First it calls drm_atomic_helper_check_modeset()
9468c2ecf20Sopenharmony_ci * and then drm_atomic_helper_check_planes(). The assumption is that the
9478c2ecf20Sopenharmony_ci * @drm_plane_helper_funcs.atomic_check and @drm_crtc_helper_funcs.atomic_check
9488c2ecf20Sopenharmony_ci * functions depend upon an updated adjusted_mode.clock to e.g. properly compute
9498c2ecf20Sopenharmony_ci * watermarks.
9508c2ecf20Sopenharmony_ci *
9518c2ecf20Sopenharmony_ci * Note that zpos normalization will add all enable planes to the state which
9528c2ecf20Sopenharmony_ci * might not desired for some drivers.
9538c2ecf20Sopenharmony_ci * For example enable/disable of a cursor plane which have fixed zpos value
9548c2ecf20Sopenharmony_ci * would trigger all other enabled planes to be forced to the state change.
9558c2ecf20Sopenharmony_ci *
9568c2ecf20Sopenharmony_ci * RETURNS:
9578c2ecf20Sopenharmony_ci * Zero for success or -errno
9588c2ecf20Sopenharmony_ci */
9598c2ecf20Sopenharmony_ciint drm_atomic_helper_check(struct drm_device *dev,
9608c2ecf20Sopenharmony_ci			    struct drm_atomic_state *state)
9618c2ecf20Sopenharmony_ci{
9628c2ecf20Sopenharmony_ci	int ret;
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci	ret = drm_atomic_helper_check_modeset(dev, state);
9658c2ecf20Sopenharmony_ci	if (ret)
9668c2ecf20Sopenharmony_ci		return ret;
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci	if (dev->mode_config.normalize_zpos) {
9698c2ecf20Sopenharmony_ci		ret = drm_atomic_normalize_zpos(dev, state);
9708c2ecf20Sopenharmony_ci		if (ret)
9718c2ecf20Sopenharmony_ci			return ret;
9728c2ecf20Sopenharmony_ci	}
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci	ret = drm_atomic_helper_check_planes(dev, state);
9758c2ecf20Sopenharmony_ci	if (ret)
9768c2ecf20Sopenharmony_ci		return ret;
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci	if (state->legacy_cursor_update)
9798c2ecf20Sopenharmony_ci		state->async_update = !drm_atomic_helper_async_check(dev, state);
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci	drm_self_refresh_helper_alter_state(state);
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci	return ret;
9848c2ecf20Sopenharmony_ci}
9858c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_check);
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_cistatic bool
9888c2ecf20Sopenharmony_cicrtc_needs_disable(struct drm_crtc_state *old_state,
9898c2ecf20Sopenharmony_ci		   struct drm_crtc_state *new_state)
9908c2ecf20Sopenharmony_ci{
9918c2ecf20Sopenharmony_ci	/*
9928c2ecf20Sopenharmony_ci	 * No new_state means the CRTC is off, so the only criteria is whether
9938c2ecf20Sopenharmony_ci	 * it's currently active or in self refresh mode.
9948c2ecf20Sopenharmony_ci	 */
9958c2ecf20Sopenharmony_ci	if (!new_state)
9968c2ecf20Sopenharmony_ci		return drm_atomic_crtc_effectively_active(old_state);
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ci	/*
9998c2ecf20Sopenharmony_ci	 * We need to disable bridge(s) and CRTC if we're transitioning out of
10008c2ecf20Sopenharmony_ci	 * self-refresh and changing CRTCs at the same time, because the
10018c2ecf20Sopenharmony_ci	 * bridge tracks self-refresh status via CRTC state.
10028c2ecf20Sopenharmony_ci	 */
10038c2ecf20Sopenharmony_ci	if (old_state->self_refresh_active &&
10048c2ecf20Sopenharmony_ci	    old_state->crtc != new_state->crtc)
10058c2ecf20Sopenharmony_ci		return true;
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ci	/*
10088c2ecf20Sopenharmony_ci	 * We also need to run through the crtc_funcs->disable() function if
10098c2ecf20Sopenharmony_ci	 * the CRTC is currently on, if it's transitioning to self refresh
10108c2ecf20Sopenharmony_ci	 * mode, or if it's in self refresh mode and needs to be fully
10118c2ecf20Sopenharmony_ci	 * disabled.
10128c2ecf20Sopenharmony_ci	 */
10138c2ecf20Sopenharmony_ci	return old_state->active ||
10148c2ecf20Sopenharmony_ci	       (old_state->self_refresh_active && !new_state->enable) ||
10158c2ecf20Sopenharmony_ci	       new_state->self_refresh_active;
10168c2ecf20Sopenharmony_ci}
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_cistatic void
10198c2ecf20Sopenharmony_cidisable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
10208c2ecf20Sopenharmony_ci{
10218c2ecf20Sopenharmony_ci	struct drm_connector *connector;
10228c2ecf20Sopenharmony_ci	struct drm_connector_state *old_conn_state, *new_conn_state;
10238c2ecf20Sopenharmony_ci	struct drm_crtc *crtc;
10248c2ecf20Sopenharmony_ci	struct drm_crtc_state *old_crtc_state, *new_crtc_state;
10258c2ecf20Sopenharmony_ci	int i;
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci	for_each_oldnew_connector_in_state(old_state, connector, old_conn_state, new_conn_state, i) {
10288c2ecf20Sopenharmony_ci		const struct drm_encoder_helper_funcs *funcs;
10298c2ecf20Sopenharmony_ci		struct drm_encoder *encoder;
10308c2ecf20Sopenharmony_ci		struct drm_bridge *bridge;
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci		/* Shut down everything that's in the changeset and currently
10338c2ecf20Sopenharmony_ci		 * still on. So need to check the old, saved state. */
10348c2ecf20Sopenharmony_ci		if (!old_conn_state->crtc)
10358c2ecf20Sopenharmony_ci			continue;
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_ci		old_crtc_state = drm_atomic_get_old_crtc_state(old_state, old_conn_state->crtc);
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ci		if (new_conn_state->crtc)
10408c2ecf20Sopenharmony_ci			new_crtc_state = drm_atomic_get_new_crtc_state(
10418c2ecf20Sopenharmony_ci						old_state,
10428c2ecf20Sopenharmony_ci						new_conn_state->crtc);
10438c2ecf20Sopenharmony_ci		else
10448c2ecf20Sopenharmony_ci			new_crtc_state = NULL;
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_ci		if (!crtc_needs_disable(old_crtc_state, new_crtc_state) ||
10478c2ecf20Sopenharmony_ci		    !drm_atomic_crtc_needs_modeset(old_conn_state->crtc->state))
10488c2ecf20Sopenharmony_ci			continue;
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_ci		encoder = old_conn_state->best_encoder;
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci		/* We shouldn't get this far if we didn't previously have
10538c2ecf20Sopenharmony_ci		 * an encoder.. but WARN_ON() rather than explode.
10548c2ecf20Sopenharmony_ci		 */
10558c2ecf20Sopenharmony_ci		if (WARN_ON(!encoder))
10568c2ecf20Sopenharmony_ci			continue;
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci		funcs = encoder->helper_private;
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_ci		DRM_DEBUG_ATOMIC("disabling [ENCODER:%d:%s]\n",
10618c2ecf20Sopenharmony_ci				 encoder->base.id, encoder->name);
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_ci		/*
10648c2ecf20Sopenharmony_ci		 * Each encoder has at most one connector (since we always steal
10658c2ecf20Sopenharmony_ci		 * it away), so we won't call disable hooks twice.
10668c2ecf20Sopenharmony_ci		 */
10678c2ecf20Sopenharmony_ci		bridge = drm_bridge_chain_get_first_bridge(encoder);
10688c2ecf20Sopenharmony_ci		drm_atomic_bridge_chain_disable(bridge, old_state);
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci		/* Right function depends upon target state. */
10718c2ecf20Sopenharmony_ci		if (funcs) {
10728c2ecf20Sopenharmony_ci			if (funcs->atomic_disable)
10738c2ecf20Sopenharmony_ci				funcs->atomic_disable(encoder, old_state);
10748c2ecf20Sopenharmony_ci			else if (new_conn_state->crtc && funcs->prepare)
10758c2ecf20Sopenharmony_ci				funcs->prepare(encoder);
10768c2ecf20Sopenharmony_ci			else if (funcs->disable)
10778c2ecf20Sopenharmony_ci				funcs->disable(encoder);
10788c2ecf20Sopenharmony_ci			else if (funcs->dpms)
10798c2ecf20Sopenharmony_ci				funcs->dpms(encoder, DRM_MODE_DPMS_OFF);
10808c2ecf20Sopenharmony_ci		}
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_ci		drm_atomic_bridge_chain_post_disable(bridge, old_state);
10838c2ecf20Sopenharmony_ci	}
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci	for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) {
10868c2ecf20Sopenharmony_ci		const struct drm_crtc_helper_funcs *funcs;
10878c2ecf20Sopenharmony_ci		int ret;
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci		/* Shut down everything that needs a full modeset. */
10908c2ecf20Sopenharmony_ci		if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
10918c2ecf20Sopenharmony_ci			continue;
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_ci		if (!crtc_needs_disable(old_crtc_state, new_crtc_state))
10948c2ecf20Sopenharmony_ci			continue;
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci		funcs = crtc->helper_private;
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci		DRM_DEBUG_ATOMIC("disabling [CRTC:%d:%s]\n",
10998c2ecf20Sopenharmony_ci				 crtc->base.id, crtc->name);
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci		/* Right function depends upon target state. */
11038c2ecf20Sopenharmony_ci		if (new_crtc_state->enable && funcs->prepare)
11048c2ecf20Sopenharmony_ci			funcs->prepare(crtc);
11058c2ecf20Sopenharmony_ci		else if (funcs->atomic_disable)
11068c2ecf20Sopenharmony_ci			funcs->atomic_disable(crtc, old_crtc_state);
11078c2ecf20Sopenharmony_ci		else if (funcs->disable)
11088c2ecf20Sopenharmony_ci			funcs->disable(crtc);
11098c2ecf20Sopenharmony_ci		else if (funcs->dpms)
11108c2ecf20Sopenharmony_ci			funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
11118c2ecf20Sopenharmony_ci
11128c2ecf20Sopenharmony_ci		if (!drm_dev_has_vblank(dev))
11138c2ecf20Sopenharmony_ci			continue;
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_ci		ret = drm_crtc_vblank_get(crtc);
11168c2ecf20Sopenharmony_ci		/*
11178c2ecf20Sopenharmony_ci		 * Self-refresh is not a true "disable"; ensure vblank remains
11188c2ecf20Sopenharmony_ci		 * enabled.
11198c2ecf20Sopenharmony_ci		 */
11208c2ecf20Sopenharmony_ci		if (new_crtc_state->self_refresh_active)
11218c2ecf20Sopenharmony_ci			WARN_ONCE(ret != 0,
11228c2ecf20Sopenharmony_ci				  "driver disabled vblank in self-refresh\n");
11238c2ecf20Sopenharmony_ci		else
11248c2ecf20Sopenharmony_ci			WARN_ONCE(ret != -EINVAL,
11258c2ecf20Sopenharmony_ci				  "driver forgot to call drm_crtc_vblank_off()\n");
11268c2ecf20Sopenharmony_ci		if (ret == 0)
11278c2ecf20Sopenharmony_ci			drm_crtc_vblank_put(crtc);
11288c2ecf20Sopenharmony_ci	}
11298c2ecf20Sopenharmony_ci}
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_ci/**
11328c2ecf20Sopenharmony_ci * drm_atomic_helper_update_legacy_modeset_state - update legacy modeset state
11338c2ecf20Sopenharmony_ci * @dev: DRM device
11348c2ecf20Sopenharmony_ci * @old_state: atomic state object with old state structures
11358c2ecf20Sopenharmony_ci *
11368c2ecf20Sopenharmony_ci * This function updates all the various legacy modeset state pointers in
11378c2ecf20Sopenharmony_ci * connectors, encoders and CRTCs.
11388c2ecf20Sopenharmony_ci *
11398c2ecf20Sopenharmony_ci * Drivers can use this for building their own atomic commit if they don't have
11408c2ecf20Sopenharmony_ci * a pure helper-based modeset implementation.
11418c2ecf20Sopenharmony_ci *
11428c2ecf20Sopenharmony_ci * Since these updates are not synchronized with lockings, only code paths
11438c2ecf20Sopenharmony_ci * called from &drm_mode_config_helper_funcs.atomic_commit_tail can look at the
11448c2ecf20Sopenharmony_ci * legacy state filled out by this helper. Defacto this means this helper and
11458c2ecf20Sopenharmony_ci * the legacy state pointers are only really useful for transitioning an
11468c2ecf20Sopenharmony_ci * existing driver to the atomic world.
11478c2ecf20Sopenharmony_ci */
11488c2ecf20Sopenharmony_civoid
11498c2ecf20Sopenharmony_cidrm_atomic_helper_update_legacy_modeset_state(struct drm_device *dev,
11508c2ecf20Sopenharmony_ci					      struct drm_atomic_state *old_state)
11518c2ecf20Sopenharmony_ci{
11528c2ecf20Sopenharmony_ci	struct drm_connector *connector;
11538c2ecf20Sopenharmony_ci	struct drm_connector_state *old_conn_state, *new_conn_state;
11548c2ecf20Sopenharmony_ci	struct drm_crtc *crtc;
11558c2ecf20Sopenharmony_ci	struct drm_crtc_state *new_crtc_state;
11568c2ecf20Sopenharmony_ci	int i;
11578c2ecf20Sopenharmony_ci
11588c2ecf20Sopenharmony_ci	/* clear out existing links and update dpms */
11598c2ecf20Sopenharmony_ci	for_each_oldnew_connector_in_state(old_state, connector, old_conn_state, new_conn_state, i) {
11608c2ecf20Sopenharmony_ci		if (connector->encoder) {
11618c2ecf20Sopenharmony_ci			WARN_ON(!connector->encoder->crtc);
11628c2ecf20Sopenharmony_ci
11638c2ecf20Sopenharmony_ci			connector->encoder->crtc = NULL;
11648c2ecf20Sopenharmony_ci			connector->encoder = NULL;
11658c2ecf20Sopenharmony_ci		}
11668c2ecf20Sopenharmony_ci
11678c2ecf20Sopenharmony_ci		crtc = new_conn_state->crtc;
11688c2ecf20Sopenharmony_ci		if ((!crtc && old_conn_state->crtc) ||
11698c2ecf20Sopenharmony_ci		    (crtc && drm_atomic_crtc_needs_modeset(crtc->state))) {
11708c2ecf20Sopenharmony_ci			int mode = DRM_MODE_DPMS_OFF;
11718c2ecf20Sopenharmony_ci
11728c2ecf20Sopenharmony_ci			if (crtc && crtc->state->active)
11738c2ecf20Sopenharmony_ci				mode = DRM_MODE_DPMS_ON;
11748c2ecf20Sopenharmony_ci
11758c2ecf20Sopenharmony_ci			connector->dpms = mode;
11768c2ecf20Sopenharmony_ci		}
11778c2ecf20Sopenharmony_ci	}
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_ci	/* set new links */
11808c2ecf20Sopenharmony_ci	for_each_new_connector_in_state(old_state, connector, new_conn_state, i) {
11818c2ecf20Sopenharmony_ci		if (!new_conn_state->crtc)
11828c2ecf20Sopenharmony_ci			continue;
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci		if (WARN_ON(!new_conn_state->best_encoder))
11858c2ecf20Sopenharmony_ci			continue;
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_ci		connector->encoder = new_conn_state->best_encoder;
11888c2ecf20Sopenharmony_ci		connector->encoder->crtc = new_conn_state->crtc;
11898c2ecf20Sopenharmony_ci	}
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_ci	/* set legacy state in the crtc structure */
11928c2ecf20Sopenharmony_ci	for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i) {
11938c2ecf20Sopenharmony_ci		struct drm_plane *primary = crtc->primary;
11948c2ecf20Sopenharmony_ci		struct drm_plane_state *new_plane_state;
11958c2ecf20Sopenharmony_ci
11968c2ecf20Sopenharmony_ci		crtc->mode = new_crtc_state->mode;
11978c2ecf20Sopenharmony_ci		crtc->enabled = new_crtc_state->enable;
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_ci		new_plane_state =
12008c2ecf20Sopenharmony_ci			drm_atomic_get_new_plane_state(old_state, primary);
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_ci		if (new_plane_state && new_plane_state->crtc == crtc) {
12038c2ecf20Sopenharmony_ci			crtc->x = new_plane_state->src_x >> 16;
12048c2ecf20Sopenharmony_ci			crtc->y = new_plane_state->src_y >> 16;
12058c2ecf20Sopenharmony_ci		}
12068c2ecf20Sopenharmony_ci	}
12078c2ecf20Sopenharmony_ci}
12088c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_update_legacy_modeset_state);
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_ci/**
12118c2ecf20Sopenharmony_ci * drm_atomic_helper_calc_timestamping_constants - update vblank timestamping constants
12128c2ecf20Sopenharmony_ci * @state: atomic state object
12138c2ecf20Sopenharmony_ci *
12148c2ecf20Sopenharmony_ci * Updates the timestamping constants used for precise vblank timestamps
12158c2ecf20Sopenharmony_ci * by calling drm_calc_timestamping_constants() for all enabled crtcs in @state.
12168c2ecf20Sopenharmony_ci */
12178c2ecf20Sopenharmony_civoid drm_atomic_helper_calc_timestamping_constants(struct drm_atomic_state *state)
12188c2ecf20Sopenharmony_ci{
12198c2ecf20Sopenharmony_ci	struct drm_crtc_state *new_crtc_state;
12208c2ecf20Sopenharmony_ci	struct drm_crtc *crtc;
12218c2ecf20Sopenharmony_ci	int i;
12228c2ecf20Sopenharmony_ci
12238c2ecf20Sopenharmony_ci	for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
12248c2ecf20Sopenharmony_ci		if (new_crtc_state->enable)
12258c2ecf20Sopenharmony_ci			drm_calc_timestamping_constants(crtc,
12268c2ecf20Sopenharmony_ci							&new_crtc_state->adjusted_mode);
12278c2ecf20Sopenharmony_ci	}
12288c2ecf20Sopenharmony_ci}
12298c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_calc_timestamping_constants);
12308c2ecf20Sopenharmony_ci
12318c2ecf20Sopenharmony_cistatic void
12328c2ecf20Sopenharmony_cicrtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)
12338c2ecf20Sopenharmony_ci{
12348c2ecf20Sopenharmony_ci	struct drm_crtc *crtc;
12358c2ecf20Sopenharmony_ci	struct drm_crtc_state *new_crtc_state;
12368c2ecf20Sopenharmony_ci	struct drm_connector *connector;
12378c2ecf20Sopenharmony_ci	struct drm_connector_state *new_conn_state;
12388c2ecf20Sopenharmony_ci	int i;
12398c2ecf20Sopenharmony_ci
12408c2ecf20Sopenharmony_ci	for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i) {
12418c2ecf20Sopenharmony_ci		const struct drm_crtc_helper_funcs *funcs;
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_ci		if (!new_crtc_state->mode_changed)
12448c2ecf20Sopenharmony_ci			continue;
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_ci		funcs = crtc->helper_private;
12478c2ecf20Sopenharmony_ci
12488c2ecf20Sopenharmony_ci		if (new_crtc_state->enable && funcs->mode_set_nofb) {
12498c2ecf20Sopenharmony_ci			DRM_DEBUG_ATOMIC("modeset on [CRTC:%d:%s]\n",
12508c2ecf20Sopenharmony_ci					 crtc->base.id, crtc->name);
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_ci			funcs->mode_set_nofb(crtc);
12538c2ecf20Sopenharmony_ci		}
12548c2ecf20Sopenharmony_ci	}
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_ci	for_each_new_connector_in_state(old_state, connector, new_conn_state, i) {
12578c2ecf20Sopenharmony_ci		const struct drm_encoder_helper_funcs *funcs;
12588c2ecf20Sopenharmony_ci		struct drm_encoder *encoder;
12598c2ecf20Sopenharmony_ci		struct drm_display_mode *mode, *adjusted_mode;
12608c2ecf20Sopenharmony_ci		struct drm_bridge *bridge;
12618c2ecf20Sopenharmony_ci
12628c2ecf20Sopenharmony_ci		if (!new_conn_state->best_encoder)
12638c2ecf20Sopenharmony_ci			continue;
12648c2ecf20Sopenharmony_ci
12658c2ecf20Sopenharmony_ci		encoder = new_conn_state->best_encoder;
12668c2ecf20Sopenharmony_ci		funcs = encoder->helper_private;
12678c2ecf20Sopenharmony_ci		new_crtc_state = new_conn_state->crtc->state;
12688c2ecf20Sopenharmony_ci		mode = &new_crtc_state->mode;
12698c2ecf20Sopenharmony_ci		adjusted_mode = &new_crtc_state->adjusted_mode;
12708c2ecf20Sopenharmony_ci
12718c2ecf20Sopenharmony_ci		if (!new_crtc_state->mode_changed)
12728c2ecf20Sopenharmony_ci			continue;
12738c2ecf20Sopenharmony_ci
12748c2ecf20Sopenharmony_ci		DRM_DEBUG_ATOMIC("modeset on [ENCODER:%d:%s]\n",
12758c2ecf20Sopenharmony_ci				 encoder->base.id, encoder->name);
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_ci		/*
12788c2ecf20Sopenharmony_ci		 * Each encoder has at most one connector (since we always steal
12798c2ecf20Sopenharmony_ci		 * it away), so we won't call mode_set hooks twice.
12808c2ecf20Sopenharmony_ci		 */
12818c2ecf20Sopenharmony_ci		if (funcs && funcs->atomic_mode_set) {
12828c2ecf20Sopenharmony_ci			funcs->atomic_mode_set(encoder, new_crtc_state,
12838c2ecf20Sopenharmony_ci					       new_conn_state);
12848c2ecf20Sopenharmony_ci		} else if (funcs && funcs->mode_set) {
12858c2ecf20Sopenharmony_ci			funcs->mode_set(encoder, mode, adjusted_mode);
12868c2ecf20Sopenharmony_ci		}
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_ci		bridge = drm_bridge_chain_get_first_bridge(encoder);
12898c2ecf20Sopenharmony_ci		drm_bridge_chain_mode_set(bridge, mode, adjusted_mode);
12908c2ecf20Sopenharmony_ci	}
12918c2ecf20Sopenharmony_ci}
12928c2ecf20Sopenharmony_ci
12938c2ecf20Sopenharmony_ci/**
12948c2ecf20Sopenharmony_ci * drm_atomic_helper_commit_modeset_disables - modeset commit to disable outputs
12958c2ecf20Sopenharmony_ci * @dev: DRM device
12968c2ecf20Sopenharmony_ci * @old_state: atomic state object with old state structures
12978c2ecf20Sopenharmony_ci *
12988c2ecf20Sopenharmony_ci * This function shuts down all the outputs that need to be shut down and
12998c2ecf20Sopenharmony_ci * prepares them (if required) with the new mode.
13008c2ecf20Sopenharmony_ci *
13018c2ecf20Sopenharmony_ci * For compatibility with legacy CRTC helpers this should be called before
13028c2ecf20Sopenharmony_ci * drm_atomic_helper_commit_planes(), which is what the default commit function
13038c2ecf20Sopenharmony_ci * does. But drivers with different needs can group the modeset commits together
13048c2ecf20Sopenharmony_ci * and do the plane commits at the end. This is useful for drivers doing runtime
13058c2ecf20Sopenharmony_ci * PM since planes updates then only happen when the CRTC is actually enabled.
13068c2ecf20Sopenharmony_ci */
13078c2ecf20Sopenharmony_civoid drm_atomic_helper_commit_modeset_disables(struct drm_device *dev,
13088c2ecf20Sopenharmony_ci					       struct drm_atomic_state *old_state)
13098c2ecf20Sopenharmony_ci{
13108c2ecf20Sopenharmony_ci	disable_outputs(dev, old_state);
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci	drm_atomic_helper_update_legacy_modeset_state(dev, old_state);
13138c2ecf20Sopenharmony_ci	drm_atomic_helper_calc_timestamping_constants(old_state);
13148c2ecf20Sopenharmony_ci
13158c2ecf20Sopenharmony_ci	crtc_set_mode(dev, old_state);
13168c2ecf20Sopenharmony_ci}
13178c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_commit_modeset_disables);
13188c2ecf20Sopenharmony_ci
13198c2ecf20Sopenharmony_cistatic void drm_atomic_helper_commit_writebacks(struct drm_device *dev,
13208c2ecf20Sopenharmony_ci						struct drm_atomic_state *old_state)
13218c2ecf20Sopenharmony_ci{
13228c2ecf20Sopenharmony_ci	struct drm_connector *connector;
13238c2ecf20Sopenharmony_ci	struct drm_connector_state *new_conn_state;
13248c2ecf20Sopenharmony_ci	int i;
13258c2ecf20Sopenharmony_ci
13268c2ecf20Sopenharmony_ci	for_each_new_connector_in_state(old_state, connector, new_conn_state, i) {
13278c2ecf20Sopenharmony_ci		const struct drm_connector_helper_funcs *funcs;
13288c2ecf20Sopenharmony_ci
13298c2ecf20Sopenharmony_ci		funcs = connector->helper_private;
13308c2ecf20Sopenharmony_ci		if (!funcs->atomic_commit)
13318c2ecf20Sopenharmony_ci			continue;
13328c2ecf20Sopenharmony_ci
13338c2ecf20Sopenharmony_ci		if (new_conn_state->writeback_job && new_conn_state->writeback_job->fb) {
13348c2ecf20Sopenharmony_ci			WARN_ON(connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK);
13358c2ecf20Sopenharmony_ci			funcs->atomic_commit(connector, new_conn_state);
13368c2ecf20Sopenharmony_ci		}
13378c2ecf20Sopenharmony_ci	}
13388c2ecf20Sopenharmony_ci}
13398c2ecf20Sopenharmony_ci
13408c2ecf20Sopenharmony_ci/**
13418c2ecf20Sopenharmony_ci * drm_atomic_helper_commit_modeset_enables - modeset commit to enable outputs
13428c2ecf20Sopenharmony_ci * @dev: DRM device
13438c2ecf20Sopenharmony_ci * @old_state: atomic state object with old state structures
13448c2ecf20Sopenharmony_ci *
13458c2ecf20Sopenharmony_ci * This function enables all the outputs with the new configuration which had to
13468c2ecf20Sopenharmony_ci * be turned off for the update.
13478c2ecf20Sopenharmony_ci *
13488c2ecf20Sopenharmony_ci * For compatibility with legacy CRTC helpers this should be called after
13498c2ecf20Sopenharmony_ci * drm_atomic_helper_commit_planes(), which is what the default commit function
13508c2ecf20Sopenharmony_ci * does. But drivers with different needs can group the modeset commits together
13518c2ecf20Sopenharmony_ci * and do the plane commits at the end. This is useful for drivers doing runtime
13528c2ecf20Sopenharmony_ci * PM since planes updates then only happen when the CRTC is actually enabled.
13538c2ecf20Sopenharmony_ci */
13548c2ecf20Sopenharmony_civoid drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
13558c2ecf20Sopenharmony_ci					      struct drm_atomic_state *old_state)
13568c2ecf20Sopenharmony_ci{
13578c2ecf20Sopenharmony_ci	struct drm_crtc *crtc;
13588c2ecf20Sopenharmony_ci	struct drm_crtc_state *old_crtc_state;
13598c2ecf20Sopenharmony_ci	struct drm_crtc_state *new_crtc_state;
13608c2ecf20Sopenharmony_ci	struct drm_connector *connector;
13618c2ecf20Sopenharmony_ci	struct drm_connector_state *new_conn_state;
13628c2ecf20Sopenharmony_ci	int i;
13638c2ecf20Sopenharmony_ci
13648c2ecf20Sopenharmony_ci	for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) {
13658c2ecf20Sopenharmony_ci		const struct drm_crtc_helper_funcs *funcs;
13668c2ecf20Sopenharmony_ci
13678c2ecf20Sopenharmony_ci		/* Need to filter out CRTCs where only planes change. */
13688c2ecf20Sopenharmony_ci		if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
13698c2ecf20Sopenharmony_ci			continue;
13708c2ecf20Sopenharmony_ci
13718c2ecf20Sopenharmony_ci		if (!new_crtc_state->active)
13728c2ecf20Sopenharmony_ci			continue;
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_ci		funcs = crtc->helper_private;
13758c2ecf20Sopenharmony_ci
13768c2ecf20Sopenharmony_ci		if (new_crtc_state->enable) {
13778c2ecf20Sopenharmony_ci			DRM_DEBUG_ATOMIC("enabling [CRTC:%d:%s]\n",
13788c2ecf20Sopenharmony_ci					 crtc->base.id, crtc->name);
13798c2ecf20Sopenharmony_ci			if (funcs->atomic_enable)
13808c2ecf20Sopenharmony_ci				funcs->atomic_enable(crtc, old_crtc_state);
13818c2ecf20Sopenharmony_ci			else if (funcs->commit)
13828c2ecf20Sopenharmony_ci				funcs->commit(crtc);
13838c2ecf20Sopenharmony_ci		}
13848c2ecf20Sopenharmony_ci	}
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_ci	for_each_new_connector_in_state(old_state, connector, new_conn_state, i) {
13878c2ecf20Sopenharmony_ci		const struct drm_encoder_helper_funcs *funcs;
13888c2ecf20Sopenharmony_ci		struct drm_encoder *encoder;
13898c2ecf20Sopenharmony_ci		struct drm_bridge *bridge;
13908c2ecf20Sopenharmony_ci
13918c2ecf20Sopenharmony_ci		if (!new_conn_state->best_encoder)
13928c2ecf20Sopenharmony_ci			continue;
13938c2ecf20Sopenharmony_ci
13948c2ecf20Sopenharmony_ci		if (!new_conn_state->crtc->state->active ||
13958c2ecf20Sopenharmony_ci		    !drm_atomic_crtc_needs_modeset(new_conn_state->crtc->state))
13968c2ecf20Sopenharmony_ci			continue;
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_ci		encoder = new_conn_state->best_encoder;
13998c2ecf20Sopenharmony_ci		funcs = encoder->helper_private;
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_ci		DRM_DEBUG_ATOMIC("enabling [ENCODER:%d:%s]\n",
14028c2ecf20Sopenharmony_ci				 encoder->base.id, encoder->name);
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_ci		/*
14058c2ecf20Sopenharmony_ci		 * Each encoder has at most one connector (since we always steal
14068c2ecf20Sopenharmony_ci		 * it away), so we won't call enable hooks twice.
14078c2ecf20Sopenharmony_ci		 */
14088c2ecf20Sopenharmony_ci		bridge = drm_bridge_chain_get_first_bridge(encoder);
14098c2ecf20Sopenharmony_ci		drm_atomic_bridge_chain_pre_enable(bridge, old_state);
14108c2ecf20Sopenharmony_ci
14118c2ecf20Sopenharmony_ci		if (funcs) {
14128c2ecf20Sopenharmony_ci			if (funcs->atomic_enable)
14138c2ecf20Sopenharmony_ci				funcs->atomic_enable(encoder, old_state);
14148c2ecf20Sopenharmony_ci			else if (funcs->enable)
14158c2ecf20Sopenharmony_ci				funcs->enable(encoder);
14168c2ecf20Sopenharmony_ci			else if (funcs->commit)
14178c2ecf20Sopenharmony_ci				funcs->commit(encoder);
14188c2ecf20Sopenharmony_ci		}
14198c2ecf20Sopenharmony_ci
14208c2ecf20Sopenharmony_ci		drm_atomic_bridge_chain_enable(bridge, old_state);
14218c2ecf20Sopenharmony_ci	}
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ci	drm_atomic_helper_commit_writebacks(dev, old_state);
14248c2ecf20Sopenharmony_ci}
14258c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_commit_modeset_enables);
14268c2ecf20Sopenharmony_ci
14278c2ecf20Sopenharmony_ci/**
14288c2ecf20Sopenharmony_ci * drm_atomic_helper_wait_for_fences - wait for fences stashed in plane state
14298c2ecf20Sopenharmony_ci * @dev: DRM device
14308c2ecf20Sopenharmony_ci * @state: atomic state object with old state structures
14318c2ecf20Sopenharmony_ci * @pre_swap: If true, do an interruptible wait, and @state is the new state.
14328c2ecf20Sopenharmony_ci * 	Otherwise @state is the old state.
14338c2ecf20Sopenharmony_ci *
14348c2ecf20Sopenharmony_ci * For implicit sync, driver should fish the exclusive fence out from the
14358c2ecf20Sopenharmony_ci * incoming fb's and stash it in the drm_plane_state.  This is called after
14368c2ecf20Sopenharmony_ci * drm_atomic_helper_swap_state() so it uses the current plane state (and
14378c2ecf20Sopenharmony_ci * just uses the atomic state to find the changed planes)
14388c2ecf20Sopenharmony_ci *
14398c2ecf20Sopenharmony_ci * Note that @pre_swap is needed since the point where we block for fences moves
14408c2ecf20Sopenharmony_ci * around depending upon whether an atomic commit is blocking or
14418c2ecf20Sopenharmony_ci * non-blocking. For non-blocking commit all waiting needs to happen after
14428c2ecf20Sopenharmony_ci * drm_atomic_helper_swap_state() is called, but for blocking commits we want
14438c2ecf20Sopenharmony_ci * to wait **before** we do anything that can't be easily rolled back. That is
14448c2ecf20Sopenharmony_ci * before we call drm_atomic_helper_swap_state().
14458c2ecf20Sopenharmony_ci *
14468c2ecf20Sopenharmony_ci * Returns zero if success or < 0 if dma_fence_wait() fails.
14478c2ecf20Sopenharmony_ci */
14488c2ecf20Sopenharmony_ciint drm_atomic_helper_wait_for_fences(struct drm_device *dev,
14498c2ecf20Sopenharmony_ci				      struct drm_atomic_state *state,
14508c2ecf20Sopenharmony_ci				      bool pre_swap)
14518c2ecf20Sopenharmony_ci{
14528c2ecf20Sopenharmony_ci	struct drm_plane *plane;
14538c2ecf20Sopenharmony_ci	struct drm_plane_state *new_plane_state;
14548c2ecf20Sopenharmony_ci	int i, ret;
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_ci	for_each_new_plane_in_state(state, plane, new_plane_state, i) {
14578c2ecf20Sopenharmony_ci		if (!new_plane_state->fence)
14588c2ecf20Sopenharmony_ci			continue;
14598c2ecf20Sopenharmony_ci
14608c2ecf20Sopenharmony_ci		WARN_ON(!new_plane_state->fb);
14618c2ecf20Sopenharmony_ci
14628c2ecf20Sopenharmony_ci		/*
14638c2ecf20Sopenharmony_ci		 * If waiting for fences pre-swap (ie: nonblock), userspace can
14648c2ecf20Sopenharmony_ci		 * still interrupt the operation. Instead of blocking until the
14658c2ecf20Sopenharmony_ci		 * timer expires, make the wait interruptible.
14668c2ecf20Sopenharmony_ci		 */
14678c2ecf20Sopenharmony_ci		ret = dma_fence_wait(new_plane_state->fence, pre_swap);
14688c2ecf20Sopenharmony_ci		if (ret)
14698c2ecf20Sopenharmony_ci			return ret;
14708c2ecf20Sopenharmony_ci
14718c2ecf20Sopenharmony_ci		dma_fence_put(new_plane_state->fence);
14728c2ecf20Sopenharmony_ci		new_plane_state->fence = NULL;
14738c2ecf20Sopenharmony_ci	}
14748c2ecf20Sopenharmony_ci
14758c2ecf20Sopenharmony_ci	return 0;
14768c2ecf20Sopenharmony_ci}
14778c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_wait_for_fences);
14788c2ecf20Sopenharmony_ci
14798c2ecf20Sopenharmony_ci/**
14808c2ecf20Sopenharmony_ci * drm_atomic_helper_wait_for_vblanks - wait for vblank on CRTCs
14818c2ecf20Sopenharmony_ci * @dev: DRM device
14828c2ecf20Sopenharmony_ci * @old_state: atomic state object with old state structures
14838c2ecf20Sopenharmony_ci *
14848c2ecf20Sopenharmony_ci * Helper to, after atomic commit, wait for vblanks on all affected
14858c2ecf20Sopenharmony_ci * CRTCs (ie. before cleaning up old framebuffers using
14868c2ecf20Sopenharmony_ci * drm_atomic_helper_cleanup_planes()). It will only wait on CRTCs where the
14878c2ecf20Sopenharmony_ci * framebuffers have actually changed to optimize for the legacy cursor and
14888c2ecf20Sopenharmony_ci * plane update use-case.
14898c2ecf20Sopenharmony_ci *
14908c2ecf20Sopenharmony_ci * Drivers using the nonblocking commit tracking support initialized by calling
14918c2ecf20Sopenharmony_ci * drm_atomic_helper_setup_commit() should look at
14928c2ecf20Sopenharmony_ci * drm_atomic_helper_wait_for_flip_done() as an alternative.
14938c2ecf20Sopenharmony_ci */
14948c2ecf20Sopenharmony_civoid
14958c2ecf20Sopenharmony_cidrm_atomic_helper_wait_for_vblanks(struct drm_device *dev,
14968c2ecf20Sopenharmony_ci		struct drm_atomic_state *old_state)
14978c2ecf20Sopenharmony_ci{
14988c2ecf20Sopenharmony_ci	struct drm_crtc *crtc;
14998c2ecf20Sopenharmony_ci	struct drm_crtc_state *old_crtc_state, *new_crtc_state;
15008c2ecf20Sopenharmony_ci	int i, ret;
15018c2ecf20Sopenharmony_ci	unsigned crtc_mask = 0;
15028c2ecf20Sopenharmony_ci
15038c2ecf20Sopenharmony_ci	 /*
15048c2ecf20Sopenharmony_ci	  * Legacy cursor ioctls are completely unsynced, and userspace
15058c2ecf20Sopenharmony_ci	  * relies on that (by doing tons of cursor updates).
15068c2ecf20Sopenharmony_ci	  */
15078c2ecf20Sopenharmony_ci	if (old_state->legacy_cursor_update)
15088c2ecf20Sopenharmony_ci		return;
15098c2ecf20Sopenharmony_ci
15108c2ecf20Sopenharmony_ci	for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) {
15118c2ecf20Sopenharmony_ci		if (!new_crtc_state->active)
15128c2ecf20Sopenharmony_ci			continue;
15138c2ecf20Sopenharmony_ci
15148c2ecf20Sopenharmony_ci		ret = drm_crtc_vblank_get(crtc);
15158c2ecf20Sopenharmony_ci		if (ret != 0)
15168c2ecf20Sopenharmony_ci			continue;
15178c2ecf20Sopenharmony_ci
15188c2ecf20Sopenharmony_ci		crtc_mask |= drm_crtc_mask(crtc);
15198c2ecf20Sopenharmony_ci		old_state->crtcs[i].last_vblank_count = drm_crtc_vblank_count(crtc);
15208c2ecf20Sopenharmony_ci	}
15218c2ecf20Sopenharmony_ci
15228c2ecf20Sopenharmony_ci	for_each_old_crtc_in_state(old_state, crtc, old_crtc_state, i) {
15238c2ecf20Sopenharmony_ci		if (!(crtc_mask & drm_crtc_mask(crtc)))
15248c2ecf20Sopenharmony_ci			continue;
15258c2ecf20Sopenharmony_ci
15268c2ecf20Sopenharmony_ci		ret = wait_event_timeout(dev->vblank[i].queue,
15278c2ecf20Sopenharmony_ci				old_state->crtcs[i].last_vblank_count !=
15288c2ecf20Sopenharmony_ci					drm_crtc_vblank_count(crtc),
15298c2ecf20Sopenharmony_ci				msecs_to_jiffies(100));
15308c2ecf20Sopenharmony_ci
15318c2ecf20Sopenharmony_ci		WARN(!ret, "[CRTC:%d:%s] vblank wait timed out\n",
15328c2ecf20Sopenharmony_ci		     crtc->base.id, crtc->name);
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_ci		drm_crtc_vblank_put(crtc);
15358c2ecf20Sopenharmony_ci	}
15368c2ecf20Sopenharmony_ci}
15378c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_wait_for_vblanks);
15388c2ecf20Sopenharmony_ci
15398c2ecf20Sopenharmony_ci/**
15408c2ecf20Sopenharmony_ci * drm_atomic_helper_wait_for_flip_done - wait for all page flips to be done
15418c2ecf20Sopenharmony_ci * @dev: DRM device
15428c2ecf20Sopenharmony_ci * @old_state: atomic state object with old state structures
15438c2ecf20Sopenharmony_ci *
15448c2ecf20Sopenharmony_ci * Helper to, after atomic commit, wait for page flips on all affected
15458c2ecf20Sopenharmony_ci * crtcs (ie. before cleaning up old framebuffers using
15468c2ecf20Sopenharmony_ci * drm_atomic_helper_cleanup_planes()). Compared to
15478c2ecf20Sopenharmony_ci * drm_atomic_helper_wait_for_vblanks() this waits for the completion on all
15488c2ecf20Sopenharmony_ci * CRTCs, assuming that cursors-only updates are signalling their completion
15498c2ecf20Sopenharmony_ci * immediately (or using a different path).
15508c2ecf20Sopenharmony_ci *
15518c2ecf20Sopenharmony_ci * This requires that drivers use the nonblocking commit tracking support
15528c2ecf20Sopenharmony_ci * initialized using drm_atomic_helper_setup_commit().
15538c2ecf20Sopenharmony_ci */
15548c2ecf20Sopenharmony_civoid drm_atomic_helper_wait_for_flip_done(struct drm_device *dev,
15558c2ecf20Sopenharmony_ci					  struct drm_atomic_state *old_state)
15568c2ecf20Sopenharmony_ci{
15578c2ecf20Sopenharmony_ci	struct drm_crtc *crtc;
15588c2ecf20Sopenharmony_ci	int i;
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_ci	for (i = 0; i < dev->mode_config.num_crtc; i++) {
15618c2ecf20Sopenharmony_ci		struct drm_crtc_commit *commit = old_state->crtcs[i].commit;
15628c2ecf20Sopenharmony_ci		int ret;
15638c2ecf20Sopenharmony_ci
15648c2ecf20Sopenharmony_ci		crtc = old_state->crtcs[i].ptr;
15658c2ecf20Sopenharmony_ci
15668c2ecf20Sopenharmony_ci		if (!crtc || !commit)
15678c2ecf20Sopenharmony_ci			continue;
15688c2ecf20Sopenharmony_ci
15698c2ecf20Sopenharmony_ci		ret = wait_for_completion_timeout(&commit->flip_done, 10 * HZ);
15708c2ecf20Sopenharmony_ci		if (ret == 0)
15718c2ecf20Sopenharmony_ci			DRM_ERROR("[CRTC:%d:%s] flip_done timed out\n",
15728c2ecf20Sopenharmony_ci				  crtc->base.id, crtc->name);
15738c2ecf20Sopenharmony_ci	}
15748c2ecf20Sopenharmony_ci
15758c2ecf20Sopenharmony_ci	if (old_state->fake_commit)
15768c2ecf20Sopenharmony_ci		complete_all(&old_state->fake_commit->flip_done);
15778c2ecf20Sopenharmony_ci}
15788c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_wait_for_flip_done);
15798c2ecf20Sopenharmony_ci
15808c2ecf20Sopenharmony_ci/**
15818c2ecf20Sopenharmony_ci * drm_atomic_helper_commit_tail - commit atomic update to hardware
15828c2ecf20Sopenharmony_ci * @old_state: atomic state object with old state structures
15838c2ecf20Sopenharmony_ci *
15848c2ecf20Sopenharmony_ci * This is the default implementation for the
15858c2ecf20Sopenharmony_ci * &drm_mode_config_helper_funcs.atomic_commit_tail hook, for drivers
15868c2ecf20Sopenharmony_ci * that do not support runtime_pm or do not need the CRTC to be
15878c2ecf20Sopenharmony_ci * enabled to perform a commit. Otherwise, see
15888c2ecf20Sopenharmony_ci * drm_atomic_helper_commit_tail_rpm().
15898c2ecf20Sopenharmony_ci *
15908c2ecf20Sopenharmony_ci * Note that the default ordering of how the various stages are called is to
15918c2ecf20Sopenharmony_ci * match the legacy modeset helper library closest.
15928c2ecf20Sopenharmony_ci */
15938c2ecf20Sopenharmony_civoid drm_atomic_helper_commit_tail(struct drm_atomic_state *old_state)
15948c2ecf20Sopenharmony_ci{
15958c2ecf20Sopenharmony_ci	struct drm_device *dev = old_state->dev;
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_ci	drm_atomic_helper_commit_modeset_disables(dev, old_state);
15988c2ecf20Sopenharmony_ci
15998c2ecf20Sopenharmony_ci	drm_atomic_helper_commit_planes(dev, old_state, 0);
16008c2ecf20Sopenharmony_ci
16018c2ecf20Sopenharmony_ci	drm_atomic_helper_commit_modeset_enables(dev, old_state);
16028c2ecf20Sopenharmony_ci
16038c2ecf20Sopenharmony_ci	drm_atomic_helper_fake_vblank(old_state);
16048c2ecf20Sopenharmony_ci
16058c2ecf20Sopenharmony_ci	drm_atomic_helper_commit_hw_done(old_state);
16068c2ecf20Sopenharmony_ci
16078c2ecf20Sopenharmony_ci	drm_atomic_helper_wait_for_vblanks(dev, old_state);
16088c2ecf20Sopenharmony_ci
16098c2ecf20Sopenharmony_ci	drm_atomic_helper_cleanup_planes(dev, old_state);
16108c2ecf20Sopenharmony_ci}
16118c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_commit_tail);
16128c2ecf20Sopenharmony_ci
16138c2ecf20Sopenharmony_ci/**
16148c2ecf20Sopenharmony_ci * drm_atomic_helper_commit_tail_rpm - commit atomic update to hardware
16158c2ecf20Sopenharmony_ci * @old_state: new modeset state to be committed
16168c2ecf20Sopenharmony_ci *
16178c2ecf20Sopenharmony_ci * This is an alternative implementation for the
16188c2ecf20Sopenharmony_ci * &drm_mode_config_helper_funcs.atomic_commit_tail hook, for drivers
16198c2ecf20Sopenharmony_ci * that support runtime_pm or need the CRTC to be enabled to perform a
16208c2ecf20Sopenharmony_ci * commit. Otherwise, one should use the default implementation
16218c2ecf20Sopenharmony_ci * drm_atomic_helper_commit_tail().
16228c2ecf20Sopenharmony_ci */
16238c2ecf20Sopenharmony_civoid drm_atomic_helper_commit_tail_rpm(struct drm_atomic_state *old_state)
16248c2ecf20Sopenharmony_ci{
16258c2ecf20Sopenharmony_ci	struct drm_device *dev = old_state->dev;
16268c2ecf20Sopenharmony_ci
16278c2ecf20Sopenharmony_ci	drm_atomic_helper_commit_modeset_disables(dev, old_state);
16288c2ecf20Sopenharmony_ci
16298c2ecf20Sopenharmony_ci	drm_atomic_helper_commit_modeset_enables(dev, old_state);
16308c2ecf20Sopenharmony_ci
16318c2ecf20Sopenharmony_ci	drm_atomic_helper_commit_planes(dev, old_state,
16328c2ecf20Sopenharmony_ci					DRM_PLANE_COMMIT_ACTIVE_ONLY);
16338c2ecf20Sopenharmony_ci
16348c2ecf20Sopenharmony_ci	drm_atomic_helper_fake_vblank(old_state);
16358c2ecf20Sopenharmony_ci
16368c2ecf20Sopenharmony_ci	drm_atomic_helper_commit_hw_done(old_state);
16378c2ecf20Sopenharmony_ci
16388c2ecf20Sopenharmony_ci	drm_atomic_helper_wait_for_vblanks(dev, old_state);
16398c2ecf20Sopenharmony_ci
16408c2ecf20Sopenharmony_ci	drm_atomic_helper_cleanup_planes(dev, old_state);
16418c2ecf20Sopenharmony_ci}
16428c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_commit_tail_rpm);
16438c2ecf20Sopenharmony_ci
16448c2ecf20Sopenharmony_cistatic void commit_tail(struct drm_atomic_state *old_state)
16458c2ecf20Sopenharmony_ci{
16468c2ecf20Sopenharmony_ci	struct drm_device *dev = old_state->dev;
16478c2ecf20Sopenharmony_ci	const struct drm_mode_config_helper_funcs *funcs;
16488c2ecf20Sopenharmony_ci	struct drm_crtc_state *new_crtc_state;
16498c2ecf20Sopenharmony_ci	struct drm_crtc *crtc;
16508c2ecf20Sopenharmony_ci	ktime_t start;
16518c2ecf20Sopenharmony_ci	s64 commit_time_ms;
16528c2ecf20Sopenharmony_ci	unsigned int i, new_self_refresh_mask = 0;
16538c2ecf20Sopenharmony_ci
16548c2ecf20Sopenharmony_ci	funcs = dev->mode_config.helper_private;
16558c2ecf20Sopenharmony_ci
16568c2ecf20Sopenharmony_ci	/*
16578c2ecf20Sopenharmony_ci	 * We're measuring the _entire_ commit, so the time will vary depending
16588c2ecf20Sopenharmony_ci	 * on how many fences and objects are involved. For the purposes of self
16598c2ecf20Sopenharmony_ci	 * refresh, this is desirable since it'll give us an idea of how
16608c2ecf20Sopenharmony_ci	 * congested things are. This will inform our decision on how often we
16618c2ecf20Sopenharmony_ci	 * should enter self refresh after idle.
16628c2ecf20Sopenharmony_ci	 *
16638c2ecf20Sopenharmony_ci	 * These times will be averaged out in the self refresh helpers to avoid
16648c2ecf20Sopenharmony_ci	 * overreacting over one outlier frame
16658c2ecf20Sopenharmony_ci	 */
16668c2ecf20Sopenharmony_ci	start = ktime_get();
16678c2ecf20Sopenharmony_ci
16688c2ecf20Sopenharmony_ci	drm_atomic_helper_wait_for_fences(dev, old_state, false);
16698c2ecf20Sopenharmony_ci
16708c2ecf20Sopenharmony_ci	drm_atomic_helper_wait_for_dependencies(old_state);
16718c2ecf20Sopenharmony_ci
16728c2ecf20Sopenharmony_ci	/*
16738c2ecf20Sopenharmony_ci	 * We cannot safely access new_crtc_state after
16748c2ecf20Sopenharmony_ci	 * drm_atomic_helper_commit_hw_done() so figure out which crtc's have
16758c2ecf20Sopenharmony_ci	 * self-refresh active beforehand:
16768c2ecf20Sopenharmony_ci	 */
16778c2ecf20Sopenharmony_ci	for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i)
16788c2ecf20Sopenharmony_ci		if (new_crtc_state->self_refresh_active)
16798c2ecf20Sopenharmony_ci			new_self_refresh_mask |= BIT(i);
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_ci	if (funcs && funcs->atomic_commit_tail)
16828c2ecf20Sopenharmony_ci		funcs->atomic_commit_tail(old_state);
16838c2ecf20Sopenharmony_ci	else
16848c2ecf20Sopenharmony_ci		drm_atomic_helper_commit_tail(old_state);
16858c2ecf20Sopenharmony_ci
16868c2ecf20Sopenharmony_ci	commit_time_ms = ktime_ms_delta(ktime_get(), start);
16878c2ecf20Sopenharmony_ci	if (commit_time_ms > 0)
16888c2ecf20Sopenharmony_ci		drm_self_refresh_helper_update_avg_times(old_state,
16898c2ecf20Sopenharmony_ci						 (unsigned long)commit_time_ms,
16908c2ecf20Sopenharmony_ci						 new_self_refresh_mask);
16918c2ecf20Sopenharmony_ci
16928c2ecf20Sopenharmony_ci	drm_atomic_helper_commit_cleanup_done(old_state);
16938c2ecf20Sopenharmony_ci
16948c2ecf20Sopenharmony_ci	drm_atomic_state_put(old_state);
16958c2ecf20Sopenharmony_ci}
16968c2ecf20Sopenharmony_ci
16978c2ecf20Sopenharmony_cistatic void commit_work(struct work_struct *work)
16988c2ecf20Sopenharmony_ci{
16998c2ecf20Sopenharmony_ci	struct drm_atomic_state *state = container_of(work,
17008c2ecf20Sopenharmony_ci						      struct drm_atomic_state,
17018c2ecf20Sopenharmony_ci						      commit_work);
17028c2ecf20Sopenharmony_ci	commit_tail(state);
17038c2ecf20Sopenharmony_ci}
17048c2ecf20Sopenharmony_ci
17058c2ecf20Sopenharmony_ci/**
17068c2ecf20Sopenharmony_ci * drm_atomic_helper_async_check - check if state can be commited asynchronously
17078c2ecf20Sopenharmony_ci * @dev: DRM device
17088c2ecf20Sopenharmony_ci * @state: the driver state object
17098c2ecf20Sopenharmony_ci *
17108c2ecf20Sopenharmony_ci * This helper will check if it is possible to commit the state asynchronously.
17118c2ecf20Sopenharmony_ci * Async commits are not supposed to swap the states like normal sync commits
17128c2ecf20Sopenharmony_ci * but just do in-place changes on the current state.
17138c2ecf20Sopenharmony_ci *
17148c2ecf20Sopenharmony_ci * It will return 0 if the commit can happen in an asynchronous fashion or error
17158c2ecf20Sopenharmony_ci * if not. Note that error just mean it can't be commited asynchronously, if it
17168c2ecf20Sopenharmony_ci * fails the commit should be treated like a normal synchronous commit.
17178c2ecf20Sopenharmony_ci */
17188c2ecf20Sopenharmony_ciint drm_atomic_helper_async_check(struct drm_device *dev,
17198c2ecf20Sopenharmony_ci				   struct drm_atomic_state *state)
17208c2ecf20Sopenharmony_ci{
17218c2ecf20Sopenharmony_ci	struct drm_crtc *crtc;
17228c2ecf20Sopenharmony_ci	struct drm_crtc_state *crtc_state;
17238c2ecf20Sopenharmony_ci	struct drm_plane *plane = NULL;
17248c2ecf20Sopenharmony_ci	struct drm_plane_state *old_plane_state = NULL;
17258c2ecf20Sopenharmony_ci	struct drm_plane_state *new_plane_state = NULL;
17268c2ecf20Sopenharmony_ci	const struct drm_plane_helper_funcs *funcs;
17278c2ecf20Sopenharmony_ci	int i, n_planes = 0;
17288c2ecf20Sopenharmony_ci
17298c2ecf20Sopenharmony_ci	for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
17308c2ecf20Sopenharmony_ci		if (drm_atomic_crtc_needs_modeset(crtc_state))
17318c2ecf20Sopenharmony_ci			return -EINVAL;
17328c2ecf20Sopenharmony_ci	}
17338c2ecf20Sopenharmony_ci
17348c2ecf20Sopenharmony_ci	for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i)
17358c2ecf20Sopenharmony_ci		n_planes++;
17368c2ecf20Sopenharmony_ci
17378c2ecf20Sopenharmony_ci	/* FIXME: we support only single plane updates for now */
17388c2ecf20Sopenharmony_ci	if (n_planes != 1)
17398c2ecf20Sopenharmony_ci		return -EINVAL;
17408c2ecf20Sopenharmony_ci
17418c2ecf20Sopenharmony_ci	if (!new_plane_state->crtc ||
17428c2ecf20Sopenharmony_ci	    old_plane_state->crtc != new_plane_state->crtc)
17438c2ecf20Sopenharmony_ci		return -EINVAL;
17448c2ecf20Sopenharmony_ci
17458c2ecf20Sopenharmony_ci	funcs = plane->helper_private;
17468c2ecf20Sopenharmony_ci	if (!funcs->atomic_async_update)
17478c2ecf20Sopenharmony_ci		return -EINVAL;
17488c2ecf20Sopenharmony_ci
17498c2ecf20Sopenharmony_ci	if (new_plane_state->fence)
17508c2ecf20Sopenharmony_ci		return -EINVAL;
17518c2ecf20Sopenharmony_ci
17528c2ecf20Sopenharmony_ci	/*
17538c2ecf20Sopenharmony_ci	 * Don't do an async update if there is an outstanding commit modifying
17548c2ecf20Sopenharmony_ci	 * the plane.  This prevents our async update's changes from getting
17558c2ecf20Sopenharmony_ci	 * overridden by a previous synchronous update's state.
17568c2ecf20Sopenharmony_ci	 */
17578c2ecf20Sopenharmony_ci	if (old_plane_state->commit &&
17588c2ecf20Sopenharmony_ci	    !try_wait_for_completion(&old_plane_state->commit->hw_done))
17598c2ecf20Sopenharmony_ci		return -EBUSY;
17608c2ecf20Sopenharmony_ci
17618c2ecf20Sopenharmony_ci	return funcs->atomic_async_check(plane, new_plane_state);
17628c2ecf20Sopenharmony_ci}
17638c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_async_check);
17648c2ecf20Sopenharmony_ci
17658c2ecf20Sopenharmony_ci/**
17668c2ecf20Sopenharmony_ci * drm_atomic_helper_async_commit - commit state asynchronously
17678c2ecf20Sopenharmony_ci * @dev: DRM device
17688c2ecf20Sopenharmony_ci * @state: the driver state object
17698c2ecf20Sopenharmony_ci *
17708c2ecf20Sopenharmony_ci * This function commits a state asynchronously, i.e., not vblank
17718c2ecf20Sopenharmony_ci * synchronized. It should be used on a state only when
17728c2ecf20Sopenharmony_ci * drm_atomic_async_check() succeeds. Async commits are not supposed to swap
17738c2ecf20Sopenharmony_ci * the states like normal sync commits, but just do in-place changes on the
17748c2ecf20Sopenharmony_ci * current state.
17758c2ecf20Sopenharmony_ci *
17768c2ecf20Sopenharmony_ci * TODO: Implement full swap instead of doing in-place changes.
17778c2ecf20Sopenharmony_ci */
17788c2ecf20Sopenharmony_civoid drm_atomic_helper_async_commit(struct drm_device *dev,
17798c2ecf20Sopenharmony_ci				    struct drm_atomic_state *state)
17808c2ecf20Sopenharmony_ci{
17818c2ecf20Sopenharmony_ci	struct drm_plane *plane;
17828c2ecf20Sopenharmony_ci	struct drm_plane_state *plane_state;
17838c2ecf20Sopenharmony_ci	const struct drm_plane_helper_funcs *funcs;
17848c2ecf20Sopenharmony_ci	int i;
17858c2ecf20Sopenharmony_ci
17868c2ecf20Sopenharmony_ci	for_each_new_plane_in_state(state, plane, plane_state, i) {
17878c2ecf20Sopenharmony_ci		struct drm_framebuffer *new_fb = plane_state->fb;
17888c2ecf20Sopenharmony_ci		struct drm_framebuffer *old_fb = plane->state->fb;
17898c2ecf20Sopenharmony_ci
17908c2ecf20Sopenharmony_ci		funcs = plane->helper_private;
17918c2ecf20Sopenharmony_ci		funcs->atomic_async_update(plane, plane_state);
17928c2ecf20Sopenharmony_ci
17938c2ecf20Sopenharmony_ci		/*
17948c2ecf20Sopenharmony_ci		 * ->atomic_async_update() is supposed to update the
17958c2ecf20Sopenharmony_ci		 * plane->state in-place, make sure at least common
17968c2ecf20Sopenharmony_ci		 * properties have been properly updated.
17978c2ecf20Sopenharmony_ci		 */
17988c2ecf20Sopenharmony_ci		WARN_ON_ONCE(plane->state->fb != new_fb);
17998c2ecf20Sopenharmony_ci		WARN_ON_ONCE(plane->state->crtc_x != plane_state->crtc_x);
18008c2ecf20Sopenharmony_ci		WARN_ON_ONCE(plane->state->crtc_y != plane_state->crtc_y);
18018c2ecf20Sopenharmony_ci		WARN_ON_ONCE(plane->state->src_x != plane_state->src_x);
18028c2ecf20Sopenharmony_ci		WARN_ON_ONCE(plane->state->src_y != plane_state->src_y);
18038c2ecf20Sopenharmony_ci
18048c2ecf20Sopenharmony_ci		/*
18058c2ecf20Sopenharmony_ci		 * Make sure the FBs have been swapped so that cleanups in the
18068c2ecf20Sopenharmony_ci		 * new_state performs a cleanup in the old FB.
18078c2ecf20Sopenharmony_ci		 */
18088c2ecf20Sopenharmony_ci		WARN_ON_ONCE(plane_state->fb != old_fb);
18098c2ecf20Sopenharmony_ci	}
18108c2ecf20Sopenharmony_ci}
18118c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_async_commit);
18128c2ecf20Sopenharmony_ci
18138c2ecf20Sopenharmony_ci/**
18148c2ecf20Sopenharmony_ci * drm_atomic_helper_commit - commit validated state object
18158c2ecf20Sopenharmony_ci * @dev: DRM device
18168c2ecf20Sopenharmony_ci * @state: the driver state object
18178c2ecf20Sopenharmony_ci * @nonblock: whether nonblocking behavior is requested.
18188c2ecf20Sopenharmony_ci *
18198c2ecf20Sopenharmony_ci * This function commits a with drm_atomic_helper_check() pre-validated state
18208c2ecf20Sopenharmony_ci * object. This can still fail when e.g. the framebuffer reservation fails. This
18218c2ecf20Sopenharmony_ci * function implements nonblocking commits, using
18228c2ecf20Sopenharmony_ci * drm_atomic_helper_setup_commit() and related functions.
18238c2ecf20Sopenharmony_ci *
18248c2ecf20Sopenharmony_ci * Committing the actual hardware state is done through the
18258c2ecf20Sopenharmony_ci * &drm_mode_config_helper_funcs.atomic_commit_tail callback, or its default
18268c2ecf20Sopenharmony_ci * implementation drm_atomic_helper_commit_tail().
18278c2ecf20Sopenharmony_ci *
18288c2ecf20Sopenharmony_ci * RETURNS:
18298c2ecf20Sopenharmony_ci * Zero for success or -errno.
18308c2ecf20Sopenharmony_ci */
18318c2ecf20Sopenharmony_ciint drm_atomic_helper_commit(struct drm_device *dev,
18328c2ecf20Sopenharmony_ci			     struct drm_atomic_state *state,
18338c2ecf20Sopenharmony_ci			     bool nonblock)
18348c2ecf20Sopenharmony_ci{
18358c2ecf20Sopenharmony_ci	int ret;
18368c2ecf20Sopenharmony_ci
18378c2ecf20Sopenharmony_ci	if (state->async_update) {
18388c2ecf20Sopenharmony_ci		ret = drm_atomic_helper_prepare_planes(dev, state);
18398c2ecf20Sopenharmony_ci		if (ret)
18408c2ecf20Sopenharmony_ci			return ret;
18418c2ecf20Sopenharmony_ci
18428c2ecf20Sopenharmony_ci		drm_atomic_helper_async_commit(dev, state);
18438c2ecf20Sopenharmony_ci		drm_atomic_helper_cleanup_planes(dev, state);
18448c2ecf20Sopenharmony_ci
18458c2ecf20Sopenharmony_ci		return 0;
18468c2ecf20Sopenharmony_ci	}
18478c2ecf20Sopenharmony_ci
18488c2ecf20Sopenharmony_ci	ret = drm_atomic_helper_setup_commit(state, nonblock);
18498c2ecf20Sopenharmony_ci	if (ret)
18508c2ecf20Sopenharmony_ci		return ret;
18518c2ecf20Sopenharmony_ci
18528c2ecf20Sopenharmony_ci	INIT_WORK(&state->commit_work, commit_work);
18538c2ecf20Sopenharmony_ci
18548c2ecf20Sopenharmony_ci	ret = drm_atomic_helper_prepare_planes(dev, state);
18558c2ecf20Sopenharmony_ci	if (ret)
18568c2ecf20Sopenharmony_ci		return ret;
18578c2ecf20Sopenharmony_ci
18588c2ecf20Sopenharmony_ci	if (!nonblock) {
18598c2ecf20Sopenharmony_ci		ret = drm_atomic_helper_wait_for_fences(dev, state, true);
18608c2ecf20Sopenharmony_ci		if (ret)
18618c2ecf20Sopenharmony_ci			goto err;
18628c2ecf20Sopenharmony_ci	}
18638c2ecf20Sopenharmony_ci
18648c2ecf20Sopenharmony_ci	/*
18658c2ecf20Sopenharmony_ci	 * This is the point of no return - everything below never fails except
18668c2ecf20Sopenharmony_ci	 * when the hw goes bonghits. Which means we can commit the new state on
18678c2ecf20Sopenharmony_ci	 * the software side now.
18688c2ecf20Sopenharmony_ci	 */
18698c2ecf20Sopenharmony_ci
18708c2ecf20Sopenharmony_ci	ret = drm_atomic_helper_swap_state(state, true);
18718c2ecf20Sopenharmony_ci	if (ret)
18728c2ecf20Sopenharmony_ci		goto err;
18738c2ecf20Sopenharmony_ci
18748c2ecf20Sopenharmony_ci	/*
18758c2ecf20Sopenharmony_ci	 * Everything below can be run asynchronously without the need to grab
18768c2ecf20Sopenharmony_ci	 * any modeset locks at all under one condition: It must be guaranteed
18778c2ecf20Sopenharmony_ci	 * that the asynchronous work has either been cancelled (if the driver
18788c2ecf20Sopenharmony_ci	 * supports it, which at least requires that the framebuffers get
18798c2ecf20Sopenharmony_ci	 * cleaned up with drm_atomic_helper_cleanup_planes()) or completed
18808c2ecf20Sopenharmony_ci	 * before the new state gets committed on the software side with
18818c2ecf20Sopenharmony_ci	 * drm_atomic_helper_swap_state().
18828c2ecf20Sopenharmony_ci	 *
18838c2ecf20Sopenharmony_ci	 * This scheme allows new atomic state updates to be prepared and
18848c2ecf20Sopenharmony_ci	 * checked in parallel to the asynchronous completion of the previous
18858c2ecf20Sopenharmony_ci	 * update. Which is important since compositors need to figure out the
18868c2ecf20Sopenharmony_ci	 * composition of the next frame right after having submitted the
18878c2ecf20Sopenharmony_ci	 * current layout.
18888c2ecf20Sopenharmony_ci	 *
18898c2ecf20Sopenharmony_ci	 * NOTE: Commit work has multiple phases, first hardware commit, then
18908c2ecf20Sopenharmony_ci	 * cleanup. We want them to overlap, hence need system_unbound_wq to
18918c2ecf20Sopenharmony_ci	 * make sure work items don't artificially stall on each another.
18928c2ecf20Sopenharmony_ci	 */
18938c2ecf20Sopenharmony_ci
18948c2ecf20Sopenharmony_ci	drm_atomic_state_get(state);
18958c2ecf20Sopenharmony_ci	if (nonblock)
18968c2ecf20Sopenharmony_ci		queue_work(system_unbound_wq, &state->commit_work);
18978c2ecf20Sopenharmony_ci	else
18988c2ecf20Sopenharmony_ci		commit_tail(state);
18998c2ecf20Sopenharmony_ci
19008c2ecf20Sopenharmony_ci	return 0;
19018c2ecf20Sopenharmony_ci
19028c2ecf20Sopenharmony_cierr:
19038c2ecf20Sopenharmony_ci	drm_atomic_helper_cleanup_planes(dev, state);
19048c2ecf20Sopenharmony_ci	return ret;
19058c2ecf20Sopenharmony_ci}
19068c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_commit);
19078c2ecf20Sopenharmony_ci
19088c2ecf20Sopenharmony_ci/**
19098c2ecf20Sopenharmony_ci * DOC: implementing nonblocking commit
19108c2ecf20Sopenharmony_ci *
19118c2ecf20Sopenharmony_ci * Nonblocking atomic commits should use struct &drm_crtc_commit to sequence
19128c2ecf20Sopenharmony_ci * different operations against each another. Locks, especially struct
19138c2ecf20Sopenharmony_ci * &drm_modeset_lock, should not be held in worker threads or any other
19148c2ecf20Sopenharmony_ci * asynchronous context used to commit the hardware state.
19158c2ecf20Sopenharmony_ci *
19168c2ecf20Sopenharmony_ci * drm_atomic_helper_commit() implements the recommended sequence for
19178c2ecf20Sopenharmony_ci * nonblocking commits, using drm_atomic_helper_setup_commit() internally:
19188c2ecf20Sopenharmony_ci *
19198c2ecf20Sopenharmony_ci * 1. Run drm_atomic_helper_prepare_planes(). Since this can fail and we
19208c2ecf20Sopenharmony_ci * need to propagate out of memory/VRAM errors to userspace, it must be called
19218c2ecf20Sopenharmony_ci * synchronously.
19228c2ecf20Sopenharmony_ci *
19238c2ecf20Sopenharmony_ci * 2. Synchronize with any outstanding nonblocking commit worker threads which
19248c2ecf20Sopenharmony_ci * might be affected by the new state update. This is handled by
19258c2ecf20Sopenharmony_ci * drm_atomic_helper_setup_commit().
19268c2ecf20Sopenharmony_ci *
19278c2ecf20Sopenharmony_ci * Asynchronous workers need to have sufficient parallelism to be able to run
19288c2ecf20Sopenharmony_ci * different atomic commits on different CRTCs in parallel. The simplest way to
19298c2ecf20Sopenharmony_ci * achieve this is by running them on the &system_unbound_wq work queue. Note
19308c2ecf20Sopenharmony_ci * that drivers are not required to split up atomic commits and run an
19318c2ecf20Sopenharmony_ci * individual commit in parallel - userspace is supposed to do that if it cares.
19328c2ecf20Sopenharmony_ci * But it might be beneficial to do that for modesets, since those necessarily
19338c2ecf20Sopenharmony_ci * must be done as one global operation, and enabling or disabling a CRTC can
19348c2ecf20Sopenharmony_ci * take a long time. But even that is not required.
19358c2ecf20Sopenharmony_ci *
19368c2ecf20Sopenharmony_ci * IMPORTANT: A &drm_atomic_state update for multiple CRTCs is sequenced
19378c2ecf20Sopenharmony_ci * against all CRTCs therein. Therefore for atomic state updates which only flip
19388c2ecf20Sopenharmony_ci * planes the driver must not get the struct &drm_crtc_state of unrelated CRTCs
19398c2ecf20Sopenharmony_ci * in its atomic check code: This would prevent committing of atomic updates to
19408c2ecf20Sopenharmony_ci * multiple CRTCs in parallel. In general, adding additional state structures
19418c2ecf20Sopenharmony_ci * should be avoided as much as possible, because this reduces parallelism in
19428c2ecf20Sopenharmony_ci * (nonblocking) commits, both due to locking and due to commit sequencing
19438c2ecf20Sopenharmony_ci * requirements.
19448c2ecf20Sopenharmony_ci *
19458c2ecf20Sopenharmony_ci * 3. The software state is updated synchronously with
19468c2ecf20Sopenharmony_ci * drm_atomic_helper_swap_state(). Doing this under the protection of all modeset
19478c2ecf20Sopenharmony_ci * locks means concurrent callers never see inconsistent state. Note that commit
19488c2ecf20Sopenharmony_ci * workers do not hold any locks; their access is only coordinated through
19498c2ecf20Sopenharmony_ci * ordering. If workers would access state only through the pointers in the
19508c2ecf20Sopenharmony_ci * free-standing state objects (currently not the case for any driver) then even
19518c2ecf20Sopenharmony_ci * multiple pending commits could be in-flight at the same time.
19528c2ecf20Sopenharmony_ci *
19538c2ecf20Sopenharmony_ci * 4. Schedule a work item to do all subsequent steps, using the split-out
19548c2ecf20Sopenharmony_ci * commit helpers: a) pre-plane commit b) plane commit c) post-plane commit and
19558c2ecf20Sopenharmony_ci * then cleaning up the framebuffers after the old framebuffer is no longer
19568c2ecf20Sopenharmony_ci * being displayed. The scheduled work should synchronize against other workers
19578c2ecf20Sopenharmony_ci * using the &drm_crtc_commit infrastructure as needed. See
19588c2ecf20Sopenharmony_ci * drm_atomic_helper_setup_commit() for more details.
19598c2ecf20Sopenharmony_ci */
19608c2ecf20Sopenharmony_ci
19618c2ecf20Sopenharmony_cistatic int stall_checks(struct drm_crtc *crtc, bool nonblock)
19628c2ecf20Sopenharmony_ci{
19638c2ecf20Sopenharmony_ci	struct drm_crtc_commit *commit, *stall_commit = NULL;
19648c2ecf20Sopenharmony_ci	bool completed = true;
19658c2ecf20Sopenharmony_ci	int i;
19668c2ecf20Sopenharmony_ci	long ret = 0;
19678c2ecf20Sopenharmony_ci
19688c2ecf20Sopenharmony_ci	spin_lock(&crtc->commit_lock);
19698c2ecf20Sopenharmony_ci	i = 0;
19708c2ecf20Sopenharmony_ci	list_for_each_entry(commit, &crtc->commit_list, commit_entry) {
19718c2ecf20Sopenharmony_ci		if (i == 0) {
19728c2ecf20Sopenharmony_ci			completed = try_wait_for_completion(&commit->flip_done);
19738c2ecf20Sopenharmony_ci			/* Userspace is not allowed to get ahead of the previous
19748c2ecf20Sopenharmony_ci			 * commit with nonblocking ones. */
19758c2ecf20Sopenharmony_ci			if (!completed && nonblock) {
19768c2ecf20Sopenharmony_ci				spin_unlock(&crtc->commit_lock);
19778c2ecf20Sopenharmony_ci				return -EBUSY;
19788c2ecf20Sopenharmony_ci			}
19798c2ecf20Sopenharmony_ci		} else if (i == 1) {
19808c2ecf20Sopenharmony_ci			stall_commit = drm_crtc_commit_get(commit);
19818c2ecf20Sopenharmony_ci			break;
19828c2ecf20Sopenharmony_ci		}
19838c2ecf20Sopenharmony_ci
19848c2ecf20Sopenharmony_ci		i++;
19858c2ecf20Sopenharmony_ci	}
19868c2ecf20Sopenharmony_ci	spin_unlock(&crtc->commit_lock);
19878c2ecf20Sopenharmony_ci
19888c2ecf20Sopenharmony_ci	if (!stall_commit)
19898c2ecf20Sopenharmony_ci		return 0;
19908c2ecf20Sopenharmony_ci
19918c2ecf20Sopenharmony_ci	/* We don't want to let commits get ahead of cleanup work too much,
19928c2ecf20Sopenharmony_ci	 * stalling on 2nd previous commit means triple-buffer won't ever stall.
19938c2ecf20Sopenharmony_ci	 */
19948c2ecf20Sopenharmony_ci	ret = wait_for_completion_interruptible_timeout(&stall_commit->cleanup_done,
19958c2ecf20Sopenharmony_ci							10*HZ);
19968c2ecf20Sopenharmony_ci	if (ret == 0)
19978c2ecf20Sopenharmony_ci		DRM_ERROR("[CRTC:%d:%s] cleanup_done timed out\n",
19988c2ecf20Sopenharmony_ci			  crtc->base.id, crtc->name);
19998c2ecf20Sopenharmony_ci
20008c2ecf20Sopenharmony_ci	drm_crtc_commit_put(stall_commit);
20018c2ecf20Sopenharmony_ci
20028c2ecf20Sopenharmony_ci	return ret < 0 ? ret : 0;
20038c2ecf20Sopenharmony_ci}
20048c2ecf20Sopenharmony_ci
20058c2ecf20Sopenharmony_cistatic void release_crtc_commit(struct completion *completion)
20068c2ecf20Sopenharmony_ci{
20078c2ecf20Sopenharmony_ci	struct drm_crtc_commit *commit = container_of(completion,
20088c2ecf20Sopenharmony_ci						      typeof(*commit),
20098c2ecf20Sopenharmony_ci						      flip_done);
20108c2ecf20Sopenharmony_ci
20118c2ecf20Sopenharmony_ci	drm_crtc_commit_put(commit);
20128c2ecf20Sopenharmony_ci}
20138c2ecf20Sopenharmony_ci
20148c2ecf20Sopenharmony_cistatic void init_commit(struct drm_crtc_commit *commit, struct drm_crtc *crtc)
20158c2ecf20Sopenharmony_ci{
20168c2ecf20Sopenharmony_ci	init_completion(&commit->flip_done);
20178c2ecf20Sopenharmony_ci	init_completion(&commit->hw_done);
20188c2ecf20Sopenharmony_ci	init_completion(&commit->cleanup_done);
20198c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&commit->commit_entry);
20208c2ecf20Sopenharmony_ci	kref_init(&commit->ref);
20218c2ecf20Sopenharmony_ci	commit->crtc = crtc;
20228c2ecf20Sopenharmony_ci}
20238c2ecf20Sopenharmony_ci
20248c2ecf20Sopenharmony_cistatic struct drm_crtc_commit *
20258c2ecf20Sopenharmony_cicrtc_or_fake_commit(struct drm_atomic_state *state, struct drm_crtc *crtc)
20268c2ecf20Sopenharmony_ci{
20278c2ecf20Sopenharmony_ci	if (crtc) {
20288c2ecf20Sopenharmony_ci		struct drm_crtc_state *new_crtc_state;
20298c2ecf20Sopenharmony_ci
20308c2ecf20Sopenharmony_ci		new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
20318c2ecf20Sopenharmony_ci
20328c2ecf20Sopenharmony_ci		return new_crtc_state->commit;
20338c2ecf20Sopenharmony_ci	}
20348c2ecf20Sopenharmony_ci
20358c2ecf20Sopenharmony_ci	if (!state->fake_commit) {
20368c2ecf20Sopenharmony_ci		state->fake_commit = kzalloc(sizeof(*state->fake_commit), GFP_KERNEL);
20378c2ecf20Sopenharmony_ci		if (!state->fake_commit)
20388c2ecf20Sopenharmony_ci			return NULL;
20398c2ecf20Sopenharmony_ci
20408c2ecf20Sopenharmony_ci		init_commit(state->fake_commit, NULL);
20418c2ecf20Sopenharmony_ci	}
20428c2ecf20Sopenharmony_ci
20438c2ecf20Sopenharmony_ci	return state->fake_commit;
20448c2ecf20Sopenharmony_ci}
20458c2ecf20Sopenharmony_ci
20468c2ecf20Sopenharmony_ci/**
20478c2ecf20Sopenharmony_ci * drm_atomic_helper_setup_commit - setup possibly nonblocking commit
20488c2ecf20Sopenharmony_ci * @state: new modeset state to be committed
20498c2ecf20Sopenharmony_ci * @nonblock: whether nonblocking behavior is requested.
20508c2ecf20Sopenharmony_ci *
20518c2ecf20Sopenharmony_ci * This function prepares @state to be used by the atomic helper's support for
20528c2ecf20Sopenharmony_ci * nonblocking commits. Drivers using the nonblocking commit infrastructure
20538c2ecf20Sopenharmony_ci * should always call this function from their
20548c2ecf20Sopenharmony_ci * &drm_mode_config_funcs.atomic_commit hook.
20558c2ecf20Sopenharmony_ci *
20568c2ecf20Sopenharmony_ci * To be able to use this support drivers need to use a few more helper
20578c2ecf20Sopenharmony_ci * functions. drm_atomic_helper_wait_for_dependencies() must be called before
20588c2ecf20Sopenharmony_ci * actually committing the hardware state, and for nonblocking commits this call
20598c2ecf20Sopenharmony_ci * must be placed in the async worker. See also drm_atomic_helper_swap_state()
20608c2ecf20Sopenharmony_ci * and its stall parameter, for when a driver's commit hooks look at the
20618c2ecf20Sopenharmony_ci * &drm_crtc.state, &drm_plane.state or &drm_connector.state pointer directly.
20628c2ecf20Sopenharmony_ci *
20638c2ecf20Sopenharmony_ci * Completion of the hardware commit step must be signalled using
20648c2ecf20Sopenharmony_ci * drm_atomic_helper_commit_hw_done(). After this step the driver is not allowed
20658c2ecf20Sopenharmony_ci * to read or change any permanent software or hardware modeset state. The only
20668c2ecf20Sopenharmony_ci * exception is state protected by other means than &drm_modeset_lock locks.
20678c2ecf20Sopenharmony_ci * Only the free standing @state with pointers to the old state structures can
20688c2ecf20Sopenharmony_ci * be inspected, e.g. to clean up old buffers using
20698c2ecf20Sopenharmony_ci * drm_atomic_helper_cleanup_planes().
20708c2ecf20Sopenharmony_ci *
20718c2ecf20Sopenharmony_ci * At the very end, before cleaning up @state drivers must call
20728c2ecf20Sopenharmony_ci * drm_atomic_helper_commit_cleanup_done().
20738c2ecf20Sopenharmony_ci *
20748c2ecf20Sopenharmony_ci * This is all implemented by in drm_atomic_helper_commit(), giving drivers a
20758c2ecf20Sopenharmony_ci * complete and easy-to-use default implementation of the atomic_commit() hook.
20768c2ecf20Sopenharmony_ci *
20778c2ecf20Sopenharmony_ci * The tracking of asynchronously executed and still pending commits is done
20788c2ecf20Sopenharmony_ci * using the core structure &drm_crtc_commit.
20798c2ecf20Sopenharmony_ci *
20808c2ecf20Sopenharmony_ci * By default there's no need to clean up resources allocated by this function
20818c2ecf20Sopenharmony_ci * explicitly: drm_atomic_state_default_clear() will take care of that
20828c2ecf20Sopenharmony_ci * automatically.
20838c2ecf20Sopenharmony_ci *
20848c2ecf20Sopenharmony_ci * Returns:
20858c2ecf20Sopenharmony_ci *
20868c2ecf20Sopenharmony_ci * 0 on success. -EBUSY when userspace schedules nonblocking commits too fast,
20878c2ecf20Sopenharmony_ci * -ENOMEM on allocation failures and -EINTR when a signal is pending.
20888c2ecf20Sopenharmony_ci */
20898c2ecf20Sopenharmony_ciint drm_atomic_helper_setup_commit(struct drm_atomic_state *state,
20908c2ecf20Sopenharmony_ci				   bool nonblock)
20918c2ecf20Sopenharmony_ci{
20928c2ecf20Sopenharmony_ci	struct drm_crtc *crtc;
20938c2ecf20Sopenharmony_ci	struct drm_crtc_state *old_crtc_state, *new_crtc_state;
20948c2ecf20Sopenharmony_ci	struct drm_connector *conn;
20958c2ecf20Sopenharmony_ci	struct drm_connector_state *old_conn_state, *new_conn_state;
20968c2ecf20Sopenharmony_ci	struct drm_plane *plane;
20978c2ecf20Sopenharmony_ci	struct drm_plane_state *old_plane_state, *new_plane_state;
20988c2ecf20Sopenharmony_ci	struct drm_crtc_commit *commit;
20998c2ecf20Sopenharmony_ci	int i, ret;
21008c2ecf20Sopenharmony_ci
21018c2ecf20Sopenharmony_ci	for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
21028c2ecf20Sopenharmony_ci		commit = kzalloc(sizeof(*commit), GFP_KERNEL);
21038c2ecf20Sopenharmony_ci		if (!commit)
21048c2ecf20Sopenharmony_ci			return -ENOMEM;
21058c2ecf20Sopenharmony_ci
21068c2ecf20Sopenharmony_ci		init_commit(commit, crtc);
21078c2ecf20Sopenharmony_ci
21088c2ecf20Sopenharmony_ci		new_crtc_state->commit = commit;
21098c2ecf20Sopenharmony_ci
21108c2ecf20Sopenharmony_ci		ret = stall_checks(crtc, nonblock);
21118c2ecf20Sopenharmony_ci		if (ret)
21128c2ecf20Sopenharmony_ci			return ret;
21138c2ecf20Sopenharmony_ci
21148c2ecf20Sopenharmony_ci		/* Drivers only send out events when at least either current or
21158c2ecf20Sopenharmony_ci		 * new CRTC state is active. Complete right away if everything
21168c2ecf20Sopenharmony_ci		 * stays off. */
21178c2ecf20Sopenharmony_ci		if (!old_crtc_state->active && !new_crtc_state->active) {
21188c2ecf20Sopenharmony_ci			complete_all(&commit->flip_done);
21198c2ecf20Sopenharmony_ci			continue;
21208c2ecf20Sopenharmony_ci		}
21218c2ecf20Sopenharmony_ci
21228c2ecf20Sopenharmony_ci		/* Legacy cursor updates are fully unsynced. */
21238c2ecf20Sopenharmony_ci		if (state->legacy_cursor_update) {
21248c2ecf20Sopenharmony_ci			complete_all(&commit->flip_done);
21258c2ecf20Sopenharmony_ci			continue;
21268c2ecf20Sopenharmony_ci		}
21278c2ecf20Sopenharmony_ci
21288c2ecf20Sopenharmony_ci		if (!new_crtc_state->event) {
21298c2ecf20Sopenharmony_ci			commit->event = kzalloc(sizeof(*commit->event),
21308c2ecf20Sopenharmony_ci						GFP_KERNEL);
21318c2ecf20Sopenharmony_ci			if (!commit->event)
21328c2ecf20Sopenharmony_ci				return -ENOMEM;
21338c2ecf20Sopenharmony_ci
21348c2ecf20Sopenharmony_ci			new_crtc_state->event = commit->event;
21358c2ecf20Sopenharmony_ci		}
21368c2ecf20Sopenharmony_ci
21378c2ecf20Sopenharmony_ci		new_crtc_state->event->base.completion = &commit->flip_done;
21388c2ecf20Sopenharmony_ci		new_crtc_state->event->base.completion_release = release_crtc_commit;
21398c2ecf20Sopenharmony_ci		drm_crtc_commit_get(commit);
21408c2ecf20Sopenharmony_ci
21418c2ecf20Sopenharmony_ci		commit->abort_completion = true;
21428c2ecf20Sopenharmony_ci
21438c2ecf20Sopenharmony_ci		state->crtcs[i].commit = commit;
21448c2ecf20Sopenharmony_ci		drm_crtc_commit_get(commit);
21458c2ecf20Sopenharmony_ci	}
21468c2ecf20Sopenharmony_ci
21478c2ecf20Sopenharmony_ci	for_each_oldnew_connector_in_state(state, conn, old_conn_state, new_conn_state, i) {
21488c2ecf20Sopenharmony_ci		/* Userspace is not allowed to get ahead of the previous
21498c2ecf20Sopenharmony_ci		 * commit with nonblocking ones. */
21508c2ecf20Sopenharmony_ci		if (nonblock && old_conn_state->commit &&
21518c2ecf20Sopenharmony_ci		    !try_wait_for_completion(&old_conn_state->commit->flip_done))
21528c2ecf20Sopenharmony_ci			return -EBUSY;
21538c2ecf20Sopenharmony_ci
21548c2ecf20Sopenharmony_ci		/* Always track connectors explicitly for e.g. link retraining. */
21558c2ecf20Sopenharmony_ci		commit = crtc_or_fake_commit(state, new_conn_state->crtc ?: old_conn_state->crtc);
21568c2ecf20Sopenharmony_ci		if (!commit)
21578c2ecf20Sopenharmony_ci			return -ENOMEM;
21588c2ecf20Sopenharmony_ci
21598c2ecf20Sopenharmony_ci		new_conn_state->commit = drm_crtc_commit_get(commit);
21608c2ecf20Sopenharmony_ci	}
21618c2ecf20Sopenharmony_ci
21628c2ecf20Sopenharmony_ci	for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {
21638c2ecf20Sopenharmony_ci		/* Userspace is not allowed to get ahead of the previous
21648c2ecf20Sopenharmony_ci		 * commit with nonblocking ones. */
21658c2ecf20Sopenharmony_ci		if (nonblock && old_plane_state->commit &&
21668c2ecf20Sopenharmony_ci		    !try_wait_for_completion(&old_plane_state->commit->flip_done))
21678c2ecf20Sopenharmony_ci			return -EBUSY;
21688c2ecf20Sopenharmony_ci
21698c2ecf20Sopenharmony_ci		/* Always track planes explicitly for async pageflip support. */
21708c2ecf20Sopenharmony_ci		commit = crtc_or_fake_commit(state, new_plane_state->crtc ?: old_plane_state->crtc);
21718c2ecf20Sopenharmony_ci		if (!commit)
21728c2ecf20Sopenharmony_ci			return -ENOMEM;
21738c2ecf20Sopenharmony_ci
21748c2ecf20Sopenharmony_ci		new_plane_state->commit = drm_crtc_commit_get(commit);
21758c2ecf20Sopenharmony_ci	}
21768c2ecf20Sopenharmony_ci
21778c2ecf20Sopenharmony_ci	return 0;
21788c2ecf20Sopenharmony_ci}
21798c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_setup_commit);
21808c2ecf20Sopenharmony_ci
21818c2ecf20Sopenharmony_ci/**
21828c2ecf20Sopenharmony_ci * drm_atomic_helper_wait_for_dependencies - wait for required preceeding commits
21838c2ecf20Sopenharmony_ci * @old_state: atomic state object with old state structures
21848c2ecf20Sopenharmony_ci *
21858c2ecf20Sopenharmony_ci * This function waits for all preceeding commits that touch the same CRTC as
21868c2ecf20Sopenharmony_ci * @old_state to both be committed to the hardware (as signalled by
21878c2ecf20Sopenharmony_ci * drm_atomic_helper_commit_hw_done()) and executed by the hardware (as signalled
21888c2ecf20Sopenharmony_ci * by calling drm_crtc_send_vblank_event() on the &drm_crtc_state.event).
21898c2ecf20Sopenharmony_ci *
21908c2ecf20Sopenharmony_ci * This is part of the atomic helper support for nonblocking commits, see
21918c2ecf20Sopenharmony_ci * drm_atomic_helper_setup_commit() for an overview.
21928c2ecf20Sopenharmony_ci */
21938c2ecf20Sopenharmony_civoid drm_atomic_helper_wait_for_dependencies(struct drm_atomic_state *old_state)
21948c2ecf20Sopenharmony_ci{
21958c2ecf20Sopenharmony_ci	struct drm_crtc *crtc;
21968c2ecf20Sopenharmony_ci	struct drm_crtc_state *old_crtc_state;
21978c2ecf20Sopenharmony_ci	struct drm_plane *plane;
21988c2ecf20Sopenharmony_ci	struct drm_plane_state *old_plane_state;
21998c2ecf20Sopenharmony_ci	struct drm_connector *conn;
22008c2ecf20Sopenharmony_ci	struct drm_connector_state *old_conn_state;
22018c2ecf20Sopenharmony_ci	struct drm_crtc_commit *commit;
22028c2ecf20Sopenharmony_ci	int i;
22038c2ecf20Sopenharmony_ci	long ret;
22048c2ecf20Sopenharmony_ci
22058c2ecf20Sopenharmony_ci	for_each_old_crtc_in_state(old_state, crtc, old_crtc_state, i) {
22068c2ecf20Sopenharmony_ci		commit = old_crtc_state->commit;
22078c2ecf20Sopenharmony_ci
22088c2ecf20Sopenharmony_ci		if (!commit)
22098c2ecf20Sopenharmony_ci			continue;
22108c2ecf20Sopenharmony_ci
22118c2ecf20Sopenharmony_ci		ret = wait_for_completion_timeout(&commit->hw_done,
22128c2ecf20Sopenharmony_ci						  10*HZ);
22138c2ecf20Sopenharmony_ci		if (ret == 0)
22148c2ecf20Sopenharmony_ci			DRM_ERROR("[CRTC:%d:%s] hw_done timed out\n",
22158c2ecf20Sopenharmony_ci				  crtc->base.id, crtc->name);
22168c2ecf20Sopenharmony_ci
22178c2ecf20Sopenharmony_ci		/* Currently no support for overwriting flips, hence
22188c2ecf20Sopenharmony_ci		 * stall for previous one to execute completely. */
22198c2ecf20Sopenharmony_ci		ret = wait_for_completion_timeout(&commit->flip_done,
22208c2ecf20Sopenharmony_ci						  10*HZ);
22218c2ecf20Sopenharmony_ci		if (ret == 0)
22228c2ecf20Sopenharmony_ci			DRM_ERROR("[CRTC:%d:%s] flip_done timed out\n",
22238c2ecf20Sopenharmony_ci				  crtc->base.id, crtc->name);
22248c2ecf20Sopenharmony_ci	}
22258c2ecf20Sopenharmony_ci
22268c2ecf20Sopenharmony_ci	for_each_old_connector_in_state(old_state, conn, old_conn_state, i) {
22278c2ecf20Sopenharmony_ci		commit = old_conn_state->commit;
22288c2ecf20Sopenharmony_ci
22298c2ecf20Sopenharmony_ci		if (!commit)
22308c2ecf20Sopenharmony_ci			continue;
22318c2ecf20Sopenharmony_ci
22328c2ecf20Sopenharmony_ci		ret = wait_for_completion_timeout(&commit->hw_done,
22338c2ecf20Sopenharmony_ci						  10*HZ);
22348c2ecf20Sopenharmony_ci		if (ret == 0)
22358c2ecf20Sopenharmony_ci			DRM_ERROR("[CONNECTOR:%d:%s] hw_done timed out\n",
22368c2ecf20Sopenharmony_ci				  conn->base.id, conn->name);
22378c2ecf20Sopenharmony_ci
22388c2ecf20Sopenharmony_ci		/* Currently no support for overwriting flips, hence
22398c2ecf20Sopenharmony_ci		 * stall for previous one to execute completely. */
22408c2ecf20Sopenharmony_ci		ret = wait_for_completion_timeout(&commit->flip_done,
22418c2ecf20Sopenharmony_ci						  10*HZ);
22428c2ecf20Sopenharmony_ci		if (ret == 0)
22438c2ecf20Sopenharmony_ci			DRM_ERROR("[CONNECTOR:%d:%s] flip_done timed out\n",
22448c2ecf20Sopenharmony_ci				  conn->base.id, conn->name);
22458c2ecf20Sopenharmony_ci	}
22468c2ecf20Sopenharmony_ci
22478c2ecf20Sopenharmony_ci	for_each_old_plane_in_state(old_state, plane, old_plane_state, i) {
22488c2ecf20Sopenharmony_ci		commit = old_plane_state->commit;
22498c2ecf20Sopenharmony_ci
22508c2ecf20Sopenharmony_ci		if (!commit)
22518c2ecf20Sopenharmony_ci			continue;
22528c2ecf20Sopenharmony_ci
22538c2ecf20Sopenharmony_ci		ret = wait_for_completion_timeout(&commit->hw_done,
22548c2ecf20Sopenharmony_ci						  10*HZ);
22558c2ecf20Sopenharmony_ci		if (ret == 0)
22568c2ecf20Sopenharmony_ci			DRM_ERROR("[PLANE:%d:%s] hw_done timed out\n",
22578c2ecf20Sopenharmony_ci				  plane->base.id, plane->name);
22588c2ecf20Sopenharmony_ci
22598c2ecf20Sopenharmony_ci		/* Currently no support for overwriting flips, hence
22608c2ecf20Sopenharmony_ci		 * stall for previous one to execute completely. */
22618c2ecf20Sopenharmony_ci		ret = wait_for_completion_timeout(&commit->flip_done,
22628c2ecf20Sopenharmony_ci						  10*HZ);
22638c2ecf20Sopenharmony_ci		if (ret == 0)
22648c2ecf20Sopenharmony_ci			DRM_ERROR("[PLANE:%d:%s] flip_done timed out\n",
22658c2ecf20Sopenharmony_ci				  plane->base.id, plane->name);
22668c2ecf20Sopenharmony_ci	}
22678c2ecf20Sopenharmony_ci}
22688c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_wait_for_dependencies);
22698c2ecf20Sopenharmony_ci
22708c2ecf20Sopenharmony_ci/**
22718c2ecf20Sopenharmony_ci * drm_atomic_helper_fake_vblank - fake VBLANK events if needed
22728c2ecf20Sopenharmony_ci * @old_state: atomic state object with old state structures
22738c2ecf20Sopenharmony_ci *
22748c2ecf20Sopenharmony_ci * This function walks all CRTCs and fakes VBLANK events on those with
22758c2ecf20Sopenharmony_ci * &drm_crtc_state.no_vblank set to true and &drm_crtc_state.event != NULL.
22768c2ecf20Sopenharmony_ci * The primary use of this function is writeback connectors working in oneshot
22778c2ecf20Sopenharmony_ci * mode and faking VBLANK events. In this case they only fake the VBLANK event
22788c2ecf20Sopenharmony_ci * when a job is queued, and any change to the pipeline that does not touch the
22798c2ecf20Sopenharmony_ci * connector is leading to timeouts when calling
22808c2ecf20Sopenharmony_ci * drm_atomic_helper_wait_for_vblanks() or
22818c2ecf20Sopenharmony_ci * drm_atomic_helper_wait_for_flip_done(). In addition to writeback
22828c2ecf20Sopenharmony_ci * connectors, this function can also fake VBLANK events for CRTCs without
22838c2ecf20Sopenharmony_ci * VBLANK interrupt.
22848c2ecf20Sopenharmony_ci *
22858c2ecf20Sopenharmony_ci * This is part of the atomic helper support for nonblocking commits, see
22868c2ecf20Sopenharmony_ci * drm_atomic_helper_setup_commit() for an overview.
22878c2ecf20Sopenharmony_ci */
22888c2ecf20Sopenharmony_civoid drm_atomic_helper_fake_vblank(struct drm_atomic_state *old_state)
22898c2ecf20Sopenharmony_ci{
22908c2ecf20Sopenharmony_ci	struct drm_crtc_state *new_crtc_state;
22918c2ecf20Sopenharmony_ci	struct drm_crtc *crtc;
22928c2ecf20Sopenharmony_ci	int i;
22938c2ecf20Sopenharmony_ci
22948c2ecf20Sopenharmony_ci	for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i) {
22958c2ecf20Sopenharmony_ci		unsigned long flags;
22968c2ecf20Sopenharmony_ci
22978c2ecf20Sopenharmony_ci		if (!new_crtc_state->no_vblank)
22988c2ecf20Sopenharmony_ci			continue;
22998c2ecf20Sopenharmony_ci
23008c2ecf20Sopenharmony_ci		spin_lock_irqsave(&old_state->dev->event_lock, flags);
23018c2ecf20Sopenharmony_ci		if (new_crtc_state->event) {
23028c2ecf20Sopenharmony_ci			drm_crtc_send_vblank_event(crtc,
23038c2ecf20Sopenharmony_ci						   new_crtc_state->event);
23048c2ecf20Sopenharmony_ci			new_crtc_state->event = NULL;
23058c2ecf20Sopenharmony_ci		}
23068c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&old_state->dev->event_lock, flags);
23078c2ecf20Sopenharmony_ci	}
23088c2ecf20Sopenharmony_ci}
23098c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_fake_vblank);
23108c2ecf20Sopenharmony_ci
23118c2ecf20Sopenharmony_ci/**
23128c2ecf20Sopenharmony_ci * drm_atomic_helper_commit_hw_done - setup possible nonblocking commit
23138c2ecf20Sopenharmony_ci * @old_state: atomic state object with old state structures
23148c2ecf20Sopenharmony_ci *
23158c2ecf20Sopenharmony_ci * This function is used to signal completion of the hardware commit step. After
23168c2ecf20Sopenharmony_ci * this step the driver is not allowed to read or change any permanent software
23178c2ecf20Sopenharmony_ci * or hardware modeset state. The only exception is state protected by other
23188c2ecf20Sopenharmony_ci * means than &drm_modeset_lock locks.
23198c2ecf20Sopenharmony_ci *
23208c2ecf20Sopenharmony_ci * Drivers should try to postpone any expensive or delayed cleanup work after
23218c2ecf20Sopenharmony_ci * this function is called.
23228c2ecf20Sopenharmony_ci *
23238c2ecf20Sopenharmony_ci * This is part of the atomic helper support for nonblocking commits, see
23248c2ecf20Sopenharmony_ci * drm_atomic_helper_setup_commit() for an overview.
23258c2ecf20Sopenharmony_ci */
23268c2ecf20Sopenharmony_civoid drm_atomic_helper_commit_hw_done(struct drm_atomic_state *old_state)
23278c2ecf20Sopenharmony_ci{
23288c2ecf20Sopenharmony_ci	struct drm_crtc *crtc;
23298c2ecf20Sopenharmony_ci	struct drm_crtc_state *old_crtc_state, *new_crtc_state;
23308c2ecf20Sopenharmony_ci	struct drm_crtc_commit *commit;
23318c2ecf20Sopenharmony_ci	int i;
23328c2ecf20Sopenharmony_ci
23338c2ecf20Sopenharmony_ci	for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) {
23348c2ecf20Sopenharmony_ci		commit = new_crtc_state->commit;
23358c2ecf20Sopenharmony_ci		if (!commit)
23368c2ecf20Sopenharmony_ci			continue;
23378c2ecf20Sopenharmony_ci
23388c2ecf20Sopenharmony_ci		/*
23398c2ecf20Sopenharmony_ci		 * copy new_crtc_state->commit to old_crtc_state->commit,
23408c2ecf20Sopenharmony_ci		 * it's unsafe to touch new_crtc_state after hw_done,
23418c2ecf20Sopenharmony_ci		 * but we still need to do so in cleanup_done().
23428c2ecf20Sopenharmony_ci		 */
23438c2ecf20Sopenharmony_ci		if (old_crtc_state->commit)
23448c2ecf20Sopenharmony_ci			drm_crtc_commit_put(old_crtc_state->commit);
23458c2ecf20Sopenharmony_ci
23468c2ecf20Sopenharmony_ci		old_crtc_state->commit = drm_crtc_commit_get(commit);
23478c2ecf20Sopenharmony_ci
23488c2ecf20Sopenharmony_ci		/* backend must have consumed any event by now */
23498c2ecf20Sopenharmony_ci		WARN_ON(new_crtc_state->event);
23508c2ecf20Sopenharmony_ci		complete_all(&commit->hw_done);
23518c2ecf20Sopenharmony_ci	}
23528c2ecf20Sopenharmony_ci
23538c2ecf20Sopenharmony_ci	if (old_state->fake_commit) {
23548c2ecf20Sopenharmony_ci		complete_all(&old_state->fake_commit->hw_done);
23558c2ecf20Sopenharmony_ci		complete_all(&old_state->fake_commit->flip_done);
23568c2ecf20Sopenharmony_ci	}
23578c2ecf20Sopenharmony_ci}
23588c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_commit_hw_done);
23598c2ecf20Sopenharmony_ci
23608c2ecf20Sopenharmony_ci/**
23618c2ecf20Sopenharmony_ci * drm_atomic_helper_commit_cleanup_done - signal completion of commit
23628c2ecf20Sopenharmony_ci * @old_state: atomic state object with old state structures
23638c2ecf20Sopenharmony_ci *
23648c2ecf20Sopenharmony_ci * This signals completion of the atomic update @old_state, including any
23658c2ecf20Sopenharmony_ci * cleanup work. If used, it must be called right before calling
23668c2ecf20Sopenharmony_ci * drm_atomic_state_put().
23678c2ecf20Sopenharmony_ci *
23688c2ecf20Sopenharmony_ci * This is part of the atomic helper support for nonblocking commits, see
23698c2ecf20Sopenharmony_ci * drm_atomic_helper_setup_commit() for an overview.
23708c2ecf20Sopenharmony_ci */
23718c2ecf20Sopenharmony_civoid drm_atomic_helper_commit_cleanup_done(struct drm_atomic_state *old_state)
23728c2ecf20Sopenharmony_ci{
23738c2ecf20Sopenharmony_ci	struct drm_crtc *crtc;
23748c2ecf20Sopenharmony_ci	struct drm_crtc_state *old_crtc_state;
23758c2ecf20Sopenharmony_ci	struct drm_crtc_commit *commit;
23768c2ecf20Sopenharmony_ci	int i;
23778c2ecf20Sopenharmony_ci
23788c2ecf20Sopenharmony_ci	for_each_old_crtc_in_state(old_state, crtc, old_crtc_state, i) {
23798c2ecf20Sopenharmony_ci		commit = old_crtc_state->commit;
23808c2ecf20Sopenharmony_ci		if (WARN_ON(!commit))
23818c2ecf20Sopenharmony_ci			continue;
23828c2ecf20Sopenharmony_ci
23838c2ecf20Sopenharmony_ci		complete_all(&commit->cleanup_done);
23848c2ecf20Sopenharmony_ci		WARN_ON(!try_wait_for_completion(&commit->hw_done));
23858c2ecf20Sopenharmony_ci
23868c2ecf20Sopenharmony_ci		spin_lock(&crtc->commit_lock);
23878c2ecf20Sopenharmony_ci		list_del(&commit->commit_entry);
23888c2ecf20Sopenharmony_ci		spin_unlock(&crtc->commit_lock);
23898c2ecf20Sopenharmony_ci	}
23908c2ecf20Sopenharmony_ci
23918c2ecf20Sopenharmony_ci	if (old_state->fake_commit) {
23928c2ecf20Sopenharmony_ci		complete_all(&old_state->fake_commit->cleanup_done);
23938c2ecf20Sopenharmony_ci		WARN_ON(!try_wait_for_completion(&old_state->fake_commit->hw_done));
23948c2ecf20Sopenharmony_ci	}
23958c2ecf20Sopenharmony_ci}
23968c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_commit_cleanup_done);
23978c2ecf20Sopenharmony_ci
23988c2ecf20Sopenharmony_ci/**
23998c2ecf20Sopenharmony_ci * drm_atomic_helper_prepare_planes - prepare plane resources before commit
24008c2ecf20Sopenharmony_ci * @dev: DRM device
24018c2ecf20Sopenharmony_ci * @state: atomic state object with new state structures
24028c2ecf20Sopenharmony_ci *
24038c2ecf20Sopenharmony_ci * This function prepares plane state, specifically framebuffers, for the new
24048c2ecf20Sopenharmony_ci * configuration, by calling &drm_plane_helper_funcs.prepare_fb. If any failure
24058c2ecf20Sopenharmony_ci * is encountered this function will call &drm_plane_helper_funcs.cleanup_fb on
24068c2ecf20Sopenharmony_ci * any already successfully prepared framebuffer.
24078c2ecf20Sopenharmony_ci *
24088c2ecf20Sopenharmony_ci * Returns:
24098c2ecf20Sopenharmony_ci * 0 on success, negative error code on failure.
24108c2ecf20Sopenharmony_ci */
24118c2ecf20Sopenharmony_ciint drm_atomic_helper_prepare_planes(struct drm_device *dev,
24128c2ecf20Sopenharmony_ci				     struct drm_atomic_state *state)
24138c2ecf20Sopenharmony_ci{
24148c2ecf20Sopenharmony_ci	struct drm_connector *connector;
24158c2ecf20Sopenharmony_ci	struct drm_connector_state *new_conn_state;
24168c2ecf20Sopenharmony_ci	struct drm_plane *plane;
24178c2ecf20Sopenharmony_ci	struct drm_plane_state *new_plane_state;
24188c2ecf20Sopenharmony_ci	int ret, i, j;
24198c2ecf20Sopenharmony_ci
24208c2ecf20Sopenharmony_ci	for_each_new_connector_in_state(state, connector, new_conn_state, i) {
24218c2ecf20Sopenharmony_ci		if (!new_conn_state->writeback_job)
24228c2ecf20Sopenharmony_ci			continue;
24238c2ecf20Sopenharmony_ci
24248c2ecf20Sopenharmony_ci		ret = drm_writeback_prepare_job(new_conn_state->writeback_job);
24258c2ecf20Sopenharmony_ci		if (ret < 0)
24268c2ecf20Sopenharmony_ci			return ret;
24278c2ecf20Sopenharmony_ci	}
24288c2ecf20Sopenharmony_ci
24298c2ecf20Sopenharmony_ci	for_each_new_plane_in_state(state, plane, new_plane_state, i) {
24308c2ecf20Sopenharmony_ci		const struct drm_plane_helper_funcs *funcs;
24318c2ecf20Sopenharmony_ci
24328c2ecf20Sopenharmony_ci		funcs = plane->helper_private;
24338c2ecf20Sopenharmony_ci
24348c2ecf20Sopenharmony_ci		if (funcs->prepare_fb) {
24358c2ecf20Sopenharmony_ci			ret = funcs->prepare_fb(plane, new_plane_state);
24368c2ecf20Sopenharmony_ci			if (ret)
24378c2ecf20Sopenharmony_ci				goto fail;
24388c2ecf20Sopenharmony_ci		}
24398c2ecf20Sopenharmony_ci	}
24408c2ecf20Sopenharmony_ci
24418c2ecf20Sopenharmony_ci	return 0;
24428c2ecf20Sopenharmony_ci
24438c2ecf20Sopenharmony_cifail:
24448c2ecf20Sopenharmony_ci	for_each_new_plane_in_state(state, plane, new_plane_state, j) {
24458c2ecf20Sopenharmony_ci		const struct drm_plane_helper_funcs *funcs;
24468c2ecf20Sopenharmony_ci
24478c2ecf20Sopenharmony_ci		if (j >= i)
24488c2ecf20Sopenharmony_ci			continue;
24498c2ecf20Sopenharmony_ci
24508c2ecf20Sopenharmony_ci		funcs = plane->helper_private;
24518c2ecf20Sopenharmony_ci
24528c2ecf20Sopenharmony_ci		if (funcs->cleanup_fb)
24538c2ecf20Sopenharmony_ci			funcs->cleanup_fb(plane, new_plane_state);
24548c2ecf20Sopenharmony_ci	}
24558c2ecf20Sopenharmony_ci
24568c2ecf20Sopenharmony_ci	return ret;
24578c2ecf20Sopenharmony_ci}
24588c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_prepare_planes);
24598c2ecf20Sopenharmony_ci
24608c2ecf20Sopenharmony_cistatic bool plane_crtc_active(const struct drm_plane_state *state)
24618c2ecf20Sopenharmony_ci{
24628c2ecf20Sopenharmony_ci	return state->crtc && state->crtc->state->active;
24638c2ecf20Sopenharmony_ci}
24648c2ecf20Sopenharmony_ci
24658c2ecf20Sopenharmony_ci/**
24668c2ecf20Sopenharmony_ci * drm_atomic_helper_commit_planes - commit plane state
24678c2ecf20Sopenharmony_ci * @dev: DRM device
24688c2ecf20Sopenharmony_ci * @old_state: atomic state object with old state structures
24698c2ecf20Sopenharmony_ci * @flags: flags for committing plane state
24708c2ecf20Sopenharmony_ci *
24718c2ecf20Sopenharmony_ci * This function commits the new plane state using the plane and atomic helper
24728c2ecf20Sopenharmony_ci * functions for planes and CRTCs. It assumes that the atomic state has already
24738c2ecf20Sopenharmony_ci * been pushed into the relevant object state pointers, since this step can no
24748c2ecf20Sopenharmony_ci * longer fail.
24758c2ecf20Sopenharmony_ci *
24768c2ecf20Sopenharmony_ci * It still requires the global state object @old_state to know which planes and
24778c2ecf20Sopenharmony_ci * crtcs need to be updated though.
24788c2ecf20Sopenharmony_ci *
24798c2ecf20Sopenharmony_ci * Note that this function does all plane updates across all CRTCs in one step.
24808c2ecf20Sopenharmony_ci * If the hardware can't support this approach look at
24818c2ecf20Sopenharmony_ci * drm_atomic_helper_commit_planes_on_crtc() instead.
24828c2ecf20Sopenharmony_ci *
24838c2ecf20Sopenharmony_ci * Plane parameters can be updated by applications while the associated CRTC is
24848c2ecf20Sopenharmony_ci * disabled. The DRM/KMS core will store the parameters in the plane state,
24858c2ecf20Sopenharmony_ci * which will be available to the driver when the CRTC is turned on. As a result
24868c2ecf20Sopenharmony_ci * most drivers don't need to be immediately notified of plane updates for a
24878c2ecf20Sopenharmony_ci * disabled CRTC.
24888c2ecf20Sopenharmony_ci *
24898c2ecf20Sopenharmony_ci * Unless otherwise needed, drivers are advised to set the ACTIVE_ONLY flag in
24908c2ecf20Sopenharmony_ci * @flags in order not to receive plane update notifications related to a
24918c2ecf20Sopenharmony_ci * disabled CRTC. This avoids the need to manually ignore plane updates in
24928c2ecf20Sopenharmony_ci * driver code when the driver and/or hardware can't or just don't need to deal
24938c2ecf20Sopenharmony_ci * with updates on disabled CRTCs, for example when supporting runtime PM.
24948c2ecf20Sopenharmony_ci *
24958c2ecf20Sopenharmony_ci * Drivers may set the NO_DISABLE_AFTER_MODESET flag in @flags if the relevant
24968c2ecf20Sopenharmony_ci * display controllers require to disable a CRTC's planes when the CRTC is
24978c2ecf20Sopenharmony_ci * disabled. This function would skip the &drm_plane_helper_funcs.atomic_disable
24988c2ecf20Sopenharmony_ci * call for a plane if the CRTC of the old plane state needs a modesetting
24998c2ecf20Sopenharmony_ci * operation. Of course, the drivers need to disable the planes in their CRTC
25008c2ecf20Sopenharmony_ci * disable callbacks since no one else would do that.
25018c2ecf20Sopenharmony_ci *
25028c2ecf20Sopenharmony_ci * The drm_atomic_helper_commit() default implementation doesn't set the
25038c2ecf20Sopenharmony_ci * ACTIVE_ONLY flag to most closely match the behaviour of the legacy helpers.
25048c2ecf20Sopenharmony_ci * This should not be copied blindly by drivers.
25058c2ecf20Sopenharmony_ci */
25068c2ecf20Sopenharmony_civoid drm_atomic_helper_commit_planes(struct drm_device *dev,
25078c2ecf20Sopenharmony_ci				     struct drm_atomic_state *old_state,
25088c2ecf20Sopenharmony_ci				     uint32_t flags)
25098c2ecf20Sopenharmony_ci{
25108c2ecf20Sopenharmony_ci	struct drm_crtc *crtc;
25118c2ecf20Sopenharmony_ci	struct drm_crtc_state *old_crtc_state, *new_crtc_state;
25128c2ecf20Sopenharmony_ci	struct drm_plane *plane;
25138c2ecf20Sopenharmony_ci	struct drm_plane_state *old_plane_state, *new_plane_state;
25148c2ecf20Sopenharmony_ci	int i;
25158c2ecf20Sopenharmony_ci	bool active_only = flags & DRM_PLANE_COMMIT_ACTIVE_ONLY;
25168c2ecf20Sopenharmony_ci	bool no_disable = flags & DRM_PLANE_COMMIT_NO_DISABLE_AFTER_MODESET;
25178c2ecf20Sopenharmony_ci
25188c2ecf20Sopenharmony_ci	for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) {
25198c2ecf20Sopenharmony_ci		const struct drm_crtc_helper_funcs *funcs;
25208c2ecf20Sopenharmony_ci
25218c2ecf20Sopenharmony_ci		funcs = crtc->helper_private;
25228c2ecf20Sopenharmony_ci
25238c2ecf20Sopenharmony_ci		if (!funcs || !funcs->atomic_begin)
25248c2ecf20Sopenharmony_ci			continue;
25258c2ecf20Sopenharmony_ci
25268c2ecf20Sopenharmony_ci		if (active_only && !new_crtc_state->active)
25278c2ecf20Sopenharmony_ci			continue;
25288c2ecf20Sopenharmony_ci
25298c2ecf20Sopenharmony_ci		funcs->atomic_begin(crtc, old_crtc_state);
25308c2ecf20Sopenharmony_ci	}
25318c2ecf20Sopenharmony_ci
25328c2ecf20Sopenharmony_ci	for_each_oldnew_plane_in_state(old_state, plane, old_plane_state, new_plane_state, i) {
25338c2ecf20Sopenharmony_ci		const struct drm_plane_helper_funcs *funcs;
25348c2ecf20Sopenharmony_ci		bool disabling;
25358c2ecf20Sopenharmony_ci
25368c2ecf20Sopenharmony_ci		funcs = plane->helper_private;
25378c2ecf20Sopenharmony_ci
25388c2ecf20Sopenharmony_ci		if (!funcs)
25398c2ecf20Sopenharmony_ci			continue;
25408c2ecf20Sopenharmony_ci
25418c2ecf20Sopenharmony_ci		disabling = drm_atomic_plane_disabling(old_plane_state,
25428c2ecf20Sopenharmony_ci						       new_plane_state);
25438c2ecf20Sopenharmony_ci
25448c2ecf20Sopenharmony_ci		if (active_only) {
25458c2ecf20Sopenharmony_ci			/*
25468c2ecf20Sopenharmony_ci			 * Skip planes related to inactive CRTCs. If the plane
25478c2ecf20Sopenharmony_ci			 * is enabled use the state of the current CRTC. If the
25488c2ecf20Sopenharmony_ci			 * plane is being disabled use the state of the old
25498c2ecf20Sopenharmony_ci			 * CRTC to avoid skipping planes being disabled on an
25508c2ecf20Sopenharmony_ci			 * active CRTC.
25518c2ecf20Sopenharmony_ci			 */
25528c2ecf20Sopenharmony_ci			if (!disabling && !plane_crtc_active(new_plane_state))
25538c2ecf20Sopenharmony_ci				continue;
25548c2ecf20Sopenharmony_ci			if (disabling && !plane_crtc_active(old_plane_state))
25558c2ecf20Sopenharmony_ci				continue;
25568c2ecf20Sopenharmony_ci		}
25578c2ecf20Sopenharmony_ci
25588c2ecf20Sopenharmony_ci		/*
25598c2ecf20Sopenharmony_ci		 * Special-case disabling the plane if drivers support it.
25608c2ecf20Sopenharmony_ci		 */
25618c2ecf20Sopenharmony_ci		if (disabling && funcs->atomic_disable) {
25628c2ecf20Sopenharmony_ci			struct drm_crtc_state *crtc_state;
25638c2ecf20Sopenharmony_ci
25648c2ecf20Sopenharmony_ci			crtc_state = old_plane_state->crtc->state;
25658c2ecf20Sopenharmony_ci
25668c2ecf20Sopenharmony_ci			if (drm_atomic_crtc_needs_modeset(crtc_state) &&
25678c2ecf20Sopenharmony_ci			    no_disable)
25688c2ecf20Sopenharmony_ci				continue;
25698c2ecf20Sopenharmony_ci
25708c2ecf20Sopenharmony_ci			funcs->atomic_disable(plane, old_plane_state);
25718c2ecf20Sopenharmony_ci		} else if (new_plane_state->crtc || disabling) {
25728c2ecf20Sopenharmony_ci			funcs->atomic_update(plane, old_plane_state);
25738c2ecf20Sopenharmony_ci		}
25748c2ecf20Sopenharmony_ci	}
25758c2ecf20Sopenharmony_ci
25768c2ecf20Sopenharmony_ci	for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) {
25778c2ecf20Sopenharmony_ci		const struct drm_crtc_helper_funcs *funcs;
25788c2ecf20Sopenharmony_ci
25798c2ecf20Sopenharmony_ci		funcs = crtc->helper_private;
25808c2ecf20Sopenharmony_ci
25818c2ecf20Sopenharmony_ci		if (!funcs || !funcs->atomic_flush)
25828c2ecf20Sopenharmony_ci			continue;
25838c2ecf20Sopenharmony_ci
25848c2ecf20Sopenharmony_ci		if (active_only && !new_crtc_state->active)
25858c2ecf20Sopenharmony_ci			continue;
25868c2ecf20Sopenharmony_ci
25878c2ecf20Sopenharmony_ci		funcs->atomic_flush(crtc, old_crtc_state);
25888c2ecf20Sopenharmony_ci	}
25898c2ecf20Sopenharmony_ci}
25908c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_commit_planes);
25918c2ecf20Sopenharmony_ci
25928c2ecf20Sopenharmony_ci/**
25938c2ecf20Sopenharmony_ci * drm_atomic_helper_commit_planes_on_crtc - commit plane state for a CRTC
25948c2ecf20Sopenharmony_ci * @old_crtc_state: atomic state object with the old CRTC state
25958c2ecf20Sopenharmony_ci *
25968c2ecf20Sopenharmony_ci * This function commits the new plane state using the plane and atomic helper
25978c2ecf20Sopenharmony_ci * functions for planes on the specific CRTC. It assumes that the atomic state
25988c2ecf20Sopenharmony_ci * has already been pushed into the relevant object state pointers, since this
25998c2ecf20Sopenharmony_ci * step can no longer fail.
26008c2ecf20Sopenharmony_ci *
26018c2ecf20Sopenharmony_ci * This function is useful when plane updates should be done CRTC-by-CRTC
26028c2ecf20Sopenharmony_ci * instead of one global step like drm_atomic_helper_commit_planes() does.
26038c2ecf20Sopenharmony_ci *
26048c2ecf20Sopenharmony_ci * This function can only be savely used when planes are not allowed to move
26058c2ecf20Sopenharmony_ci * between different CRTCs because this function doesn't handle inter-CRTC
26068c2ecf20Sopenharmony_ci * depencies. Callers need to ensure that either no such depencies exist,
26078c2ecf20Sopenharmony_ci * resolve them through ordering of commit calls or through some other means.
26088c2ecf20Sopenharmony_ci */
26098c2ecf20Sopenharmony_civoid
26108c2ecf20Sopenharmony_cidrm_atomic_helper_commit_planes_on_crtc(struct drm_crtc_state *old_crtc_state)
26118c2ecf20Sopenharmony_ci{
26128c2ecf20Sopenharmony_ci	const struct drm_crtc_helper_funcs *crtc_funcs;
26138c2ecf20Sopenharmony_ci	struct drm_crtc *crtc = old_crtc_state->crtc;
26148c2ecf20Sopenharmony_ci	struct drm_atomic_state *old_state = old_crtc_state->state;
26158c2ecf20Sopenharmony_ci	struct drm_crtc_state *new_crtc_state =
26168c2ecf20Sopenharmony_ci		drm_atomic_get_new_crtc_state(old_state, crtc);
26178c2ecf20Sopenharmony_ci	struct drm_plane *plane;
26188c2ecf20Sopenharmony_ci	unsigned plane_mask;
26198c2ecf20Sopenharmony_ci
26208c2ecf20Sopenharmony_ci	plane_mask = old_crtc_state->plane_mask;
26218c2ecf20Sopenharmony_ci	plane_mask |= new_crtc_state->plane_mask;
26228c2ecf20Sopenharmony_ci
26238c2ecf20Sopenharmony_ci	crtc_funcs = crtc->helper_private;
26248c2ecf20Sopenharmony_ci	if (crtc_funcs && crtc_funcs->atomic_begin)
26258c2ecf20Sopenharmony_ci		crtc_funcs->atomic_begin(crtc, old_crtc_state);
26268c2ecf20Sopenharmony_ci
26278c2ecf20Sopenharmony_ci	drm_for_each_plane_mask(plane, crtc->dev, plane_mask) {
26288c2ecf20Sopenharmony_ci		struct drm_plane_state *old_plane_state =
26298c2ecf20Sopenharmony_ci			drm_atomic_get_old_plane_state(old_state, plane);
26308c2ecf20Sopenharmony_ci		struct drm_plane_state *new_plane_state =
26318c2ecf20Sopenharmony_ci			drm_atomic_get_new_plane_state(old_state, plane);
26328c2ecf20Sopenharmony_ci		const struct drm_plane_helper_funcs *plane_funcs;
26338c2ecf20Sopenharmony_ci
26348c2ecf20Sopenharmony_ci		plane_funcs = plane->helper_private;
26358c2ecf20Sopenharmony_ci
26368c2ecf20Sopenharmony_ci		if (!old_plane_state || !plane_funcs)
26378c2ecf20Sopenharmony_ci			continue;
26388c2ecf20Sopenharmony_ci
26398c2ecf20Sopenharmony_ci		WARN_ON(new_plane_state->crtc &&
26408c2ecf20Sopenharmony_ci			new_plane_state->crtc != crtc);
26418c2ecf20Sopenharmony_ci
26428c2ecf20Sopenharmony_ci		if (drm_atomic_plane_disabling(old_plane_state, new_plane_state) &&
26438c2ecf20Sopenharmony_ci		    plane_funcs->atomic_disable)
26448c2ecf20Sopenharmony_ci			plane_funcs->atomic_disable(plane, old_plane_state);
26458c2ecf20Sopenharmony_ci		else if (new_plane_state->crtc ||
26468c2ecf20Sopenharmony_ci			 drm_atomic_plane_disabling(old_plane_state, new_plane_state))
26478c2ecf20Sopenharmony_ci			plane_funcs->atomic_update(plane, old_plane_state);
26488c2ecf20Sopenharmony_ci	}
26498c2ecf20Sopenharmony_ci
26508c2ecf20Sopenharmony_ci	if (crtc_funcs && crtc_funcs->atomic_flush)
26518c2ecf20Sopenharmony_ci		crtc_funcs->atomic_flush(crtc, old_crtc_state);
26528c2ecf20Sopenharmony_ci}
26538c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_commit_planes_on_crtc);
26548c2ecf20Sopenharmony_ci
26558c2ecf20Sopenharmony_ci/**
26568c2ecf20Sopenharmony_ci * drm_atomic_helper_disable_planes_on_crtc - helper to disable CRTC's planes
26578c2ecf20Sopenharmony_ci * @old_crtc_state: atomic state object with the old CRTC state
26588c2ecf20Sopenharmony_ci * @atomic: if set, synchronize with CRTC's atomic_begin/flush hooks
26598c2ecf20Sopenharmony_ci *
26608c2ecf20Sopenharmony_ci * Disables all planes associated with the given CRTC. This can be
26618c2ecf20Sopenharmony_ci * used for instance in the CRTC helper atomic_disable callback to disable
26628c2ecf20Sopenharmony_ci * all planes.
26638c2ecf20Sopenharmony_ci *
26648c2ecf20Sopenharmony_ci * If the atomic-parameter is set the function calls the CRTC's
26658c2ecf20Sopenharmony_ci * atomic_begin hook before and atomic_flush hook after disabling the
26668c2ecf20Sopenharmony_ci * planes.
26678c2ecf20Sopenharmony_ci *
26688c2ecf20Sopenharmony_ci * It is a bug to call this function without having implemented the
26698c2ecf20Sopenharmony_ci * &drm_plane_helper_funcs.atomic_disable plane hook.
26708c2ecf20Sopenharmony_ci */
26718c2ecf20Sopenharmony_civoid
26728c2ecf20Sopenharmony_cidrm_atomic_helper_disable_planes_on_crtc(struct drm_crtc_state *old_crtc_state,
26738c2ecf20Sopenharmony_ci					 bool atomic)
26748c2ecf20Sopenharmony_ci{
26758c2ecf20Sopenharmony_ci	struct drm_crtc *crtc = old_crtc_state->crtc;
26768c2ecf20Sopenharmony_ci	const struct drm_crtc_helper_funcs *crtc_funcs =
26778c2ecf20Sopenharmony_ci		crtc->helper_private;
26788c2ecf20Sopenharmony_ci	struct drm_plane *plane;
26798c2ecf20Sopenharmony_ci
26808c2ecf20Sopenharmony_ci	if (atomic && crtc_funcs && crtc_funcs->atomic_begin)
26818c2ecf20Sopenharmony_ci		crtc_funcs->atomic_begin(crtc, NULL);
26828c2ecf20Sopenharmony_ci
26838c2ecf20Sopenharmony_ci	drm_atomic_crtc_state_for_each_plane(plane, old_crtc_state) {
26848c2ecf20Sopenharmony_ci		const struct drm_plane_helper_funcs *plane_funcs =
26858c2ecf20Sopenharmony_ci			plane->helper_private;
26868c2ecf20Sopenharmony_ci
26878c2ecf20Sopenharmony_ci		if (!plane_funcs)
26888c2ecf20Sopenharmony_ci			continue;
26898c2ecf20Sopenharmony_ci
26908c2ecf20Sopenharmony_ci		WARN_ON(!plane_funcs->atomic_disable);
26918c2ecf20Sopenharmony_ci		if (plane_funcs->atomic_disable)
26928c2ecf20Sopenharmony_ci			plane_funcs->atomic_disable(plane, NULL);
26938c2ecf20Sopenharmony_ci	}
26948c2ecf20Sopenharmony_ci
26958c2ecf20Sopenharmony_ci	if (atomic && crtc_funcs && crtc_funcs->atomic_flush)
26968c2ecf20Sopenharmony_ci		crtc_funcs->atomic_flush(crtc, NULL);
26978c2ecf20Sopenharmony_ci}
26988c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_disable_planes_on_crtc);
26998c2ecf20Sopenharmony_ci
27008c2ecf20Sopenharmony_ci/**
27018c2ecf20Sopenharmony_ci * drm_atomic_helper_cleanup_planes - cleanup plane resources after commit
27028c2ecf20Sopenharmony_ci * @dev: DRM device
27038c2ecf20Sopenharmony_ci * @old_state: atomic state object with old state structures
27048c2ecf20Sopenharmony_ci *
27058c2ecf20Sopenharmony_ci * This function cleans up plane state, specifically framebuffers, from the old
27068c2ecf20Sopenharmony_ci * configuration. Hence the old configuration must be perserved in @old_state to
27078c2ecf20Sopenharmony_ci * be able to call this function.
27088c2ecf20Sopenharmony_ci *
27098c2ecf20Sopenharmony_ci * This function must also be called on the new state when the atomic update
27108c2ecf20Sopenharmony_ci * fails at any point after calling drm_atomic_helper_prepare_planes().
27118c2ecf20Sopenharmony_ci */
27128c2ecf20Sopenharmony_civoid drm_atomic_helper_cleanup_planes(struct drm_device *dev,
27138c2ecf20Sopenharmony_ci				      struct drm_atomic_state *old_state)
27148c2ecf20Sopenharmony_ci{
27158c2ecf20Sopenharmony_ci	struct drm_plane *plane;
27168c2ecf20Sopenharmony_ci	struct drm_plane_state *old_plane_state, *new_plane_state;
27178c2ecf20Sopenharmony_ci	int i;
27188c2ecf20Sopenharmony_ci
27198c2ecf20Sopenharmony_ci	for_each_oldnew_plane_in_state(old_state, plane, old_plane_state, new_plane_state, i) {
27208c2ecf20Sopenharmony_ci		const struct drm_plane_helper_funcs *funcs;
27218c2ecf20Sopenharmony_ci		struct drm_plane_state *plane_state;
27228c2ecf20Sopenharmony_ci
27238c2ecf20Sopenharmony_ci		/*
27248c2ecf20Sopenharmony_ci		 * This might be called before swapping when commit is aborted,
27258c2ecf20Sopenharmony_ci		 * in which case we have to cleanup the new state.
27268c2ecf20Sopenharmony_ci		 */
27278c2ecf20Sopenharmony_ci		if (old_plane_state == plane->state)
27288c2ecf20Sopenharmony_ci			plane_state = new_plane_state;
27298c2ecf20Sopenharmony_ci		else
27308c2ecf20Sopenharmony_ci			plane_state = old_plane_state;
27318c2ecf20Sopenharmony_ci
27328c2ecf20Sopenharmony_ci		funcs = plane->helper_private;
27338c2ecf20Sopenharmony_ci
27348c2ecf20Sopenharmony_ci		if (funcs->cleanup_fb)
27358c2ecf20Sopenharmony_ci			funcs->cleanup_fb(plane, plane_state);
27368c2ecf20Sopenharmony_ci	}
27378c2ecf20Sopenharmony_ci}
27388c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_cleanup_planes);
27398c2ecf20Sopenharmony_ci
27408c2ecf20Sopenharmony_ci/**
27418c2ecf20Sopenharmony_ci * drm_atomic_helper_swap_state - store atomic state into current sw state
27428c2ecf20Sopenharmony_ci * @state: atomic state
27438c2ecf20Sopenharmony_ci * @stall: stall for preceeding commits
27448c2ecf20Sopenharmony_ci *
27458c2ecf20Sopenharmony_ci * This function stores the atomic state into the current state pointers in all
27468c2ecf20Sopenharmony_ci * driver objects. It should be called after all failing steps have been done
27478c2ecf20Sopenharmony_ci * and succeeded, but before the actual hardware state is committed.
27488c2ecf20Sopenharmony_ci *
27498c2ecf20Sopenharmony_ci * For cleanup and error recovery the current state for all changed objects will
27508c2ecf20Sopenharmony_ci * be swapped into @state.
27518c2ecf20Sopenharmony_ci *
27528c2ecf20Sopenharmony_ci * With that sequence it fits perfectly into the plane prepare/cleanup sequence:
27538c2ecf20Sopenharmony_ci *
27548c2ecf20Sopenharmony_ci * 1. Call drm_atomic_helper_prepare_planes() with the staged atomic state.
27558c2ecf20Sopenharmony_ci *
27568c2ecf20Sopenharmony_ci * 2. Do any other steps that might fail.
27578c2ecf20Sopenharmony_ci *
27588c2ecf20Sopenharmony_ci * 3. Put the staged state into the current state pointers with this function.
27598c2ecf20Sopenharmony_ci *
27608c2ecf20Sopenharmony_ci * 4. Actually commit the hardware state.
27618c2ecf20Sopenharmony_ci *
27628c2ecf20Sopenharmony_ci * 5. Call drm_atomic_helper_cleanup_planes() with @state, which since step 3
27638c2ecf20Sopenharmony_ci * contains the old state. Also do any other cleanup required with that state.
27648c2ecf20Sopenharmony_ci *
27658c2ecf20Sopenharmony_ci * @stall must be set when nonblocking commits for this driver directly access
27668c2ecf20Sopenharmony_ci * the &drm_plane.state, &drm_crtc.state or &drm_connector.state pointer. With
27678c2ecf20Sopenharmony_ci * the current atomic helpers this is almost always the case, since the helpers
27688c2ecf20Sopenharmony_ci * don't pass the right state structures to the callbacks.
27698c2ecf20Sopenharmony_ci *
27708c2ecf20Sopenharmony_ci * Returns:
27718c2ecf20Sopenharmony_ci *
27728c2ecf20Sopenharmony_ci * Returns 0 on success. Can return -ERESTARTSYS when @stall is true and the
27738c2ecf20Sopenharmony_ci * waiting for the previous commits has been interrupted.
27748c2ecf20Sopenharmony_ci */
27758c2ecf20Sopenharmony_ciint drm_atomic_helper_swap_state(struct drm_atomic_state *state,
27768c2ecf20Sopenharmony_ci				  bool stall)
27778c2ecf20Sopenharmony_ci{
27788c2ecf20Sopenharmony_ci	int i, ret;
27798c2ecf20Sopenharmony_ci	struct drm_connector *connector;
27808c2ecf20Sopenharmony_ci	struct drm_connector_state *old_conn_state, *new_conn_state;
27818c2ecf20Sopenharmony_ci	struct drm_crtc *crtc;
27828c2ecf20Sopenharmony_ci	struct drm_crtc_state *old_crtc_state, *new_crtc_state;
27838c2ecf20Sopenharmony_ci	struct drm_plane *plane;
27848c2ecf20Sopenharmony_ci	struct drm_plane_state *old_plane_state, *new_plane_state;
27858c2ecf20Sopenharmony_ci	struct drm_crtc_commit *commit;
27868c2ecf20Sopenharmony_ci	struct drm_private_obj *obj;
27878c2ecf20Sopenharmony_ci	struct drm_private_state *old_obj_state, *new_obj_state;
27888c2ecf20Sopenharmony_ci
27898c2ecf20Sopenharmony_ci	if (stall) {
27908c2ecf20Sopenharmony_ci		/*
27918c2ecf20Sopenharmony_ci		 * We have to stall for hw_done here before
27928c2ecf20Sopenharmony_ci		 * drm_atomic_helper_wait_for_dependencies() because flip
27938c2ecf20Sopenharmony_ci		 * depth > 1 is not yet supported by all drivers. As long as
27948c2ecf20Sopenharmony_ci		 * obj->state is directly dereferenced anywhere in the drivers
27958c2ecf20Sopenharmony_ci		 * atomic_commit_tail function, then it's unsafe to swap state
27968c2ecf20Sopenharmony_ci		 * before drm_atomic_helper_commit_hw_done() is called.
27978c2ecf20Sopenharmony_ci		 */
27988c2ecf20Sopenharmony_ci
27998c2ecf20Sopenharmony_ci		for_each_old_crtc_in_state(state, crtc, old_crtc_state, i) {
28008c2ecf20Sopenharmony_ci			commit = old_crtc_state->commit;
28018c2ecf20Sopenharmony_ci
28028c2ecf20Sopenharmony_ci			if (!commit)
28038c2ecf20Sopenharmony_ci				continue;
28048c2ecf20Sopenharmony_ci
28058c2ecf20Sopenharmony_ci			ret = wait_for_completion_interruptible(&commit->hw_done);
28068c2ecf20Sopenharmony_ci			if (ret)
28078c2ecf20Sopenharmony_ci				return ret;
28088c2ecf20Sopenharmony_ci		}
28098c2ecf20Sopenharmony_ci
28108c2ecf20Sopenharmony_ci		for_each_old_connector_in_state(state, connector, old_conn_state, i) {
28118c2ecf20Sopenharmony_ci			commit = old_conn_state->commit;
28128c2ecf20Sopenharmony_ci
28138c2ecf20Sopenharmony_ci			if (!commit)
28148c2ecf20Sopenharmony_ci				continue;
28158c2ecf20Sopenharmony_ci
28168c2ecf20Sopenharmony_ci			ret = wait_for_completion_interruptible(&commit->hw_done);
28178c2ecf20Sopenharmony_ci			if (ret)
28188c2ecf20Sopenharmony_ci				return ret;
28198c2ecf20Sopenharmony_ci		}
28208c2ecf20Sopenharmony_ci
28218c2ecf20Sopenharmony_ci		for_each_old_plane_in_state(state, plane, old_plane_state, i) {
28228c2ecf20Sopenharmony_ci			commit = old_plane_state->commit;
28238c2ecf20Sopenharmony_ci
28248c2ecf20Sopenharmony_ci			if (!commit)
28258c2ecf20Sopenharmony_ci				continue;
28268c2ecf20Sopenharmony_ci
28278c2ecf20Sopenharmony_ci			ret = wait_for_completion_interruptible(&commit->hw_done);
28288c2ecf20Sopenharmony_ci			if (ret)
28298c2ecf20Sopenharmony_ci				return ret;
28308c2ecf20Sopenharmony_ci		}
28318c2ecf20Sopenharmony_ci	}
28328c2ecf20Sopenharmony_ci
28338c2ecf20Sopenharmony_ci	for_each_oldnew_connector_in_state(state, connector, old_conn_state, new_conn_state, i) {
28348c2ecf20Sopenharmony_ci		WARN_ON(connector->state != old_conn_state);
28358c2ecf20Sopenharmony_ci
28368c2ecf20Sopenharmony_ci		old_conn_state->state = state;
28378c2ecf20Sopenharmony_ci		new_conn_state->state = NULL;
28388c2ecf20Sopenharmony_ci
28398c2ecf20Sopenharmony_ci		state->connectors[i].state = old_conn_state;
28408c2ecf20Sopenharmony_ci		connector->state = new_conn_state;
28418c2ecf20Sopenharmony_ci	}
28428c2ecf20Sopenharmony_ci
28438c2ecf20Sopenharmony_ci	for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
28448c2ecf20Sopenharmony_ci		WARN_ON(crtc->state != old_crtc_state);
28458c2ecf20Sopenharmony_ci
28468c2ecf20Sopenharmony_ci		old_crtc_state->state = state;
28478c2ecf20Sopenharmony_ci		new_crtc_state->state = NULL;
28488c2ecf20Sopenharmony_ci
28498c2ecf20Sopenharmony_ci		state->crtcs[i].state = old_crtc_state;
28508c2ecf20Sopenharmony_ci		crtc->state = new_crtc_state;
28518c2ecf20Sopenharmony_ci
28528c2ecf20Sopenharmony_ci		if (new_crtc_state->commit) {
28538c2ecf20Sopenharmony_ci			spin_lock(&crtc->commit_lock);
28548c2ecf20Sopenharmony_ci			list_add(&new_crtc_state->commit->commit_entry,
28558c2ecf20Sopenharmony_ci				 &crtc->commit_list);
28568c2ecf20Sopenharmony_ci			spin_unlock(&crtc->commit_lock);
28578c2ecf20Sopenharmony_ci
28588c2ecf20Sopenharmony_ci			new_crtc_state->commit->event = NULL;
28598c2ecf20Sopenharmony_ci		}
28608c2ecf20Sopenharmony_ci	}
28618c2ecf20Sopenharmony_ci
28628c2ecf20Sopenharmony_ci	for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {
28638c2ecf20Sopenharmony_ci		WARN_ON(plane->state != old_plane_state);
28648c2ecf20Sopenharmony_ci
28658c2ecf20Sopenharmony_ci		old_plane_state->state = state;
28668c2ecf20Sopenharmony_ci		new_plane_state->state = NULL;
28678c2ecf20Sopenharmony_ci
28688c2ecf20Sopenharmony_ci		state->planes[i].state = old_plane_state;
28698c2ecf20Sopenharmony_ci		plane->state = new_plane_state;
28708c2ecf20Sopenharmony_ci	}
28718c2ecf20Sopenharmony_ci
28728c2ecf20Sopenharmony_ci	for_each_oldnew_private_obj_in_state(state, obj, old_obj_state, new_obj_state, i) {
28738c2ecf20Sopenharmony_ci		WARN_ON(obj->state != old_obj_state);
28748c2ecf20Sopenharmony_ci
28758c2ecf20Sopenharmony_ci		old_obj_state->state = state;
28768c2ecf20Sopenharmony_ci		new_obj_state->state = NULL;
28778c2ecf20Sopenharmony_ci
28788c2ecf20Sopenharmony_ci		state->private_objs[i].state = old_obj_state;
28798c2ecf20Sopenharmony_ci		obj->state = new_obj_state;
28808c2ecf20Sopenharmony_ci	}
28818c2ecf20Sopenharmony_ci
28828c2ecf20Sopenharmony_ci	return 0;
28838c2ecf20Sopenharmony_ci}
28848c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_swap_state);
28858c2ecf20Sopenharmony_ci
28868c2ecf20Sopenharmony_ci/**
28878c2ecf20Sopenharmony_ci * drm_atomic_helper_update_plane - Helper for primary plane update using atomic
28888c2ecf20Sopenharmony_ci * @plane: plane object to update
28898c2ecf20Sopenharmony_ci * @crtc: owning CRTC of owning plane
28908c2ecf20Sopenharmony_ci * @fb: framebuffer to flip onto plane
28918c2ecf20Sopenharmony_ci * @crtc_x: x offset of primary plane on @crtc
28928c2ecf20Sopenharmony_ci * @crtc_y: y offset of primary plane on @crtc
28938c2ecf20Sopenharmony_ci * @crtc_w: width of primary plane rectangle on @crtc
28948c2ecf20Sopenharmony_ci * @crtc_h: height of primary plane rectangle on @crtc
28958c2ecf20Sopenharmony_ci * @src_x: x offset of @fb for panning
28968c2ecf20Sopenharmony_ci * @src_y: y offset of @fb for panning
28978c2ecf20Sopenharmony_ci * @src_w: width of source rectangle in @fb
28988c2ecf20Sopenharmony_ci * @src_h: height of source rectangle in @fb
28998c2ecf20Sopenharmony_ci * @ctx: lock acquire context
29008c2ecf20Sopenharmony_ci *
29018c2ecf20Sopenharmony_ci * Provides a default plane update handler using the atomic driver interface.
29028c2ecf20Sopenharmony_ci *
29038c2ecf20Sopenharmony_ci * RETURNS:
29048c2ecf20Sopenharmony_ci * Zero on success, error code on failure
29058c2ecf20Sopenharmony_ci */
29068c2ecf20Sopenharmony_ciint drm_atomic_helper_update_plane(struct drm_plane *plane,
29078c2ecf20Sopenharmony_ci				   struct drm_crtc *crtc,
29088c2ecf20Sopenharmony_ci				   struct drm_framebuffer *fb,
29098c2ecf20Sopenharmony_ci				   int crtc_x, int crtc_y,
29108c2ecf20Sopenharmony_ci				   unsigned int crtc_w, unsigned int crtc_h,
29118c2ecf20Sopenharmony_ci				   uint32_t src_x, uint32_t src_y,
29128c2ecf20Sopenharmony_ci				   uint32_t src_w, uint32_t src_h,
29138c2ecf20Sopenharmony_ci				   struct drm_modeset_acquire_ctx *ctx)
29148c2ecf20Sopenharmony_ci{
29158c2ecf20Sopenharmony_ci	struct drm_atomic_state *state;
29168c2ecf20Sopenharmony_ci	struct drm_plane_state *plane_state;
29178c2ecf20Sopenharmony_ci	int ret = 0;
29188c2ecf20Sopenharmony_ci
29198c2ecf20Sopenharmony_ci	state = drm_atomic_state_alloc(plane->dev);
29208c2ecf20Sopenharmony_ci	if (!state)
29218c2ecf20Sopenharmony_ci		return -ENOMEM;
29228c2ecf20Sopenharmony_ci
29238c2ecf20Sopenharmony_ci	state->acquire_ctx = ctx;
29248c2ecf20Sopenharmony_ci	plane_state = drm_atomic_get_plane_state(state, plane);
29258c2ecf20Sopenharmony_ci	if (IS_ERR(plane_state)) {
29268c2ecf20Sopenharmony_ci		ret = PTR_ERR(plane_state);
29278c2ecf20Sopenharmony_ci		goto fail;
29288c2ecf20Sopenharmony_ci	}
29298c2ecf20Sopenharmony_ci
29308c2ecf20Sopenharmony_ci	ret = drm_atomic_set_crtc_for_plane(plane_state, crtc);
29318c2ecf20Sopenharmony_ci	if (ret != 0)
29328c2ecf20Sopenharmony_ci		goto fail;
29338c2ecf20Sopenharmony_ci	drm_atomic_set_fb_for_plane(plane_state, fb);
29348c2ecf20Sopenharmony_ci	plane_state->crtc_x = crtc_x;
29358c2ecf20Sopenharmony_ci	plane_state->crtc_y = crtc_y;
29368c2ecf20Sopenharmony_ci	plane_state->crtc_w = crtc_w;
29378c2ecf20Sopenharmony_ci	plane_state->crtc_h = crtc_h;
29388c2ecf20Sopenharmony_ci	plane_state->src_x = src_x;
29398c2ecf20Sopenharmony_ci	plane_state->src_y = src_y;
29408c2ecf20Sopenharmony_ci	plane_state->src_w = src_w;
29418c2ecf20Sopenharmony_ci	plane_state->src_h = src_h;
29428c2ecf20Sopenharmony_ci
29438c2ecf20Sopenharmony_ci	if (plane == crtc->cursor)
29448c2ecf20Sopenharmony_ci		state->legacy_cursor_update = true;
29458c2ecf20Sopenharmony_ci
29468c2ecf20Sopenharmony_ci	ret = drm_atomic_commit(state);
29478c2ecf20Sopenharmony_cifail:
29488c2ecf20Sopenharmony_ci	drm_atomic_state_put(state);
29498c2ecf20Sopenharmony_ci	return ret;
29508c2ecf20Sopenharmony_ci}
29518c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_update_plane);
29528c2ecf20Sopenharmony_ci
29538c2ecf20Sopenharmony_ci/**
29548c2ecf20Sopenharmony_ci * drm_atomic_helper_disable_plane - Helper for primary plane disable using * atomic
29558c2ecf20Sopenharmony_ci * @plane: plane to disable
29568c2ecf20Sopenharmony_ci * @ctx: lock acquire context
29578c2ecf20Sopenharmony_ci *
29588c2ecf20Sopenharmony_ci * Provides a default plane disable handler using the atomic driver interface.
29598c2ecf20Sopenharmony_ci *
29608c2ecf20Sopenharmony_ci * RETURNS:
29618c2ecf20Sopenharmony_ci * Zero on success, error code on failure
29628c2ecf20Sopenharmony_ci */
29638c2ecf20Sopenharmony_ciint drm_atomic_helper_disable_plane(struct drm_plane *plane,
29648c2ecf20Sopenharmony_ci				    struct drm_modeset_acquire_ctx *ctx)
29658c2ecf20Sopenharmony_ci{
29668c2ecf20Sopenharmony_ci	struct drm_atomic_state *state;
29678c2ecf20Sopenharmony_ci	struct drm_plane_state *plane_state;
29688c2ecf20Sopenharmony_ci	int ret = 0;
29698c2ecf20Sopenharmony_ci
29708c2ecf20Sopenharmony_ci	state = drm_atomic_state_alloc(plane->dev);
29718c2ecf20Sopenharmony_ci	if (!state)
29728c2ecf20Sopenharmony_ci		return -ENOMEM;
29738c2ecf20Sopenharmony_ci
29748c2ecf20Sopenharmony_ci	state->acquire_ctx = ctx;
29758c2ecf20Sopenharmony_ci	plane_state = drm_atomic_get_plane_state(state, plane);
29768c2ecf20Sopenharmony_ci	if (IS_ERR(plane_state)) {
29778c2ecf20Sopenharmony_ci		ret = PTR_ERR(plane_state);
29788c2ecf20Sopenharmony_ci		goto fail;
29798c2ecf20Sopenharmony_ci	}
29808c2ecf20Sopenharmony_ci
29818c2ecf20Sopenharmony_ci	if (plane_state->crtc && plane_state->crtc->cursor == plane)
29828c2ecf20Sopenharmony_ci		plane_state->state->legacy_cursor_update = true;
29838c2ecf20Sopenharmony_ci
29848c2ecf20Sopenharmony_ci	ret = __drm_atomic_helper_disable_plane(plane, plane_state);
29858c2ecf20Sopenharmony_ci	if (ret != 0)
29868c2ecf20Sopenharmony_ci		goto fail;
29878c2ecf20Sopenharmony_ci
29888c2ecf20Sopenharmony_ci	ret = drm_atomic_commit(state);
29898c2ecf20Sopenharmony_cifail:
29908c2ecf20Sopenharmony_ci	drm_atomic_state_put(state);
29918c2ecf20Sopenharmony_ci	return ret;
29928c2ecf20Sopenharmony_ci}
29938c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_disable_plane);
29948c2ecf20Sopenharmony_ci
29958c2ecf20Sopenharmony_ci/**
29968c2ecf20Sopenharmony_ci * drm_atomic_helper_set_config - set a new config from userspace
29978c2ecf20Sopenharmony_ci * @set: mode set configuration
29988c2ecf20Sopenharmony_ci * @ctx: lock acquisition context
29998c2ecf20Sopenharmony_ci *
30008c2ecf20Sopenharmony_ci * Provides a default CRTC set_config handler using the atomic driver interface.
30018c2ecf20Sopenharmony_ci *
30028c2ecf20Sopenharmony_ci * NOTE: For backwards compatibility with old userspace this automatically
30038c2ecf20Sopenharmony_ci * resets the "link-status" property to GOOD, to force any link
30048c2ecf20Sopenharmony_ci * re-training. The SETCRTC ioctl does not define whether an update does
30058c2ecf20Sopenharmony_ci * need a full modeset or just a plane update, hence we're allowed to do
30068c2ecf20Sopenharmony_ci * that. See also drm_connector_set_link_status_property().
30078c2ecf20Sopenharmony_ci *
30088c2ecf20Sopenharmony_ci * Returns:
30098c2ecf20Sopenharmony_ci * Returns 0 on success, negative errno numbers on failure.
30108c2ecf20Sopenharmony_ci */
30118c2ecf20Sopenharmony_ciint drm_atomic_helper_set_config(struct drm_mode_set *set,
30128c2ecf20Sopenharmony_ci				 struct drm_modeset_acquire_ctx *ctx)
30138c2ecf20Sopenharmony_ci{
30148c2ecf20Sopenharmony_ci	struct drm_atomic_state *state;
30158c2ecf20Sopenharmony_ci	struct drm_crtc *crtc = set->crtc;
30168c2ecf20Sopenharmony_ci	int ret = 0;
30178c2ecf20Sopenharmony_ci
30188c2ecf20Sopenharmony_ci	state = drm_atomic_state_alloc(crtc->dev);
30198c2ecf20Sopenharmony_ci	if (!state)
30208c2ecf20Sopenharmony_ci		return -ENOMEM;
30218c2ecf20Sopenharmony_ci
30228c2ecf20Sopenharmony_ci	state->acquire_ctx = ctx;
30238c2ecf20Sopenharmony_ci	ret = __drm_atomic_helper_set_config(set, state);
30248c2ecf20Sopenharmony_ci	if (ret != 0)
30258c2ecf20Sopenharmony_ci		goto fail;
30268c2ecf20Sopenharmony_ci
30278c2ecf20Sopenharmony_ci	ret = handle_conflicting_encoders(state, true);
30288c2ecf20Sopenharmony_ci	if (ret)
30298c2ecf20Sopenharmony_ci		goto fail;
30308c2ecf20Sopenharmony_ci
30318c2ecf20Sopenharmony_ci	ret = drm_atomic_commit(state);
30328c2ecf20Sopenharmony_ci
30338c2ecf20Sopenharmony_cifail:
30348c2ecf20Sopenharmony_ci	drm_atomic_state_put(state);
30358c2ecf20Sopenharmony_ci	return ret;
30368c2ecf20Sopenharmony_ci}
30378c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_set_config);
30388c2ecf20Sopenharmony_ci
30398c2ecf20Sopenharmony_ci/**
30408c2ecf20Sopenharmony_ci * drm_atomic_helper_disable_all - disable all currently active outputs
30418c2ecf20Sopenharmony_ci * @dev: DRM device
30428c2ecf20Sopenharmony_ci * @ctx: lock acquisition context
30438c2ecf20Sopenharmony_ci *
30448c2ecf20Sopenharmony_ci * Loops through all connectors, finding those that aren't turned off and then
30458c2ecf20Sopenharmony_ci * turns them off by setting their DPMS mode to OFF and deactivating the CRTC
30468c2ecf20Sopenharmony_ci * that they are connected to.
30478c2ecf20Sopenharmony_ci *
30488c2ecf20Sopenharmony_ci * This is used for example in suspend/resume to disable all currently active
30498c2ecf20Sopenharmony_ci * functions when suspending. If you just want to shut down everything at e.g.
30508c2ecf20Sopenharmony_ci * driver unload, look at drm_atomic_helper_shutdown().
30518c2ecf20Sopenharmony_ci *
30528c2ecf20Sopenharmony_ci * Note that if callers haven't already acquired all modeset locks this might
30538c2ecf20Sopenharmony_ci * return -EDEADLK, which must be handled by calling drm_modeset_backoff().
30548c2ecf20Sopenharmony_ci *
30558c2ecf20Sopenharmony_ci * Returns:
30568c2ecf20Sopenharmony_ci * 0 on success or a negative error code on failure.
30578c2ecf20Sopenharmony_ci *
30588c2ecf20Sopenharmony_ci * See also:
30598c2ecf20Sopenharmony_ci * drm_atomic_helper_suspend(), drm_atomic_helper_resume() and
30608c2ecf20Sopenharmony_ci * drm_atomic_helper_shutdown().
30618c2ecf20Sopenharmony_ci */
30628c2ecf20Sopenharmony_ciint drm_atomic_helper_disable_all(struct drm_device *dev,
30638c2ecf20Sopenharmony_ci				  struct drm_modeset_acquire_ctx *ctx)
30648c2ecf20Sopenharmony_ci{
30658c2ecf20Sopenharmony_ci	struct drm_atomic_state *state;
30668c2ecf20Sopenharmony_ci	struct drm_connector_state *conn_state;
30678c2ecf20Sopenharmony_ci	struct drm_connector *conn;
30688c2ecf20Sopenharmony_ci	struct drm_plane_state *plane_state;
30698c2ecf20Sopenharmony_ci	struct drm_plane *plane;
30708c2ecf20Sopenharmony_ci	struct drm_crtc_state *crtc_state;
30718c2ecf20Sopenharmony_ci	struct drm_crtc *crtc;
30728c2ecf20Sopenharmony_ci	int ret, i;
30738c2ecf20Sopenharmony_ci
30748c2ecf20Sopenharmony_ci	state = drm_atomic_state_alloc(dev);
30758c2ecf20Sopenharmony_ci	if (!state)
30768c2ecf20Sopenharmony_ci		return -ENOMEM;
30778c2ecf20Sopenharmony_ci
30788c2ecf20Sopenharmony_ci	state->acquire_ctx = ctx;
30798c2ecf20Sopenharmony_ci
30808c2ecf20Sopenharmony_ci	drm_for_each_crtc(crtc, dev) {
30818c2ecf20Sopenharmony_ci		crtc_state = drm_atomic_get_crtc_state(state, crtc);
30828c2ecf20Sopenharmony_ci		if (IS_ERR(crtc_state)) {
30838c2ecf20Sopenharmony_ci			ret = PTR_ERR(crtc_state);
30848c2ecf20Sopenharmony_ci			goto free;
30858c2ecf20Sopenharmony_ci		}
30868c2ecf20Sopenharmony_ci
30878c2ecf20Sopenharmony_ci		crtc_state->active = false;
30888c2ecf20Sopenharmony_ci
30898c2ecf20Sopenharmony_ci		ret = drm_atomic_set_mode_prop_for_crtc(crtc_state, NULL);
30908c2ecf20Sopenharmony_ci		if (ret < 0)
30918c2ecf20Sopenharmony_ci			goto free;
30928c2ecf20Sopenharmony_ci
30938c2ecf20Sopenharmony_ci		ret = drm_atomic_add_affected_planes(state, crtc);
30948c2ecf20Sopenharmony_ci		if (ret < 0)
30958c2ecf20Sopenharmony_ci			goto free;
30968c2ecf20Sopenharmony_ci
30978c2ecf20Sopenharmony_ci		ret = drm_atomic_add_affected_connectors(state, crtc);
30988c2ecf20Sopenharmony_ci		if (ret < 0)
30998c2ecf20Sopenharmony_ci			goto free;
31008c2ecf20Sopenharmony_ci	}
31018c2ecf20Sopenharmony_ci
31028c2ecf20Sopenharmony_ci	for_each_new_connector_in_state(state, conn, conn_state, i) {
31038c2ecf20Sopenharmony_ci		ret = drm_atomic_set_crtc_for_connector(conn_state, NULL);
31048c2ecf20Sopenharmony_ci		if (ret < 0)
31058c2ecf20Sopenharmony_ci			goto free;
31068c2ecf20Sopenharmony_ci	}
31078c2ecf20Sopenharmony_ci
31088c2ecf20Sopenharmony_ci	for_each_new_plane_in_state(state, plane, plane_state, i) {
31098c2ecf20Sopenharmony_ci		ret = drm_atomic_set_crtc_for_plane(plane_state, NULL);
31108c2ecf20Sopenharmony_ci		if (ret < 0)
31118c2ecf20Sopenharmony_ci			goto free;
31128c2ecf20Sopenharmony_ci
31138c2ecf20Sopenharmony_ci		drm_atomic_set_fb_for_plane(plane_state, NULL);
31148c2ecf20Sopenharmony_ci	}
31158c2ecf20Sopenharmony_ci
31168c2ecf20Sopenharmony_ci	ret = drm_atomic_commit(state);
31178c2ecf20Sopenharmony_cifree:
31188c2ecf20Sopenharmony_ci	drm_atomic_state_put(state);
31198c2ecf20Sopenharmony_ci	return ret;
31208c2ecf20Sopenharmony_ci}
31218c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_disable_all);
31228c2ecf20Sopenharmony_ci
31238c2ecf20Sopenharmony_ci/**
31248c2ecf20Sopenharmony_ci * drm_atomic_helper_shutdown - shutdown all CRTC
31258c2ecf20Sopenharmony_ci * @dev: DRM device
31268c2ecf20Sopenharmony_ci *
31278c2ecf20Sopenharmony_ci * This shuts down all CRTC, which is useful for driver unloading. Shutdown on
31288c2ecf20Sopenharmony_ci * suspend should instead be handled with drm_atomic_helper_suspend(), since
31298c2ecf20Sopenharmony_ci * that also takes a snapshot of the modeset state to be restored on resume.
31308c2ecf20Sopenharmony_ci *
31318c2ecf20Sopenharmony_ci * This is just a convenience wrapper around drm_atomic_helper_disable_all(),
31328c2ecf20Sopenharmony_ci * and it is the atomic version of drm_crtc_force_disable_all().
31338c2ecf20Sopenharmony_ci */
31348c2ecf20Sopenharmony_civoid drm_atomic_helper_shutdown(struct drm_device *dev)
31358c2ecf20Sopenharmony_ci{
31368c2ecf20Sopenharmony_ci	struct drm_modeset_acquire_ctx ctx;
31378c2ecf20Sopenharmony_ci	int ret;
31388c2ecf20Sopenharmony_ci
31398c2ecf20Sopenharmony_ci	DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret);
31408c2ecf20Sopenharmony_ci
31418c2ecf20Sopenharmony_ci	ret = drm_atomic_helper_disable_all(dev, &ctx);
31428c2ecf20Sopenharmony_ci	if (ret)
31438c2ecf20Sopenharmony_ci		DRM_ERROR("Disabling all crtc's during unload failed with %i\n", ret);
31448c2ecf20Sopenharmony_ci
31458c2ecf20Sopenharmony_ci	DRM_MODESET_LOCK_ALL_END(dev, ctx, ret);
31468c2ecf20Sopenharmony_ci}
31478c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_shutdown);
31488c2ecf20Sopenharmony_ci
31498c2ecf20Sopenharmony_ci/**
31508c2ecf20Sopenharmony_ci * drm_atomic_helper_duplicate_state - duplicate an atomic state object
31518c2ecf20Sopenharmony_ci * @dev: DRM device
31528c2ecf20Sopenharmony_ci * @ctx: lock acquisition context
31538c2ecf20Sopenharmony_ci *
31548c2ecf20Sopenharmony_ci * Makes a copy of the current atomic state by looping over all objects and
31558c2ecf20Sopenharmony_ci * duplicating their respective states. This is used for example by suspend/
31568c2ecf20Sopenharmony_ci * resume support code to save the state prior to suspend such that it can
31578c2ecf20Sopenharmony_ci * be restored upon resume.
31588c2ecf20Sopenharmony_ci *
31598c2ecf20Sopenharmony_ci * Note that this treats atomic state as persistent between save and restore.
31608c2ecf20Sopenharmony_ci * Drivers must make sure that this is possible and won't result in confusion
31618c2ecf20Sopenharmony_ci * or erroneous behaviour.
31628c2ecf20Sopenharmony_ci *
31638c2ecf20Sopenharmony_ci * Note that if callers haven't already acquired all modeset locks this might
31648c2ecf20Sopenharmony_ci * return -EDEADLK, which must be handled by calling drm_modeset_backoff().
31658c2ecf20Sopenharmony_ci *
31668c2ecf20Sopenharmony_ci * Returns:
31678c2ecf20Sopenharmony_ci * A pointer to the copy of the atomic state object on success or an
31688c2ecf20Sopenharmony_ci * ERR_PTR()-encoded error code on failure.
31698c2ecf20Sopenharmony_ci *
31708c2ecf20Sopenharmony_ci * See also:
31718c2ecf20Sopenharmony_ci * drm_atomic_helper_suspend(), drm_atomic_helper_resume()
31728c2ecf20Sopenharmony_ci */
31738c2ecf20Sopenharmony_cistruct drm_atomic_state *
31748c2ecf20Sopenharmony_cidrm_atomic_helper_duplicate_state(struct drm_device *dev,
31758c2ecf20Sopenharmony_ci				  struct drm_modeset_acquire_ctx *ctx)
31768c2ecf20Sopenharmony_ci{
31778c2ecf20Sopenharmony_ci	struct drm_atomic_state *state;
31788c2ecf20Sopenharmony_ci	struct drm_connector *conn;
31798c2ecf20Sopenharmony_ci	struct drm_connector_list_iter conn_iter;
31808c2ecf20Sopenharmony_ci	struct drm_plane *plane;
31818c2ecf20Sopenharmony_ci	struct drm_crtc *crtc;
31828c2ecf20Sopenharmony_ci	int err = 0;
31838c2ecf20Sopenharmony_ci
31848c2ecf20Sopenharmony_ci	state = drm_atomic_state_alloc(dev);
31858c2ecf20Sopenharmony_ci	if (!state)
31868c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
31878c2ecf20Sopenharmony_ci
31888c2ecf20Sopenharmony_ci	state->acquire_ctx = ctx;
31898c2ecf20Sopenharmony_ci	state->duplicated = true;
31908c2ecf20Sopenharmony_ci
31918c2ecf20Sopenharmony_ci	drm_for_each_crtc(crtc, dev) {
31928c2ecf20Sopenharmony_ci		struct drm_crtc_state *crtc_state;
31938c2ecf20Sopenharmony_ci
31948c2ecf20Sopenharmony_ci		crtc_state = drm_atomic_get_crtc_state(state, crtc);
31958c2ecf20Sopenharmony_ci		if (IS_ERR(crtc_state)) {
31968c2ecf20Sopenharmony_ci			err = PTR_ERR(crtc_state);
31978c2ecf20Sopenharmony_ci			goto free;
31988c2ecf20Sopenharmony_ci		}
31998c2ecf20Sopenharmony_ci	}
32008c2ecf20Sopenharmony_ci
32018c2ecf20Sopenharmony_ci	drm_for_each_plane(plane, dev) {
32028c2ecf20Sopenharmony_ci		struct drm_plane_state *plane_state;
32038c2ecf20Sopenharmony_ci
32048c2ecf20Sopenharmony_ci		plane_state = drm_atomic_get_plane_state(state, plane);
32058c2ecf20Sopenharmony_ci		if (IS_ERR(plane_state)) {
32068c2ecf20Sopenharmony_ci			err = PTR_ERR(plane_state);
32078c2ecf20Sopenharmony_ci			goto free;
32088c2ecf20Sopenharmony_ci		}
32098c2ecf20Sopenharmony_ci	}
32108c2ecf20Sopenharmony_ci
32118c2ecf20Sopenharmony_ci	drm_connector_list_iter_begin(dev, &conn_iter);
32128c2ecf20Sopenharmony_ci	drm_for_each_connector_iter(conn, &conn_iter) {
32138c2ecf20Sopenharmony_ci		struct drm_connector_state *conn_state;
32148c2ecf20Sopenharmony_ci
32158c2ecf20Sopenharmony_ci		conn_state = drm_atomic_get_connector_state(state, conn);
32168c2ecf20Sopenharmony_ci		if (IS_ERR(conn_state)) {
32178c2ecf20Sopenharmony_ci			err = PTR_ERR(conn_state);
32188c2ecf20Sopenharmony_ci			drm_connector_list_iter_end(&conn_iter);
32198c2ecf20Sopenharmony_ci			goto free;
32208c2ecf20Sopenharmony_ci		}
32218c2ecf20Sopenharmony_ci	}
32228c2ecf20Sopenharmony_ci	drm_connector_list_iter_end(&conn_iter);
32238c2ecf20Sopenharmony_ci
32248c2ecf20Sopenharmony_ci	/* clear the acquire context so that it isn't accidentally reused */
32258c2ecf20Sopenharmony_ci	state->acquire_ctx = NULL;
32268c2ecf20Sopenharmony_ci
32278c2ecf20Sopenharmony_cifree:
32288c2ecf20Sopenharmony_ci	if (err < 0) {
32298c2ecf20Sopenharmony_ci		drm_atomic_state_put(state);
32308c2ecf20Sopenharmony_ci		state = ERR_PTR(err);
32318c2ecf20Sopenharmony_ci	}
32328c2ecf20Sopenharmony_ci
32338c2ecf20Sopenharmony_ci	return state;
32348c2ecf20Sopenharmony_ci}
32358c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_duplicate_state);
32368c2ecf20Sopenharmony_ci
32378c2ecf20Sopenharmony_ci/**
32388c2ecf20Sopenharmony_ci * drm_atomic_helper_suspend - subsystem-level suspend helper
32398c2ecf20Sopenharmony_ci * @dev: DRM device
32408c2ecf20Sopenharmony_ci *
32418c2ecf20Sopenharmony_ci * Duplicates the current atomic state, disables all active outputs and then
32428c2ecf20Sopenharmony_ci * returns a pointer to the original atomic state to the caller. Drivers can
32438c2ecf20Sopenharmony_ci * pass this pointer to the drm_atomic_helper_resume() helper upon resume to
32448c2ecf20Sopenharmony_ci * restore the output configuration that was active at the time the system
32458c2ecf20Sopenharmony_ci * entered suspend.
32468c2ecf20Sopenharmony_ci *
32478c2ecf20Sopenharmony_ci * Note that it is potentially unsafe to use this. The atomic state object
32488c2ecf20Sopenharmony_ci * returned by this function is assumed to be persistent. Drivers must ensure
32498c2ecf20Sopenharmony_ci * that this holds true. Before calling this function, drivers must make sure
32508c2ecf20Sopenharmony_ci * to suspend fbdev emulation so that nothing can be using the device.
32518c2ecf20Sopenharmony_ci *
32528c2ecf20Sopenharmony_ci * Returns:
32538c2ecf20Sopenharmony_ci * A pointer to a copy of the state before suspend on success or an ERR_PTR()-
32548c2ecf20Sopenharmony_ci * encoded error code on failure. Drivers should store the returned atomic
32558c2ecf20Sopenharmony_ci * state object and pass it to the drm_atomic_helper_resume() helper upon
32568c2ecf20Sopenharmony_ci * resume.
32578c2ecf20Sopenharmony_ci *
32588c2ecf20Sopenharmony_ci * See also:
32598c2ecf20Sopenharmony_ci * drm_atomic_helper_duplicate_state(), drm_atomic_helper_disable_all(),
32608c2ecf20Sopenharmony_ci * drm_atomic_helper_resume(), drm_atomic_helper_commit_duplicated_state()
32618c2ecf20Sopenharmony_ci */
32628c2ecf20Sopenharmony_cistruct drm_atomic_state *drm_atomic_helper_suspend(struct drm_device *dev)
32638c2ecf20Sopenharmony_ci{
32648c2ecf20Sopenharmony_ci	struct drm_modeset_acquire_ctx ctx;
32658c2ecf20Sopenharmony_ci	struct drm_atomic_state *state;
32668c2ecf20Sopenharmony_ci	int err;
32678c2ecf20Sopenharmony_ci
32688c2ecf20Sopenharmony_ci	/* This can never be returned, but it makes the compiler happy */
32698c2ecf20Sopenharmony_ci	state = ERR_PTR(-EINVAL);
32708c2ecf20Sopenharmony_ci
32718c2ecf20Sopenharmony_ci	DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, err);
32728c2ecf20Sopenharmony_ci
32738c2ecf20Sopenharmony_ci	state = drm_atomic_helper_duplicate_state(dev, &ctx);
32748c2ecf20Sopenharmony_ci	if (IS_ERR(state))
32758c2ecf20Sopenharmony_ci		goto unlock;
32768c2ecf20Sopenharmony_ci
32778c2ecf20Sopenharmony_ci	err = drm_atomic_helper_disable_all(dev, &ctx);
32788c2ecf20Sopenharmony_ci	if (err < 0) {
32798c2ecf20Sopenharmony_ci		drm_atomic_state_put(state);
32808c2ecf20Sopenharmony_ci		state = ERR_PTR(err);
32818c2ecf20Sopenharmony_ci		goto unlock;
32828c2ecf20Sopenharmony_ci	}
32838c2ecf20Sopenharmony_ci
32848c2ecf20Sopenharmony_ciunlock:
32858c2ecf20Sopenharmony_ci	DRM_MODESET_LOCK_ALL_END(dev, ctx, err);
32868c2ecf20Sopenharmony_ci	if (err)
32878c2ecf20Sopenharmony_ci		return ERR_PTR(err);
32888c2ecf20Sopenharmony_ci
32898c2ecf20Sopenharmony_ci	return state;
32908c2ecf20Sopenharmony_ci}
32918c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_suspend);
32928c2ecf20Sopenharmony_ci
32938c2ecf20Sopenharmony_ci/**
32948c2ecf20Sopenharmony_ci * drm_atomic_helper_commit_duplicated_state - commit duplicated state
32958c2ecf20Sopenharmony_ci * @state: duplicated atomic state to commit
32968c2ecf20Sopenharmony_ci * @ctx: pointer to acquire_ctx to use for commit.
32978c2ecf20Sopenharmony_ci *
32988c2ecf20Sopenharmony_ci * The state returned by drm_atomic_helper_duplicate_state() and
32998c2ecf20Sopenharmony_ci * drm_atomic_helper_suspend() is partially invalid, and needs to
33008c2ecf20Sopenharmony_ci * be fixed up before commit.
33018c2ecf20Sopenharmony_ci *
33028c2ecf20Sopenharmony_ci * Returns:
33038c2ecf20Sopenharmony_ci * 0 on success or a negative error code on failure.
33048c2ecf20Sopenharmony_ci *
33058c2ecf20Sopenharmony_ci * See also:
33068c2ecf20Sopenharmony_ci * drm_atomic_helper_suspend()
33078c2ecf20Sopenharmony_ci */
33088c2ecf20Sopenharmony_ciint drm_atomic_helper_commit_duplicated_state(struct drm_atomic_state *state,
33098c2ecf20Sopenharmony_ci					      struct drm_modeset_acquire_ctx *ctx)
33108c2ecf20Sopenharmony_ci{
33118c2ecf20Sopenharmony_ci	int i, ret;
33128c2ecf20Sopenharmony_ci	struct drm_plane *plane;
33138c2ecf20Sopenharmony_ci	struct drm_plane_state *new_plane_state;
33148c2ecf20Sopenharmony_ci	struct drm_connector *connector;
33158c2ecf20Sopenharmony_ci	struct drm_connector_state *new_conn_state;
33168c2ecf20Sopenharmony_ci	struct drm_crtc *crtc;
33178c2ecf20Sopenharmony_ci	struct drm_crtc_state *new_crtc_state;
33188c2ecf20Sopenharmony_ci
33198c2ecf20Sopenharmony_ci	state->acquire_ctx = ctx;
33208c2ecf20Sopenharmony_ci
33218c2ecf20Sopenharmony_ci	for_each_new_plane_in_state(state, plane, new_plane_state, i)
33228c2ecf20Sopenharmony_ci		state->planes[i].old_state = plane->state;
33238c2ecf20Sopenharmony_ci
33248c2ecf20Sopenharmony_ci	for_each_new_crtc_in_state(state, crtc, new_crtc_state, i)
33258c2ecf20Sopenharmony_ci		state->crtcs[i].old_state = crtc->state;
33268c2ecf20Sopenharmony_ci
33278c2ecf20Sopenharmony_ci	for_each_new_connector_in_state(state, connector, new_conn_state, i)
33288c2ecf20Sopenharmony_ci		state->connectors[i].old_state = connector->state;
33298c2ecf20Sopenharmony_ci
33308c2ecf20Sopenharmony_ci	ret = drm_atomic_commit(state);
33318c2ecf20Sopenharmony_ci
33328c2ecf20Sopenharmony_ci	state->acquire_ctx = NULL;
33338c2ecf20Sopenharmony_ci
33348c2ecf20Sopenharmony_ci	return ret;
33358c2ecf20Sopenharmony_ci}
33368c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_commit_duplicated_state);
33378c2ecf20Sopenharmony_ci
33388c2ecf20Sopenharmony_ci/**
33398c2ecf20Sopenharmony_ci * drm_atomic_helper_resume - subsystem-level resume helper
33408c2ecf20Sopenharmony_ci * @dev: DRM device
33418c2ecf20Sopenharmony_ci * @state: atomic state to resume to
33428c2ecf20Sopenharmony_ci *
33438c2ecf20Sopenharmony_ci * Calls drm_mode_config_reset() to synchronize hardware and software states,
33448c2ecf20Sopenharmony_ci * grabs all modeset locks and commits the atomic state object. This can be
33458c2ecf20Sopenharmony_ci * used in conjunction with the drm_atomic_helper_suspend() helper to
33468c2ecf20Sopenharmony_ci * implement suspend/resume for drivers that support atomic mode-setting.
33478c2ecf20Sopenharmony_ci *
33488c2ecf20Sopenharmony_ci * Returns:
33498c2ecf20Sopenharmony_ci * 0 on success or a negative error code on failure.
33508c2ecf20Sopenharmony_ci *
33518c2ecf20Sopenharmony_ci * See also:
33528c2ecf20Sopenharmony_ci * drm_atomic_helper_suspend()
33538c2ecf20Sopenharmony_ci */
33548c2ecf20Sopenharmony_ciint drm_atomic_helper_resume(struct drm_device *dev,
33558c2ecf20Sopenharmony_ci			     struct drm_atomic_state *state)
33568c2ecf20Sopenharmony_ci{
33578c2ecf20Sopenharmony_ci	struct drm_modeset_acquire_ctx ctx;
33588c2ecf20Sopenharmony_ci	int err;
33598c2ecf20Sopenharmony_ci
33608c2ecf20Sopenharmony_ci	drm_mode_config_reset(dev);
33618c2ecf20Sopenharmony_ci
33628c2ecf20Sopenharmony_ci	DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, err);
33638c2ecf20Sopenharmony_ci
33648c2ecf20Sopenharmony_ci	err = drm_atomic_helper_commit_duplicated_state(state, &ctx);
33658c2ecf20Sopenharmony_ci
33668c2ecf20Sopenharmony_ci	DRM_MODESET_LOCK_ALL_END(dev, ctx, err);
33678c2ecf20Sopenharmony_ci	drm_atomic_state_put(state);
33688c2ecf20Sopenharmony_ci
33698c2ecf20Sopenharmony_ci	return err;
33708c2ecf20Sopenharmony_ci}
33718c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_resume);
33728c2ecf20Sopenharmony_ci
33738c2ecf20Sopenharmony_cistatic int page_flip_common(struct drm_atomic_state *state,
33748c2ecf20Sopenharmony_ci			    struct drm_crtc *crtc,
33758c2ecf20Sopenharmony_ci			    struct drm_framebuffer *fb,
33768c2ecf20Sopenharmony_ci			    struct drm_pending_vblank_event *event,
33778c2ecf20Sopenharmony_ci			    uint32_t flags)
33788c2ecf20Sopenharmony_ci{
33798c2ecf20Sopenharmony_ci	struct drm_plane *plane = crtc->primary;
33808c2ecf20Sopenharmony_ci	struct drm_plane_state *plane_state;
33818c2ecf20Sopenharmony_ci	struct drm_crtc_state *crtc_state;
33828c2ecf20Sopenharmony_ci	int ret = 0;
33838c2ecf20Sopenharmony_ci
33848c2ecf20Sopenharmony_ci	crtc_state = drm_atomic_get_crtc_state(state, crtc);
33858c2ecf20Sopenharmony_ci	if (IS_ERR(crtc_state))
33868c2ecf20Sopenharmony_ci		return PTR_ERR(crtc_state);
33878c2ecf20Sopenharmony_ci
33888c2ecf20Sopenharmony_ci	crtc_state->event = event;
33898c2ecf20Sopenharmony_ci	crtc_state->async_flip = flags & DRM_MODE_PAGE_FLIP_ASYNC;
33908c2ecf20Sopenharmony_ci
33918c2ecf20Sopenharmony_ci	plane_state = drm_atomic_get_plane_state(state, plane);
33928c2ecf20Sopenharmony_ci	if (IS_ERR(plane_state))
33938c2ecf20Sopenharmony_ci		return PTR_ERR(plane_state);
33948c2ecf20Sopenharmony_ci
33958c2ecf20Sopenharmony_ci	ret = drm_atomic_set_crtc_for_plane(plane_state, crtc);
33968c2ecf20Sopenharmony_ci	if (ret != 0)
33978c2ecf20Sopenharmony_ci		return ret;
33988c2ecf20Sopenharmony_ci	drm_atomic_set_fb_for_plane(plane_state, fb);
33998c2ecf20Sopenharmony_ci
34008c2ecf20Sopenharmony_ci	/* Make sure we don't accidentally do a full modeset. */
34018c2ecf20Sopenharmony_ci	state->allow_modeset = false;
34028c2ecf20Sopenharmony_ci	if (!crtc_state->active) {
34038c2ecf20Sopenharmony_ci		DRM_DEBUG_ATOMIC("[CRTC:%d:%s] disabled, rejecting legacy flip\n",
34048c2ecf20Sopenharmony_ci				 crtc->base.id, crtc->name);
34058c2ecf20Sopenharmony_ci		return -EINVAL;
34068c2ecf20Sopenharmony_ci	}
34078c2ecf20Sopenharmony_ci
34088c2ecf20Sopenharmony_ci	return ret;
34098c2ecf20Sopenharmony_ci}
34108c2ecf20Sopenharmony_ci
34118c2ecf20Sopenharmony_ci/**
34128c2ecf20Sopenharmony_ci * drm_atomic_helper_page_flip - execute a legacy page flip
34138c2ecf20Sopenharmony_ci * @crtc: DRM CRTC
34148c2ecf20Sopenharmony_ci * @fb: DRM framebuffer
34158c2ecf20Sopenharmony_ci * @event: optional DRM event to signal upon completion
34168c2ecf20Sopenharmony_ci * @flags: flip flags for non-vblank sync'ed updates
34178c2ecf20Sopenharmony_ci * @ctx: lock acquisition context
34188c2ecf20Sopenharmony_ci *
34198c2ecf20Sopenharmony_ci * Provides a default &drm_crtc_funcs.page_flip implementation
34208c2ecf20Sopenharmony_ci * using the atomic driver interface.
34218c2ecf20Sopenharmony_ci *
34228c2ecf20Sopenharmony_ci * Returns:
34238c2ecf20Sopenharmony_ci * Returns 0 on success, negative errno numbers on failure.
34248c2ecf20Sopenharmony_ci *
34258c2ecf20Sopenharmony_ci * See also:
34268c2ecf20Sopenharmony_ci * drm_atomic_helper_page_flip_target()
34278c2ecf20Sopenharmony_ci */
34288c2ecf20Sopenharmony_ciint drm_atomic_helper_page_flip(struct drm_crtc *crtc,
34298c2ecf20Sopenharmony_ci				struct drm_framebuffer *fb,
34308c2ecf20Sopenharmony_ci				struct drm_pending_vblank_event *event,
34318c2ecf20Sopenharmony_ci				uint32_t flags,
34328c2ecf20Sopenharmony_ci				struct drm_modeset_acquire_ctx *ctx)
34338c2ecf20Sopenharmony_ci{
34348c2ecf20Sopenharmony_ci	struct drm_plane *plane = crtc->primary;
34358c2ecf20Sopenharmony_ci	struct drm_atomic_state *state;
34368c2ecf20Sopenharmony_ci	int ret = 0;
34378c2ecf20Sopenharmony_ci
34388c2ecf20Sopenharmony_ci	state = drm_atomic_state_alloc(plane->dev);
34398c2ecf20Sopenharmony_ci	if (!state)
34408c2ecf20Sopenharmony_ci		return -ENOMEM;
34418c2ecf20Sopenharmony_ci
34428c2ecf20Sopenharmony_ci	state->acquire_ctx = ctx;
34438c2ecf20Sopenharmony_ci
34448c2ecf20Sopenharmony_ci	ret = page_flip_common(state, crtc, fb, event, flags);
34458c2ecf20Sopenharmony_ci	if (ret != 0)
34468c2ecf20Sopenharmony_ci		goto fail;
34478c2ecf20Sopenharmony_ci
34488c2ecf20Sopenharmony_ci	ret = drm_atomic_nonblocking_commit(state);
34498c2ecf20Sopenharmony_cifail:
34508c2ecf20Sopenharmony_ci	drm_atomic_state_put(state);
34518c2ecf20Sopenharmony_ci	return ret;
34528c2ecf20Sopenharmony_ci}
34538c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_page_flip);
34548c2ecf20Sopenharmony_ci
34558c2ecf20Sopenharmony_ci/**
34568c2ecf20Sopenharmony_ci * drm_atomic_helper_page_flip_target - do page flip on target vblank period.
34578c2ecf20Sopenharmony_ci * @crtc: DRM CRTC
34588c2ecf20Sopenharmony_ci * @fb: DRM framebuffer
34598c2ecf20Sopenharmony_ci * @event: optional DRM event to signal upon completion
34608c2ecf20Sopenharmony_ci * @flags: flip flags for non-vblank sync'ed updates
34618c2ecf20Sopenharmony_ci * @target: specifying the target vblank period when the flip to take effect
34628c2ecf20Sopenharmony_ci * @ctx: lock acquisition context
34638c2ecf20Sopenharmony_ci *
34648c2ecf20Sopenharmony_ci * Provides a default &drm_crtc_funcs.page_flip_target implementation.
34658c2ecf20Sopenharmony_ci * Similar to drm_atomic_helper_page_flip() with extra parameter to specify
34668c2ecf20Sopenharmony_ci * target vblank period to flip.
34678c2ecf20Sopenharmony_ci *
34688c2ecf20Sopenharmony_ci * Returns:
34698c2ecf20Sopenharmony_ci * Returns 0 on success, negative errno numbers on failure.
34708c2ecf20Sopenharmony_ci */
34718c2ecf20Sopenharmony_ciint drm_atomic_helper_page_flip_target(struct drm_crtc *crtc,
34728c2ecf20Sopenharmony_ci				       struct drm_framebuffer *fb,
34738c2ecf20Sopenharmony_ci				       struct drm_pending_vblank_event *event,
34748c2ecf20Sopenharmony_ci				       uint32_t flags,
34758c2ecf20Sopenharmony_ci				       uint32_t target,
34768c2ecf20Sopenharmony_ci				       struct drm_modeset_acquire_ctx *ctx)
34778c2ecf20Sopenharmony_ci{
34788c2ecf20Sopenharmony_ci	struct drm_plane *plane = crtc->primary;
34798c2ecf20Sopenharmony_ci	struct drm_atomic_state *state;
34808c2ecf20Sopenharmony_ci	struct drm_crtc_state *crtc_state;
34818c2ecf20Sopenharmony_ci	int ret = 0;
34828c2ecf20Sopenharmony_ci
34838c2ecf20Sopenharmony_ci	state = drm_atomic_state_alloc(plane->dev);
34848c2ecf20Sopenharmony_ci	if (!state)
34858c2ecf20Sopenharmony_ci		return -ENOMEM;
34868c2ecf20Sopenharmony_ci
34878c2ecf20Sopenharmony_ci	state->acquire_ctx = ctx;
34888c2ecf20Sopenharmony_ci
34898c2ecf20Sopenharmony_ci	ret = page_flip_common(state, crtc, fb, event, flags);
34908c2ecf20Sopenharmony_ci	if (ret != 0)
34918c2ecf20Sopenharmony_ci		goto fail;
34928c2ecf20Sopenharmony_ci
34938c2ecf20Sopenharmony_ci	crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
34948c2ecf20Sopenharmony_ci	if (WARN_ON(!crtc_state)) {
34958c2ecf20Sopenharmony_ci		ret = -EINVAL;
34968c2ecf20Sopenharmony_ci		goto fail;
34978c2ecf20Sopenharmony_ci	}
34988c2ecf20Sopenharmony_ci	crtc_state->target_vblank = target;
34998c2ecf20Sopenharmony_ci
35008c2ecf20Sopenharmony_ci	ret = drm_atomic_nonblocking_commit(state);
35018c2ecf20Sopenharmony_cifail:
35028c2ecf20Sopenharmony_ci	drm_atomic_state_put(state);
35038c2ecf20Sopenharmony_ci	return ret;
35048c2ecf20Sopenharmony_ci}
35058c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_page_flip_target);
35068c2ecf20Sopenharmony_ci
35078c2ecf20Sopenharmony_ci/**
35088c2ecf20Sopenharmony_ci * drm_atomic_helper_legacy_gamma_set - set the legacy gamma correction table
35098c2ecf20Sopenharmony_ci * @crtc: CRTC object
35108c2ecf20Sopenharmony_ci * @red: red correction table
35118c2ecf20Sopenharmony_ci * @green: green correction table
35128c2ecf20Sopenharmony_ci * @blue: green correction table
35138c2ecf20Sopenharmony_ci * @size: size of the tables
35148c2ecf20Sopenharmony_ci * @ctx: lock acquire context
35158c2ecf20Sopenharmony_ci *
35168c2ecf20Sopenharmony_ci * Implements support for legacy gamma correction table for drivers
35178c2ecf20Sopenharmony_ci * that support color management through the DEGAMMA_LUT/GAMMA_LUT
35188c2ecf20Sopenharmony_ci * properties. See drm_crtc_enable_color_mgmt() and the containing chapter for
35198c2ecf20Sopenharmony_ci * how the atomic color management and gamma tables work.
35208c2ecf20Sopenharmony_ci */
35218c2ecf20Sopenharmony_ciint drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
35228c2ecf20Sopenharmony_ci				       u16 *red, u16 *green, u16 *blue,
35238c2ecf20Sopenharmony_ci				       uint32_t size,
35248c2ecf20Sopenharmony_ci				       struct drm_modeset_acquire_ctx *ctx)
35258c2ecf20Sopenharmony_ci{
35268c2ecf20Sopenharmony_ci	struct drm_device *dev = crtc->dev;
35278c2ecf20Sopenharmony_ci	struct drm_atomic_state *state;
35288c2ecf20Sopenharmony_ci	struct drm_crtc_state *crtc_state;
35298c2ecf20Sopenharmony_ci	struct drm_property_blob *blob = NULL;
35308c2ecf20Sopenharmony_ci	struct drm_color_lut *blob_data;
35318c2ecf20Sopenharmony_ci	int i, ret = 0;
35328c2ecf20Sopenharmony_ci	bool replaced;
35338c2ecf20Sopenharmony_ci
35348c2ecf20Sopenharmony_ci	state = drm_atomic_state_alloc(crtc->dev);
35358c2ecf20Sopenharmony_ci	if (!state)
35368c2ecf20Sopenharmony_ci		return -ENOMEM;
35378c2ecf20Sopenharmony_ci
35388c2ecf20Sopenharmony_ci	blob = drm_property_create_blob(dev,
35398c2ecf20Sopenharmony_ci					sizeof(struct drm_color_lut) * size,
35408c2ecf20Sopenharmony_ci					NULL);
35418c2ecf20Sopenharmony_ci	if (IS_ERR(blob)) {
35428c2ecf20Sopenharmony_ci		ret = PTR_ERR(blob);
35438c2ecf20Sopenharmony_ci		blob = NULL;
35448c2ecf20Sopenharmony_ci		goto fail;
35458c2ecf20Sopenharmony_ci	}
35468c2ecf20Sopenharmony_ci
35478c2ecf20Sopenharmony_ci	/* Prepare GAMMA_LUT with the legacy values. */
35488c2ecf20Sopenharmony_ci	blob_data = blob->data;
35498c2ecf20Sopenharmony_ci	for (i = 0; i < size; i++) {
35508c2ecf20Sopenharmony_ci		blob_data[i].red = red[i];
35518c2ecf20Sopenharmony_ci		blob_data[i].green = green[i];
35528c2ecf20Sopenharmony_ci		blob_data[i].blue = blue[i];
35538c2ecf20Sopenharmony_ci	}
35548c2ecf20Sopenharmony_ci
35558c2ecf20Sopenharmony_ci	state->acquire_ctx = ctx;
35568c2ecf20Sopenharmony_ci	crtc_state = drm_atomic_get_crtc_state(state, crtc);
35578c2ecf20Sopenharmony_ci	if (IS_ERR(crtc_state)) {
35588c2ecf20Sopenharmony_ci		ret = PTR_ERR(crtc_state);
35598c2ecf20Sopenharmony_ci		goto fail;
35608c2ecf20Sopenharmony_ci	}
35618c2ecf20Sopenharmony_ci
35628c2ecf20Sopenharmony_ci	/* Reset DEGAMMA_LUT and CTM properties. */
35638c2ecf20Sopenharmony_ci	replaced  = drm_property_replace_blob(&crtc_state->degamma_lut, NULL);
35648c2ecf20Sopenharmony_ci	replaced |= drm_property_replace_blob(&crtc_state->ctm, NULL);
35658c2ecf20Sopenharmony_ci	replaced |= drm_property_replace_blob(&crtc_state->gamma_lut, blob);
35668c2ecf20Sopenharmony_ci	crtc_state->color_mgmt_changed |= replaced;
35678c2ecf20Sopenharmony_ci
35688c2ecf20Sopenharmony_ci	ret = drm_atomic_commit(state);
35698c2ecf20Sopenharmony_ci
35708c2ecf20Sopenharmony_cifail:
35718c2ecf20Sopenharmony_ci	drm_atomic_state_put(state);
35728c2ecf20Sopenharmony_ci	drm_property_blob_put(blob);
35738c2ecf20Sopenharmony_ci	return ret;
35748c2ecf20Sopenharmony_ci}
35758c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set);
35768c2ecf20Sopenharmony_ci
35778c2ecf20Sopenharmony_ci/**
35788c2ecf20Sopenharmony_ci * drm_atomic_helper_bridge_propagate_bus_fmt() - Propagate output format to
35798c2ecf20Sopenharmony_ci *						  the input end of a bridge
35808c2ecf20Sopenharmony_ci * @bridge: bridge control structure
35818c2ecf20Sopenharmony_ci * @bridge_state: new bridge state
35828c2ecf20Sopenharmony_ci * @crtc_state: new CRTC state
35838c2ecf20Sopenharmony_ci * @conn_state: new connector state
35848c2ecf20Sopenharmony_ci * @output_fmt: tested output bus format
35858c2ecf20Sopenharmony_ci * @num_input_fmts: will contain the size of the returned array
35868c2ecf20Sopenharmony_ci *
35878c2ecf20Sopenharmony_ci * This helper is a pluggable implementation of the
35888c2ecf20Sopenharmony_ci * &drm_bridge_funcs.atomic_get_input_bus_fmts operation for bridges that don't
35898c2ecf20Sopenharmony_ci * modify the bus configuration between their input and their output. It
35908c2ecf20Sopenharmony_ci * returns an array of input formats with a single element set to @output_fmt.
35918c2ecf20Sopenharmony_ci *
35928c2ecf20Sopenharmony_ci * RETURNS:
35938c2ecf20Sopenharmony_ci * a valid format array of size @num_input_fmts, or NULL if the allocation
35948c2ecf20Sopenharmony_ci * failed
35958c2ecf20Sopenharmony_ci */
35968c2ecf20Sopenharmony_ciu32 *
35978c2ecf20Sopenharmony_cidrm_atomic_helper_bridge_propagate_bus_fmt(struct drm_bridge *bridge,
35988c2ecf20Sopenharmony_ci					struct drm_bridge_state *bridge_state,
35998c2ecf20Sopenharmony_ci					struct drm_crtc_state *crtc_state,
36008c2ecf20Sopenharmony_ci					struct drm_connector_state *conn_state,
36018c2ecf20Sopenharmony_ci					u32 output_fmt,
36028c2ecf20Sopenharmony_ci					unsigned int *num_input_fmts)
36038c2ecf20Sopenharmony_ci{
36048c2ecf20Sopenharmony_ci	u32 *input_fmts;
36058c2ecf20Sopenharmony_ci
36068c2ecf20Sopenharmony_ci	input_fmts = kzalloc(sizeof(*input_fmts), GFP_KERNEL);
36078c2ecf20Sopenharmony_ci	if (!input_fmts) {
36088c2ecf20Sopenharmony_ci		*num_input_fmts = 0;
36098c2ecf20Sopenharmony_ci		return NULL;
36108c2ecf20Sopenharmony_ci	}
36118c2ecf20Sopenharmony_ci
36128c2ecf20Sopenharmony_ci	*num_input_fmts = 1;
36138c2ecf20Sopenharmony_ci	input_fmts[0] = output_fmt;
36148c2ecf20Sopenharmony_ci	return input_fmts;
36158c2ecf20Sopenharmony_ci}
36168c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_helper_bridge_propagate_bus_fmt);
3617