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 298c2ecf20Sopenharmony_ci#include <linux/sync_file.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include <drm/drm_atomic.h> 328c2ecf20Sopenharmony_ci#include <drm/drm_atomic_uapi.h> 338c2ecf20Sopenharmony_ci#include <drm/drm_bridge.h> 348c2ecf20Sopenharmony_ci#include <drm/drm_debugfs.h> 358c2ecf20Sopenharmony_ci#include <drm/drm_device.h> 368c2ecf20Sopenharmony_ci#include <drm/drm_drv.h> 378c2ecf20Sopenharmony_ci#include <drm/drm_file.h> 388c2ecf20Sopenharmony_ci#include <drm/drm_fourcc.h> 398c2ecf20Sopenharmony_ci#include <drm/drm_mode.h> 408c2ecf20Sopenharmony_ci#include <drm/drm_print.h> 418c2ecf20Sopenharmony_ci#include <drm/drm_writeback.h> 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#include "drm_crtc_internal.h" 448c2ecf20Sopenharmony_ci#include "drm_internal.h" 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_civoid __drm_crtc_commit_free(struct kref *kref) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci struct drm_crtc_commit *commit = 498c2ecf20Sopenharmony_ci container_of(kref, struct drm_crtc_commit, ref); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci kfree(commit); 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__drm_crtc_commit_free); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci/** 568c2ecf20Sopenharmony_ci * drm_atomic_state_default_release - 578c2ecf20Sopenharmony_ci * release memory initialized by drm_atomic_state_init 588c2ecf20Sopenharmony_ci * @state: atomic state 598c2ecf20Sopenharmony_ci * 608c2ecf20Sopenharmony_ci * Free all the memory allocated by drm_atomic_state_init. 618c2ecf20Sopenharmony_ci * This should only be used by drivers which are still subclassing 628c2ecf20Sopenharmony_ci * &drm_atomic_state and haven't switched to &drm_private_state yet. 638c2ecf20Sopenharmony_ci */ 648c2ecf20Sopenharmony_civoid drm_atomic_state_default_release(struct drm_atomic_state *state) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci kfree(state->connectors); 678c2ecf20Sopenharmony_ci kfree(state->crtcs); 688c2ecf20Sopenharmony_ci kfree(state->planes); 698c2ecf20Sopenharmony_ci kfree(state->private_objs); 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_state_default_release); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/** 748c2ecf20Sopenharmony_ci * drm_atomic_state_init - init new atomic state 758c2ecf20Sopenharmony_ci * @dev: DRM device 768c2ecf20Sopenharmony_ci * @state: atomic state 778c2ecf20Sopenharmony_ci * 788c2ecf20Sopenharmony_ci * Default implementation for filling in a new atomic state. 798c2ecf20Sopenharmony_ci * This should only be used by drivers which are still subclassing 808c2ecf20Sopenharmony_ci * &drm_atomic_state and haven't switched to &drm_private_state yet. 818c2ecf20Sopenharmony_ci */ 828c2ecf20Sopenharmony_ciint 838c2ecf20Sopenharmony_cidrm_atomic_state_init(struct drm_device *dev, struct drm_atomic_state *state) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci kref_init(&state->ref); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci /* TODO legacy paths should maybe do a better job about 888c2ecf20Sopenharmony_ci * setting this appropriately? 898c2ecf20Sopenharmony_ci */ 908c2ecf20Sopenharmony_ci state->allow_modeset = true; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci state->crtcs = kcalloc(dev->mode_config.num_crtc, 938c2ecf20Sopenharmony_ci sizeof(*state->crtcs), GFP_KERNEL); 948c2ecf20Sopenharmony_ci if (!state->crtcs) 958c2ecf20Sopenharmony_ci goto fail; 968c2ecf20Sopenharmony_ci state->planes = kcalloc(dev->mode_config.num_total_plane, 978c2ecf20Sopenharmony_ci sizeof(*state->planes), GFP_KERNEL); 988c2ecf20Sopenharmony_ci if (!state->planes) 998c2ecf20Sopenharmony_ci goto fail; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci /* 1028c2ecf20Sopenharmony_ci * Because drm_atomic_state can be committed asynchronously we need our 1038c2ecf20Sopenharmony_ci * own reference and cannot rely on the on implied by drm_file in the 1048c2ecf20Sopenharmony_ci * ioctl call. 1058c2ecf20Sopenharmony_ci */ 1068c2ecf20Sopenharmony_ci drm_dev_get(dev); 1078c2ecf20Sopenharmony_ci state->dev = dev; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci DRM_DEBUG_ATOMIC("Allocated atomic state %p\n", state); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci return 0; 1128c2ecf20Sopenharmony_cifail: 1138c2ecf20Sopenharmony_ci drm_atomic_state_default_release(state); 1148c2ecf20Sopenharmony_ci return -ENOMEM; 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_state_init); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci/** 1198c2ecf20Sopenharmony_ci * drm_atomic_state_alloc - allocate atomic state 1208c2ecf20Sopenharmony_ci * @dev: DRM device 1218c2ecf20Sopenharmony_ci * 1228c2ecf20Sopenharmony_ci * This allocates an empty atomic state to track updates. 1238c2ecf20Sopenharmony_ci */ 1248c2ecf20Sopenharmony_cistruct drm_atomic_state * 1258c2ecf20Sopenharmony_cidrm_atomic_state_alloc(struct drm_device *dev) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci struct drm_mode_config *config = &dev->mode_config; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci if (!config->funcs->atomic_state_alloc) { 1308c2ecf20Sopenharmony_ci struct drm_atomic_state *state; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci state = kzalloc(sizeof(*state), GFP_KERNEL); 1338c2ecf20Sopenharmony_ci if (!state) 1348c2ecf20Sopenharmony_ci return NULL; 1358c2ecf20Sopenharmony_ci if (drm_atomic_state_init(dev, state) < 0) { 1368c2ecf20Sopenharmony_ci kfree(state); 1378c2ecf20Sopenharmony_ci return NULL; 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci return state; 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci return config->funcs->atomic_state_alloc(dev); 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_state_alloc); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci/** 1478c2ecf20Sopenharmony_ci * drm_atomic_state_default_clear - clear base atomic state 1488c2ecf20Sopenharmony_ci * @state: atomic state 1498c2ecf20Sopenharmony_ci * 1508c2ecf20Sopenharmony_ci * Default implementation for clearing atomic state. 1518c2ecf20Sopenharmony_ci * This should only be used by drivers which are still subclassing 1528c2ecf20Sopenharmony_ci * &drm_atomic_state and haven't switched to &drm_private_state yet. 1538c2ecf20Sopenharmony_ci */ 1548c2ecf20Sopenharmony_civoid drm_atomic_state_default_clear(struct drm_atomic_state *state) 1558c2ecf20Sopenharmony_ci{ 1568c2ecf20Sopenharmony_ci struct drm_device *dev = state->dev; 1578c2ecf20Sopenharmony_ci struct drm_mode_config *config = &dev->mode_config; 1588c2ecf20Sopenharmony_ci int i; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci DRM_DEBUG_ATOMIC("Clearing atomic state %p\n", state); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci for (i = 0; i < state->num_connector; i++) { 1638c2ecf20Sopenharmony_ci struct drm_connector *connector = state->connectors[i].ptr; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci if (!connector) 1668c2ecf20Sopenharmony_ci continue; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci connector->funcs->atomic_destroy_state(connector, 1698c2ecf20Sopenharmony_ci state->connectors[i].state); 1708c2ecf20Sopenharmony_ci state->connectors[i].ptr = NULL; 1718c2ecf20Sopenharmony_ci state->connectors[i].state = NULL; 1728c2ecf20Sopenharmony_ci state->connectors[i].old_state = NULL; 1738c2ecf20Sopenharmony_ci state->connectors[i].new_state = NULL; 1748c2ecf20Sopenharmony_ci drm_connector_put(connector); 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci for (i = 0; i < config->num_crtc; i++) { 1788c2ecf20Sopenharmony_ci struct drm_crtc *crtc = state->crtcs[i].ptr; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci if (!crtc) 1818c2ecf20Sopenharmony_ci continue; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci crtc->funcs->atomic_destroy_state(crtc, 1848c2ecf20Sopenharmony_ci state->crtcs[i].state); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci state->crtcs[i].ptr = NULL; 1878c2ecf20Sopenharmony_ci state->crtcs[i].state = NULL; 1888c2ecf20Sopenharmony_ci state->crtcs[i].old_state = NULL; 1898c2ecf20Sopenharmony_ci state->crtcs[i].new_state = NULL; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci if (state->crtcs[i].commit) { 1928c2ecf20Sopenharmony_ci drm_crtc_commit_put(state->crtcs[i].commit); 1938c2ecf20Sopenharmony_ci state->crtcs[i].commit = NULL; 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci } 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci for (i = 0; i < config->num_total_plane; i++) { 1988c2ecf20Sopenharmony_ci struct drm_plane *plane = state->planes[i].ptr; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci if (!plane) 2018c2ecf20Sopenharmony_ci continue; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci plane->funcs->atomic_destroy_state(plane, 2048c2ecf20Sopenharmony_ci state->planes[i].state); 2058c2ecf20Sopenharmony_ci state->planes[i].ptr = NULL; 2068c2ecf20Sopenharmony_ci state->planes[i].state = NULL; 2078c2ecf20Sopenharmony_ci state->planes[i].old_state = NULL; 2088c2ecf20Sopenharmony_ci state->planes[i].new_state = NULL; 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci for (i = 0; i < state->num_private_objs; i++) { 2128c2ecf20Sopenharmony_ci struct drm_private_obj *obj = state->private_objs[i].ptr; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci obj->funcs->atomic_destroy_state(obj, 2158c2ecf20Sopenharmony_ci state->private_objs[i].state); 2168c2ecf20Sopenharmony_ci state->private_objs[i].ptr = NULL; 2178c2ecf20Sopenharmony_ci state->private_objs[i].state = NULL; 2188c2ecf20Sopenharmony_ci state->private_objs[i].old_state = NULL; 2198c2ecf20Sopenharmony_ci state->private_objs[i].new_state = NULL; 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci state->num_private_objs = 0; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci if (state->fake_commit) { 2248c2ecf20Sopenharmony_ci drm_crtc_commit_put(state->fake_commit); 2258c2ecf20Sopenharmony_ci state->fake_commit = NULL; 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_state_default_clear); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci/** 2318c2ecf20Sopenharmony_ci * drm_atomic_state_clear - clear state object 2328c2ecf20Sopenharmony_ci * @state: atomic state 2338c2ecf20Sopenharmony_ci * 2348c2ecf20Sopenharmony_ci * When the w/w mutex algorithm detects a deadlock we need to back off and drop 2358c2ecf20Sopenharmony_ci * all locks. So someone else could sneak in and change the current modeset 2368c2ecf20Sopenharmony_ci * configuration. Which means that all the state assembled in @state is no 2378c2ecf20Sopenharmony_ci * longer an atomic update to the current state, but to some arbitrary earlier 2388c2ecf20Sopenharmony_ci * state. Which could break assumptions the driver's 2398c2ecf20Sopenharmony_ci * &drm_mode_config_funcs.atomic_check likely relies on. 2408c2ecf20Sopenharmony_ci * 2418c2ecf20Sopenharmony_ci * Hence we must clear all cached state and completely start over, using this 2428c2ecf20Sopenharmony_ci * function. 2438c2ecf20Sopenharmony_ci */ 2448c2ecf20Sopenharmony_civoid drm_atomic_state_clear(struct drm_atomic_state *state) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci struct drm_device *dev = state->dev; 2478c2ecf20Sopenharmony_ci struct drm_mode_config *config = &dev->mode_config; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci if (config->funcs->atomic_state_clear) 2508c2ecf20Sopenharmony_ci config->funcs->atomic_state_clear(state); 2518c2ecf20Sopenharmony_ci else 2528c2ecf20Sopenharmony_ci drm_atomic_state_default_clear(state); 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_state_clear); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci/** 2578c2ecf20Sopenharmony_ci * __drm_atomic_state_free - free all memory for an atomic state 2588c2ecf20Sopenharmony_ci * @ref: This atomic state to deallocate 2598c2ecf20Sopenharmony_ci * 2608c2ecf20Sopenharmony_ci * This frees all memory associated with an atomic state, including all the 2618c2ecf20Sopenharmony_ci * per-object state for planes, CRTCs and connectors. 2628c2ecf20Sopenharmony_ci */ 2638c2ecf20Sopenharmony_civoid __drm_atomic_state_free(struct kref *ref) 2648c2ecf20Sopenharmony_ci{ 2658c2ecf20Sopenharmony_ci struct drm_atomic_state *state = container_of(ref, typeof(*state), ref); 2668c2ecf20Sopenharmony_ci struct drm_device *dev = state->dev; 2678c2ecf20Sopenharmony_ci struct drm_mode_config *config = &dev->mode_config; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci drm_atomic_state_clear(state); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci DRM_DEBUG_ATOMIC("Freeing atomic state %p\n", state); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci if (config->funcs->atomic_state_free) { 2748c2ecf20Sopenharmony_ci config->funcs->atomic_state_free(state); 2758c2ecf20Sopenharmony_ci } else { 2768c2ecf20Sopenharmony_ci drm_atomic_state_default_release(state); 2778c2ecf20Sopenharmony_ci kfree(state); 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci drm_dev_put(dev); 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__drm_atomic_state_free); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci/** 2858c2ecf20Sopenharmony_ci * drm_atomic_get_crtc_state - get CRTC state 2868c2ecf20Sopenharmony_ci * @state: global atomic state object 2878c2ecf20Sopenharmony_ci * @crtc: CRTC to get state object for 2888c2ecf20Sopenharmony_ci * 2898c2ecf20Sopenharmony_ci * This function returns the CRTC state for the given CRTC, allocating it if 2908c2ecf20Sopenharmony_ci * needed. It will also grab the relevant CRTC lock to make sure that the state 2918c2ecf20Sopenharmony_ci * is consistent. 2928c2ecf20Sopenharmony_ci * 2938c2ecf20Sopenharmony_ci * Returns: 2948c2ecf20Sopenharmony_ci * 2958c2ecf20Sopenharmony_ci * Either the allocated state or the error code encoded into the pointer. When 2968c2ecf20Sopenharmony_ci * the error is EDEADLK then the w/w mutex code has detected a deadlock and the 2978c2ecf20Sopenharmony_ci * entire atomic sequence must be restarted. All other errors are fatal. 2988c2ecf20Sopenharmony_ci */ 2998c2ecf20Sopenharmony_cistruct drm_crtc_state * 3008c2ecf20Sopenharmony_cidrm_atomic_get_crtc_state(struct drm_atomic_state *state, 3018c2ecf20Sopenharmony_ci struct drm_crtc *crtc) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci int ret, index = drm_crtc_index(crtc); 3048c2ecf20Sopenharmony_ci struct drm_crtc_state *crtc_state; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci WARN_ON(!state->acquire_ctx); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci crtc_state = drm_atomic_get_existing_crtc_state(state, crtc); 3098c2ecf20Sopenharmony_ci if (crtc_state) 3108c2ecf20Sopenharmony_ci return crtc_state; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci ret = drm_modeset_lock(&crtc->mutex, state->acquire_ctx); 3138c2ecf20Sopenharmony_ci if (ret) 3148c2ecf20Sopenharmony_ci return ERR_PTR(ret); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci crtc_state = crtc->funcs->atomic_duplicate_state(crtc); 3178c2ecf20Sopenharmony_ci if (!crtc_state) 3188c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci state->crtcs[index].state = crtc_state; 3218c2ecf20Sopenharmony_ci state->crtcs[index].old_state = crtc->state; 3228c2ecf20Sopenharmony_ci state->crtcs[index].new_state = crtc_state; 3238c2ecf20Sopenharmony_ci state->crtcs[index].ptr = crtc; 3248c2ecf20Sopenharmony_ci crtc_state->state = state; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci DRM_DEBUG_ATOMIC("Added [CRTC:%d:%s] %p state to %p\n", 3278c2ecf20Sopenharmony_ci crtc->base.id, crtc->name, crtc_state, state); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci return crtc_state; 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_get_crtc_state); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cistatic int drm_atomic_crtc_check(const struct drm_crtc_state *old_crtc_state, 3348c2ecf20Sopenharmony_ci const struct drm_crtc_state *new_crtc_state) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci struct drm_crtc *crtc = new_crtc_state->crtc; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci /* NOTE: we explicitly don't enforce constraints such as primary 3398c2ecf20Sopenharmony_ci * layer covering entire screen, since that is something we want 3408c2ecf20Sopenharmony_ci * to allow (on hw that supports it). For hw that does not, it 3418c2ecf20Sopenharmony_ci * should be checked in driver's crtc->atomic_check() vfunc. 3428c2ecf20Sopenharmony_ci * 3438c2ecf20Sopenharmony_ci * TODO: Add generic modeset state checks once we support those. 3448c2ecf20Sopenharmony_ci */ 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci if (new_crtc_state->active && !new_crtc_state->enable) { 3478c2ecf20Sopenharmony_ci DRM_DEBUG_ATOMIC("[CRTC:%d:%s] active without enabled\n", 3488c2ecf20Sopenharmony_ci crtc->base.id, crtc->name); 3498c2ecf20Sopenharmony_ci return -EINVAL; 3508c2ecf20Sopenharmony_ci } 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci /* The state->enable vs. state->mode_blob checks can be WARN_ON, 3538c2ecf20Sopenharmony_ci * as this is a kernel-internal detail that userspace should never 3548c2ecf20Sopenharmony_ci * be able to trigger. */ 3558c2ecf20Sopenharmony_ci if (drm_core_check_feature(crtc->dev, DRIVER_ATOMIC) && 3568c2ecf20Sopenharmony_ci WARN_ON(new_crtc_state->enable && !new_crtc_state->mode_blob)) { 3578c2ecf20Sopenharmony_ci DRM_DEBUG_ATOMIC("[CRTC:%d:%s] enabled without mode blob\n", 3588c2ecf20Sopenharmony_ci crtc->base.id, crtc->name); 3598c2ecf20Sopenharmony_ci return -EINVAL; 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci if (drm_core_check_feature(crtc->dev, DRIVER_ATOMIC) && 3638c2ecf20Sopenharmony_ci WARN_ON(!new_crtc_state->enable && new_crtc_state->mode_blob)) { 3648c2ecf20Sopenharmony_ci DRM_DEBUG_ATOMIC("[CRTC:%d:%s] disabled with mode blob\n", 3658c2ecf20Sopenharmony_ci crtc->base.id, crtc->name); 3668c2ecf20Sopenharmony_ci return -EINVAL; 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci /* 3708c2ecf20Sopenharmony_ci * Reject event generation for when a CRTC is off and stays off. 3718c2ecf20Sopenharmony_ci * It wouldn't be hard to implement this, but userspace has a track 3728c2ecf20Sopenharmony_ci * record of happily burning through 100% cpu (or worse, crash) when the 3738c2ecf20Sopenharmony_ci * display pipe is suspended. To avoid all that fun just reject updates 3748c2ecf20Sopenharmony_ci * that ask for events since likely that indicates a bug in the 3758c2ecf20Sopenharmony_ci * compositor's drawing loop. This is consistent with the vblank IOCTL 3768c2ecf20Sopenharmony_ci * and legacy page_flip IOCTL which also reject service on a disabled 3778c2ecf20Sopenharmony_ci * pipe. 3788c2ecf20Sopenharmony_ci */ 3798c2ecf20Sopenharmony_ci if (new_crtc_state->event && 3808c2ecf20Sopenharmony_ci !new_crtc_state->active && !old_crtc_state->active) { 3818c2ecf20Sopenharmony_ci DRM_DEBUG_ATOMIC("[CRTC:%d:%s] requesting event but off\n", 3828c2ecf20Sopenharmony_ci crtc->base.id, crtc->name); 3838c2ecf20Sopenharmony_ci return -EINVAL; 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci return 0; 3878c2ecf20Sopenharmony_ci} 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_cistatic void drm_atomic_crtc_print_state(struct drm_printer *p, 3908c2ecf20Sopenharmony_ci const struct drm_crtc_state *state) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci struct drm_crtc *crtc = state->crtc; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci drm_printf(p, "crtc[%u]: %s\n", crtc->base.id, crtc->name); 3958c2ecf20Sopenharmony_ci drm_printf(p, "\tenable=%d\n", state->enable); 3968c2ecf20Sopenharmony_ci drm_printf(p, "\tactive=%d\n", state->active); 3978c2ecf20Sopenharmony_ci drm_printf(p, "\tself_refresh_active=%d\n", state->self_refresh_active); 3988c2ecf20Sopenharmony_ci drm_printf(p, "\tplanes_changed=%d\n", state->planes_changed); 3998c2ecf20Sopenharmony_ci drm_printf(p, "\tmode_changed=%d\n", state->mode_changed); 4008c2ecf20Sopenharmony_ci drm_printf(p, "\tactive_changed=%d\n", state->active_changed); 4018c2ecf20Sopenharmony_ci drm_printf(p, "\tconnectors_changed=%d\n", state->connectors_changed); 4028c2ecf20Sopenharmony_ci drm_printf(p, "\tcolor_mgmt_changed=%d\n", state->color_mgmt_changed); 4038c2ecf20Sopenharmony_ci drm_printf(p, "\tplane_mask=%x\n", state->plane_mask); 4048c2ecf20Sopenharmony_ci drm_printf(p, "\tconnector_mask=%x\n", state->connector_mask); 4058c2ecf20Sopenharmony_ci drm_printf(p, "\tencoder_mask=%x\n", state->encoder_mask); 4068c2ecf20Sopenharmony_ci drm_printf(p, "\tmode: " DRM_MODE_FMT "\n", DRM_MODE_ARG(&state->mode)); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci if (crtc->funcs->atomic_print_state) 4098c2ecf20Sopenharmony_ci crtc->funcs->atomic_print_state(p, state); 4108c2ecf20Sopenharmony_ci} 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_cistatic int drm_atomic_connector_check(struct drm_connector *connector, 4138c2ecf20Sopenharmony_ci struct drm_connector_state *state) 4148c2ecf20Sopenharmony_ci{ 4158c2ecf20Sopenharmony_ci struct drm_crtc_state *crtc_state; 4168c2ecf20Sopenharmony_ci struct drm_writeback_job *writeback_job = state->writeback_job; 4178c2ecf20Sopenharmony_ci const struct drm_display_info *info = &connector->display_info; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci state->max_bpc = info->bpc ? info->bpc : 8; 4208c2ecf20Sopenharmony_ci if (connector->max_bpc_property) 4218c2ecf20Sopenharmony_ci state->max_bpc = min(state->max_bpc, state->max_requested_bpc); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci if ((connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) || !writeback_job) 4248c2ecf20Sopenharmony_ci return 0; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci if (writeback_job->fb && !state->crtc) { 4278c2ecf20Sopenharmony_ci DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] framebuffer without CRTC\n", 4288c2ecf20Sopenharmony_ci connector->base.id, connector->name); 4298c2ecf20Sopenharmony_ci return -EINVAL; 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci if (state->crtc) 4338c2ecf20Sopenharmony_ci crtc_state = drm_atomic_get_existing_crtc_state(state->state, 4348c2ecf20Sopenharmony_ci state->crtc); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci if (writeback_job->fb && !crtc_state->active) { 4378c2ecf20Sopenharmony_ci DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] has framebuffer, but [CRTC:%d] is off\n", 4388c2ecf20Sopenharmony_ci connector->base.id, connector->name, 4398c2ecf20Sopenharmony_ci state->crtc->base.id); 4408c2ecf20Sopenharmony_ci return -EINVAL; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci if (!writeback_job->fb) { 4448c2ecf20Sopenharmony_ci if (writeback_job->out_fence) { 4458c2ecf20Sopenharmony_ci DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] requesting out-fence without framebuffer\n", 4468c2ecf20Sopenharmony_ci connector->base.id, connector->name); 4478c2ecf20Sopenharmony_ci return -EINVAL; 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci drm_writeback_cleanup_job(writeback_job); 4518c2ecf20Sopenharmony_ci state->writeback_job = NULL; 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci return 0; 4558c2ecf20Sopenharmony_ci} 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci/** 4588c2ecf20Sopenharmony_ci * drm_atomic_get_plane_state - get plane state 4598c2ecf20Sopenharmony_ci * @state: global atomic state object 4608c2ecf20Sopenharmony_ci * @plane: plane to get state object for 4618c2ecf20Sopenharmony_ci * 4628c2ecf20Sopenharmony_ci * This function returns the plane state for the given plane, allocating it if 4638c2ecf20Sopenharmony_ci * needed. It will also grab the relevant plane lock to make sure that the state 4648c2ecf20Sopenharmony_ci * is consistent. 4658c2ecf20Sopenharmony_ci * 4668c2ecf20Sopenharmony_ci * Returns: 4678c2ecf20Sopenharmony_ci * 4688c2ecf20Sopenharmony_ci * Either the allocated state or the error code encoded into the pointer. When 4698c2ecf20Sopenharmony_ci * the error is EDEADLK then the w/w mutex code has detected a deadlock and the 4708c2ecf20Sopenharmony_ci * entire atomic sequence must be restarted. All other errors are fatal. 4718c2ecf20Sopenharmony_ci */ 4728c2ecf20Sopenharmony_cistruct drm_plane_state * 4738c2ecf20Sopenharmony_cidrm_atomic_get_plane_state(struct drm_atomic_state *state, 4748c2ecf20Sopenharmony_ci struct drm_plane *plane) 4758c2ecf20Sopenharmony_ci{ 4768c2ecf20Sopenharmony_ci int ret, index = drm_plane_index(plane); 4778c2ecf20Sopenharmony_ci struct drm_plane_state *plane_state; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci WARN_ON(!state->acquire_ctx); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci /* the legacy pointers should never be set */ 4828c2ecf20Sopenharmony_ci WARN_ON(plane->fb); 4838c2ecf20Sopenharmony_ci WARN_ON(plane->old_fb); 4848c2ecf20Sopenharmony_ci WARN_ON(plane->crtc); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci plane_state = drm_atomic_get_existing_plane_state(state, plane); 4878c2ecf20Sopenharmony_ci if (plane_state) 4888c2ecf20Sopenharmony_ci return plane_state; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci ret = drm_modeset_lock(&plane->mutex, state->acquire_ctx); 4918c2ecf20Sopenharmony_ci if (ret) 4928c2ecf20Sopenharmony_ci return ERR_PTR(ret); 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci plane_state = plane->funcs->atomic_duplicate_state(plane); 4958c2ecf20Sopenharmony_ci if (!plane_state) 4968c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci state->planes[index].state = plane_state; 4998c2ecf20Sopenharmony_ci state->planes[index].ptr = plane; 5008c2ecf20Sopenharmony_ci state->planes[index].old_state = plane->state; 5018c2ecf20Sopenharmony_ci state->planes[index].new_state = plane_state; 5028c2ecf20Sopenharmony_ci plane_state->state = state; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci DRM_DEBUG_ATOMIC("Added [PLANE:%d:%s] %p state to %p\n", 5058c2ecf20Sopenharmony_ci plane->base.id, plane->name, plane_state, state); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci if (plane_state->crtc) { 5088c2ecf20Sopenharmony_ci struct drm_crtc_state *crtc_state; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci crtc_state = drm_atomic_get_crtc_state(state, 5118c2ecf20Sopenharmony_ci plane_state->crtc); 5128c2ecf20Sopenharmony_ci if (IS_ERR(crtc_state)) 5138c2ecf20Sopenharmony_ci return ERR_CAST(crtc_state); 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci return plane_state; 5178c2ecf20Sopenharmony_ci} 5188c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_get_plane_state); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_cistatic bool 5218c2ecf20Sopenharmony_ciplane_switching_crtc(const struct drm_plane_state *old_plane_state, 5228c2ecf20Sopenharmony_ci const struct drm_plane_state *new_plane_state) 5238c2ecf20Sopenharmony_ci{ 5248c2ecf20Sopenharmony_ci if (!old_plane_state->crtc || !new_plane_state->crtc) 5258c2ecf20Sopenharmony_ci return false; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci if (old_plane_state->crtc == new_plane_state->crtc) 5288c2ecf20Sopenharmony_ci return false; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci /* This could be refined, but currently there's no helper or driver code 5318c2ecf20Sopenharmony_ci * to implement direct switching of active planes nor userspace to take 5328c2ecf20Sopenharmony_ci * advantage of more direct plane switching without the intermediate 5338c2ecf20Sopenharmony_ci * full OFF state. 5348c2ecf20Sopenharmony_ci */ 5358c2ecf20Sopenharmony_ci return true; 5368c2ecf20Sopenharmony_ci} 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci/** 5398c2ecf20Sopenharmony_ci * drm_atomic_plane_check - check plane state 5408c2ecf20Sopenharmony_ci * @old_plane_state: old plane state to check 5418c2ecf20Sopenharmony_ci * @new_plane_state: new plane state to check 5428c2ecf20Sopenharmony_ci * 5438c2ecf20Sopenharmony_ci * Provides core sanity checks for plane state. 5448c2ecf20Sopenharmony_ci * 5458c2ecf20Sopenharmony_ci * RETURNS: 5468c2ecf20Sopenharmony_ci * Zero on success, error code on failure 5478c2ecf20Sopenharmony_ci */ 5488c2ecf20Sopenharmony_cistatic int drm_atomic_plane_check(const struct drm_plane_state *old_plane_state, 5498c2ecf20Sopenharmony_ci const struct drm_plane_state *new_plane_state) 5508c2ecf20Sopenharmony_ci{ 5518c2ecf20Sopenharmony_ci struct drm_plane *plane = new_plane_state->plane; 5528c2ecf20Sopenharmony_ci struct drm_crtc *crtc = new_plane_state->crtc; 5538c2ecf20Sopenharmony_ci const struct drm_framebuffer *fb = new_plane_state->fb; 5548c2ecf20Sopenharmony_ci unsigned int fb_width, fb_height; 5558c2ecf20Sopenharmony_ci struct drm_mode_rect *clips; 5568c2ecf20Sopenharmony_ci uint32_t num_clips; 5578c2ecf20Sopenharmony_ci int ret; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci /* either *both* CRTC and FB must be set, or neither */ 5608c2ecf20Sopenharmony_ci if (crtc && !fb) { 5618c2ecf20Sopenharmony_ci DRM_DEBUG_ATOMIC("[PLANE:%d:%s] CRTC set but no FB\n", 5628c2ecf20Sopenharmony_ci plane->base.id, plane->name); 5638c2ecf20Sopenharmony_ci return -EINVAL; 5648c2ecf20Sopenharmony_ci } else if (fb && !crtc) { 5658c2ecf20Sopenharmony_ci DRM_DEBUG_ATOMIC("[PLANE:%d:%s] FB set but no CRTC\n", 5668c2ecf20Sopenharmony_ci plane->base.id, plane->name); 5678c2ecf20Sopenharmony_ci return -EINVAL; 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci /* if disabled, we don't care about the rest of the state: */ 5718c2ecf20Sopenharmony_ci if (!crtc) 5728c2ecf20Sopenharmony_ci return 0; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci /* Check whether this plane is usable on this CRTC */ 5758c2ecf20Sopenharmony_ci if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) { 5768c2ecf20Sopenharmony_ci DRM_DEBUG_ATOMIC("Invalid [CRTC:%d:%s] for [PLANE:%d:%s]\n", 5778c2ecf20Sopenharmony_ci crtc->base.id, crtc->name, 5788c2ecf20Sopenharmony_ci plane->base.id, plane->name); 5798c2ecf20Sopenharmony_ci return -EINVAL; 5808c2ecf20Sopenharmony_ci } 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci /* Check whether this plane supports the fb pixel format. */ 5838c2ecf20Sopenharmony_ci ret = drm_plane_check_pixel_format(plane, fb->format->format, 5848c2ecf20Sopenharmony_ci fb->modifier); 5858c2ecf20Sopenharmony_ci if (ret) { 5868c2ecf20Sopenharmony_ci struct drm_format_name_buf format_name; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci DRM_DEBUG_ATOMIC("[PLANE:%d:%s] invalid pixel format %s, modifier 0x%llx\n", 5898c2ecf20Sopenharmony_ci plane->base.id, plane->name, 5908c2ecf20Sopenharmony_ci drm_get_format_name(fb->format->format, 5918c2ecf20Sopenharmony_ci &format_name), 5928c2ecf20Sopenharmony_ci fb->modifier); 5938c2ecf20Sopenharmony_ci return ret; 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci /* Give drivers some help against integer overflows */ 5978c2ecf20Sopenharmony_ci if (new_plane_state->crtc_w > INT_MAX || 5988c2ecf20Sopenharmony_ci new_plane_state->crtc_x > INT_MAX - (int32_t) new_plane_state->crtc_w || 5998c2ecf20Sopenharmony_ci new_plane_state->crtc_h > INT_MAX || 6008c2ecf20Sopenharmony_ci new_plane_state->crtc_y > INT_MAX - (int32_t) new_plane_state->crtc_h) { 6018c2ecf20Sopenharmony_ci DRM_DEBUG_ATOMIC("[PLANE:%d:%s] invalid CRTC coordinates %ux%u+%d+%d\n", 6028c2ecf20Sopenharmony_ci plane->base.id, plane->name, 6038c2ecf20Sopenharmony_ci new_plane_state->crtc_w, new_plane_state->crtc_h, 6048c2ecf20Sopenharmony_ci new_plane_state->crtc_x, new_plane_state->crtc_y); 6058c2ecf20Sopenharmony_ci return -ERANGE; 6068c2ecf20Sopenharmony_ci } 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci fb_width = fb->width << 16; 6098c2ecf20Sopenharmony_ci fb_height = fb->height << 16; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci /* Make sure source coordinates are inside the fb. */ 6128c2ecf20Sopenharmony_ci if (new_plane_state->src_w > fb_width || 6138c2ecf20Sopenharmony_ci new_plane_state->src_x > fb_width - new_plane_state->src_w || 6148c2ecf20Sopenharmony_ci new_plane_state->src_h > fb_height || 6158c2ecf20Sopenharmony_ci new_plane_state->src_y > fb_height - new_plane_state->src_h) { 6168c2ecf20Sopenharmony_ci DRM_DEBUG_ATOMIC("[PLANE:%d:%s] invalid source coordinates " 6178c2ecf20Sopenharmony_ci "%u.%06ux%u.%06u+%u.%06u+%u.%06u (fb %ux%u)\n", 6188c2ecf20Sopenharmony_ci plane->base.id, plane->name, 6198c2ecf20Sopenharmony_ci new_plane_state->src_w >> 16, 6208c2ecf20Sopenharmony_ci ((new_plane_state->src_w & 0xffff) * 15625) >> 10, 6218c2ecf20Sopenharmony_ci new_plane_state->src_h >> 16, 6228c2ecf20Sopenharmony_ci ((new_plane_state->src_h & 0xffff) * 15625) >> 10, 6238c2ecf20Sopenharmony_ci new_plane_state->src_x >> 16, 6248c2ecf20Sopenharmony_ci ((new_plane_state->src_x & 0xffff) * 15625) >> 10, 6258c2ecf20Sopenharmony_ci new_plane_state->src_y >> 16, 6268c2ecf20Sopenharmony_ci ((new_plane_state->src_y & 0xffff) * 15625) >> 10, 6278c2ecf20Sopenharmony_ci fb->width, fb->height); 6288c2ecf20Sopenharmony_ci return -ENOSPC; 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci clips = drm_plane_get_damage_clips(new_plane_state); 6328c2ecf20Sopenharmony_ci num_clips = drm_plane_get_damage_clips_count(new_plane_state); 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci /* Make sure damage clips are valid and inside the fb. */ 6358c2ecf20Sopenharmony_ci while (num_clips > 0) { 6368c2ecf20Sopenharmony_ci if (clips->x1 >= clips->x2 || 6378c2ecf20Sopenharmony_ci clips->y1 >= clips->y2 || 6388c2ecf20Sopenharmony_ci clips->x1 < 0 || 6398c2ecf20Sopenharmony_ci clips->y1 < 0 || 6408c2ecf20Sopenharmony_ci clips->x2 > fb_width || 6418c2ecf20Sopenharmony_ci clips->y2 > fb_height) { 6428c2ecf20Sopenharmony_ci DRM_DEBUG_ATOMIC("[PLANE:%d:%s] invalid damage clip %d %d %d %d\n", 6438c2ecf20Sopenharmony_ci plane->base.id, plane->name, clips->x1, 6448c2ecf20Sopenharmony_ci clips->y1, clips->x2, clips->y2); 6458c2ecf20Sopenharmony_ci return -EINVAL; 6468c2ecf20Sopenharmony_ci } 6478c2ecf20Sopenharmony_ci clips++; 6488c2ecf20Sopenharmony_ci num_clips--; 6498c2ecf20Sopenharmony_ci } 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci if (plane_switching_crtc(old_plane_state, new_plane_state)) { 6528c2ecf20Sopenharmony_ci DRM_DEBUG_ATOMIC("[PLANE:%d:%s] switching CRTC directly\n", 6538c2ecf20Sopenharmony_ci plane->base.id, plane->name); 6548c2ecf20Sopenharmony_ci return -EINVAL; 6558c2ecf20Sopenharmony_ci } 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci return 0; 6588c2ecf20Sopenharmony_ci} 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_cistatic void drm_atomic_plane_print_state(struct drm_printer *p, 6618c2ecf20Sopenharmony_ci const struct drm_plane_state *state) 6628c2ecf20Sopenharmony_ci{ 6638c2ecf20Sopenharmony_ci struct drm_plane *plane = state->plane; 6648c2ecf20Sopenharmony_ci struct drm_rect src = drm_plane_state_src(state); 6658c2ecf20Sopenharmony_ci struct drm_rect dest = drm_plane_state_dest(state); 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci drm_printf(p, "plane[%u]: %s\n", plane->base.id, plane->name); 6688c2ecf20Sopenharmony_ci drm_printf(p, "\tcrtc=%s\n", state->crtc ? state->crtc->name : "(null)"); 6698c2ecf20Sopenharmony_ci drm_printf(p, "\tfb=%u\n", state->fb ? state->fb->base.id : 0); 6708c2ecf20Sopenharmony_ci if (state->fb) 6718c2ecf20Sopenharmony_ci drm_framebuffer_print_info(p, 2, state->fb); 6728c2ecf20Sopenharmony_ci drm_printf(p, "\tcrtc-pos=" DRM_RECT_FMT "\n", DRM_RECT_ARG(&dest)); 6738c2ecf20Sopenharmony_ci drm_printf(p, "\tsrc-pos=" DRM_RECT_FP_FMT "\n", DRM_RECT_FP_ARG(&src)); 6748c2ecf20Sopenharmony_ci drm_printf(p, "\trotation=%x\n", state->rotation); 6758c2ecf20Sopenharmony_ci drm_printf(p, "\tnormalized-zpos=%x\n", state->normalized_zpos); 6768c2ecf20Sopenharmony_ci drm_printf(p, "\tcolor-encoding=%s\n", 6778c2ecf20Sopenharmony_ci drm_get_color_encoding_name(state->color_encoding)); 6788c2ecf20Sopenharmony_ci drm_printf(p, "\tcolor-range=%s\n", 6798c2ecf20Sopenharmony_ci drm_get_color_range_name(state->color_range)); 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci if (plane->funcs->atomic_print_state) 6828c2ecf20Sopenharmony_ci plane->funcs->atomic_print_state(p, state); 6838c2ecf20Sopenharmony_ci} 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci/** 6868c2ecf20Sopenharmony_ci * DOC: handling driver private state 6878c2ecf20Sopenharmony_ci * 6888c2ecf20Sopenharmony_ci * Very often the DRM objects exposed to userspace in the atomic modeset api 6898c2ecf20Sopenharmony_ci * (&drm_connector, &drm_crtc and &drm_plane) do not map neatly to the 6908c2ecf20Sopenharmony_ci * underlying hardware. Especially for any kind of shared resources (e.g. shared 6918c2ecf20Sopenharmony_ci * clocks, scaler units, bandwidth and fifo limits shared among a group of 6928c2ecf20Sopenharmony_ci * planes or CRTCs, and so on) it makes sense to model these as independent 6938c2ecf20Sopenharmony_ci * objects. Drivers then need to do similar state tracking and commit ordering for 6948c2ecf20Sopenharmony_ci * such private (since not exposed to userpace) objects as the atomic core and 6958c2ecf20Sopenharmony_ci * helpers already provide for connectors, planes and CRTCs. 6968c2ecf20Sopenharmony_ci * 6978c2ecf20Sopenharmony_ci * To make this easier on drivers the atomic core provides some support to track 6988c2ecf20Sopenharmony_ci * driver private state objects using struct &drm_private_obj, with the 6998c2ecf20Sopenharmony_ci * associated state struct &drm_private_state. 7008c2ecf20Sopenharmony_ci * 7018c2ecf20Sopenharmony_ci * Similar to userspace-exposed objects, private state structures can be 7028c2ecf20Sopenharmony_ci * acquired by calling drm_atomic_get_private_obj_state(). This also takes care 7038c2ecf20Sopenharmony_ci * of locking, hence drivers should not have a need to call drm_modeset_lock() 7048c2ecf20Sopenharmony_ci * directly. Sequence of the actual hardware state commit is not handled, 7058c2ecf20Sopenharmony_ci * drivers might need to keep track of struct drm_crtc_commit within subclassed 7068c2ecf20Sopenharmony_ci * structure of &drm_private_state as necessary, e.g. similar to 7078c2ecf20Sopenharmony_ci * &drm_plane_state.commit. See also &drm_atomic_state.fake_commit. 7088c2ecf20Sopenharmony_ci * 7098c2ecf20Sopenharmony_ci * All private state structures contained in a &drm_atomic_state update can be 7108c2ecf20Sopenharmony_ci * iterated using for_each_oldnew_private_obj_in_state(), 7118c2ecf20Sopenharmony_ci * for_each_new_private_obj_in_state() and for_each_old_private_obj_in_state(). 7128c2ecf20Sopenharmony_ci * Drivers are recommended to wrap these for each type of driver private state 7138c2ecf20Sopenharmony_ci * object they have, filtering on &drm_private_obj.funcs using for_each_if(), at 7148c2ecf20Sopenharmony_ci * least if they want to iterate over all objects of a given type. 7158c2ecf20Sopenharmony_ci * 7168c2ecf20Sopenharmony_ci * An earlier way to handle driver private state was by subclassing struct 7178c2ecf20Sopenharmony_ci * &drm_atomic_state. But since that encourages non-standard ways to implement 7188c2ecf20Sopenharmony_ci * the check/commit split atomic requires (by using e.g. "check and rollback or 7198c2ecf20Sopenharmony_ci * commit instead" of "duplicate state, check, then either commit or release 7208c2ecf20Sopenharmony_ci * duplicated state) it is deprecated in favour of using &drm_private_state. 7218c2ecf20Sopenharmony_ci */ 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci/** 7248c2ecf20Sopenharmony_ci * drm_atomic_private_obj_init - initialize private object 7258c2ecf20Sopenharmony_ci * @dev: DRM device this object will be attached to 7268c2ecf20Sopenharmony_ci * @obj: private object 7278c2ecf20Sopenharmony_ci * @state: initial private object state 7288c2ecf20Sopenharmony_ci * @funcs: pointer to the struct of function pointers that identify the object 7298c2ecf20Sopenharmony_ci * type 7308c2ecf20Sopenharmony_ci * 7318c2ecf20Sopenharmony_ci * Initialize the private object, which can be embedded into any 7328c2ecf20Sopenharmony_ci * driver private object that needs its own atomic state. 7338c2ecf20Sopenharmony_ci */ 7348c2ecf20Sopenharmony_civoid 7358c2ecf20Sopenharmony_cidrm_atomic_private_obj_init(struct drm_device *dev, 7368c2ecf20Sopenharmony_ci struct drm_private_obj *obj, 7378c2ecf20Sopenharmony_ci struct drm_private_state *state, 7388c2ecf20Sopenharmony_ci const struct drm_private_state_funcs *funcs) 7398c2ecf20Sopenharmony_ci{ 7408c2ecf20Sopenharmony_ci memset(obj, 0, sizeof(*obj)); 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci drm_modeset_lock_init(&obj->lock); 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci obj->state = state; 7458c2ecf20Sopenharmony_ci obj->funcs = funcs; 7468c2ecf20Sopenharmony_ci list_add_tail(&obj->head, &dev->mode_config.privobj_list); 7478c2ecf20Sopenharmony_ci} 7488c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_private_obj_init); 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci/** 7518c2ecf20Sopenharmony_ci * drm_atomic_private_obj_fini - finalize private object 7528c2ecf20Sopenharmony_ci * @obj: private object 7538c2ecf20Sopenharmony_ci * 7548c2ecf20Sopenharmony_ci * Finalize the private object. 7558c2ecf20Sopenharmony_ci */ 7568c2ecf20Sopenharmony_civoid 7578c2ecf20Sopenharmony_cidrm_atomic_private_obj_fini(struct drm_private_obj *obj) 7588c2ecf20Sopenharmony_ci{ 7598c2ecf20Sopenharmony_ci list_del(&obj->head); 7608c2ecf20Sopenharmony_ci obj->funcs->atomic_destroy_state(obj, obj->state); 7618c2ecf20Sopenharmony_ci drm_modeset_lock_fini(&obj->lock); 7628c2ecf20Sopenharmony_ci} 7638c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_private_obj_fini); 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci/** 7668c2ecf20Sopenharmony_ci * drm_atomic_get_private_obj_state - get private object state 7678c2ecf20Sopenharmony_ci * @state: global atomic state 7688c2ecf20Sopenharmony_ci * @obj: private object to get the state for 7698c2ecf20Sopenharmony_ci * 7708c2ecf20Sopenharmony_ci * This function returns the private object state for the given private object, 7718c2ecf20Sopenharmony_ci * allocating the state if needed. It will also grab the relevant private 7728c2ecf20Sopenharmony_ci * object lock to make sure that the state is consistent. 7738c2ecf20Sopenharmony_ci * 7748c2ecf20Sopenharmony_ci * RETURNS: 7758c2ecf20Sopenharmony_ci * 7768c2ecf20Sopenharmony_ci * Either the allocated state or the error code encoded into a pointer. 7778c2ecf20Sopenharmony_ci */ 7788c2ecf20Sopenharmony_cistruct drm_private_state * 7798c2ecf20Sopenharmony_cidrm_atomic_get_private_obj_state(struct drm_atomic_state *state, 7808c2ecf20Sopenharmony_ci struct drm_private_obj *obj) 7818c2ecf20Sopenharmony_ci{ 7828c2ecf20Sopenharmony_ci int index, num_objs, i, ret; 7838c2ecf20Sopenharmony_ci size_t size; 7848c2ecf20Sopenharmony_ci struct __drm_private_objs_state *arr; 7858c2ecf20Sopenharmony_ci struct drm_private_state *obj_state; 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci for (i = 0; i < state->num_private_objs; i++) 7888c2ecf20Sopenharmony_ci if (obj == state->private_objs[i].ptr) 7898c2ecf20Sopenharmony_ci return state->private_objs[i].state; 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci ret = drm_modeset_lock(&obj->lock, state->acquire_ctx); 7928c2ecf20Sopenharmony_ci if (ret) 7938c2ecf20Sopenharmony_ci return ERR_PTR(ret); 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci num_objs = state->num_private_objs + 1; 7968c2ecf20Sopenharmony_ci size = sizeof(*state->private_objs) * num_objs; 7978c2ecf20Sopenharmony_ci arr = krealloc(state->private_objs, size, GFP_KERNEL); 7988c2ecf20Sopenharmony_ci if (!arr) 7998c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci state->private_objs = arr; 8028c2ecf20Sopenharmony_ci index = state->num_private_objs; 8038c2ecf20Sopenharmony_ci memset(&state->private_objs[index], 0, sizeof(*state->private_objs)); 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci obj_state = obj->funcs->atomic_duplicate_state(obj); 8068c2ecf20Sopenharmony_ci if (!obj_state) 8078c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci state->private_objs[index].state = obj_state; 8108c2ecf20Sopenharmony_ci state->private_objs[index].old_state = obj->state; 8118c2ecf20Sopenharmony_ci state->private_objs[index].new_state = obj_state; 8128c2ecf20Sopenharmony_ci state->private_objs[index].ptr = obj; 8138c2ecf20Sopenharmony_ci obj_state->state = state; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci state->num_private_objs = num_objs; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci DRM_DEBUG_ATOMIC("Added new private object %p state %p to %p\n", 8188c2ecf20Sopenharmony_ci obj, obj_state, state); 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci return obj_state; 8218c2ecf20Sopenharmony_ci} 8228c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_get_private_obj_state); 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci/** 8258c2ecf20Sopenharmony_ci * drm_atomic_get_old_private_obj_state 8268c2ecf20Sopenharmony_ci * @state: global atomic state object 8278c2ecf20Sopenharmony_ci * @obj: private_obj to grab 8288c2ecf20Sopenharmony_ci * 8298c2ecf20Sopenharmony_ci * This function returns the old private object state for the given private_obj, 8308c2ecf20Sopenharmony_ci * or NULL if the private_obj is not part of the global atomic state. 8318c2ecf20Sopenharmony_ci */ 8328c2ecf20Sopenharmony_cistruct drm_private_state * 8338c2ecf20Sopenharmony_cidrm_atomic_get_old_private_obj_state(struct drm_atomic_state *state, 8348c2ecf20Sopenharmony_ci struct drm_private_obj *obj) 8358c2ecf20Sopenharmony_ci{ 8368c2ecf20Sopenharmony_ci int i; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci for (i = 0; i < state->num_private_objs; i++) 8398c2ecf20Sopenharmony_ci if (obj == state->private_objs[i].ptr) 8408c2ecf20Sopenharmony_ci return state->private_objs[i].old_state; 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci return NULL; 8438c2ecf20Sopenharmony_ci} 8448c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_get_old_private_obj_state); 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci/** 8478c2ecf20Sopenharmony_ci * drm_atomic_get_new_private_obj_state 8488c2ecf20Sopenharmony_ci * @state: global atomic state object 8498c2ecf20Sopenharmony_ci * @obj: private_obj to grab 8508c2ecf20Sopenharmony_ci * 8518c2ecf20Sopenharmony_ci * This function returns the new private object state for the given private_obj, 8528c2ecf20Sopenharmony_ci * or NULL if the private_obj is not part of the global atomic state. 8538c2ecf20Sopenharmony_ci */ 8548c2ecf20Sopenharmony_cistruct drm_private_state * 8558c2ecf20Sopenharmony_cidrm_atomic_get_new_private_obj_state(struct drm_atomic_state *state, 8568c2ecf20Sopenharmony_ci struct drm_private_obj *obj) 8578c2ecf20Sopenharmony_ci{ 8588c2ecf20Sopenharmony_ci int i; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci for (i = 0; i < state->num_private_objs; i++) 8618c2ecf20Sopenharmony_ci if (obj == state->private_objs[i].ptr) 8628c2ecf20Sopenharmony_ci return state->private_objs[i].new_state; 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci return NULL; 8658c2ecf20Sopenharmony_ci} 8668c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_get_new_private_obj_state); 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci/** 8698c2ecf20Sopenharmony_ci * drm_atomic_get_old_connector_for_encoder - Get old connector for an encoder 8708c2ecf20Sopenharmony_ci * @state: Atomic state 8718c2ecf20Sopenharmony_ci * @encoder: The encoder to fetch the connector state for 8728c2ecf20Sopenharmony_ci * 8738c2ecf20Sopenharmony_ci * This function finds and returns the connector that was connected to @encoder 8748c2ecf20Sopenharmony_ci * as specified by the @state. 8758c2ecf20Sopenharmony_ci * 8768c2ecf20Sopenharmony_ci * If there is no connector in @state which previously had @encoder connected to 8778c2ecf20Sopenharmony_ci * it, this function will return NULL. While this may seem like an invalid use 8788c2ecf20Sopenharmony_ci * case, it is sometimes useful to differentiate commits which had no prior 8798c2ecf20Sopenharmony_ci * connectors attached to @encoder vs ones that did (and to inspect their 8808c2ecf20Sopenharmony_ci * state). This is especially true in enable hooks because the pipeline has 8818c2ecf20Sopenharmony_ci * changed. 8828c2ecf20Sopenharmony_ci * 8838c2ecf20Sopenharmony_ci * Returns: The old connector connected to @encoder, or NULL if the encoder is 8848c2ecf20Sopenharmony_ci * not connected. 8858c2ecf20Sopenharmony_ci */ 8868c2ecf20Sopenharmony_cistruct drm_connector * 8878c2ecf20Sopenharmony_cidrm_atomic_get_old_connector_for_encoder(struct drm_atomic_state *state, 8888c2ecf20Sopenharmony_ci struct drm_encoder *encoder) 8898c2ecf20Sopenharmony_ci{ 8908c2ecf20Sopenharmony_ci struct drm_connector_state *conn_state; 8918c2ecf20Sopenharmony_ci struct drm_connector *connector; 8928c2ecf20Sopenharmony_ci unsigned int i; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci for_each_old_connector_in_state(state, connector, conn_state, i) { 8958c2ecf20Sopenharmony_ci if (conn_state->best_encoder == encoder) 8968c2ecf20Sopenharmony_ci return connector; 8978c2ecf20Sopenharmony_ci } 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci return NULL; 9008c2ecf20Sopenharmony_ci} 9018c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_get_old_connector_for_encoder); 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci/** 9048c2ecf20Sopenharmony_ci * drm_atomic_get_new_connector_for_encoder - Get new connector for an encoder 9058c2ecf20Sopenharmony_ci * @state: Atomic state 9068c2ecf20Sopenharmony_ci * @encoder: The encoder to fetch the connector state for 9078c2ecf20Sopenharmony_ci * 9088c2ecf20Sopenharmony_ci * This function finds and returns the connector that will be connected to 9098c2ecf20Sopenharmony_ci * @encoder as specified by the @state. 9108c2ecf20Sopenharmony_ci * 9118c2ecf20Sopenharmony_ci * If there is no connector in @state which will have @encoder connected to it, 9128c2ecf20Sopenharmony_ci * this function will return NULL. While this may seem like an invalid use case, 9138c2ecf20Sopenharmony_ci * it is sometimes useful to differentiate commits which have no connectors 9148c2ecf20Sopenharmony_ci * attached to @encoder vs ones that do (and to inspect their state). This is 9158c2ecf20Sopenharmony_ci * especially true in disable hooks because the pipeline will change. 9168c2ecf20Sopenharmony_ci * 9178c2ecf20Sopenharmony_ci * Returns: The new connector connected to @encoder, or NULL if the encoder is 9188c2ecf20Sopenharmony_ci * not connected. 9198c2ecf20Sopenharmony_ci */ 9208c2ecf20Sopenharmony_cistruct drm_connector * 9218c2ecf20Sopenharmony_cidrm_atomic_get_new_connector_for_encoder(struct drm_atomic_state *state, 9228c2ecf20Sopenharmony_ci struct drm_encoder *encoder) 9238c2ecf20Sopenharmony_ci{ 9248c2ecf20Sopenharmony_ci struct drm_connector_state *conn_state; 9258c2ecf20Sopenharmony_ci struct drm_connector *connector; 9268c2ecf20Sopenharmony_ci unsigned int i; 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci for_each_new_connector_in_state(state, connector, conn_state, i) { 9298c2ecf20Sopenharmony_ci if (conn_state->best_encoder == encoder) 9308c2ecf20Sopenharmony_ci return connector; 9318c2ecf20Sopenharmony_ci } 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci return NULL; 9348c2ecf20Sopenharmony_ci} 9358c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder); 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci/** 9388c2ecf20Sopenharmony_ci * drm_atomic_get_connector_state - get connector state 9398c2ecf20Sopenharmony_ci * @state: global atomic state object 9408c2ecf20Sopenharmony_ci * @connector: connector to get state object for 9418c2ecf20Sopenharmony_ci * 9428c2ecf20Sopenharmony_ci * This function returns the connector state for the given connector, 9438c2ecf20Sopenharmony_ci * allocating it if needed. It will also grab the relevant connector lock to 9448c2ecf20Sopenharmony_ci * make sure that the state is consistent. 9458c2ecf20Sopenharmony_ci * 9468c2ecf20Sopenharmony_ci * Returns: 9478c2ecf20Sopenharmony_ci * 9488c2ecf20Sopenharmony_ci * Either the allocated state or the error code encoded into the pointer. When 9498c2ecf20Sopenharmony_ci * the error is EDEADLK then the w/w mutex code has detected a deadlock and the 9508c2ecf20Sopenharmony_ci * entire atomic sequence must be restarted. All other errors are fatal. 9518c2ecf20Sopenharmony_ci */ 9528c2ecf20Sopenharmony_cistruct drm_connector_state * 9538c2ecf20Sopenharmony_cidrm_atomic_get_connector_state(struct drm_atomic_state *state, 9548c2ecf20Sopenharmony_ci struct drm_connector *connector) 9558c2ecf20Sopenharmony_ci{ 9568c2ecf20Sopenharmony_ci int ret, index; 9578c2ecf20Sopenharmony_ci struct drm_mode_config *config = &connector->dev->mode_config; 9588c2ecf20Sopenharmony_ci struct drm_connector_state *connector_state; 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci WARN_ON(!state->acquire_ctx); 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci ret = drm_modeset_lock(&config->connection_mutex, state->acquire_ctx); 9638c2ecf20Sopenharmony_ci if (ret) 9648c2ecf20Sopenharmony_ci return ERR_PTR(ret); 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci index = drm_connector_index(connector); 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci if (index >= state->num_connector) { 9698c2ecf20Sopenharmony_ci struct __drm_connnectors_state *c; 9708c2ecf20Sopenharmony_ci int alloc = max(index + 1, config->num_connector); 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci c = krealloc(state->connectors, alloc * sizeof(*state->connectors), GFP_KERNEL); 9738c2ecf20Sopenharmony_ci if (!c) 9748c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci state->connectors = c; 9778c2ecf20Sopenharmony_ci memset(&state->connectors[state->num_connector], 0, 9788c2ecf20Sopenharmony_ci sizeof(*state->connectors) * (alloc - state->num_connector)); 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci state->num_connector = alloc; 9818c2ecf20Sopenharmony_ci } 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci if (state->connectors[index].state) 9848c2ecf20Sopenharmony_ci return state->connectors[index].state; 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci connector_state = connector->funcs->atomic_duplicate_state(connector); 9878c2ecf20Sopenharmony_ci if (!connector_state) 9888c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci drm_connector_get(connector); 9918c2ecf20Sopenharmony_ci state->connectors[index].state = connector_state; 9928c2ecf20Sopenharmony_ci state->connectors[index].old_state = connector->state; 9938c2ecf20Sopenharmony_ci state->connectors[index].new_state = connector_state; 9948c2ecf20Sopenharmony_ci state->connectors[index].ptr = connector; 9958c2ecf20Sopenharmony_ci connector_state->state = state; 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci DRM_DEBUG_ATOMIC("Added [CONNECTOR:%d:%s] %p state to %p\n", 9988c2ecf20Sopenharmony_ci connector->base.id, connector->name, 9998c2ecf20Sopenharmony_ci connector_state, state); 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci if (connector_state->crtc) { 10028c2ecf20Sopenharmony_ci struct drm_crtc_state *crtc_state; 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci crtc_state = drm_atomic_get_crtc_state(state, 10058c2ecf20Sopenharmony_ci connector_state->crtc); 10068c2ecf20Sopenharmony_ci if (IS_ERR(crtc_state)) 10078c2ecf20Sopenharmony_ci return ERR_CAST(crtc_state); 10088c2ecf20Sopenharmony_ci } 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci return connector_state; 10118c2ecf20Sopenharmony_ci} 10128c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_get_connector_state); 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_cistatic void drm_atomic_connector_print_state(struct drm_printer *p, 10158c2ecf20Sopenharmony_ci const struct drm_connector_state *state) 10168c2ecf20Sopenharmony_ci{ 10178c2ecf20Sopenharmony_ci struct drm_connector *connector = state->connector; 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci drm_printf(p, "connector[%u]: %s\n", connector->base.id, connector->name); 10208c2ecf20Sopenharmony_ci drm_printf(p, "\tcrtc=%s\n", state->crtc ? state->crtc->name : "(null)"); 10218c2ecf20Sopenharmony_ci drm_printf(p, "\tself_refresh_aware=%d\n", state->self_refresh_aware); 10228c2ecf20Sopenharmony_ci drm_printf(p, "\tmax_requested_bpc=%d\n", state->max_requested_bpc); 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) 10258c2ecf20Sopenharmony_ci if (state->writeback_job && state->writeback_job->fb) 10268c2ecf20Sopenharmony_ci drm_printf(p, "\tfb=%d\n", state->writeback_job->fb->base.id); 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci if (connector->funcs->atomic_print_state) 10298c2ecf20Sopenharmony_ci connector->funcs->atomic_print_state(p, state); 10308c2ecf20Sopenharmony_ci} 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci/** 10338c2ecf20Sopenharmony_ci * drm_atomic_get_bridge_state - get bridge state 10348c2ecf20Sopenharmony_ci * @state: global atomic state object 10358c2ecf20Sopenharmony_ci * @bridge: bridge to get state object for 10368c2ecf20Sopenharmony_ci * 10378c2ecf20Sopenharmony_ci * This function returns the bridge state for the given bridge, allocating it 10388c2ecf20Sopenharmony_ci * if needed. It will also grab the relevant bridge lock to make sure that the 10398c2ecf20Sopenharmony_ci * state is consistent. 10408c2ecf20Sopenharmony_ci * 10418c2ecf20Sopenharmony_ci * Returns: 10428c2ecf20Sopenharmony_ci * 10438c2ecf20Sopenharmony_ci * Either the allocated state or the error code encoded into the pointer. When 10448c2ecf20Sopenharmony_ci * the error is EDEADLK then the w/w mutex code has detected a deadlock and the 10458c2ecf20Sopenharmony_ci * entire atomic sequence must be restarted. 10468c2ecf20Sopenharmony_ci */ 10478c2ecf20Sopenharmony_cistruct drm_bridge_state * 10488c2ecf20Sopenharmony_cidrm_atomic_get_bridge_state(struct drm_atomic_state *state, 10498c2ecf20Sopenharmony_ci struct drm_bridge *bridge) 10508c2ecf20Sopenharmony_ci{ 10518c2ecf20Sopenharmony_ci struct drm_private_state *obj_state; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci obj_state = drm_atomic_get_private_obj_state(state, &bridge->base); 10548c2ecf20Sopenharmony_ci if (IS_ERR(obj_state)) 10558c2ecf20Sopenharmony_ci return ERR_CAST(obj_state); 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci return drm_priv_to_bridge_state(obj_state); 10588c2ecf20Sopenharmony_ci} 10598c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_get_bridge_state); 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci/** 10628c2ecf20Sopenharmony_ci * drm_atomic_get_old_bridge_state - get old bridge state, if it exists 10638c2ecf20Sopenharmony_ci * @state: global atomic state object 10648c2ecf20Sopenharmony_ci * @bridge: bridge to grab 10658c2ecf20Sopenharmony_ci * 10668c2ecf20Sopenharmony_ci * This function returns the old bridge state for the given bridge, or NULL if 10678c2ecf20Sopenharmony_ci * the bridge is not part of the global atomic state. 10688c2ecf20Sopenharmony_ci */ 10698c2ecf20Sopenharmony_cistruct drm_bridge_state * 10708c2ecf20Sopenharmony_cidrm_atomic_get_old_bridge_state(struct drm_atomic_state *state, 10718c2ecf20Sopenharmony_ci struct drm_bridge *bridge) 10728c2ecf20Sopenharmony_ci{ 10738c2ecf20Sopenharmony_ci struct drm_private_state *obj_state; 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci obj_state = drm_atomic_get_old_private_obj_state(state, &bridge->base); 10768c2ecf20Sopenharmony_ci if (!obj_state) 10778c2ecf20Sopenharmony_ci return NULL; 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci return drm_priv_to_bridge_state(obj_state); 10808c2ecf20Sopenharmony_ci} 10818c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_get_old_bridge_state); 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci/** 10848c2ecf20Sopenharmony_ci * drm_atomic_get_new_bridge_state - get new bridge state, if it exists 10858c2ecf20Sopenharmony_ci * @state: global atomic state object 10868c2ecf20Sopenharmony_ci * @bridge: bridge to grab 10878c2ecf20Sopenharmony_ci * 10888c2ecf20Sopenharmony_ci * This function returns the new bridge state for the given bridge, or NULL if 10898c2ecf20Sopenharmony_ci * the bridge is not part of the global atomic state. 10908c2ecf20Sopenharmony_ci */ 10918c2ecf20Sopenharmony_cistruct drm_bridge_state * 10928c2ecf20Sopenharmony_cidrm_atomic_get_new_bridge_state(struct drm_atomic_state *state, 10938c2ecf20Sopenharmony_ci struct drm_bridge *bridge) 10948c2ecf20Sopenharmony_ci{ 10958c2ecf20Sopenharmony_ci struct drm_private_state *obj_state; 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci obj_state = drm_atomic_get_new_private_obj_state(state, &bridge->base); 10988c2ecf20Sopenharmony_ci if (!obj_state) 10998c2ecf20Sopenharmony_ci return NULL; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci return drm_priv_to_bridge_state(obj_state); 11028c2ecf20Sopenharmony_ci} 11038c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_get_new_bridge_state); 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci/** 11068c2ecf20Sopenharmony_ci * drm_atomic_add_encoder_bridges - add bridges attached to an encoder 11078c2ecf20Sopenharmony_ci * @state: atomic state 11088c2ecf20Sopenharmony_ci * @encoder: DRM encoder 11098c2ecf20Sopenharmony_ci * 11108c2ecf20Sopenharmony_ci * This function adds all bridges attached to @encoder. This is needed to add 11118c2ecf20Sopenharmony_ci * bridge states to @state and make them available when 11128c2ecf20Sopenharmony_ci * &drm_bridge_funcs.atomic_check(), &drm_bridge_funcs.atomic_pre_enable(), 11138c2ecf20Sopenharmony_ci * &drm_bridge_funcs.atomic_enable(), 11148c2ecf20Sopenharmony_ci * &drm_bridge_funcs.atomic_disable_post_disable() are called. 11158c2ecf20Sopenharmony_ci * 11168c2ecf20Sopenharmony_ci * Returns: 11178c2ecf20Sopenharmony_ci * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK 11188c2ecf20Sopenharmony_ci * then the w/w mutex code has detected a deadlock and the entire atomic 11198c2ecf20Sopenharmony_ci * sequence must be restarted. All other errors are fatal. 11208c2ecf20Sopenharmony_ci */ 11218c2ecf20Sopenharmony_ciint 11228c2ecf20Sopenharmony_cidrm_atomic_add_encoder_bridges(struct drm_atomic_state *state, 11238c2ecf20Sopenharmony_ci struct drm_encoder *encoder) 11248c2ecf20Sopenharmony_ci{ 11258c2ecf20Sopenharmony_ci struct drm_bridge_state *bridge_state; 11268c2ecf20Sopenharmony_ci struct drm_bridge *bridge; 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci if (!encoder) 11298c2ecf20Sopenharmony_ci return 0; 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci DRM_DEBUG_ATOMIC("Adding all bridges for [encoder:%d:%s] to %p\n", 11328c2ecf20Sopenharmony_ci encoder->base.id, encoder->name, state); 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci drm_for_each_bridge_in_chain(encoder, bridge) { 11358c2ecf20Sopenharmony_ci /* Skip bridges that don't implement the atomic state hooks. */ 11368c2ecf20Sopenharmony_ci if (!bridge->funcs->atomic_duplicate_state) 11378c2ecf20Sopenharmony_ci continue; 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci bridge_state = drm_atomic_get_bridge_state(state, bridge); 11408c2ecf20Sopenharmony_ci if (IS_ERR(bridge_state)) 11418c2ecf20Sopenharmony_ci return PTR_ERR(bridge_state); 11428c2ecf20Sopenharmony_ci } 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci return 0; 11458c2ecf20Sopenharmony_ci} 11468c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_add_encoder_bridges); 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci/** 11498c2ecf20Sopenharmony_ci * drm_atomic_add_affected_connectors - add connectors for CRTC 11508c2ecf20Sopenharmony_ci * @state: atomic state 11518c2ecf20Sopenharmony_ci * @crtc: DRM CRTC 11528c2ecf20Sopenharmony_ci * 11538c2ecf20Sopenharmony_ci * This function walks the current configuration and adds all connectors 11548c2ecf20Sopenharmony_ci * currently using @crtc to the atomic configuration @state. Note that this 11558c2ecf20Sopenharmony_ci * function must acquire the connection mutex. This can potentially cause 11568c2ecf20Sopenharmony_ci * unneeded seralization if the update is just for the planes on one CRTC. Hence 11578c2ecf20Sopenharmony_ci * drivers and helpers should only call this when really needed (e.g. when a 11588c2ecf20Sopenharmony_ci * full modeset needs to happen due to some change). 11598c2ecf20Sopenharmony_ci * 11608c2ecf20Sopenharmony_ci * Returns: 11618c2ecf20Sopenharmony_ci * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK 11628c2ecf20Sopenharmony_ci * then the w/w mutex code has detected a deadlock and the entire atomic 11638c2ecf20Sopenharmony_ci * sequence must be restarted. All other errors are fatal. 11648c2ecf20Sopenharmony_ci */ 11658c2ecf20Sopenharmony_ciint 11668c2ecf20Sopenharmony_cidrm_atomic_add_affected_connectors(struct drm_atomic_state *state, 11678c2ecf20Sopenharmony_ci struct drm_crtc *crtc) 11688c2ecf20Sopenharmony_ci{ 11698c2ecf20Sopenharmony_ci struct drm_mode_config *config = &state->dev->mode_config; 11708c2ecf20Sopenharmony_ci struct drm_connector *connector; 11718c2ecf20Sopenharmony_ci struct drm_connector_state *conn_state; 11728c2ecf20Sopenharmony_ci struct drm_connector_list_iter conn_iter; 11738c2ecf20Sopenharmony_ci struct drm_crtc_state *crtc_state; 11748c2ecf20Sopenharmony_ci int ret; 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci crtc_state = drm_atomic_get_crtc_state(state, crtc); 11778c2ecf20Sopenharmony_ci if (IS_ERR(crtc_state)) 11788c2ecf20Sopenharmony_ci return PTR_ERR(crtc_state); 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci ret = drm_modeset_lock(&config->connection_mutex, state->acquire_ctx); 11818c2ecf20Sopenharmony_ci if (ret) 11828c2ecf20Sopenharmony_ci return ret; 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci DRM_DEBUG_ATOMIC("Adding all current connectors for [CRTC:%d:%s] to %p\n", 11858c2ecf20Sopenharmony_ci crtc->base.id, crtc->name, state); 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci /* 11888c2ecf20Sopenharmony_ci * Changed connectors are already in @state, so only need to look 11898c2ecf20Sopenharmony_ci * at the connector_mask in crtc_state. 11908c2ecf20Sopenharmony_ci */ 11918c2ecf20Sopenharmony_ci drm_connector_list_iter_begin(state->dev, &conn_iter); 11928c2ecf20Sopenharmony_ci drm_for_each_connector_iter(connector, &conn_iter) { 11938c2ecf20Sopenharmony_ci if (!(crtc_state->connector_mask & drm_connector_mask(connector))) 11948c2ecf20Sopenharmony_ci continue; 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci conn_state = drm_atomic_get_connector_state(state, connector); 11978c2ecf20Sopenharmony_ci if (IS_ERR(conn_state)) { 11988c2ecf20Sopenharmony_ci drm_connector_list_iter_end(&conn_iter); 11998c2ecf20Sopenharmony_ci return PTR_ERR(conn_state); 12008c2ecf20Sopenharmony_ci } 12018c2ecf20Sopenharmony_ci } 12028c2ecf20Sopenharmony_ci drm_connector_list_iter_end(&conn_iter); 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci return 0; 12058c2ecf20Sopenharmony_ci} 12068c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_add_affected_connectors); 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci/** 12098c2ecf20Sopenharmony_ci * drm_atomic_add_affected_planes - add planes for CRTC 12108c2ecf20Sopenharmony_ci * @state: atomic state 12118c2ecf20Sopenharmony_ci * @crtc: DRM CRTC 12128c2ecf20Sopenharmony_ci * 12138c2ecf20Sopenharmony_ci * This function walks the current configuration and adds all planes 12148c2ecf20Sopenharmony_ci * currently used by @crtc to the atomic configuration @state. This is useful 12158c2ecf20Sopenharmony_ci * when an atomic commit also needs to check all currently enabled plane on 12168c2ecf20Sopenharmony_ci * @crtc, e.g. when changing the mode. It's also useful when re-enabling a CRTC 12178c2ecf20Sopenharmony_ci * to avoid special code to force-enable all planes. 12188c2ecf20Sopenharmony_ci * 12198c2ecf20Sopenharmony_ci * Since acquiring a plane state will always also acquire the w/w mutex of the 12208c2ecf20Sopenharmony_ci * current CRTC for that plane (if there is any) adding all the plane states for 12218c2ecf20Sopenharmony_ci * a CRTC will not reduce parallism of atomic updates. 12228c2ecf20Sopenharmony_ci * 12238c2ecf20Sopenharmony_ci * Returns: 12248c2ecf20Sopenharmony_ci * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK 12258c2ecf20Sopenharmony_ci * then the w/w mutex code has detected a deadlock and the entire atomic 12268c2ecf20Sopenharmony_ci * sequence must be restarted. All other errors are fatal. 12278c2ecf20Sopenharmony_ci */ 12288c2ecf20Sopenharmony_ciint 12298c2ecf20Sopenharmony_cidrm_atomic_add_affected_planes(struct drm_atomic_state *state, 12308c2ecf20Sopenharmony_ci struct drm_crtc *crtc) 12318c2ecf20Sopenharmony_ci{ 12328c2ecf20Sopenharmony_ci const struct drm_crtc_state *old_crtc_state = 12338c2ecf20Sopenharmony_ci drm_atomic_get_old_crtc_state(state, crtc); 12348c2ecf20Sopenharmony_ci struct drm_plane *plane; 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci WARN_ON(!drm_atomic_get_new_crtc_state(state, crtc)); 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci DRM_DEBUG_ATOMIC("Adding all current planes for [CRTC:%d:%s] to %p\n", 12398c2ecf20Sopenharmony_ci crtc->base.id, crtc->name, state); 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci drm_for_each_plane_mask(plane, state->dev, old_crtc_state->plane_mask) { 12428c2ecf20Sopenharmony_ci struct drm_plane_state *plane_state = 12438c2ecf20Sopenharmony_ci drm_atomic_get_plane_state(state, plane); 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci if (IS_ERR(plane_state)) 12468c2ecf20Sopenharmony_ci return PTR_ERR(plane_state); 12478c2ecf20Sopenharmony_ci } 12488c2ecf20Sopenharmony_ci return 0; 12498c2ecf20Sopenharmony_ci} 12508c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_add_affected_planes); 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci/** 12538c2ecf20Sopenharmony_ci * drm_atomic_check_only - check whether a given config would work 12548c2ecf20Sopenharmony_ci * @state: atomic configuration to check 12558c2ecf20Sopenharmony_ci * 12568c2ecf20Sopenharmony_ci * Note that this function can return -EDEADLK if the driver needed to acquire 12578c2ecf20Sopenharmony_ci * more locks but encountered a deadlock. The caller must then do the usual w/w 12588c2ecf20Sopenharmony_ci * backoff dance and restart. All other errors are fatal. 12598c2ecf20Sopenharmony_ci * 12608c2ecf20Sopenharmony_ci * Returns: 12618c2ecf20Sopenharmony_ci * 0 on success, negative error code on failure. 12628c2ecf20Sopenharmony_ci */ 12638c2ecf20Sopenharmony_ciint drm_atomic_check_only(struct drm_atomic_state *state) 12648c2ecf20Sopenharmony_ci{ 12658c2ecf20Sopenharmony_ci struct drm_device *dev = state->dev; 12668c2ecf20Sopenharmony_ci struct drm_mode_config *config = &dev->mode_config; 12678c2ecf20Sopenharmony_ci struct drm_plane *plane; 12688c2ecf20Sopenharmony_ci struct drm_plane_state *old_plane_state; 12698c2ecf20Sopenharmony_ci struct drm_plane_state *new_plane_state; 12708c2ecf20Sopenharmony_ci struct drm_crtc *crtc; 12718c2ecf20Sopenharmony_ci struct drm_crtc_state *old_crtc_state; 12728c2ecf20Sopenharmony_ci struct drm_crtc_state *new_crtc_state; 12738c2ecf20Sopenharmony_ci struct drm_connector *conn; 12748c2ecf20Sopenharmony_ci struct drm_connector_state *conn_state; 12758c2ecf20Sopenharmony_ci int i, ret = 0; 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci DRM_DEBUG_ATOMIC("checking %p\n", state); 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) { 12808c2ecf20Sopenharmony_ci ret = drm_atomic_plane_check(old_plane_state, new_plane_state); 12818c2ecf20Sopenharmony_ci if (ret) { 12828c2ecf20Sopenharmony_ci DRM_DEBUG_ATOMIC("[PLANE:%d:%s] atomic core check failed\n", 12838c2ecf20Sopenharmony_ci plane->base.id, plane->name); 12848c2ecf20Sopenharmony_ci return ret; 12858c2ecf20Sopenharmony_ci } 12868c2ecf20Sopenharmony_ci } 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { 12898c2ecf20Sopenharmony_ci ret = drm_atomic_crtc_check(old_crtc_state, new_crtc_state); 12908c2ecf20Sopenharmony_ci if (ret) { 12918c2ecf20Sopenharmony_ci DRM_DEBUG_ATOMIC("[CRTC:%d:%s] atomic core check failed\n", 12928c2ecf20Sopenharmony_ci crtc->base.id, crtc->name); 12938c2ecf20Sopenharmony_ci return ret; 12948c2ecf20Sopenharmony_ci } 12958c2ecf20Sopenharmony_ci } 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci for_each_new_connector_in_state(state, conn, conn_state, i) { 12988c2ecf20Sopenharmony_ci ret = drm_atomic_connector_check(conn, conn_state); 12998c2ecf20Sopenharmony_ci if (ret) { 13008c2ecf20Sopenharmony_ci DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] atomic core check failed\n", 13018c2ecf20Sopenharmony_ci conn->base.id, conn->name); 13028c2ecf20Sopenharmony_ci return ret; 13038c2ecf20Sopenharmony_ci } 13048c2ecf20Sopenharmony_ci } 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci if (config->funcs->atomic_check) { 13078c2ecf20Sopenharmony_ci ret = config->funcs->atomic_check(state->dev, state); 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci if (ret) { 13108c2ecf20Sopenharmony_ci DRM_DEBUG_ATOMIC("atomic driver check for %p failed: %d\n", 13118c2ecf20Sopenharmony_ci state, ret); 13128c2ecf20Sopenharmony_ci return ret; 13138c2ecf20Sopenharmony_ci } 13148c2ecf20Sopenharmony_ci } 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci if (!state->allow_modeset) { 13178c2ecf20Sopenharmony_ci for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) { 13188c2ecf20Sopenharmony_ci if (drm_atomic_crtc_needs_modeset(new_crtc_state)) { 13198c2ecf20Sopenharmony_ci DRM_DEBUG_ATOMIC("[CRTC:%d:%s] requires full modeset\n", 13208c2ecf20Sopenharmony_ci crtc->base.id, crtc->name); 13218c2ecf20Sopenharmony_ci return -EINVAL; 13228c2ecf20Sopenharmony_ci } 13238c2ecf20Sopenharmony_ci } 13248c2ecf20Sopenharmony_ci } 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci return 0; 13278c2ecf20Sopenharmony_ci} 13288c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_check_only); 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci/** 13318c2ecf20Sopenharmony_ci * drm_atomic_commit - commit configuration atomically 13328c2ecf20Sopenharmony_ci * @state: atomic configuration to check 13338c2ecf20Sopenharmony_ci * 13348c2ecf20Sopenharmony_ci * Note that this function can return -EDEADLK if the driver needed to acquire 13358c2ecf20Sopenharmony_ci * more locks but encountered a deadlock. The caller must then do the usual w/w 13368c2ecf20Sopenharmony_ci * backoff dance and restart. All other errors are fatal. 13378c2ecf20Sopenharmony_ci * 13388c2ecf20Sopenharmony_ci * This function will take its own reference on @state. 13398c2ecf20Sopenharmony_ci * Callers should always release their reference with drm_atomic_state_put(). 13408c2ecf20Sopenharmony_ci * 13418c2ecf20Sopenharmony_ci * Returns: 13428c2ecf20Sopenharmony_ci * 0 on success, negative error code on failure. 13438c2ecf20Sopenharmony_ci */ 13448c2ecf20Sopenharmony_ciint drm_atomic_commit(struct drm_atomic_state *state) 13458c2ecf20Sopenharmony_ci{ 13468c2ecf20Sopenharmony_ci struct drm_mode_config *config = &state->dev->mode_config; 13478c2ecf20Sopenharmony_ci int ret; 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci ret = drm_atomic_check_only(state); 13508c2ecf20Sopenharmony_ci if (ret) 13518c2ecf20Sopenharmony_ci return ret; 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci DRM_DEBUG_ATOMIC("committing %p\n", state); 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci return config->funcs->atomic_commit(state->dev, state, false); 13568c2ecf20Sopenharmony_ci} 13578c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_commit); 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci/** 13608c2ecf20Sopenharmony_ci * drm_atomic_nonblocking_commit - atomic nonblocking commit 13618c2ecf20Sopenharmony_ci * @state: atomic configuration to check 13628c2ecf20Sopenharmony_ci * 13638c2ecf20Sopenharmony_ci * Note that this function can return -EDEADLK if the driver needed to acquire 13648c2ecf20Sopenharmony_ci * more locks but encountered a deadlock. The caller must then do the usual w/w 13658c2ecf20Sopenharmony_ci * backoff dance and restart. All other errors are fatal. 13668c2ecf20Sopenharmony_ci * 13678c2ecf20Sopenharmony_ci * This function will take its own reference on @state. 13688c2ecf20Sopenharmony_ci * Callers should always release their reference with drm_atomic_state_put(). 13698c2ecf20Sopenharmony_ci * 13708c2ecf20Sopenharmony_ci * Returns: 13718c2ecf20Sopenharmony_ci * 0 on success, negative error code on failure. 13728c2ecf20Sopenharmony_ci */ 13738c2ecf20Sopenharmony_ciint drm_atomic_nonblocking_commit(struct drm_atomic_state *state) 13748c2ecf20Sopenharmony_ci{ 13758c2ecf20Sopenharmony_ci struct drm_mode_config *config = &state->dev->mode_config; 13768c2ecf20Sopenharmony_ci int ret; 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci ret = drm_atomic_check_only(state); 13798c2ecf20Sopenharmony_ci if (ret) 13808c2ecf20Sopenharmony_ci return ret; 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci DRM_DEBUG_ATOMIC("committing %p nonblocking\n", state); 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci return config->funcs->atomic_commit(state->dev, state, true); 13858c2ecf20Sopenharmony_ci} 13868c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_nonblocking_commit); 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci/* just used from drm-client and atomic-helper: */ 13898c2ecf20Sopenharmony_ciint __drm_atomic_helper_disable_plane(struct drm_plane *plane, 13908c2ecf20Sopenharmony_ci struct drm_plane_state *plane_state) 13918c2ecf20Sopenharmony_ci{ 13928c2ecf20Sopenharmony_ci int ret; 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci ret = drm_atomic_set_crtc_for_plane(plane_state, NULL); 13958c2ecf20Sopenharmony_ci if (ret != 0) 13968c2ecf20Sopenharmony_ci return ret; 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci drm_atomic_set_fb_for_plane(plane_state, NULL); 13998c2ecf20Sopenharmony_ci plane_state->crtc_x = 0; 14008c2ecf20Sopenharmony_ci plane_state->crtc_y = 0; 14018c2ecf20Sopenharmony_ci plane_state->crtc_w = 0; 14028c2ecf20Sopenharmony_ci plane_state->crtc_h = 0; 14038c2ecf20Sopenharmony_ci plane_state->src_x = 0; 14048c2ecf20Sopenharmony_ci plane_state->src_y = 0; 14058c2ecf20Sopenharmony_ci plane_state->src_w = 0; 14068c2ecf20Sopenharmony_ci plane_state->src_h = 0; 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci return 0; 14098c2ecf20Sopenharmony_ci} 14108c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__drm_atomic_helper_disable_plane); 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_cistatic int update_output_state(struct drm_atomic_state *state, 14138c2ecf20Sopenharmony_ci struct drm_mode_set *set) 14148c2ecf20Sopenharmony_ci{ 14158c2ecf20Sopenharmony_ci struct drm_device *dev = set->crtc->dev; 14168c2ecf20Sopenharmony_ci struct drm_crtc *crtc; 14178c2ecf20Sopenharmony_ci struct drm_crtc_state *new_crtc_state; 14188c2ecf20Sopenharmony_ci struct drm_connector *connector; 14198c2ecf20Sopenharmony_ci struct drm_connector_state *new_conn_state; 14208c2ecf20Sopenharmony_ci int ret, i; 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci ret = drm_modeset_lock(&dev->mode_config.connection_mutex, 14238c2ecf20Sopenharmony_ci state->acquire_ctx); 14248c2ecf20Sopenharmony_ci if (ret) 14258c2ecf20Sopenharmony_ci return ret; 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci /* First disable all connectors on the target crtc. */ 14288c2ecf20Sopenharmony_ci ret = drm_atomic_add_affected_connectors(state, set->crtc); 14298c2ecf20Sopenharmony_ci if (ret) 14308c2ecf20Sopenharmony_ci return ret; 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci for_each_new_connector_in_state(state, connector, new_conn_state, i) { 14338c2ecf20Sopenharmony_ci if (new_conn_state->crtc == set->crtc) { 14348c2ecf20Sopenharmony_ci ret = drm_atomic_set_crtc_for_connector(new_conn_state, 14358c2ecf20Sopenharmony_ci NULL); 14368c2ecf20Sopenharmony_ci if (ret) 14378c2ecf20Sopenharmony_ci return ret; 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci /* Make sure legacy setCrtc always re-trains */ 14408c2ecf20Sopenharmony_ci new_conn_state->link_status = DRM_LINK_STATUS_GOOD; 14418c2ecf20Sopenharmony_ci } 14428c2ecf20Sopenharmony_ci } 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci /* Then set all connectors from set->connectors on the target crtc */ 14458c2ecf20Sopenharmony_ci for (i = 0; i < set->num_connectors; i++) { 14468c2ecf20Sopenharmony_ci new_conn_state = drm_atomic_get_connector_state(state, 14478c2ecf20Sopenharmony_ci set->connectors[i]); 14488c2ecf20Sopenharmony_ci if (IS_ERR(new_conn_state)) 14498c2ecf20Sopenharmony_ci return PTR_ERR(new_conn_state); 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci ret = drm_atomic_set_crtc_for_connector(new_conn_state, 14528c2ecf20Sopenharmony_ci set->crtc); 14538c2ecf20Sopenharmony_ci if (ret) 14548c2ecf20Sopenharmony_ci return ret; 14558c2ecf20Sopenharmony_ci } 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) { 14588c2ecf20Sopenharmony_ci /* 14598c2ecf20Sopenharmony_ci * Don't update ->enable for the CRTC in the set_config request, 14608c2ecf20Sopenharmony_ci * since a mismatch would indicate a bug in the upper layers. 14618c2ecf20Sopenharmony_ci * The actual modeset code later on will catch any 14628c2ecf20Sopenharmony_ci * inconsistencies here. 14638c2ecf20Sopenharmony_ci */ 14648c2ecf20Sopenharmony_ci if (crtc == set->crtc) 14658c2ecf20Sopenharmony_ci continue; 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci if (!new_crtc_state->connector_mask) { 14688c2ecf20Sopenharmony_ci ret = drm_atomic_set_mode_prop_for_crtc(new_crtc_state, 14698c2ecf20Sopenharmony_ci NULL); 14708c2ecf20Sopenharmony_ci if (ret < 0) 14718c2ecf20Sopenharmony_ci return ret; 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci new_crtc_state->active = false; 14748c2ecf20Sopenharmony_ci } 14758c2ecf20Sopenharmony_ci } 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci return 0; 14788c2ecf20Sopenharmony_ci} 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci/* just used from drm-client and atomic-helper: */ 14818c2ecf20Sopenharmony_ciint __drm_atomic_helper_set_config(struct drm_mode_set *set, 14828c2ecf20Sopenharmony_ci struct drm_atomic_state *state) 14838c2ecf20Sopenharmony_ci{ 14848c2ecf20Sopenharmony_ci struct drm_crtc_state *crtc_state; 14858c2ecf20Sopenharmony_ci struct drm_plane_state *primary_state; 14868c2ecf20Sopenharmony_ci struct drm_crtc *crtc = set->crtc; 14878c2ecf20Sopenharmony_ci int hdisplay, vdisplay; 14888c2ecf20Sopenharmony_ci int ret; 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci crtc_state = drm_atomic_get_crtc_state(state, crtc); 14918c2ecf20Sopenharmony_ci if (IS_ERR(crtc_state)) 14928c2ecf20Sopenharmony_ci return PTR_ERR(crtc_state); 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci primary_state = drm_atomic_get_plane_state(state, crtc->primary); 14958c2ecf20Sopenharmony_ci if (IS_ERR(primary_state)) 14968c2ecf20Sopenharmony_ci return PTR_ERR(primary_state); 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci if (!set->mode) { 14998c2ecf20Sopenharmony_ci WARN_ON(set->fb); 15008c2ecf20Sopenharmony_ci WARN_ON(set->num_connectors); 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL); 15038c2ecf20Sopenharmony_ci if (ret != 0) 15048c2ecf20Sopenharmony_ci return ret; 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_ci crtc_state->active = false; 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci ret = drm_atomic_set_crtc_for_plane(primary_state, NULL); 15098c2ecf20Sopenharmony_ci if (ret != 0) 15108c2ecf20Sopenharmony_ci return ret; 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ci drm_atomic_set_fb_for_plane(primary_state, NULL); 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_ci goto commit; 15158c2ecf20Sopenharmony_ci } 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_ci WARN_ON(!set->fb); 15188c2ecf20Sopenharmony_ci WARN_ON(!set->num_connectors); 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci ret = drm_atomic_set_mode_for_crtc(crtc_state, set->mode); 15218c2ecf20Sopenharmony_ci if (ret != 0) 15228c2ecf20Sopenharmony_ci return ret; 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci crtc_state->active = true; 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci ret = drm_atomic_set_crtc_for_plane(primary_state, crtc); 15278c2ecf20Sopenharmony_ci if (ret != 0) 15288c2ecf20Sopenharmony_ci return ret; 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_ci drm_mode_get_hv_timing(set->mode, &hdisplay, &vdisplay); 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci drm_atomic_set_fb_for_plane(primary_state, set->fb); 15338c2ecf20Sopenharmony_ci primary_state->crtc_x = 0; 15348c2ecf20Sopenharmony_ci primary_state->crtc_y = 0; 15358c2ecf20Sopenharmony_ci primary_state->crtc_w = hdisplay; 15368c2ecf20Sopenharmony_ci primary_state->crtc_h = vdisplay; 15378c2ecf20Sopenharmony_ci primary_state->src_x = set->x << 16; 15388c2ecf20Sopenharmony_ci primary_state->src_y = set->y << 16; 15398c2ecf20Sopenharmony_ci if (drm_rotation_90_or_270(primary_state->rotation)) { 15408c2ecf20Sopenharmony_ci primary_state->src_w = vdisplay << 16; 15418c2ecf20Sopenharmony_ci primary_state->src_h = hdisplay << 16; 15428c2ecf20Sopenharmony_ci } else { 15438c2ecf20Sopenharmony_ci primary_state->src_w = hdisplay << 16; 15448c2ecf20Sopenharmony_ci primary_state->src_h = vdisplay << 16; 15458c2ecf20Sopenharmony_ci } 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_cicommit: 15488c2ecf20Sopenharmony_ci ret = update_output_state(state, set); 15498c2ecf20Sopenharmony_ci if (ret) 15508c2ecf20Sopenharmony_ci return ret; 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci return 0; 15538c2ecf20Sopenharmony_ci} 15548c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__drm_atomic_helper_set_config); 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_civoid drm_atomic_print_state(const struct drm_atomic_state *state) 15578c2ecf20Sopenharmony_ci{ 15588c2ecf20Sopenharmony_ci struct drm_printer p = drm_info_printer(state->dev->dev); 15598c2ecf20Sopenharmony_ci struct drm_plane *plane; 15608c2ecf20Sopenharmony_ci struct drm_plane_state *plane_state; 15618c2ecf20Sopenharmony_ci struct drm_crtc *crtc; 15628c2ecf20Sopenharmony_ci struct drm_crtc_state *crtc_state; 15638c2ecf20Sopenharmony_ci struct drm_connector *connector; 15648c2ecf20Sopenharmony_ci struct drm_connector_state *connector_state; 15658c2ecf20Sopenharmony_ci int i; 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci DRM_DEBUG_ATOMIC("checking %p\n", state); 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci for_each_new_plane_in_state(state, plane, plane_state, i) 15708c2ecf20Sopenharmony_ci drm_atomic_plane_print_state(&p, plane_state); 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci for_each_new_crtc_in_state(state, crtc, crtc_state, i) 15738c2ecf20Sopenharmony_ci drm_atomic_crtc_print_state(&p, crtc_state); 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci for_each_new_connector_in_state(state, connector, connector_state, i) 15768c2ecf20Sopenharmony_ci drm_atomic_connector_print_state(&p, connector_state); 15778c2ecf20Sopenharmony_ci} 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_cistatic void __drm_state_dump(struct drm_device *dev, struct drm_printer *p, 15808c2ecf20Sopenharmony_ci bool take_locks) 15818c2ecf20Sopenharmony_ci{ 15828c2ecf20Sopenharmony_ci struct drm_mode_config *config = &dev->mode_config; 15838c2ecf20Sopenharmony_ci struct drm_plane *plane; 15848c2ecf20Sopenharmony_ci struct drm_crtc *crtc; 15858c2ecf20Sopenharmony_ci struct drm_connector *connector; 15868c2ecf20Sopenharmony_ci struct drm_connector_list_iter conn_iter; 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci if (!drm_drv_uses_atomic_modeset(dev)) 15898c2ecf20Sopenharmony_ci return; 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_ci list_for_each_entry(plane, &config->plane_list, head) { 15928c2ecf20Sopenharmony_ci if (take_locks) 15938c2ecf20Sopenharmony_ci drm_modeset_lock(&plane->mutex, NULL); 15948c2ecf20Sopenharmony_ci drm_atomic_plane_print_state(p, plane->state); 15958c2ecf20Sopenharmony_ci if (take_locks) 15968c2ecf20Sopenharmony_ci drm_modeset_unlock(&plane->mutex); 15978c2ecf20Sopenharmony_ci } 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci list_for_each_entry(crtc, &config->crtc_list, head) { 16008c2ecf20Sopenharmony_ci if (take_locks) 16018c2ecf20Sopenharmony_ci drm_modeset_lock(&crtc->mutex, NULL); 16028c2ecf20Sopenharmony_ci drm_atomic_crtc_print_state(p, crtc->state); 16038c2ecf20Sopenharmony_ci if (take_locks) 16048c2ecf20Sopenharmony_ci drm_modeset_unlock(&crtc->mutex); 16058c2ecf20Sopenharmony_ci } 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci drm_connector_list_iter_begin(dev, &conn_iter); 16088c2ecf20Sopenharmony_ci if (take_locks) 16098c2ecf20Sopenharmony_ci drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 16108c2ecf20Sopenharmony_ci drm_for_each_connector_iter(connector, &conn_iter) 16118c2ecf20Sopenharmony_ci drm_atomic_connector_print_state(p, connector->state); 16128c2ecf20Sopenharmony_ci if (take_locks) 16138c2ecf20Sopenharmony_ci drm_modeset_unlock(&dev->mode_config.connection_mutex); 16148c2ecf20Sopenharmony_ci drm_connector_list_iter_end(&conn_iter); 16158c2ecf20Sopenharmony_ci} 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_ci/** 16188c2ecf20Sopenharmony_ci * drm_state_dump - dump entire device atomic state 16198c2ecf20Sopenharmony_ci * @dev: the drm device 16208c2ecf20Sopenharmony_ci * @p: where to print the state to 16218c2ecf20Sopenharmony_ci * 16228c2ecf20Sopenharmony_ci * Just for debugging. Drivers might want an option to dump state 16238c2ecf20Sopenharmony_ci * to dmesg in case of error irq's. (Hint, you probably want to 16248c2ecf20Sopenharmony_ci * ratelimit this!) 16258c2ecf20Sopenharmony_ci * 16268c2ecf20Sopenharmony_ci * The caller must drm_modeset_lock_all(), or if this is called 16278c2ecf20Sopenharmony_ci * from error irq handler, it should not be enabled by default. 16288c2ecf20Sopenharmony_ci * (Ie. if you are debugging errors you might not care that this 16298c2ecf20Sopenharmony_ci * is racey. But calling this without all modeset locks held is 16308c2ecf20Sopenharmony_ci * not inherently safe.) 16318c2ecf20Sopenharmony_ci */ 16328c2ecf20Sopenharmony_civoid drm_state_dump(struct drm_device *dev, struct drm_printer *p) 16338c2ecf20Sopenharmony_ci{ 16348c2ecf20Sopenharmony_ci __drm_state_dump(dev, p, false); 16358c2ecf20Sopenharmony_ci} 16368c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_state_dump); 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 16398c2ecf20Sopenharmony_cistatic int drm_state_info(struct seq_file *m, void *data) 16408c2ecf20Sopenharmony_ci{ 16418c2ecf20Sopenharmony_ci struct drm_info_node *node = (struct drm_info_node *) m->private; 16428c2ecf20Sopenharmony_ci struct drm_device *dev = node->minor->dev; 16438c2ecf20Sopenharmony_ci struct drm_printer p = drm_seq_file_printer(m); 16448c2ecf20Sopenharmony_ci 16458c2ecf20Sopenharmony_ci __drm_state_dump(dev, &p, true); 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci return 0; 16488c2ecf20Sopenharmony_ci} 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci/* any use in debugfs files to dump individual planes/crtc/etc? */ 16518c2ecf20Sopenharmony_cistatic const struct drm_info_list drm_atomic_debugfs_list[] = { 16528c2ecf20Sopenharmony_ci {"state", drm_state_info, 0}, 16538c2ecf20Sopenharmony_ci}; 16548c2ecf20Sopenharmony_ci 16558c2ecf20Sopenharmony_civoid drm_atomic_debugfs_init(struct drm_minor *minor) 16568c2ecf20Sopenharmony_ci{ 16578c2ecf20Sopenharmony_ci drm_debugfs_create_files(drm_atomic_debugfs_list, 16588c2ecf20Sopenharmony_ci ARRAY_SIZE(drm_atomic_debugfs_list), 16598c2ecf20Sopenharmony_ci minor->debugfs_root, minor); 16608c2ecf20Sopenharmony_ci} 16618c2ecf20Sopenharmony_ci#endif 1662