162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (C) 2014 Red Hat 362306a36Sopenharmony_ci * Copyright (C) 2014 Intel Corp. 462306a36Sopenharmony_ci * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 762306a36Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 862306a36Sopenharmony_ci * to deal in the Software without restriction, including without limitation 962306a36Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 1062306a36Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 1162306a36Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 1462306a36Sopenharmony_ci * all copies or substantial portions of the Software. 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1762306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1862306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1962306a36Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 2062306a36Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 2162306a36Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2262306a36Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * Authors: 2562306a36Sopenharmony_ci * Rob Clark <robdclark@gmail.com> 2662306a36Sopenharmony_ci * Daniel Vetter <daniel.vetter@ffwll.ch> 2762306a36Sopenharmony_ci */ 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#include <linux/sync_file.h> 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#include <drm/drm_atomic.h> 3362306a36Sopenharmony_ci#include <drm/drm_atomic_uapi.h> 3462306a36Sopenharmony_ci#include <drm/drm_blend.h> 3562306a36Sopenharmony_ci#include <drm/drm_bridge.h> 3662306a36Sopenharmony_ci#include <drm/drm_debugfs.h> 3762306a36Sopenharmony_ci#include <drm/drm_device.h> 3862306a36Sopenharmony_ci#include <drm/drm_drv.h> 3962306a36Sopenharmony_ci#include <drm/drm_file.h> 4062306a36Sopenharmony_ci#include <drm/drm_fourcc.h> 4162306a36Sopenharmony_ci#include <drm/drm_framebuffer.h> 4262306a36Sopenharmony_ci#include <drm/drm_mode.h> 4362306a36Sopenharmony_ci#include <drm/drm_print.h> 4462306a36Sopenharmony_ci#include <drm/drm_writeback.h> 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#include "drm_crtc_internal.h" 4762306a36Sopenharmony_ci#include "drm_internal.h" 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_civoid __drm_crtc_commit_free(struct kref *kref) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci struct drm_crtc_commit *commit = 5262306a36Sopenharmony_ci container_of(kref, struct drm_crtc_commit, ref); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci kfree(commit); 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ciEXPORT_SYMBOL(__drm_crtc_commit_free); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci/** 5962306a36Sopenharmony_ci * drm_crtc_commit_wait - Waits for a commit to complete 6062306a36Sopenharmony_ci * @commit: &drm_crtc_commit to wait for 6162306a36Sopenharmony_ci * 6262306a36Sopenharmony_ci * Waits for a given &drm_crtc_commit to be programmed into the 6362306a36Sopenharmony_ci * hardware and flipped to. 6462306a36Sopenharmony_ci * 6562306a36Sopenharmony_ci * Returns: 6662306a36Sopenharmony_ci * 6762306a36Sopenharmony_ci * 0 on success, a negative error code otherwise. 6862306a36Sopenharmony_ci */ 6962306a36Sopenharmony_ciint drm_crtc_commit_wait(struct drm_crtc_commit *commit) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci unsigned long timeout = 10 * HZ; 7262306a36Sopenharmony_ci int ret; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci if (!commit) 7562306a36Sopenharmony_ci return 0; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci ret = wait_for_completion_timeout(&commit->hw_done, timeout); 7862306a36Sopenharmony_ci if (!ret) { 7962306a36Sopenharmony_ci drm_err(commit->crtc->dev, "hw_done timed out\n"); 8062306a36Sopenharmony_ci return -ETIMEDOUT; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci /* 8462306a36Sopenharmony_ci * Currently no support for overwriting flips, hence 8562306a36Sopenharmony_ci * stall for previous one to execute completely. 8662306a36Sopenharmony_ci */ 8762306a36Sopenharmony_ci ret = wait_for_completion_timeout(&commit->flip_done, timeout); 8862306a36Sopenharmony_ci if (!ret) { 8962306a36Sopenharmony_ci drm_err(commit->crtc->dev, "flip_done timed out\n"); 9062306a36Sopenharmony_ci return -ETIMEDOUT; 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci return 0; 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ciEXPORT_SYMBOL(drm_crtc_commit_wait); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci/** 9862306a36Sopenharmony_ci * drm_atomic_state_default_release - 9962306a36Sopenharmony_ci * release memory initialized by drm_atomic_state_init 10062306a36Sopenharmony_ci * @state: atomic state 10162306a36Sopenharmony_ci * 10262306a36Sopenharmony_ci * Free all the memory allocated by drm_atomic_state_init. 10362306a36Sopenharmony_ci * This should only be used by drivers which are still subclassing 10462306a36Sopenharmony_ci * &drm_atomic_state and haven't switched to &drm_private_state yet. 10562306a36Sopenharmony_ci */ 10662306a36Sopenharmony_civoid drm_atomic_state_default_release(struct drm_atomic_state *state) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci kfree(state->connectors); 10962306a36Sopenharmony_ci kfree(state->crtcs); 11062306a36Sopenharmony_ci kfree(state->planes); 11162306a36Sopenharmony_ci kfree(state->private_objs); 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_state_default_release); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci/** 11662306a36Sopenharmony_ci * drm_atomic_state_init - init new atomic state 11762306a36Sopenharmony_ci * @dev: DRM device 11862306a36Sopenharmony_ci * @state: atomic state 11962306a36Sopenharmony_ci * 12062306a36Sopenharmony_ci * Default implementation for filling in a new atomic state. 12162306a36Sopenharmony_ci * This should only be used by drivers which are still subclassing 12262306a36Sopenharmony_ci * &drm_atomic_state and haven't switched to &drm_private_state yet. 12362306a36Sopenharmony_ci */ 12462306a36Sopenharmony_ciint 12562306a36Sopenharmony_cidrm_atomic_state_init(struct drm_device *dev, struct drm_atomic_state *state) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci kref_init(&state->ref); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci /* TODO legacy paths should maybe do a better job about 13062306a36Sopenharmony_ci * setting this appropriately? 13162306a36Sopenharmony_ci */ 13262306a36Sopenharmony_ci state->allow_modeset = true; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci state->crtcs = kcalloc(dev->mode_config.num_crtc, 13562306a36Sopenharmony_ci sizeof(*state->crtcs), GFP_KERNEL); 13662306a36Sopenharmony_ci if (!state->crtcs) 13762306a36Sopenharmony_ci goto fail; 13862306a36Sopenharmony_ci state->planes = kcalloc(dev->mode_config.num_total_plane, 13962306a36Sopenharmony_ci sizeof(*state->planes), GFP_KERNEL); 14062306a36Sopenharmony_ci if (!state->planes) 14162306a36Sopenharmony_ci goto fail; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci /* 14462306a36Sopenharmony_ci * Because drm_atomic_state can be committed asynchronously we need our 14562306a36Sopenharmony_ci * own reference and cannot rely on the on implied by drm_file in the 14662306a36Sopenharmony_ci * ioctl call. 14762306a36Sopenharmony_ci */ 14862306a36Sopenharmony_ci drm_dev_get(dev); 14962306a36Sopenharmony_ci state->dev = dev; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci drm_dbg_atomic(dev, "Allocated atomic state %p\n", state); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci return 0; 15462306a36Sopenharmony_cifail: 15562306a36Sopenharmony_ci drm_atomic_state_default_release(state); 15662306a36Sopenharmony_ci return -ENOMEM; 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_state_init); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci/** 16162306a36Sopenharmony_ci * drm_atomic_state_alloc - allocate atomic state 16262306a36Sopenharmony_ci * @dev: DRM device 16362306a36Sopenharmony_ci * 16462306a36Sopenharmony_ci * This allocates an empty atomic state to track updates. 16562306a36Sopenharmony_ci */ 16662306a36Sopenharmony_cistruct drm_atomic_state * 16762306a36Sopenharmony_cidrm_atomic_state_alloc(struct drm_device *dev) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci struct drm_mode_config *config = &dev->mode_config; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci if (!config->funcs->atomic_state_alloc) { 17262306a36Sopenharmony_ci struct drm_atomic_state *state; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci state = kzalloc(sizeof(*state), GFP_KERNEL); 17562306a36Sopenharmony_ci if (!state) 17662306a36Sopenharmony_ci return NULL; 17762306a36Sopenharmony_ci if (drm_atomic_state_init(dev, state) < 0) { 17862306a36Sopenharmony_ci kfree(state); 17962306a36Sopenharmony_ci return NULL; 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci return state; 18262306a36Sopenharmony_ci } 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci return config->funcs->atomic_state_alloc(dev); 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_state_alloc); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci/** 18962306a36Sopenharmony_ci * drm_atomic_state_default_clear - clear base atomic state 19062306a36Sopenharmony_ci * @state: atomic state 19162306a36Sopenharmony_ci * 19262306a36Sopenharmony_ci * Default implementation for clearing atomic state. 19362306a36Sopenharmony_ci * This should only be used by drivers which are still subclassing 19462306a36Sopenharmony_ci * &drm_atomic_state and haven't switched to &drm_private_state yet. 19562306a36Sopenharmony_ci */ 19662306a36Sopenharmony_civoid drm_atomic_state_default_clear(struct drm_atomic_state *state) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci struct drm_device *dev = state->dev; 19962306a36Sopenharmony_ci struct drm_mode_config *config = &dev->mode_config; 20062306a36Sopenharmony_ci int i; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci drm_dbg_atomic(dev, "Clearing atomic state %p\n", state); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci for (i = 0; i < state->num_connector; i++) { 20562306a36Sopenharmony_ci struct drm_connector *connector = state->connectors[i].ptr; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci if (!connector) 20862306a36Sopenharmony_ci continue; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci connector->funcs->atomic_destroy_state(connector, 21162306a36Sopenharmony_ci state->connectors[i].state); 21262306a36Sopenharmony_ci state->connectors[i].ptr = NULL; 21362306a36Sopenharmony_ci state->connectors[i].state = NULL; 21462306a36Sopenharmony_ci state->connectors[i].old_state = NULL; 21562306a36Sopenharmony_ci state->connectors[i].new_state = NULL; 21662306a36Sopenharmony_ci drm_connector_put(connector); 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci for (i = 0; i < config->num_crtc; i++) { 22062306a36Sopenharmony_ci struct drm_crtc *crtc = state->crtcs[i].ptr; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci if (!crtc) 22362306a36Sopenharmony_ci continue; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci crtc->funcs->atomic_destroy_state(crtc, 22662306a36Sopenharmony_ci state->crtcs[i].state); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci state->crtcs[i].ptr = NULL; 22962306a36Sopenharmony_ci state->crtcs[i].state = NULL; 23062306a36Sopenharmony_ci state->crtcs[i].old_state = NULL; 23162306a36Sopenharmony_ci state->crtcs[i].new_state = NULL; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci if (state->crtcs[i].commit) { 23462306a36Sopenharmony_ci drm_crtc_commit_put(state->crtcs[i].commit); 23562306a36Sopenharmony_ci state->crtcs[i].commit = NULL; 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci } 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci for (i = 0; i < config->num_total_plane; i++) { 24062306a36Sopenharmony_ci struct drm_plane *plane = state->planes[i].ptr; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci if (!plane) 24362306a36Sopenharmony_ci continue; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci plane->funcs->atomic_destroy_state(plane, 24662306a36Sopenharmony_ci state->planes[i].state); 24762306a36Sopenharmony_ci state->planes[i].ptr = NULL; 24862306a36Sopenharmony_ci state->planes[i].state = NULL; 24962306a36Sopenharmony_ci state->planes[i].old_state = NULL; 25062306a36Sopenharmony_ci state->planes[i].new_state = NULL; 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci for (i = 0; i < state->num_private_objs; i++) { 25462306a36Sopenharmony_ci struct drm_private_obj *obj = state->private_objs[i].ptr; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci obj->funcs->atomic_destroy_state(obj, 25762306a36Sopenharmony_ci state->private_objs[i].state); 25862306a36Sopenharmony_ci state->private_objs[i].ptr = NULL; 25962306a36Sopenharmony_ci state->private_objs[i].state = NULL; 26062306a36Sopenharmony_ci state->private_objs[i].old_state = NULL; 26162306a36Sopenharmony_ci state->private_objs[i].new_state = NULL; 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci state->num_private_objs = 0; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci if (state->fake_commit) { 26662306a36Sopenharmony_ci drm_crtc_commit_put(state->fake_commit); 26762306a36Sopenharmony_ci state->fake_commit = NULL; 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_state_default_clear); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci/** 27362306a36Sopenharmony_ci * drm_atomic_state_clear - clear state object 27462306a36Sopenharmony_ci * @state: atomic state 27562306a36Sopenharmony_ci * 27662306a36Sopenharmony_ci * When the w/w mutex algorithm detects a deadlock we need to back off and drop 27762306a36Sopenharmony_ci * all locks. So someone else could sneak in and change the current modeset 27862306a36Sopenharmony_ci * configuration. Which means that all the state assembled in @state is no 27962306a36Sopenharmony_ci * longer an atomic update to the current state, but to some arbitrary earlier 28062306a36Sopenharmony_ci * state. Which could break assumptions the driver's 28162306a36Sopenharmony_ci * &drm_mode_config_funcs.atomic_check likely relies on. 28262306a36Sopenharmony_ci * 28362306a36Sopenharmony_ci * Hence we must clear all cached state and completely start over, using this 28462306a36Sopenharmony_ci * function. 28562306a36Sopenharmony_ci */ 28662306a36Sopenharmony_civoid drm_atomic_state_clear(struct drm_atomic_state *state) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci struct drm_device *dev = state->dev; 28962306a36Sopenharmony_ci struct drm_mode_config *config = &dev->mode_config; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci if (config->funcs->atomic_state_clear) 29262306a36Sopenharmony_ci config->funcs->atomic_state_clear(state); 29362306a36Sopenharmony_ci else 29462306a36Sopenharmony_ci drm_atomic_state_default_clear(state); 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_state_clear); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci/** 29962306a36Sopenharmony_ci * __drm_atomic_state_free - free all memory for an atomic state 30062306a36Sopenharmony_ci * @ref: This atomic state to deallocate 30162306a36Sopenharmony_ci * 30262306a36Sopenharmony_ci * This frees all memory associated with an atomic state, including all the 30362306a36Sopenharmony_ci * per-object state for planes, CRTCs and connectors. 30462306a36Sopenharmony_ci */ 30562306a36Sopenharmony_civoid __drm_atomic_state_free(struct kref *ref) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci struct drm_atomic_state *state = container_of(ref, typeof(*state), ref); 30862306a36Sopenharmony_ci struct drm_device *dev = state->dev; 30962306a36Sopenharmony_ci struct drm_mode_config *config = &dev->mode_config; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci drm_atomic_state_clear(state); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci drm_dbg_atomic(state->dev, "Freeing atomic state %p\n", state); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci if (config->funcs->atomic_state_free) { 31662306a36Sopenharmony_ci config->funcs->atomic_state_free(state); 31762306a36Sopenharmony_ci } else { 31862306a36Sopenharmony_ci drm_atomic_state_default_release(state); 31962306a36Sopenharmony_ci kfree(state); 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci drm_dev_put(dev); 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ciEXPORT_SYMBOL(__drm_atomic_state_free); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci/** 32762306a36Sopenharmony_ci * drm_atomic_get_crtc_state - get CRTC state 32862306a36Sopenharmony_ci * @state: global atomic state object 32962306a36Sopenharmony_ci * @crtc: CRTC to get state object for 33062306a36Sopenharmony_ci * 33162306a36Sopenharmony_ci * This function returns the CRTC state for the given CRTC, allocating it if 33262306a36Sopenharmony_ci * needed. It will also grab the relevant CRTC lock to make sure that the state 33362306a36Sopenharmony_ci * is consistent. 33462306a36Sopenharmony_ci * 33562306a36Sopenharmony_ci * WARNING: Drivers may only add new CRTC states to a @state if 33662306a36Sopenharmony_ci * drm_atomic_state.allow_modeset is set, or if it's a driver-internal commit 33762306a36Sopenharmony_ci * not created by userspace through an IOCTL call. 33862306a36Sopenharmony_ci * 33962306a36Sopenharmony_ci * Returns: 34062306a36Sopenharmony_ci * 34162306a36Sopenharmony_ci * Either the allocated state or the error code encoded into the pointer. When 34262306a36Sopenharmony_ci * the error is EDEADLK then the w/w mutex code has detected a deadlock and the 34362306a36Sopenharmony_ci * entire atomic sequence must be restarted. All other errors are fatal. 34462306a36Sopenharmony_ci */ 34562306a36Sopenharmony_cistruct drm_crtc_state * 34662306a36Sopenharmony_cidrm_atomic_get_crtc_state(struct drm_atomic_state *state, 34762306a36Sopenharmony_ci struct drm_crtc *crtc) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci int ret, index = drm_crtc_index(crtc); 35062306a36Sopenharmony_ci struct drm_crtc_state *crtc_state; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci WARN_ON(!state->acquire_ctx); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci crtc_state = drm_atomic_get_existing_crtc_state(state, crtc); 35562306a36Sopenharmony_ci if (crtc_state) 35662306a36Sopenharmony_ci return crtc_state; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci ret = drm_modeset_lock(&crtc->mutex, state->acquire_ctx); 35962306a36Sopenharmony_ci if (ret) 36062306a36Sopenharmony_ci return ERR_PTR(ret); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci crtc_state = crtc->funcs->atomic_duplicate_state(crtc); 36362306a36Sopenharmony_ci if (!crtc_state) 36462306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci state->crtcs[index].state = crtc_state; 36762306a36Sopenharmony_ci state->crtcs[index].old_state = crtc->state; 36862306a36Sopenharmony_ci state->crtcs[index].new_state = crtc_state; 36962306a36Sopenharmony_ci state->crtcs[index].ptr = crtc; 37062306a36Sopenharmony_ci crtc_state->state = state; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci drm_dbg_atomic(state->dev, "Added [CRTC:%d:%s] %p state to %p\n", 37362306a36Sopenharmony_ci crtc->base.id, crtc->name, crtc_state, state); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci return crtc_state; 37662306a36Sopenharmony_ci} 37762306a36Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_get_crtc_state); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_cistatic int drm_atomic_crtc_check(const struct drm_crtc_state *old_crtc_state, 38062306a36Sopenharmony_ci const struct drm_crtc_state *new_crtc_state) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci struct drm_crtc *crtc = new_crtc_state->crtc; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci /* NOTE: we explicitly don't enforce constraints such as primary 38562306a36Sopenharmony_ci * layer covering entire screen, since that is something we want 38662306a36Sopenharmony_ci * to allow (on hw that supports it). For hw that does not, it 38762306a36Sopenharmony_ci * should be checked in driver's crtc->atomic_check() vfunc. 38862306a36Sopenharmony_ci * 38962306a36Sopenharmony_ci * TODO: Add generic modeset state checks once we support those. 39062306a36Sopenharmony_ci */ 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci if (new_crtc_state->active && !new_crtc_state->enable) { 39362306a36Sopenharmony_ci drm_dbg_atomic(crtc->dev, 39462306a36Sopenharmony_ci "[CRTC:%d:%s] active without enabled\n", 39562306a36Sopenharmony_ci crtc->base.id, crtc->name); 39662306a36Sopenharmony_ci return -EINVAL; 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci /* The state->enable vs. state->mode_blob checks can be WARN_ON, 40062306a36Sopenharmony_ci * as this is a kernel-internal detail that userspace should never 40162306a36Sopenharmony_ci * be able to trigger. 40262306a36Sopenharmony_ci */ 40362306a36Sopenharmony_ci if (drm_core_check_feature(crtc->dev, DRIVER_ATOMIC) && 40462306a36Sopenharmony_ci WARN_ON(new_crtc_state->enable && !new_crtc_state->mode_blob)) { 40562306a36Sopenharmony_ci drm_dbg_atomic(crtc->dev, 40662306a36Sopenharmony_ci "[CRTC:%d:%s] enabled without mode blob\n", 40762306a36Sopenharmony_ci crtc->base.id, crtc->name); 40862306a36Sopenharmony_ci return -EINVAL; 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci if (drm_core_check_feature(crtc->dev, DRIVER_ATOMIC) && 41262306a36Sopenharmony_ci WARN_ON(!new_crtc_state->enable && new_crtc_state->mode_blob)) { 41362306a36Sopenharmony_ci drm_dbg_atomic(crtc->dev, 41462306a36Sopenharmony_ci "[CRTC:%d:%s] disabled with mode blob\n", 41562306a36Sopenharmony_ci crtc->base.id, crtc->name); 41662306a36Sopenharmony_ci return -EINVAL; 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci /* 42062306a36Sopenharmony_ci * Reject event generation for when a CRTC is off and stays off. 42162306a36Sopenharmony_ci * It wouldn't be hard to implement this, but userspace has a track 42262306a36Sopenharmony_ci * record of happily burning through 100% cpu (or worse, crash) when the 42362306a36Sopenharmony_ci * display pipe is suspended. To avoid all that fun just reject updates 42462306a36Sopenharmony_ci * that ask for events since likely that indicates a bug in the 42562306a36Sopenharmony_ci * compositor's drawing loop. This is consistent with the vblank IOCTL 42662306a36Sopenharmony_ci * and legacy page_flip IOCTL which also reject service on a disabled 42762306a36Sopenharmony_ci * pipe. 42862306a36Sopenharmony_ci */ 42962306a36Sopenharmony_ci if (new_crtc_state->event && 43062306a36Sopenharmony_ci !new_crtc_state->active && !old_crtc_state->active) { 43162306a36Sopenharmony_ci drm_dbg_atomic(crtc->dev, 43262306a36Sopenharmony_ci "[CRTC:%d:%s] requesting event but off\n", 43362306a36Sopenharmony_ci crtc->base.id, crtc->name); 43462306a36Sopenharmony_ci return -EINVAL; 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci return 0; 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_cistatic void drm_atomic_crtc_print_state(struct drm_printer *p, 44162306a36Sopenharmony_ci const struct drm_crtc_state *state) 44262306a36Sopenharmony_ci{ 44362306a36Sopenharmony_ci struct drm_crtc *crtc = state->crtc; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci drm_printf(p, "crtc[%u]: %s\n", crtc->base.id, crtc->name); 44662306a36Sopenharmony_ci drm_printf(p, "\tenable=%d\n", state->enable); 44762306a36Sopenharmony_ci drm_printf(p, "\tactive=%d\n", state->active); 44862306a36Sopenharmony_ci drm_printf(p, "\tself_refresh_active=%d\n", state->self_refresh_active); 44962306a36Sopenharmony_ci drm_printf(p, "\tplanes_changed=%d\n", state->planes_changed); 45062306a36Sopenharmony_ci drm_printf(p, "\tmode_changed=%d\n", state->mode_changed); 45162306a36Sopenharmony_ci drm_printf(p, "\tactive_changed=%d\n", state->active_changed); 45262306a36Sopenharmony_ci drm_printf(p, "\tconnectors_changed=%d\n", state->connectors_changed); 45362306a36Sopenharmony_ci drm_printf(p, "\tcolor_mgmt_changed=%d\n", state->color_mgmt_changed); 45462306a36Sopenharmony_ci drm_printf(p, "\tplane_mask=%x\n", state->plane_mask); 45562306a36Sopenharmony_ci drm_printf(p, "\tconnector_mask=%x\n", state->connector_mask); 45662306a36Sopenharmony_ci drm_printf(p, "\tencoder_mask=%x\n", state->encoder_mask); 45762306a36Sopenharmony_ci drm_printf(p, "\tmode: " DRM_MODE_FMT "\n", DRM_MODE_ARG(&state->mode)); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci if (crtc->funcs->atomic_print_state) 46062306a36Sopenharmony_ci crtc->funcs->atomic_print_state(p, state); 46162306a36Sopenharmony_ci} 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_cistatic int drm_atomic_connector_check(struct drm_connector *connector, 46462306a36Sopenharmony_ci struct drm_connector_state *state) 46562306a36Sopenharmony_ci{ 46662306a36Sopenharmony_ci struct drm_crtc_state *crtc_state; 46762306a36Sopenharmony_ci struct drm_writeback_job *writeback_job = state->writeback_job; 46862306a36Sopenharmony_ci const struct drm_display_info *info = &connector->display_info; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci state->max_bpc = info->bpc ? info->bpc : 8; 47162306a36Sopenharmony_ci if (connector->max_bpc_property) 47262306a36Sopenharmony_ci state->max_bpc = min(state->max_bpc, state->max_requested_bpc); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci if ((connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) || !writeback_job) 47562306a36Sopenharmony_ci return 0; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci if (writeback_job->fb && !state->crtc) { 47862306a36Sopenharmony_ci drm_dbg_atomic(connector->dev, 47962306a36Sopenharmony_ci "[CONNECTOR:%d:%s] framebuffer without CRTC\n", 48062306a36Sopenharmony_ci connector->base.id, connector->name); 48162306a36Sopenharmony_ci return -EINVAL; 48262306a36Sopenharmony_ci } 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci if (state->crtc) 48562306a36Sopenharmony_ci crtc_state = drm_atomic_get_existing_crtc_state(state->state, 48662306a36Sopenharmony_ci state->crtc); 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci if (writeback_job->fb && !crtc_state->active) { 48962306a36Sopenharmony_ci drm_dbg_atomic(connector->dev, 49062306a36Sopenharmony_ci "[CONNECTOR:%d:%s] has framebuffer, but [CRTC:%d] is off\n", 49162306a36Sopenharmony_ci connector->base.id, connector->name, 49262306a36Sopenharmony_ci state->crtc->base.id); 49362306a36Sopenharmony_ci return -EINVAL; 49462306a36Sopenharmony_ci } 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci if (!writeback_job->fb) { 49762306a36Sopenharmony_ci if (writeback_job->out_fence) { 49862306a36Sopenharmony_ci drm_dbg_atomic(connector->dev, 49962306a36Sopenharmony_ci "[CONNECTOR:%d:%s] requesting out-fence without framebuffer\n", 50062306a36Sopenharmony_ci connector->base.id, connector->name); 50162306a36Sopenharmony_ci return -EINVAL; 50262306a36Sopenharmony_ci } 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci drm_writeback_cleanup_job(writeback_job); 50562306a36Sopenharmony_ci state->writeback_job = NULL; 50662306a36Sopenharmony_ci } 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci return 0; 50962306a36Sopenharmony_ci} 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci/** 51262306a36Sopenharmony_ci * drm_atomic_get_plane_state - get plane state 51362306a36Sopenharmony_ci * @state: global atomic state object 51462306a36Sopenharmony_ci * @plane: plane to get state object for 51562306a36Sopenharmony_ci * 51662306a36Sopenharmony_ci * This function returns the plane state for the given plane, allocating it if 51762306a36Sopenharmony_ci * needed. It will also grab the relevant plane lock to make sure that the state 51862306a36Sopenharmony_ci * is consistent. 51962306a36Sopenharmony_ci * 52062306a36Sopenharmony_ci * Returns: 52162306a36Sopenharmony_ci * 52262306a36Sopenharmony_ci * Either the allocated state or the error code encoded into the pointer. When 52362306a36Sopenharmony_ci * the error is EDEADLK then the w/w mutex code has detected a deadlock and the 52462306a36Sopenharmony_ci * entire atomic sequence must be restarted. All other errors are fatal. 52562306a36Sopenharmony_ci */ 52662306a36Sopenharmony_cistruct drm_plane_state * 52762306a36Sopenharmony_cidrm_atomic_get_plane_state(struct drm_atomic_state *state, 52862306a36Sopenharmony_ci struct drm_plane *plane) 52962306a36Sopenharmony_ci{ 53062306a36Sopenharmony_ci int ret, index = drm_plane_index(plane); 53162306a36Sopenharmony_ci struct drm_plane_state *plane_state; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci WARN_ON(!state->acquire_ctx); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci /* the legacy pointers should never be set */ 53662306a36Sopenharmony_ci WARN_ON(plane->fb); 53762306a36Sopenharmony_ci WARN_ON(plane->old_fb); 53862306a36Sopenharmony_ci WARN_ON(plane->crtc); 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci plane_state = drm_atomic_get_existing_plane_state(state, plane); 54162306a36Sopenharmony_ci if (plane_state) 54262306a36Sopenharmony_ci return plane_state; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci ret = drm_modeset_lock(&plane->mutex, state->acquire_ctx); 54562306a36Sopenharmony_ci if (ret) 54662306a36Sopenharmony_ci return ERR_PTR(ret); 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci plane_state = plane->funcs->atomic_duplicate_state(plane); 54962306a36Sopenharmony_ci if (!plane_state) 55062306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci state->planes[index].state = plane_state; 55362306a36Sopenharmony_ci state->planes[index].ptr = plane; 55462306a36Sopenharmony_ci state->planes[index].old_state = plane->state; 55562306a36Sopenharmony_ci state->planes[index].new_state = plane_state; 55662306a36Sopenharmony_ci plane_state->state = state; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci drm_dbg_atomic(plane->dev, "Added [PLANE:%d:%s] %p state to %p\n", 55962306a36Sopenharmony_ci plane->base.id, plane->name, plane_state, state); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci if (plane_state->crtc) { 56262306a36Sopenharmony_ci struct drm_crtc_state *crtc_state; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci crtc_state = drm_atomic_get_crtc_state(state, 56562306a36Sopenharmony_ci plane_state->crtc); 56662306a36Sopenharmony_ci if (IS_ERR(crtc_state)) 56762306a36Sopenharmony_ci return ERR_CAST(crtc_state); 56862306a36Sopenharmony_ci } 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci return plane_state; 57162306a36Sopenharmony_ci} 57262306a36Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_get_plane_state); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_cistatic bool 57562306a36Sopenharmony_ciplane_switching_crtc(const struct drm_plane_state *old_plane_state, 57662306a36Sopenharmony_ci const struct drm_plane_state *new_plane_state) 57762306a36Sopenharmony_ci{ 57862306a36Sopenharmony_ci if (!old_plane_state->crtc || !new_plane_state->crtc) 57962306a36Sopenharmony_ci return false; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci if (old_plane_state->crtc == new_plane_state->crtc) 58262306a36Sopenharmony_ci return false; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci /* This could be refined, but currently there's no helper or driver code 58562306a36Sopenharmony_ci * to implement direct switching of active planes nor userspace to take 58662306a36Sopenharmony_ci * advantage of more direct plane switching without the intermediate 58762306a36Sopenharmony_ci * full OFF state. 58862306a36Sopenharmony_ci */ 58962306a36Sopenharmony_ci return true; 59062306a36Sopenharmony_ci} 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci/** 59362306a36Sopenharmony_ci * drm_atomic_plane_check - check plane state 59462306a36Sopenharmony_ci * @old_plane_state: old plane state to check 59562306a36Sopenharmony_ci * @new_plane_state: new plane state to check 59662306a36Sopenharmony_ci * 59762306a36Sopenharmony_ci * Provides core sanity checks for plane state. 59862306a36Sopenharmony_ci * 59962306a36Sopenharmony_ci * RETURNS: 60062306a36Sopenharmony_ci * Zero on success, error code on failure 60162306a36Sopenharmony_ci */ 60262306a36Sopenharmony_cistatic int drm_atomic_plane_check(const struct drm_plane_state *old_plane_state, 60362306a36Sopenharmony_ci const struct drm_plane_state *new_plane_state) 60462306a36Sopenharmony_ci{ 60562306a36Sopenharmony_ci struct drm_plane *plane = new_plane_state->plane; 60662306a36Sopenharmony_ci struct drm_crtc *crtc = new_plane_state->crtc; 60762306a36Sopenharmony_ci const struct drm_framebuffer *fb = new_plane_state->fb; 60862306a36Sopenharmony_ci unsigned int fb_width, fb_height; 60962306a36Sopenharmony_ci struct drm_mode_rect *clips; 61062306a36Sopenharmony_ci uint32_t num_clips; 61162306a36Sopenharmony_ci int ret; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci /* either *both* CRTC and FB must be set, or neither */ 61462306a36Sopenharmony_ci if (crtc && !fb) { 61562306a36Sopenharmony_ci drm_dbg_atomic(plane->dev, "[PLANE:%d:%s] CRTC set but no FB\n", 61662306a36Sopenharmony_ci plane->base.id, plane->name); 61762306a36Sopenharmony_ci return -EINVAL; 61862306a36Sopenharmony_ci } else if (fb && !crtc) { 61962306a36Sopenharmony_ci drm_dbg_atomic(plane->dev, "[PLANE:%d:%s] FB set but no CRTC\n", 62062306a36Sopenharmony_ci plane->base.id, plane->name); 62162306a36Sopenharmony_ci return -EINVAL; 62262306a36Sopenharmony_ci } 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci /* if disabled, we don't care about the rest of the state: */ 62562306a36Sopenharmony_ci if (!crtc) 62662306a36Sopenharmony_ci return 0; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci /* Check whether this plane is usable on this CRTC */ 62962306a36Sopenharmony_ci if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) { 63062306a36Sopenharmony_ci drm_dbg_atomic(plane->dev, 63162306a36Sopenharmony_ci "Invalid [CRTC:%d:%s] for [PLANE:%d:%s]\n", 63262306a36Sopenharmony_ci crtc->base.id, crtc->name, 63362306a36Sopenharmony_ci plane->base.id, plane->name); 63462306a36Sopenharmony_ci return -EINVAL; 63562306a36Sopenharmony_ci } 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci /* Check whether this plane supports the fb pixel format. */ 63862306a36Sopenharmony_ci ret = drm_plane_check_pixel_format(plane, fb->format->format, 63962306a36Sopenharmony_ci fb->modifier); 64062306a36Sopenharmony_ci if (ret) { 64162306a36Sopenharmony_ci drm_dbg_atomic(plane->dev, 64262306a36Sopenharmony_ci "[PLANE:%d:%s] invalid pixel format %p4cc, modifier 0x%llx\n", 64362306a36Sopenharmony_ci plane->base.id, plane->name, 64462306a36Sopenharmony_ci &fb->format->format, fb->modifier); 64562306a36Sopenharmony_ci return ret; 64662306a36Sopenharmony_ci } 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci /* Give drivers some help against integer overflows */ 64962306a36Sopenharmony_ci if (new_plane_state->crtc_w > INT_MAX || 65062306a36Sopenharmony_ci new_plane_state->crtc_x > INT_MAX - (int32_t) new_plane_state->crtc_w || 65162306a36Sopenharmony_ci new_plane_state->crtc_h > INT_MAX || 65262306a36Sopenharmony_ci new_plane_state->crtc_y > INT_MAX - (int32_t) new_plane_state->crtc_h) { 65362306a36Sopenharmony_ci drm_dbg_atomic(plane->dev, 65462306a36Sopenharmony_ci "[PLANE:%d:%s] invalid CRTC coordinates %ux%u+%d+%d\n", 65562306a36Sopenharmony_ci plane->base.id, plane->name, 65662306a36Sopenharmony_ci new_plane_state->crtc_w, new_plane_state->crtc_h, 65762306a36Sopenharmony_ci new_plane_state->crtc_x, new_plane_state->crtc_y); 65862306a36Sopenharmony_ci return -ERANGE; 65962306a36Sopenharmony_ci } 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci fb_width = fb->width << 16; 66262306a36Sopenharmony_ci fb_height = fb->height << 16; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci /* Make sure source coordinates are inside the fb. */ 66562306a36Sopenharmony_ci if (new_plane_state->src_w > fb_width || 66662306a36Sopenharmony_ci new_plane_state->src_x > fb_width - new_plane_state->src_w || 66762306a36Sopenharmony_ci new_plane_state->src_h > fb_height || 66862306a36Sopenharmony_ci new_plane_state->src_y > fb_height - new_plane_state->src_h) { 66962306a36Sopenharmony_ci drm_dbg_atomic(plane->dev, 67062306a36Sopenharmony_ci "[PLANE:%d:%s] invalid source coordinates " 67162306a36Sopenharmony_ci "%u.%06ux%u.%06u+%u.%06u+%u.%06u (fb %ux%u)\n", 67262306a36Sopenharmony_ci plane->base.id, plane->name, 67362306a36Sopenharmony_ci new_plane_state->src_w >> 16, 67462306a36Sopenharmony_ci ((new_plane_state->src_w & 0xffff) * 15625) >> 10, 67562306a36Sopenharmony_ci new_plane_state->src_h >> 16, 67662306a36Sopenharmony_ci ((new_plane_state->src_h & 0xffff) * 15625) >> 10, 67762306a36Sopenharmony_ci new_plane_state->src_x >> 16, 67862306a36Sopenharmony_ci ((new_plane_state->src_x & 0xffff) * 15625) >> 10, 67962306a36Sopenharmony_ci new_plane_state->src_y >> 16, 68062306a36Sopenharmony_ci ((new_plane_state->src_y & 0xffff) * 15625) >> 10, 68162306a36Sopenharmony_ci fb->width, fb->height); 68262306a36Sopenharmony_ci return -ENOSPC; 68362306a36Sopenharmony_ci } 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci clips = __drm_plane_get_damage_clips(new_plane_state); 68662306a36Sopenharmony_ci num_clips = drm_plane_get_damage_clips_count(new_plane_state); 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci /* Make sure damage clips are valid and inside the fb. */ 68962306a36Sopenharmony_ci while (num_clips > 0) { 69062306a36Sopenharmony_ci if (clips->x1 >= clips->x2 || 69162306a36Sopenharmony_ci clips->y1 >= clips->y2 || 69262306a36Sopenharmony_ci clips->x1 < 0 || 69362306a36Sopenharmony_ci clips->y1 < 0 || 69462306a36Sopenharmony_ci clips->x2 > fb_width || 69562306a36Sopenharmony_ci clips->y2 > fb_height) { 69662306a36Sopenharmony_ci drm_dbg_atomic(plane->dev, 69762306a36Sopenharmony_ci "[PLANE:%d:%s] invalid damage clip %d %d %d %d\n", 69862306a36Sopenharmony_ci plane->base.id, plane->name, clips->x1, 69962306a36Sopenharmony_ci clips->y1, clips->x2, clips->y2); 70062306a36Sopenharmony_ci return -EINVAL; 70162306a36Sopenharmony_ci } 70262306a36Sopenharmony_ci clips++; 70362306a36Sopenharmony_ci num_clips--; 70462306a36Sopenharmony_ci } 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci if (plane_switching_crtc(old_plane_state, new_plane_state)) { 70762306a36Sopenharmony_ci drm_dbg_atomic(plane->dev, 70862306a36Sopenharmony_ci "[PLANE:%d:%s] switching CRTC directly\n", 70962306a36Sopenharmony_ci plane->base.id, plane->name); 71062306a36Sopenharmony_ci return -EINVAL; 71162306a36Sopenharmony_ci } 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci return 0; 71462306a36Sopenharmony_ci} 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_cistatic void drm_atomic_plane_print_state(struct drm_printer *p, 71762306a36Sopenharmony_ci const struct drm_plane_state *state) 71862306a36Sopenharmony_ci{ 71962306a36Sopenharmony_ci struct drm_plane *plane = state->plane; 72062306a36Sopenharmony_ci struct drm_rect src = drm_plane_state_src(state); 72162306a36Sopenharmony_ci struct drm_rect dest = drm_plane_state_dest(state); 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci drm_printf(p, "plane[%u]: %s\n", plane->base.id, plane->name); 72462306a36Sopenharmony_ci drm_printf(p, "\tcrtc=%s\n", state->crtc ? state->crtc->name : "(null)"); 72562306a36Sopenharmony_ci drm_printf(p, "\tfb=%u\n", state->fb ? state->fb->base.id : 0); 72662306a36Sopenharmony_ci if (state->fb) 72762306a36Sopenharmony_ci drm_framebuffer_print_info(p, 2, state->fb); 72862306a36Sopenharmony_ci drm_printf(p, "\tcrtc-pos=" DRM_RECT_FMT "\n", DRM_RECT_ARG(&dest)); 72962306a36Sopenharmony_ci drm_printf(p, "\tsrc-pos=" DRM_RECT_FP_FMT "\n", DRM_RECT_FP_ARG(&src)); 73062306a36Sopenharmony_ci drm_printf(p, "\trotation=%x\n", state->rotation); 73162306a36Sopenharmony_ci drm_printf(p, "\tnormalized-zpos=%x\n", state->normalized_zpos); 73262306a36Sopenharmony_ci drm_printf(p, "\tcolor-encoding=%s\n", 73362306a36Sopenharmony_ci drm_get_color_encoding_name(state->color_encoding)); 73462306a36Sopenharmony_ci drm_printf(p, "\tcolor-range=%s\n", 73562306a36Sopenharmony_ci drm_get_color_range_name(state->color_range)); 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci if (plane->funcs->atomic_print_state) 73862306a36Sopenharmony_ci plane->funcs->atomic_print_state(p, state); 73962306a36Sopenharmony_ci} 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci/** 74262306a36Sopenharmony_ci * DOC: handling driver private state 74362306a36Sopenharmony_ci * 74462306a36Sopenharmony_ci * Very often the DRM objects exposed to userspace in the atomic modeset api 74562306a36Sopenharmony_ci * (&drm_connector, &drm_crtc and &drm_plane) do not map neatly to the 74662306a36Sopenharmony_ci * underlying hardware. Especially for any kind of shared resources (e.g. shared 74762306a36Sopenharmony_ci * clocks, scaler units, bandwidth and fifo limits shared among a group of 74862306a36Sopenharmony_ci * planes or CRTCs, and so on) it makes sense to model these as independent 74962306a36Sopenharmony_ci * objects. Drivers then need to do similar state tracking and commit ordering for 75062306a36Sopenharmony_ci * such private (since not exposed to userspace) objects as the atomic core and 75162306a36Sopenharmony_ci * helpers already provide for connectors, planes and CRTCs. 75262306a36Sopenharmony_ci * 75362306a36Sopenharmony_ci * To make this easier on drivers the atomic core provides some support to track 75462306a36Sopenharmony_ci * driver private state objects using struct &drm_private_obj, with the 75562306a36Sopenharmony_ci * associated state struct &drm_private_state. 75662306a36Sopenharmony_ci * 75762306a36Sopenharmony_ci * Similar to userspace-exposed objects, private state structures can be 75862306a36Sopenharmony_ci * acquired by calling drm_atomic_get_private_obj_state(). This also takes care 75962306a36Sopenharmony_ci * of locking, hence drivers should not have a need to call drm_modeset_lock() 76062306a36Sopenharmony_ci * directly. Sequence of the actual hardware state commit is not handled, 76162306a36Sopenharmony_ci * drivers might need to keep track of struct drm_crtc_commit within subclassed 76262306a36Sopenharmony_ci * structure of &drm_private_state as necessary, e.g. similar to 76362306a36Sopenharmony_ci * &drm_plane_state.commit. See also &drm_atomic_state.fake_commit. 76462306a36Sopenharmony_ci * 76562306a36Sopenharmony_ci * All private state structures contained in a &drm_atomic_state update can be 76662306a36Sopenharmony_ci * iterated using for_each_oldnew_private_obj_in_state(), 76762306a36Sopenharmony_ci * for_each_new_private_obj_in_state() and for_each_old_private_obj_in_state(). 76862306a36Sopenharmony_ci * Drivers are recommended to wrap these for each type of driver private state 76962306a36Sopenharmony_ci * object they have, filtering on &drm_private_obj.funcs using for_each_if(), at 77062306a36Sopenharmony_ci * least if they want to iterate over all objects of a given type. 77162306a36Sopenharmony_ci * 77262306a36Sopenharmony_ci * An earlier way to handle driver private state was by subclassing struct 77362306a36Sopenharmony_ci * &drm_atomic_state. But since that encourages non-standard ways to implement 77462306a36Sopenharmony_ci * the check/commit split atomic requires (by using e.g. "check and rollback or 77562306a36Sopenharmony_ci * commit instead" of "duplicate state, check, then either commit or release 77662306a36Sopenharmony_ci * duplicated state) it is deprecated in favour of using &drm_private_state. 77762306a36Sopenharmony_ci */ 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci/** 78062306a36Sopenharmony_ci * drm_atomic_private_obj_init - initialize private object 78162306a36Sopenharmony_ci * @dev: DRM device this object will be attached to 78262306a36Sopenharmony_ci * @obj: private object 78362306a36Sopenharmony_ci * @state: initial private object state 78462306a36Sopenharmony_ci * @funcs: pointer to the struct of function pointers that identify the object 78562306a36Sopenharmony_ci * type 78662306a36Sopenharmony_ci * 78762306a36Sopenharmony_ci * Initialize the private object, which can be embedded into any 78862306a36Sopenharmony_ci * driver private object that needs its own atomic state. 78962306a36Sopenharmony_ci */ 79062306a36Sopenharmony_civoid 79162306a36Sopenharmony_cidrm_atomic_private_obj_init(struct drm_device *dev, 79262306a36Sopenharmony_ci struct drm_private_obj *obj, 79362306a36Sopenharmony_ci struct drm_private_state *state, 79462306a36Sopenharmony_ci const struct drm_private_state_funcs *funcs) 79562306a36Sopenharmony_ci{ 79662306a36Sopenharmony_ci memset(obj, 0, sizeof(*obj)); 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci drm_modeset_lock_init(&obj->lock); 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci obj->state = state; 80162306a36Sopenharmony_ci obj->funcs = funcs; 80262306a36Sopenharmony_ci list_add_tail(&obj->head, &dev->mode_config.privobj_list); 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci state->obj = obj; 80562306a36Sopenharmony_ci} 80662306a36Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_private_obj_init); 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci/** 80962306a36Sopenharmony_ci * drm_atomic_private_obj_fini - finalize private object 81062306a36Sopenharmony_ci * @obj: private object 81162306a36Sopenharmony_ci * 81262306a36Sopenharmony_ci * Finalize the private object. 81362306a36Sopenharmony_ci */ 81462306a36Sopenharmony_civoid 81562306a36Sopenharmony_cidrm_atomic_private_obj_fini(struct drm_private_obj *obj) 81662306a36Sopenharmony_ci{ 81762306a36Sopenharmony_ci list_del(&obj->head); 81862306a36Sopenharmony_ci obj->funcs->atomic_destroy_state(obj, obj->state); 81962306a36Sopenharmony_ci drm_modeset_lock_fini(&obj->lock); 82062306a36Sopenharmony_ci} 82162306a36Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_private_obj_fini); 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci/** 82462306a36Sopenharmony_ci * drm_atomic_get_private_obj_state - get private object state 82562306a36Sopenharmony_ci * @state: global atomic state 82662306a36Sopenharmony_ci * @obj: private object to get the state for 82762306a36Sopenharmony_ci * 82862306a36Sopenharmony_ci * This function returns the private object state for the given private object, 82962306a36Sopenharmony_ci * allocating the state if needed. It will also grab the relevant private 83062306a36Sopenharmony_ci * object lock to make sure that the state is consistent. 83162306a36Sopenharmony_ci * 83262306a36Sopenharmony_ci * RETURNS: 83362306a36Sopenharmony_ci * 83462306a36Sopenharmony_ci * Either the allocated state or the error code encoded into a pointer. 83562306a36Sopenharmony_ci */ 83662306a36Sopenharmony_cistruct drm_private_state * 83762306a36Sopenharmony_cidrm_atomic_get_private_obj_state(struct drm_atomic_state *state, 83862306a36Sopenharmony_ci struct drm_private_obj *obj) 83962306a36Sopenharmony_ci{ 84062306a36Sopenharmony_ci int index, num_objs, i, ret; 84162306a36Sopenharmony_ci size_t size; 84262306a36Sopenharmony_ci struct __drm_private_objs_state *arr; 84362306a36Sopenharmony_ci struct drm_private_state *obj_state; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci for (i = 0; i < state->num_private_objs; i++) 84662306a36Sopenharmony_ci if (obj == state->private_objs[i].ptr) 84762306a36Sopenharmony_ci return state->private_objs[i].state; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci ret = drm_modeset_lock(&obj->lock, state->acquire_ctx); 85062306a36Sopenharmony_ci if (ret) 85162306a36Sopenharmony_ci return ERR_PTR(ret); 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci num_objs = state->num_private_objs + 1; 85462306a36Sopenharmony_ci size = sizeof(*state->private_objs) * num_objs; 85562306a36Sopenharmony_ci arr = krealloc(state->private_objs, size, GFP_KERNEL); 85662306a36Sopenharmony_ci if (!arr) 85762306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci state->private_objs = arr; 86062306a36Sopenharmony_ci index = state->num_private_objs; 86162306a36Sopenharmony_ci memset(&state->private_objs[index], 0, sizeof(*state->private_objs)); 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci obj_state = obj->funcs->atomic_duplicate_state(obj); 86462306a36Sopenharmony_ci if (!obj_state) 86562306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci state->private_objs[index].state = obj_state; 86862306a36Sopenharmony_ci state->private_objs[index].old_state = obj->state; 86962306a36Sopenharmony_ci state->private_objs[index].new_state = obj_state; 87062306a36Sopenharmony_ci state->private_objs[index].ptr = obj; 87162306a36Sopenharmony_ci obj_state->state = state; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci state->num_private_objs = num_objs; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci drm_dbg_atomic(state->dev, 87662306a36Sopenharmony_ci "Added new private object %p state %p to %p\n", 87762306a36Sopenharmony_ci obj, obj_state, state); 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci return obj_state; 88062306a36Sopenharmony_ci} 88162306a36Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_get_private_obj_state); 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci/** 88462306a36Sopenharmony_ci * drm_atomic_get_old_private_obj_state 88562306a36Sopenharmony_ci * @state: global atomic state object 88662306a36Sopenharmony_ci * @obj: private_obj to grab 88762306a36Sopenharmony_ci * 88862306a36Sopenharmony_ci * This function returns the old private object state for the given private_obj, 88962306a36Sopenharmony_ci * or NULL if the private_obj is not part of the global atomic state. 89062306a36Sopenharmony_ci */ 89162306a36Sopenharmony_cistruct drm_private_state * 89262306a36Sopenharmony_cidrm_atomic_get_old_private_obj_state(const struct drm_atomic_state *state, 89362306a36Sopenharmony_ci struct drm_private_obj *obj) 89462306a36Sopenharmony_ci{ 89562306a36Sopenharmony_ci int i; 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci for (i = 0; i < state->num_private_objs; i++) 89862306a36Sopenharmony_ci if (obj == state->private_objs[i].ptr) 89962306a36Sopenharmony_ci return state->private_objs[i].old_state; 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci return NULL; 90262306a36Sopenharmony_ci} 90362306a36Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_get_old_private_obj_state); 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci/** 90662306a36Sopenharmony_ci * drm_atomic_get_new_private_obj_state 90762306a36Sopenharmony_ci * @state: global atomic state object 90862306a36Sopenharmony_ci * @obj: private_obj to grab 90962306a36Sopenharmony_ci * 91062306a36Sopenharmony_ci * This function returns the new private object state for the given private_obj, 91162306a36Sopenharmony_ci * or NULL if the private_obj is not part of the global atomic state. 91262306a36Sopenharmony_ci */ 91362306a36Sopenharmony_cistruct drm_private_state * 91462306a36Sopenharmony_cidrm_atomic_get_new_private_obj_state(const struct drm_atomic_state *state, 91562306a36Sopenharmony_ci struct drm_private_obj *obj) 91662306a36Sopenharmony_ci{ 91762306a36Sopenharmony_ci int i; 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci for (i = 0; i < state->num_private_objs; i++) 92062306a36Sopenharmony_ci if (obj == state->private_objs[i].ptr) 92162306a36Sopenharmony_ci return state->private_objs[i].new_state; 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci return NULL; 92462306a36Sopenharmony_ci} 92562306a36Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_get_new_private_obj_state); 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci/** 92862306a36Sopenharmony_ci * drm_atomic_get_old_connector_for_encoder - Get old connector for an encoder 92962306a36Sopenharmony_ci * @state: Atomic state 93062306a36Sopenharmony_ci * @encoder: The encoder to fetch the connector state for 93162306a36Sopenharmony_ci * 93262306a36Sopenharmony_ci * This function finds and returns the connector that was connected to @encoder 93362306a36Sopenharmony_ci * as specified by the @state. 93462306a36Sopenharmony_ci * 93562306a36Sopenharmony_ci * If there is no connector in @state which previously had @encoder connected to 93662306a36Sopenharmony_ci * it, this function will return NULL. While this may seem like an invalid use 93762306a36Sopenharmony_ci * case, it is sometimes useful to differentiate commits which had no prior 93862306a36Sopenharmony_ci * connectors attached to @encoder vs ones that did (and to inspect their 93962306a36Sopenharmony_ci * state). This is especially true in enable hooks because the pipeline has 94062306a36Sopenharmony_ci * changed. 94162306a36Sopenharmony_ci * 94262306a36Sopenharmony_ci * Returns: The old connector connected to @encoder, or NULL if the encoder is 94362306a36Sopenharmony_ci * not connected. 94462306a36Sopenharmony_ci */ 94562306a36Sopenharmony_cistruct drm_connector * 94662306a36Sopenharmony_cidrm_atomic_get_old_connector_for_encoder(const struct drm_atomic_state *state, 94762306a36Sopenharmony_ci struct drm_encoder *encoder) 94862306a36Sopenharmony_ci{ 94962306a36Sopenharmony_ci struct drm_connector_state *conn_state; 95062306a36Sopenharmony_ci struct drm_connector *connector; 95162306a36Sopenharmony_ci unsigned int i; 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci for_each_old_connector_in_state(state, connector, conn_state, i) { 95462306a36Sopenharmony_ci if (conn_state->best_encoder == encoder) 95562306a36Sopenharmony_ci return connector; 95662306a36Sopenharmony_ci } 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci return NULL; 95962306a36Sopenharmony_ci} 96062306a36Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_get_old_connector_for_encoder); 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci/** 96362306a36Sopenharmony_ci * drm_atomic_get_new_connector_for_encoder - Get new connector for an encoder 96462306a36Sopenharmony_ci * @state: Atomic state 96562306a36Sopenharmony_ci * @encoder: The encoder to fetch the connector state for 96662306a36Sopenharmony_ci * 96762306a36Sopenharmony_ci * This function finds and returns the connector that will be connected to 96862306a36Sopenharmony_ci * @encoder as specified by the @state. 96962306a36Sopenharmony_ci * 97062306a36Sopenharmony_ci * If there is no connector in @state which will have @encoder connected to it, 97162306a36Sopenharmony_ci * this function will return NULL. While this may seem like an invalid use case, 97262306a36Sopenharmony_ci * it is sometimes useful to differentiate commits which have no connectors 97362306a36Sopenharmony_ci * attached to @encoder vs ones that do (and to inspect their state). This is 97462306a36Sopenharmony_ci * especially true in disable hooks because the pipeline will change. 97562306a36Sopenharmony_ci * 97662306a36Sopenharmony_ci * Returns: The new connector connected to @encoder, or NULL if the encoder is 97762306a36Sopenharmony_ci * not connected. 97862306a36Sopenharmony_ci */ 97962306a36Sopenharmony_cistruct drm_connector * 98062306a36Sopenharmony_cidrm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state, 98162306a36Sopenharmony_ci struct drm_encoder *encoder) 98262306a36Sopenharmony_ci{ 98362306a36Sopenharmony_ci struct drm_connector_state *conn_state; 98462306a36Sopenharmony_ci struct drm_connector *connector; 98562306a36Sopenharmony_ci unsigned int i; 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci for_each_new_connector_in_state(state, connector, conn_state, i) { 98862306a36Sopenharmony_ci if (conn_state->best_encoder == encoder) 98962306a36Sopenharmony_ci return connector; 99062306a36Sopenharmony_ci } 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci return NULL; 99362306a36Sopenharmony_ci} 99462306a36Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder); 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci/** 99762306a36Sopenharmony_ci * drm_atomic_get_old_crtc_for_encoder - Get old crtc for an encoder 99862306a36Sopenharmony_ci * @state: Atomic state 99962306a36Sopenharmony_ci * @encoder: The encoder to fetch the crtc state for 100062306a36Sopenharmony_ci * 100162306a36Sopenharmony_ci * This function finds and returns the crtc that was connected to @encoder 100262306a36Sopenharmony_ci * as specified by the @state. 100362306a36Sopenharmony_ci * 100462306a36Sopenharmony_ci * Returns: The old crtc connected to @encoder, or NULL if the encoder is 100562306a36Sopenharmony_ci * not connected. 100662306a36Sopenharmony_ci */ 100762306a36Sopenharmony_cistruct drm_crtc * 100862306a36Sopenharmony_cidrm_atomic_get_old_crtc_for_encoder(struct drm_atomic_state *state, 100962306a36Sopenharmony_ci struct drm_encoder *encoder) 101062306a36Sopenharmony_ci{ 101162306a36Sopenharmony_ci struct drm_connector *connector; 101262306a36Sopenharmony_ci struct drm_connector_state *conn_state; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci connector = drm_atomic_get_old_connector_for_encoder(state, encoder); 101562306a36Sopenharmony_ci if (!connector) 101662306a36Sopenharmony_ci return NULL; 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci conn_state = drm_atomic_get_old_connector_state(state, connector); 101962306a36Sopenharmony_ci if (!conn_state) 102062306a36Sopenharmony_ci return NULL; 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci return conn_state->crtc; 102362306a36Sopenharmony_ci} 102462306a36Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_get_old_crtc_for_encoder); 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci/** 102762306a36Sopenharmony_ci * drm_atomic_get_new_crtc_for_encoder - Get new crtc for an encoder 102862306a36Sopenharmony_ci * @state: Atomic state 102962306a36Sopenharmony_ci * @encoder: The encoder to fetch the crtc state for 103062306a36Sopenharmony_ci * 103162306a36Sopenharmony_ci * This function finds and returns the crtc that will be connected to @encoder 103262306a36Sopenharmony_ci * as specified by the @state. 103362306a36Sopenharmony_ci * 103462306a36Sopenharmony_ci * Returns: The new crtc connected to @encoder, or NULL if the encoder is 103562306a36Sopenharmony_ci * not connected. 103662306a36Sopenharmony_ci */ 103762306a36Sopenharmony_cistruct drm_crtc * 103862306a36Sopenharmony_cidrm_atomic_get_new_crtc_for_encoder(struct drm_atomic_state *state, 103962306a36Sopenharmony_ci struct drm_encoder *encoder) 104062306a36Sopenharmony_ci{ 104162306a36Sopenharmony_ci struct drm_connector *connector; 104262306a36Sopenharmony_ci struct drm_connector_state *conn_state; 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci connector = drm_atomic_get_new_connector_for_encoder(state, encoder); 104562306a36Sopenharmony_ci if (!connector) 104662306a36Sopenharmony_ci return NULL; 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci conn_state = drm_atomic_get_new_connector_state(state, connector); 104962306a36Sopenharmony_ci if (!conn_state) 105062306a36Sopenharmony_ci return NULL; 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci return conn_state->crtc; 105362306a36Sopenharmony_ci} 105462306a36Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_get_new_crtc_for_encoder); 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci/** 105762306a36Sopenharmony_ci * drm_atomic_get_connector_state - get connector state 105862306a36Sopenharmony_ci * @state: global atomic state object 105962306a36Sopenharmony_ci * @connector: connector to get state object for 106062306a36Sopenharmony_ci * 106162306a36Sopenharmony_ci * This function returns the connector state for the given connector, 106262306a36Sopenharmony_ci * allocating it if needed. It will also grab the relevant connector lock to 106362306a36Sopenharmony_ci * make sure that the state is consistent. 106462306a36Sopenharmony_ci * 106562306a36Sopenharmony_ci * Returns: 106662306a36Sopenharmony_ci * 106762306a36Sopenharmony_ci * Either the allocated state or the error code encoded into the pointer. When 106862306a36Sopenharmony_ci * the error is EDEADLK then the w/w mutex code has detected a deadlock and the 106962306a36Sopenharmony_ci * entire atomic sequence must be restarted. All other errors are fatal. 107062306a36Sopenharmony_ci */ 107162306a36Sopenharmony_cistruct drm_connector_state * 107262306a36Sopenharmony_cidrm_atomic_get_connector_state(struct drm_atomic_state *state, 107362306a36Sopenharmony_ci struct drm_connector *connector) 107462306a36Sopenharmony_ci{ 107562306a36Sopenharmony_ci int ret, index; 107662306a36Sopenharmony_ci struct drm_mode_config *config = &connector->dev->mode_config; 107762306a36Sopenharmony_ci struct drm_connector_state *connector_state; 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci WARN_ON(!state->acquire_ctx); 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci ret = drm_modeset_lock(&config->connection_mutex, state->acquire_ctx); 108262306a36Sopenharmony_ci if (ret) 108362306a36Sopenharmony_ci return ERR_PTR(ret); 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci index = drm_connector_index(connector); 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci if (index >= state->num_connector) { 108862306a36Sopenharmony_ci struct __drm_connnectors_state *c; 108962306a36Sopenharmony_ci int alloc = max(index + 1, config->num_connector); 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci c = krealloc_array(state->connectors, alloc, 109262306a36Sopenharmony_ci sizeof(*state->connectors), GFP_KERNEL); 109362306a36Sopenharmony_ci if (!c) 109462306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci state->connectors = c; 109762306a36Sopenharmony_ci memset(&state->connectors[state->num_connector], 0, 109862306a36Sopenharmony_ci sizeof(*state->connectors) * (alloc - state->num_connector)); 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci state->num_connector = alloc; 110162306a36Sopenharmony_ci } 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci if (state->connectors[index].state) 110462306a36Sopenharmony_ci return state->connectors[index].state; 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci connector_state = connector->funcs->atomic_duplicate_state(connector); 110762306a36Sopenharmony_ci if (!connector_state) 110862306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci drm_connector_get(connector); 111162306a36Sopenharmony_ci state->connectors[index].state = connector_state; 111262306a36Sopenharmony_ci state->connectors[index].old_state = connector->state; 111362306a36Sopenharmony_ci state->connectors[index].new_state = connector_state; 111462306a36Sopenharmony_ci state->connectors[index].ptr = connector; 111562306a36Sopenharmony_ci connector_state->state = state; 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci drm_dbg_atomic(connector->dev, "Added [CONNECTOR:%d:%s] %p state to %p\n", 111862306a36Sopenharmony_ci connector->base.id, connector->name, 111962306a36Sopenharmony_ci connector_state, state); 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci if (connector_state->crtc) { 112262306a36Sopenharmony_ci struct drm_crtc_state *crtc_state; 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci crtc_state = drm_atomic_get_crtc_state(state, 112562306a36Sopenharmony_ci connector_state->crtc); 112662306a36Sopenharmony_ci if (IS_ERR(crtc_state)) 112762306a36Sopenharmony_ci return ERR_CAST(crtc_state); 112862306a36Sopenharmony_ci } 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci return connector_state; 113162306a36Sopenharmony_ci} 113262306a36Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_get_connector_state); 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_cistatic void drm_atomic_connector_print_state(struct drm_printer *p, 113562306a36Sopenharmony_ci const struct drm_connector_state *state) 113662306a36Sopenharmony_ci{ 113762306a36Sopenharmony_ci struct drm_connector *connector = state->connector; 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci drm_printf(p, "connector[%u]: %s\n", connector->base.id, connector->name); 114062306a36Sopenharmony_ci drm_printf(p, "\tcrtc=%s\n", state->crtc ? state->crtc->name : "(null)"); 114162306a36Sopenharmony_ci drm_printf(p, "\tself_refresh_aware=%d\n", state->self_refresh_aware); 114262306a36Sopenharmony_ci drm_printf(p, "\tmax_requested_bpc=%d\n", state->max_requested_bpc); 114362306a36Sopenharmony_ci drm_printf(p, "\tcolorspace=%s\n", drm_get_colorspace_name(state->colorspace)); 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) 114662306a36Sopenharmony_ci if (state->writeback_job && state->writeback_job->fb) 114762306a36Sopenharmony_ci drm_printf(p, "\tfb=%d\n", state->writeback_job->fb->base.id); 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci if (connector->funcs->atomic_print_state) 115062306a36Sopenharmony_ci connector->funcs->atomic_print_state(p, state); 115162306a36Sopenharmony_ci} 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci/** 115462306a36Sopenharmony_ci * drm_atomic_get_bridge_state - get bridge state 115562306a36Sopenharmony_ci * @state: global atomic state object 115662306a36Sopenharmony_ci * @bridge: bridge to get state object for 115762306a36Sopenharmony_ci * 115862306a36Sopenharmony_ci * This function returns the bridge state for the given bridge, allocating it 115962306a36Sopenharmony_ci * if needed. It will also grab the relevant bridge lock to make sure that the 116062306a36Sopenharmony_ci * state is consistent. 116162306a36Sopenharmony_ci * 116262306a36Sopenharmony_ci * Returns: 116362306a36Sopenharmony_ci * 116462306a36Sopenharmony_ci * Either the allocated state or the error code encoded into the pointer. When 116562306a36Sopenharmony_ci * the error is EDEADLK then the w/w mutex code has detected a deadlock and the 116662306a36Sopenharmony_ci * entire atomic sequence must be restarted. 116762306a36Sopenharmony_ci */ 116862306a36Sopenharmony_cistruct drm_bridge_state * 116962306a36Sopenharmony_cidrm_atomic_get_bridge_state(struct drm_atomic_state *state, 117062306a36Sopenharmony_ci struct drm_bridge *bridge) 117162306a36Sopenharmony_ci{ 117262306a36Sopenharmony_ci struct drm_private_state *obj_state; 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci obj_state = drm_atomic_get_private_obj_state(state, &bridge->base); 117562306a36Sopenharmony_ci if (IS_ERR(obj_state)) 117662306a36Sopenharmony_ci return ERR_CAST(obj_state); 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci return drm_priv_to_bridge_state(obj_state); 117962306a36Sopenharmony_ci} 118062306a36Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_get_bridge_state); 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci/** 118362306a36Sopenharmony_ci * drm_atomic_get_old_bridge_state - get old bridge state, if it exists 118462306a36Sopenharmony_ci * @state: global atomic state object 118562306a36Sopenharmony_ci * @bridge: bridge to grab 118662306a36Sopenharmony_ci * 118762306a36Sopenharmony_ci * This function returns the old bridge state for the given bridge, or NULL if 118862306a36Sopenharmony_ci * the bridge is not part of the global atomic state. 118962306a36Sopenharmony_ci */ 119062306a36Sopenharmony_cistruct drm_bridge_state * 119162306a36Sopenharmony_cidrm_atomic_get_old_bridge_state(const struct drm_atomic_state *state, 119262306a36Sopenharmony_ci struct drm_bridge *bridge) 119362306a36Sopenharmony_ci{ 119462306a36Sopenharmony_ci struct drm_private_state *obj_state; 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci obj_state = drm_atomic_get_old_private_obj_state(state, &bridge->base); 119762306a36Sopenharmony_ci if (!obj_state) 119862306a36Sopenharmony_ci return NULL; 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci return drm_priv_to_bridge_state(obj_state); 120162306a36Sopenharmony_ci} 120262306a36Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_get_old_bridge_state); 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci/** 120562306a36Sopenharmony_ci * drm_atomic_get_new_bridge_state - get new bridge state, if it exists 120662306a36Sopenharmony_ci * @state: global atomic state object 120762306a36Sopenharmony_ci * @bridge: bridge to grab 120862306a36Sopenharmony_ci * 120962306a36Sopenharmony_ci * This function returns the new bridge state for the given bridge, or NULL if 121062306a36Sopenharmony_ci * the bridge is not part of the global atomic state. 121162306a36Sopenharmony_ci */ 121262306a36Sopenharmony_cistruct drm_bridge_state * 121362306a36Sopenharmony_cidrm_atomic_get_new_bridge_state(const struct drm_atomic_state *state, 121462306a36Sopenharmony_ci struct drm_bridge *bridge) 121562306a36Sopenharmony_ci{ 121662306a36Sopenharmony_ci struct drm_private_state *obj_state; 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci obj_state = drm_atomic_get_new_private_obj_state(state, &bridge->base); 121962306a36Sopenharmony_ci if (!obj_state) 122062306a36Sopenharmony_ci return NULL; 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci return drm_priv_to_bridge_state(obj_state); 122362306a36Sopenharmony_ci} 122462306a36Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_get_new_bridge_state); 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci/** 122762306a36Sopenharmony_ci * drm_atomic_add_encoder_bridges - add bridges attached to an encoder 122862306a36Sopenharmony_ci * @state: atomic state 122962306a36Sopenharmony_ci * @encoder: DRM encoder 123062306a36Sopenharmony_ci * 123162306a36Sopenharmony_ci * This function adds all bridges attached to @encoder. This is needed to add 123262306a36Sopenharmony_ci * bridge states to @state and make them available when 123362306a36Sopenharmony_ci * &drm_bridge_funcs.atomic_check(), &drm_bridge_funcs.atomic_pre_enable(), 123462306a36Sopenharmony_ci * &drm_bridge_funcs.atomic_enable(), 123562306a36Sopenharmony_ci * &drm_bridge_funcs.atomic_disable_post_disable() are called. 123662306a36Sopenharmony_ci * 123762306a36Sopenharmony_ci * Returns: 123862306a36Sopenharmony_ci * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK 123962306a36Sopenharmony_ci * then the w/w mutex code has detected a deadlock and the entire atomic 124062306a36Sopenharmony_ci * sequence must be restarted. All other errors are fatal. 124162306a36Sopenharmony_ci */ 124262306a36Sopenharmony_ciint 124362306a36Sopenharmony_cidrm_atomic_add_encoder_bridges(struct drm_atomic_state *state, 124462306a36Sopenharmony_ci struct drm_encoder *encoder) 124562306a36Sopenharmony_ci{ 124662306a36Sopenharmony_ci struct drm_bridge_state *bridge_state; 124762306a36Sopenharmony_ci struct drm_bridge *bridge; 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci if (!encoder) 125062306a36Sopenharmony_ci return 0; 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci drm_dbg_atomic(encoder->dev, 125362306a36Sopenharmony_ci "Adding all bridges for [encoder:%d:%s] to %p\n", 125462306a36Sopenharmony_ci encoder->base.id, encoder->name, state); 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci drm_for_each_bridge_in_chain(encoder, bridge) { 125762306a36Sopenharmony_ci /* Skip bridges that don't implement the atomic state hooks. */ 125862306a36Sopenharmony_ci if (!bridge->funcs->atomic_duplicate_state) 125962306a36Sopenharmony_ci continue; 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci bridge_state = drm_atomic_get_bridge_state(state, bridge); 126262306a36Sopenharmony_ci if (IS_ERR(bridge_state)) 126362306a36Sopenharmony_ci return PTR_ERR(bridge_state); 126462306a36Sopenharmony_ci } 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci return 0; 126762306a36Sopenharmony_ci} 126862306a36Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_add_encoder_bridges); 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci/** 127162306a36Sopenharmony_ci * drm_atomic_add_affected_connectors - add connectors for CRTC 127262306a36Sopenharmony_ci * @state: atomic state 127362306a36Sopenharmony_ci * @crtc: DRM CRTC 127462306a36Sopenharmony_ci * 127562306a36Sopenharmony_ci * This function walks the current configuration and adds all connectors 127662306a36Sopenharmony_ci * currently using @crtc to the atomic configuration @state. Note that this 127762306a36Sopenharmony_ci * function must acquire the connection mutex. This can potentially cause 127862306a36Sopenharmony_ci * unneeded serialization if the update is just for the planes on one CRTC. Hence 127962306a36Sopenharmony_ci * drivers and helpers should only call this when really needed (e.g. when a 128062306a36Sopenharmony_ci * full modeset needs to happen due to some change). 128162306a36Sopenharmony_ci * 128262306a36Sopenharmony_ci * Returns: 128362306a36Sopenharmony_ci * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK 128462306a36Sopenharmony_ci * then the w/w mutex code has detected a deadlock and the entire atomic 128562306a36Sopenharmony_ci * sequence must be restarted. All other errors are fatal. 128662306a36Sopenharmony_ci */ 128762306a36Sopenharmony_ciint 128862306a36Sopenharmony_cidrm_atomic_add_affected_connectors(struct drm_atomic_state *state, 128962306a36Sopenharmony_ci struct drm_crtc *crtc) 129062306a36Sopenharmony_ci{ 129162306a36Sopenharmony_ci struct drm_mode_config *config = &state->dev->mode_config; 129262306a36Sopenharmony_ci struct drm_connector *connector; 129362306a36Sopenharmony_ci struct drm_connector_state *conn_state; 129462306a36Sopenharmony_ci struct drm_connector_list_iter conn_iter; 129562306a36Sopenharmony_ci struct drm_crtc_state *crtc_state; 129662306a36Sopenharmony_ci int ret; 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci crtc_state = drm_atomic_get_crtc_state(state, crtc); 129962306a36Sopenharmony_ci if (IS_ERR(crtc_state)) 130062306a36Sopenharmony_ci return PTR_ERR(crtc_state); 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci ret = drm_modeset_lock(&config->connection_mutex, state->acquire_ctx); 130362306a36Sopenharmony_ci if (ret) 130462306a36Sopenharmony_ci return ret; 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci drm_dbg_atomic(crtc->dev, 130762306a36Sopenharmony_ci "Adding all current connectors for [CRTC:%d:%s] to %p\n", 130862306a36Sopenharmony_ci crtc->base.id, crtc->name, state); 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci /* 131162306a36Sopenharmony_ci * Changed connectors are already in @state, so only need to look 131262306a36Sopenharmony_ci * at the connector_mask in crtc_state. 131362306a36Sopenharmony_ci */ 131462306a36Sopenharmony_ci drm_connector_list_iter_begin(state->dev, &conn_iter); 131562306a36Sopenharmony_ci drm_for_each_connector_iter(connector, &conn_iter) { 131662306a36Sopenharmony_ci if (!(crtc_state->connector_mask & drm_connector_mask(connector))) 131762306a36Sopenharmony_ci continue; 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci conn_state = drm_atomic_get_connector_state(state, connector); 132062306a36Sopenharmony_ci if (IS_ERR(conn_state)) { 132162306a36Sopenharmony_ci drm_connector_list_iter_end(&conn_iter); 132262306a36Sopenharmony_ci return PTR_ERR(conn_state); 132362306a36Sopenharmony_ci } 132462306a36Sopenharmony_ci } 132562306a36Sopenharmony_ci drm_connector_list_iter_end(&conn_iter); 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci return 0; 132862306a36Sopenharmony_ci} 132962306a36Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_add_affected_connectors); 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci/** 133262306a36Sopenharmony_ci * drm_atomic_add_affected_planes - add planes for CRTC 133362306a36Sopenharmony_ci * @state: atomic state 133462306a36Sopenharmony_ci * @crtc: DRM CRTC 133562306a36Sopenharmony_ci * 133662306a36Sopenharmony_ci * This function walks the current configuration and adds all planes 133762306a36Sopenharmony_ci * currently used by @crtc to the atomic configuration @state. This is useful 133862306a36Sopenharmony_ci * when an atomic commit also needs to check all currently enabled plane on 133962306a36Sopenharmony_ci * @crtc, e.g. when changing the mode. It's also useful when re-enabling a CRTC 134062306a36Sopenharmony_ci * to avoid special code to force-enable all planes. 134162306a36Sopenharmony_ci * 134262306a36Sopenharmony_ci * Since acquiring a plane state will always also acquire the w/w mutex of the 134362306a36Sopenharmony_ci * current CRTC for that plane (if there is any) adding all the plane states for 134462306a36Sopenharmony_ci * a CRTC will not reduce parallelism of atomic updates. 134562306a36Sopenharmony_ci * 134662306a36Sopenharmony_ci * Returns: 134762306a36Sopenharmony_ci * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK 134862306a36Sopenharmony_ci * then the w/w mutex code has detected a deadlock and the entire atomic 134962306a36Sopenharmony_ci * sequence must be restarted. All other errors are fatal. 135062306a36Sopenharmony_ci */ 135162306a36Sopenharmony_ciint 135262306a36Sopenharmony_cidrm_atomic_add_affected_planes(struct drm_atomic_state *state, 135362306a36Sopenharmony_ci struct drm_crtc *crtc) 135462306a36Sopenharmony_ci{ 135562306a36Sopenharmony_ci const struct drm_crtc_state *old_crtc_state = 135662306a36Sopenharmony_ci drm_atomic_get_old_crtc_state(state, crtc); 135762306a36Sopenharmony_ci struct drm_plane *plane; 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ci WARN_ON(!drm_atomic_get_new_crtc_state(state, crtc)); 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ci drm_dbg_atomic(crtc->dev, 136262306a36Sopenharmony_ci "Adding all current planes for [CRTC:%d:%s] to %p\n", 136362306a36Sopenharmony_ci crtc->base.id, crtc->name, state); 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci drm_for_each_plane_mask(plane, state->dev, old_crtc_state->plane_mask) { 136662306a36Sopenharmony_ci struct drm_plane_state *plane_state = 136762306a36Sopenharmony_ci drm_atomic_get_plane_state(state, plane); 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci if (IS_ERR(plane_state)) 137062306a36Sopenharmony_ci return PTR_ERR(plane_state); 137162306a36Sopenharmony_ci } 137262306a36Sopenharmony_ci return 0; 137362306a36Sopenharmony_ci} 137462306a36Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_add_affected_planes); 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci/** 137762306a36Sopenharmony_ci * drm_atomic_check_only - check whether a given config would work 137862306a36Sopenharmony_ci * @state: atomic configuration to check 137962306a36Sopenharmony_ci * 138062306a36Sopenharmony_ci * Note that this function can return -EDEADLK if the driver needed to acquire 138162306a36Sopenharmony_ci * more locks but encountered a deadlock. The caller must then do the usual w/w 138262306a36Sopenharmony_ci * backoff dance and restart. All other errors are fatal. 138362306a36Sopenharmony_ci * 138462306a36Sopenharmony_ci * Returns: 138562306a36Sopenharmony_ci * 0 on success, negative error code on failure. 138662306a36Sopenharmony_ci */ 138762306a36Sopenharmony_ciint drm_atomic_check_only(struct drm_atomic_state *state) 138862306a36Sopenharmony_ci{ 138962306a36Sopenharmony_ci struct drm_device *dev = state->dev; 139062306a36Sopenharmony_ci struct drm_mode_config *config = &dev->mode_config; 139162306a36Sopenharmony_ci struct drm_plane *plane; 139262306a36Sopenharmony_ci struct drm_plane_state *old_plane_state; 139362306a36Sopenharmony_ci struct drm_plane_state *new_plane_state; 139462306a36Sopenharmony_ci struct drm_crtc *crtc; 139562306a36Sopenharmony_ci struct drm_crtc_state *old_crtc_state; 139662306a36Sopenharmony_ci struct drm_crtc_state *new_crtc_state; 139762306a36Sopenharmony_ci struct drm_connector *conn; 139862306a36Sopenharmony_ci struct drm_connector_state *conn_state; 139962306a36Sopenharmony_ci unsigned int requested_crtc = 0; 140062306a36Sopenharmony_ci unsigned int affected_crtc = 0; 140162306a36Sopenharmony_ci int i, ret = 0; 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci drm_dbg_atomic(dev, "checking %p\n", state); 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) { 140662306a36Sopenharmony_ci if (new_crtc_state->enable) 140762306a36Sopenharmony_ci requested_crtc |= drm_crtc_mask(crtc); 140862306a36Sopenharmony_ci } 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) { 141162306a36Sopenharmony_ci ret = drm_atomic_plane_check(old_plane_state, new_plane_state); 141262306a36Sopenharmony_ci if (ret) { 141362306a36Sopenharmony_ci drm_dbg_atomic(dev, "[PLANE:%d:%s] atomic core check failed\n", 141462306a36Sopenharmony_ci plane->base.id, plane->name); 141562306a36Sopenharmony_ci return ret; 141662306a36Sopenharmony_ci } 141762306a36Sopenharmony_ci } 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { 142062306a36Sopenharmony_ci ret = drm_atomic_crtc_check(old_crtc_state, new_crtc_state); 142162306a36Sopenharmony_ci if (ret) { 142262306a36Sopenharmony_ci drm_dbg_atomic(dev, "[CRTC:%d:%s] atomic core check failed\n", 142362306a36Sopenharmony_ci crtc->base.id, crtc->name); 142462306a36Sopenharmony_ci return ret; 142562306a36Sopenharmony_ci } 142662306a36Sopenharmony_ci } 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci for_each_new_connector_in_state(state, conn, conn_state, i) { 142962306a36Sopenharmony_ci ret = drm_atomic_connector_check(conn, conn_state); 143062306a36Sopenharmony_ci if (ret) { 143162306a36Sopenharmony_ci drm_dbg_atomic(dev, "[CONNECTOR:%d:%s] atomic core check failed\n", 143262306a36Sopenharmony_ci conn->base.id, conn->name); 143362306a36Sopenharmony_ci return ret; 143462306a36Sopenharmony_ci } 143562306a36Sopenharmony_ci } 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci if (config->funcs->atomic_check) { 143862306a36Sopenharmony_ci ret = config->funcs->atomic_check(state->dev, state); 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci if (ret) { 144162306a36Sopenharmony_ci drm_dbg_atomic(dev, "atomic driver check for %p failed: %d\n", 144262306a36Sopenharmony_ci state, ret); 144362306a36Sopenharmony_ci return ret; 144462306a36Sopenharmony_ci } 144562306a36Sopenharmony_ci } 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci if (!state->allow_modeset) { 144862306a36Sopenharmony_ci for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) { 144962306a36Sopenharmony_ci if (drm_atomic_crtc_needs_modeset(new_crtc_state)) { 145062306a36Sopenharmony_ci drm_dbg_atomic(dev, "[CRTC:%d:%s] requires full modeset\n", 145162306a36Sopenharmony_ci crtc->base.id, crtc->name); 145262306a36Sopenharmony_ci return -EINVAL; 145362306a36Sopenharmony_ci } 145462306a36Sopenharmony_ci } 145562306a36Sopenharmony_ci } 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ci for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) { 145862306a36Sopenharmony_ci if (new_crtc_state->enable) 145962306a36Sopenharmony_ci affected_crtc |= drm_crtc_mask(crtc); 146062306a36Sopenharmony_ci } 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci /* 146362306a36Sopenharmony_ci * For commits that allow modesets drivers can add other CRTCs to the 146462306a36Sopenharmony_ci * atomic commit, e.g. when they need to reallocate global resources. 146562306a36Sopenharmony_ci * This can cause spurious EBUSY, which robs compositors of a very 146662306a36Sopenharmony_ci * effective sanity check for their drawing loop. Therefor only allow 146762306a36Sopenharmony_ci * drivers to add unrelated CRTC states for modeset commits. 146862306a36Sopenharmony_ci * 146962306a36Sopenharmony_ci * FIXME: Should add affected_crtc mask to the ATOMIC IOCTL as an output 147062306a36Sopenharmony_ci * so compositors know what's going on. 147162306a36Sopenharmony_ci */ 147262306a36Sopenharmony_ci if (affected_crtc != requested_crtc) { 147362306a36Sopenharmony_ci drm_dbg_atomic(dev, 147462306a36Sopenharmony_ci "driver added CRTC to commit: requested 0x%x, affected 0x%0x\n", 147562306a36Sopenharmony_ci requested_crtc, affected_crtc); 147662306a36Sopenharmony_ci WARN(!state->allow_modeset, "adding CRTC not allowed without modesets: requested 0x%x, affected 0x%0x\n", 147762306a36Sopenharmony_ci requested_crtc, affected_crtc); 147862306a36Sopenharmony_ci } 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci return 0; 148162306a36Sopenharmony_ci} 148262306a36Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_check_only); 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ci/** 148562306a36Sopenharmony_ci * drm_atomic_commit - commit configuration atomically 148662306a36Sopenharmony_ci * @state: atomic configuration to check 148762306a36Sopenharmony_ci * 148862306a36Sopenharmony_ci * Note that this function can return -EDEADLK if the driver needed to acquire 148962306a36Sopenharmony_ci * more locks but encountered a deadlock. The caller must then do the usual w/w 149062306a36Sopenharmony_ci * backoff dance and restart. All other errors are fatal. 149162306a36Sopenharmony_ci * 149262306a36Sopenharmony_ci * This function will take its own reference on @state. 149362306a36Sopenharmony_ci * Callers should always release their reference with drm_atomic_state_put(). 149462306a36Sopenharmony_ci * 149562306a36Sopenharmony_ci * Returns: 149662306a36Sopenharmony_ci * 0 on success, negative error code on failure. 149762306a36Sopenharmony_ci */ 149862306a36Sopenharmony_ciint drm_atomic_commit(struct drm_atomic_state *state) 149962306a36Sopenharmony_ci{ 150062306a36Sopenharmony_ci struct drm_mode_config *config = &state->dev->mode_config; 150162306a36Sopenharmony_ci struct drm_printer p = drm_info_printer(state->dev->dev); 150262306a36Sopenharmony_ci int ret; 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_ci if (drm_debug_enabled(DRM_UT_STATE)) 150562306a36Sopenharmony_ci drm_atomic_print_new_state(state, &p); 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci ret = drm_atomic_check_only(state); 150862306a36Sopenharmony_ci if (ret) 150962306a36Sopenharmony_ci return ret; 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci drm_dbg_atomic(state->dev, "committing %p\n", state); 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci return config->funcs->atomic_commit(state->dev, state, false); 151462306a36Sopenharmony_ci} 151562306a36Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_commit); 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci/** 151862306a36Sopenharmony_ci * drm_atomic_nonblocking_commit - atomic nonblocking commit 151962306a36Sopenharmony_ci * @state: atomic configuration to check 152062306a36Sopenharmony_ci * 152162306a36Sopenharmony_ci * Note that this function can return -EDEADLK if the driver needed to acquire 152262306a36Sopenharmony_ci * more locks but encountered a deadlock. The caller must then do the usual w/w 152362306a36Sopenharmony_ci * backoff dance and restart. All other errors are fatal. 152462306a36Sopenharmony_ci * 152562306a36Sopenharmony_ci * This function will take its own reference on @state. 152662306a36Sopenharmony_ci * Callers should always release their reference with drm_atomic_state_put(). 152762306a36Sopenharmony_ci * 152862306a36Sopenharmony_ci * Returns: 152962306a36Sopenharmony_ci * 0 on success, negative error code on failure. 153062306a36Sopenharmony_ci */ 153162306a36Sopenharmony_ciint drm_atomic_nonblocking_commit(struct drm_atomic_state *state) 153262306a36Sopenharmony_ci{ 153362306a36Sopenharmony_ci struct drm_mode_config *config = &state->dev->mode_config; 153462306a36Sopenharmony_ci int ret; 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci ret = drm_atomic_check_only(state); 153762306a36Sopenharmony_ci if (ret) 153862306a36Sopenharmony_ci return ret; 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci drm_dbg_atomic(state->dev, "committing %p nonblocking\n", state); 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci return config->funcs->atomic_commit(state->dev, state, true); 154362306a36Sopenharmony_ci} 154462306a36Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_nonblocking_commit); 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci/* just used from drm-client and atomic-helper: */ 154762306a36Sopenharmony_ciint __drm_atomic_helper_disable_plane(struct drm_plane *plane, 154862306a36Sopenharmony_ci struct drm_plane_state *plane_state) 154962306a36Sopenharmony_ci{ 155062306a36Sopenharmony_ci int ret; 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_ci ret = drm_atomic_set_crtc_for_plane(plane_state, NULL); 155362306a36Sopenharmony_ci if (ret != 0) 155462306a36Sopenharmony_ci return ret; 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci drm_atomic_set_fb_for_plane(plane_state, NULL); 155762306a36Sopenharmony_ci plane_state->crtc_x = 0; 155862306a36Sopenharmony_ci plane_state->crtc_y = 0; 155962306a36Sopenharmony_ci plane_state->crtc_w = 0; 156062306a36Sopenharmony_ci plane_state->crtc_h = 0; 156162306a36Sopenharmony_ci plane_state->src_x = 0; 156262306a36Sopenharmony_ci plane_state->src_y = 0; 156362306a36Sopenharmony_ci plane_state->src_w = 0; 156462306a36Sopenharmony_ci plane_state->src_h = 0; 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_ci return 0; 156762306a36Sopenharmony_ci} 156862306a36Sopenharmony_ciEXPORT_SYMBOL(__drm_atomic_helper_disable_plane); 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_cistatic int update_output_state(struct drm_atomic_state *state, 157162306a36Sopenharmony_ci struct drm_mode_set *set) 157262306a36Sopenharmony_ci{ 157362306a36Sopenharmony_ci struct drm_device *dev = set->crtc->dev; 157462306a36Sopenharmony_ci struct drm_crtc *crtc; 157562306a36Sopenharmony_ci struct drm_crtc_state *new_crtc_state; 157662306a36Sopenharmony_ci struct drm_connector *connector; 157762306a36Sopenharmony_ci struct drm_connector_state *new_conn_state; 157862306a36Sopenharmony_ci int ret, i; 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci ret = drm_modeset_lock(&dev->mode_config.connection_mutex, 158162306a36Sopenharmony_ci state->acquire_ctx); 158262306a36Sopenharmony_ci if (ret) 158362306a36Sopenharmony_ci return ret; 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci /* First disable all connectors on the target crtc. */ 158662306a36Sopenharmony_ci ret = drm_atomic_add_affected_connectors(state, set->crtc); 158762306a36Sopenharmony_ci if (ret) 158862306a36Sopenharmony_ci return ret; 158962306a36Sopenharmony_ci 159062306a36Sopenharmony_ci for_each_new_connector_in_state(state, connector, new_conn_state, i) { 159162306a36Sopenharmony_ci if (new_conn_state->crtc == set->crtc) { 159262306a36Sopenharmony_ci ret = drm_atomic_set_crtc_for_connector(new_conn_state, 159362306a36Sopenharmony_ci NULL); 159462306a36Sopenharmony_ci if (ret) 159562306a36Sopenharmony_ci return ret; 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci /* Make sure legacy setCrtc always re-trains */ 159862306a36Sopenharmony_ci new_conn_state->link_status = DRM_LINK_STATUS_GOOD; 159962306a36Sopenharmony_ci } 160062306a36Sopenharmony_ci } 160162306a36Sopenharmony_ci 160262306a36Sopenharmony_ci /* Then set all connectors from set->connectors on the target crtc */ 160362306a36Sopenharmony_ci for (i = 0; i < set->num_connectors; i++) { 160462306a36Sopenharmony_ci new_conn_state = drm_atomic_get_connector_state(state, 160562306a36Sopenharmony_ci set->connectors[i]); 160662306a36Sopenharmony_ci if (IS_ERR(new_conn_state)) 160762306a36Sopenharmony_ci return PTR_ERR(new_conn_state); 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_ci ret = drm_atomic_set_crtc_for_connector(new_conn_state, 161062306a36Sopenharmony_ci set->crtc); 161162306a36Sopenharmony_ci if (ret) 161262306a36Sopenharmony_ci return ret; 161362306a36Sopenharmony_ci } 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_ci for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) { 161662306a36Sopenharmony_ci /* 161762306a36Sopenharmony_ci * Don't update ->enable for the CRTC in the set_config request, 161862306a36Sopenharmony_ci * since a mismatch would indicate a bug in the upper layers. 161962306a36Sopenharmony_ci * The actual modeset code later on will catch any 162062306a36Sopenharmony_ci * inconsistencies here. 162162306a36Sopenharmony_ci */ 162262306a36Sopenharmony_ci if (crtc == set->crtc) 162362306a36Sopenharmony_ci continue; 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_ci if (!new_crtc_state->connector_mask) { 162662306a36Sopenharmony_ci ret = drm_atomic_set_mode_prop_for_crtc(new_crtc_state, 162762306a36Sopenharmony_ci NULL); 162862306a36Sopenharmony_ci if (ret < 0) 162962306a36Sopenharmony_ci return ret; 163062306a36Sopenharmony_ci 163162306a36Sopenharmony_ci new_crtc_state->active = false; 163262306a36Sopenharmony_ci } 163362306a36Sopenharmony_ci } 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_ci return 0; 163662306a36Sopenharmony_ci} 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_ci/* just used from drm-client and atomic-helper: */ 163962306a36Sopenharmony_ciint __drm_atomic_helper_set_config(struct drm_mode_set *set, 164062306a36Sopenharmony_ci struct drm_atomic_state *state) 164162306a36Sopenharmony_ci{ 164262306a36Sopenharmony_ci struct drm_crtc_state *crtc_state; 164362306a36Sopenharmony_ci struct drm_plane_state *primary_state; 164462306a36Sopenharmony_ci struct drm_crtc *crtc = set->crtc; 164562306a36Sopenharmony_ci int hdisplay, vdisplay; 164662306a36Sopenharmony_ci int ret; 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_ci crtc_state = drm_atomic_get_crtc_state(state, crtc); 164962306a36Sopenharmony_ci if (IS_ERR(crtc_state)) 165062306a36Sopenharmony_ci return PTR_ERR(crtc_state); 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_ci primary_state = drm_atomic_get_plane_state(state, crtc->primary); 165362306a36Sopenharmony_ci if (IS_ERR(primary_state)) 165462306a36Sopenharmony_ci return PTR_ERR(primary_state); 165562306a36Sopenharmony_ci 165662306a36Sopenharmony_ci if (!set->mode) { 165762306a36Sopenharmony_ci WARN_ON(set->fb); 165862306a36Sopenharmony_ci WARN_ON(set->num_connectors); 165962306a36Sopenharmony_ci 166062306a36Sopenharmony_ci ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL); 166162306a36Sopenharmony_ci if (ret != 0) 166262306a36Sopenharmony_ci return ret; 166362306a36Sopenharmony_ci 166462306a36Sopenharmony_ci crtc_state->active = false; 166562306a36Sopenharmony_ci 166662306a36Sopenharmony_ci ret = drm_atomic_set_crtc_for_plane(primary_state, NULL); 166762306a36Sopenharmony_ci if (ret != 0) 166862306a36Sopenharmony_ci return ret; 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_ci drm_atomic_set_fb_for_plane(primary_state, NULL); 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_ci goto commit; 167362306a36Sopenharmony_ci } 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_ci WARN_ON(!set->fb); 167662306a36Sopenharmony_ci WARN_ON(!set->num_connectors); 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_ci ret = drm_atomic_set_mode_for_crtc(crtc_state, set->mode); 167962306a36Sopenharmony_ci if (ret != 0) 168062306a36Sopenharmony_ci return ret; 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci crtc_state->active = true; 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci ret = drm_atomic_set_crtc_for_plane(primary_state, crtc); 168562306a36Sopenharmony_ci if (ret != 0) 168662306a36Sopenharmony_ci return ret; 168762306a36Sopenharmony_ci 168862306a36Sopenharmony_ci drm_mode_get_hv_timing(set->mode, &hdisplay, &vdisplay); 168962306a36Sopenharmony_ci 169062306a36Sopenharmony_ci drm_atomic_set_fb_for_plane(primary_state, set->fb); 169162306a36Sopenharmony_ci primary_state->crtc_x = 0; 169262306a36Sopenharmony_ci primary_state->crtc_y = 0; 169362306a36Sopenharmony_ci primary_state->crtc_w = hdisplay; 169462306a36Sopenharmony_ci primary_state->crtc_h = vdisplay; 169562306a36Sopenharmony_ci primary_state->src_x = set->x << 16; 169662306a36Sopenharmony_ci primary_state->src_y = set->y << 16; 169762306a36Sopenharmony_ci if (drm_rotation_90_or_270(primary_state->rotation)) { 169862306a36Sopenharmony_ci primary_state->src_w = vdisplay << 16; 169962306a36Sopenharmony_ci primary_state->src_h = hdisplay << 16; 170062306a36Sopenharmony_ci } else { 170162306a36Sopenharmony_ci primary_state->src_w = hdisplay << 16; 170262306a36Sopenharmony_ci primary_state->src_h = vdisplay << 16; 170362306a36Sopenharmony_ci } 170462306a36Sopenharmony_ci 170562306a36Sopenharmony_cicommit: 170662306a36Sopenharmony_ci ret = update_output_state(state, set); 170762306a36Sopenharmony_ci if (ret) 170862306a36Sopenharmony_ci return ret; 170962306a36Sopenharmony_ci 171062306a36Sopenharmony_ci return 0; 171162306a36Sopenharmony_ci} 171262306a36Sopenharmony_ciEXPORT_SYMBOL(__drm_atomic_helper_set_config); 171362306a36Sopenharmony_ci 171462306a36Sopenharmony_cistatic void drm_atomic_private_obj_print_state(struct drm_printer *p, 171562306a36Sopenharmony_ci const struct drm_private_state *state) 171662306a36Sopenharmony_ci{ 171762306a36Sopenharmony_ci struct drm_private_obj *obj = state->obj; 171862306a36Sopenharmony_ci 171962306a36Sopenharmony_ci if (obj->funcs->atomic_print_state) 172062306a36Sopenharmony_ci obj->funcs->atomic_print_state(p, state); 172162306a36Sopenharmony_ci} 172262306a36Sopenharmony_ci 172362306a36Sopenharmony_ci/** 172462306a36Sopenharmony_ci * drm_atomic_print_new_state - prints drm atomic state 172562306a36Sopenharmony_ci * @state: atomic configuration to check 172662306a36Sopenharmony_ci * @p: drm printer 172762306a36Sopenharmony_ci * 172862306a36Sopenharmony_ci * This functions prints the drm atomic state snapshot using the drm printer 172962306a36Sopenharmony_ci * which is passed to it. This snapshot can be used for debugging purposes. 173062306a36Sopenharmony_ci * 173162306a36Sopenharmony_ci * Note that this function looks into the new state objects and hence its not 173262306a36Sopenharmony_ci * safe to be used after the call to drm_atomic_helper_commit_hw_done(). 173362306a36Sopenharmony_ci */ 173462306a36Sopenharmony_civoid drm_atomic_print_new_state(const struct drm_atomic_state *state, 173562306a36Sopenharmony_ci struct drm_printer *p) 173662306a36Sopenharmony_ci{ 173762306a36Sopenharmony_ci struct drm_plane *plane; 173862306a36Sopenharmony_ci struct drm_plane_state *plane_state; 173962306a36Sopenharmony_ci struct drm_crtc *crtc; 174062306a36Sopenharmony_ci struct drm_crtc_state *crtc_state; 174162306a36Sopenharmony_ci struct drm_connector *connector; 174262306a36Sopenharmony_ci struct drm_connector_state *connector_state; 174362306a36Sopenharmony_ci struct drm_private_obj *obj; 174462306a36Sopenharmony_ci struct drm_private_state *obj_state; 174562306a36Sopenharmony_ci int i; 174662306a36Sopenharmony_ci 174762306a36Sopenharmony_ci if (!p) { 174862306a36Sopenharmony_ci drm_err(state->dev, "invalid drm printer\n"); 174962306a36Sopenharmony_ci return; 175062306a36Sopenharmony_ci } 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_ci drm_dbg_atomic(state->dev, "checking %p\n", state); 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_ci for_each_new_plane_in_state(state, plane, plane_state, i) 175562306a36Sopenharmony_ci drm_atomic_plane_print_state(p, plane_state); 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_ci for_each_new_crtc_in_state(state, crtc, crtc_state, i) 175862306a36Sopenharmony_ci drm_atomic_crtc_print_state(p, crtc_state); 175962306a36Sopenharmony_ci 176062306a36Sopenharmony_ci for_each_new_connector_in_state(state, connector, connector_state, i) 176162306a36Sopenharmony_ci drm_atomic_connector_print_state(p, connector_state); 176262306a36Sopenharmony_ci 176362306a36Sopenharmony_ci for_each_new_private_obj_in_state(state, obj, obj_state, i) 176462306a36Sopenharmony_ci drm_atomic_private_obj_print_state(p, obj_state); 176562306a36Sopenharmony_ci} 176662306a36Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_print_new_state); 176762306a36Sopenharmony_ci 176862306a36Sopenharmony_cistatic void __drm_state_dump(struct drm_device *dev, struct drm_printer *p, 176962306a36Sopenharmony_ci bool take_locks) 177062306a36Sopenharmony_ci{ 177162306a36Sopenharmony_ci struct drm_mode_config *config = &dev->mode_config; 177262306a36Sopenharmony_ci struct drm_plane *plane; 177362306a36Sopenharmony_ci struct drm_crtc *crtc; 177462306a36Sopenharmony_ci struct drm_connector *connector; 177562306a36Sopenharmony_ci struct drm_connector_list_iter conn_iter; 177662306a36Sopenharmony_ci 177762306a36Sopenharmony_ci if (!drm_drv_uses_atomic_modeset(dev)) 177862306a36Sopenharmony_ci return; 177962306a36Sopenharmony_ci 178062306a36Sopenharmony_ci list_for_each_entry(plane, &config->plane_list, head) { 178162306a36Sopenharmony_ci if (take_locks) 178262306a36Sopenharmony_ci drm_modeset_lock(&plane->mutex, NULL); 178362306a36Sopenharmony_ci drm_atomic_plane_print_state(p, plane->state); 178462306a36Sopenharmony_ci if (take_locks) 178562306a36Sopenharmony_ci drm_modeset_unlock(&plane->mutex); 178662306a36Sopenharmony_ci } 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_ci list_for_each_entry(crtc, &config->crtc_list, head) { 178962306a36Sopenharmony_ci if (take_locks) 179062306a36Sopenharmony_ci drm_modeset_lock(&crtc->mutex, NULL); 179162306a36Sopenharmony_ci drm_atomic_crtc_print_state(p, crtc->state); 179262306a36Sopenharmony_ci if (take_locks) 179362306a36Sopenharmony_ci drm_modeset_unlock(&crtc->mutex); 179462306a36Sopenharmony_ci } 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_ci drm_connector_list_iter_begin(dev, &conn_iter); 179762306a36Sopenharmony_ci if (take_locks) 179862306a36Sopenharmony_ci drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 179962306a36Sopenharmony_ci drm_for_each_connector_iter(connector, &conn_iter) 180062306a36Sopenharmony_ci drm_atomic_connector_print_state(p, connector->state); 180162306a36Sopenharmony_ci if (take_locks) 180262306a36Sopenharmony_ci drm_modeset_unlock(&dev->mode_config.connection_mutex); 180362306a36Sopenharmony_ci drm_connector_list_iter_end(&conn_iter); 180462306a36Sopenharmony_ci} 180562306a36Sopenharmony_ci 180662306a36Sopenharmony_ci/** 180762306a36Sopenharmony_ci * drm_state_dump - dump entire device atomic state 180862306a36Sopenharmony_ci * @dev: the drm device 180962306a36Sopenharmony_ci * @p: where to print the state to 181062306a36Sopenharmony_ci * 181162306a36Sopenharmony_ci * Just for debugging. Drivers might want an option to dump state 181262306a36Sopenharmony_ci * to dmesg in case of error irq's. (Hint, you probably want to 181362306a36Sopenharmony_ci * ratelimit this!) 181462306a36Sopenharmony_ci * 181562306a36Sopenharmony_ci * The caller must wrap this drm_modeset_lock_all_ctx() and 181662306a36Sopenharmony_ci * drm_modeset_drop_locks(). If this is called from error irq handler, it should 181762306a36Sopenharmony_ci * not be enabled by default - if you are debugging errors you might 181862306a36Sopenharmony_ci * not care that this is racey, but calling this without all modeset locks held 181962306a36Sopenharmony_ci * is inherently unsafe. 182062306a36Sopenharmony_ci */ 182162306a36Sopenharmony_civoid drm_state_dump(struct drm_device *dev, struct drm_printer *p) 182262306a36Sopenharmony_ci{ 182362306a36Sopenharmony_ci __drm_state_dump(dev, p, false); 182462306a36Sopenharmony_ci} 182562306a36Sopenharmony_ciEXPORT_SYMBOL(drm_state_dump); 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 182862306a36Sopenharmony_cistatic int drm_state_info(struct seq_file *m, void *data) 182962306a36Sopenharmony_ci{ 183062306a36Sopenharmony_ci struct drm_debugfs_entry *entry = m->private; 183162306a36Sopenharmony_ci struct drm_device *dev = entry->dev; 183262306a36Sopenharmony_ci struct drm_printer p = drm_seq_file_printer(m); 183362306a36Sopenharmony_ci 183462306a36Sopenharmony_ci __drm_state_dump(dev, &p, true); 183562306a36Sopenharmony_ci 183662306a36Sopenharmony_ci return 0; 183762306a36Sopenharmony_ci} 183862306a36Sopenharmony_ci 183962306a36Sopenharmony_ci/* any use in debugfs files to dump individual planes/crtc/etc? */ 184062306a36Sopenharmony_cistatic const struct drm_debugfs_info drm_atomic_debugfs_list[] = { 184162306a36Sopenharmony_ci {"state", drm_state_info, 0}, 184262306a36Sopenharmony_ci}; 184362306a36Sopenharmony_ci 184462306a36Sopenharmony_civoid drm_atomic_debugfs_init(struct drm_minor *minor) 184562306a36Sopenharmony_ci{ 184662306a36Sopenharmony_ci drm_debugfs_add_files(minor->dev, drm_atomic_debugfs_list, 184762306a36Sopenharmony_ci ARRAY_SIZE(drm_atomic_debugfs_list)); 184862306a36Sopenharmony_ci} 184962306a36Sopenharmony_ci#endif 1850