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