162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci#include <linux/dma-resv.h> 462306a36Sopenharmony_ci#include <linux/dma-fence-chain.h> 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <drm/drm_atomic_state_helper.h> 762306a36Sopenharmony_ci#include <drm/drm_atomic_uapi.h> 862306a36Sopenharmony_ci#include <drm/drm_framebuffer.h> 962306a36Sopenharmony_ci#include <drm/drm_gem.h> 1062306a36Sopenharmony_ci#include <drm/drm_gem_atomic_helper.h> 1162306a36Sopenharmony_ci#include <drm/drm_gem_framebuffer_helper.h> 1262306a36Sopenharmony_ci#include <drm/drm_simple_kms_helper.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include "drm_internal.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci/** 1762306a36Sopenharmony_ci * DOC: overview 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * The GEM atomic helpers library implements generic atomic-commit 2062306a36Sopenharmony_ci * functions for drivers that use GEM objects. Currently, it provides 2162306a36Sopenharmony_ci * synchronization helpers, and plane state and framebuffer BO mappings 2262306a36Sopenharmony_ci * for planes with shadow buffers. 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * Before scanout, a plane's framebuffer needs to be synchronized with 2562306a36Sopenharmony_ci * possible writers that draw into the framebuffer. All drivers should 2662306a36Sopenharmony_ci * call drm_gem_plane_helper_prepare_fb() from their implementation of 2762306a36Sopenharmony_ci * struct &drm_plane_helper.prepare_fb . It sets the plane's fence from 2862306a36Sopenharmony_ci * the framebuffer so that the DRM core can synchronize access automatically. 2962306a36Sopenharmony_ci * drm_gem_plane_helper_prepare_fb() can also be used directly as 3062306a36Sopenharmony_ci * implementation of prepare_fb. 3162306a36Sopenharmony_ci * 3262306a36Sopenharmony_ci * .. code-block:: c 3362306a36Sopenharmony_ci * 3462306a36Sopenharmony_ci * #include <drm/drm_gem_atomic_helper.h> 3562306a36Sopenharmony_ci * 3662306a36Sopenharmony_ci * struct drm_plane_helper_funcs driver_plane_helper_funcs = { 3762306a36Sopenharmony_ci * ..., 3862306a36Sopenharmony_ci * . prepare_fb = drm_gem_plane_helper_prepare_fb, 3962306a36Sopenharmony_ci * }; 4062306a36Sopenharmony_ci * 4162306a36Sopenharmony_ci * A driver using a shadow buffer copies the content of the shadow buffers 4262306a36Sopenharmony_ci * into the HW's framebuffer memory during an atomic update. This requires 4362306a36Sopenharmony_ci * a mapping of the shadow buffer into kernel address space. The mappings 4462306a36Sopenharmony_ci * cannot be established by commit-tail functions, such as atomic_update, 4562306a36Sopenharmony_ci * as this would violate locking rules around dma_buf_vmap(). 4662306a36Sopenharmony_ci * 4762306a36Sopenharmony_ci * The helpers for shadow-buffered planes establish and release mappings, 4862306a36Sopenharmony_ci * and provide struct drm_shadow_plane_state, which stores the plane's mapping 4962306a36Sopenharmony_ci * for commit-tail functions. 5062306a36Sopenharmony_ci * 5162306a36Sopenharmony_ci * Shadow-buffered planes can easily be enabled by using the provided macros 5262306a36Sopenharmony_ci * %DRM_GEM_SHADOW_PLANE_FUNCS and %DRM_GEM_SHADOW_PLANE_HELPER_FUNCS. 5362306a36Sopenharmony_ci * These macros set up the plane and plane-helper callbacks to point to the 5462306a36Sopenharmony_ci * shadow-buffer helpers. 5562306a36Sopenharmony_ci * 5662306a36Sopenharmony_ci * .. code-block:: c 5762306a36Sopenharmony_ci * 5862306a36Sopenharmony_ci * #include <drm/drm_gem_atomic_helper.h> 5962306a36Sopenharmony_ci * 6062306a36Sopenharmony_ci * struct drm_plane_funcs driver_plane_funcs = { 6162306a36Sopenharmony_ci * ..., 6262306a36Sopenharmony_ci * DRM_GEM_SHADOW_PLANE_FUNCS, 6362306a36Sopenharmony_ci * }; 6462306a36Sopenharmony_ci * 6562306a36Sopenharmony_ci * struct drm_plane_helper_funcs driver_plane_helper_funcs = { 6662306a36Sopenharmony_ci * ..., 6762306a36Sopenharmony_ci * DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, 6862306a36Sopenharmony_ci * }; 6962306a36Sopenharmony_ci * 7062306a36Sopenharmony_ci * In the driver's atomic-update function, shadow-buffer mappings are available 7162306a36Sopenharmony_ci * from the plane state. Use to_drm_shadow_plane_state() to upcast from 7262306a36Sopenharmony_ci * struct drm_plane_state. 7362306a36Sopenharmony_ci * 7462306a36Sopenharmony_ci * .. code-block:: c 7562306a36Sopenharmony_ci * 7662306a36Sopenharmony_ci * void driver_plane_atomic_update(struct drm_plane *plane, 7762306a36Sopenharmony_ci * struct drm_plane_state *old_plane_state) 7862306a36Sopenharmony_ci * { 7962306a36Sopenharmony_ci * struct drm_plane_state *plane_state = plane->state; 8062306a36Sopenharmony_ci * struct drm_shadow_plane_state *shadow_plane_state = 8162306a36Sopenharmony_ci * to_drm_shadow_plane_state(plane_state); 8262306a36Sopenharmony_ci * 8362306a36Sopenharmony_ci * // access shadow buffer via shadow_plane_state->map 8462306a36Sopenharmony_ci * } 8562306a36Sopenharmony_ci * 8662306a36Sopenharmony_ci * A mapping address for each of the framebuffer's buffer object is stored in 8762306a36Sopenharmony_ci * struct &drm_shadow_plane_state.map. The mappings are valid while the state 8862306a36Sopenharmony_ci * is being used. 8962306a36Sopenharmony_ci * 9062306a36Sopenharmony_ci * Drivers that use struct drm_simple_display_pipe can use 9162306a36Sopenharmony_ci * %DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS to initialize the rsp 9262306a36Sopenharmony_ci * callbacks. Access to shadow-buffer mappings is similar to regular 9362306a36Sopenharmony_ci * atomic_update. 9462306a36Sopenharmony_ci * 9562306a36Sopenharmony_ci * .. code-block:: c 9662306a36Sopenharmony_ci * 9762306a36Sopenharmony_ci * struct drm_simple_display_pipe_funcs driver_pipe_funcs = { 9862306a36Sopenharmony_ci * ..., 9962306a36Sopenharmony_ci * DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS, 10062306a36Sopenharmony_ci * }; 10162306a36Sopenharmony_ci * 10262306a36Sopenharmony_ci * void driver_pipe_enable(struct drm_simple_display_pipe *pipe, 10362306a36Sopenharmony_ci * struct drm_crtc_state *crtc_state, 10462306a36Sopenharmony_ci * struct drm_plane_state *plane_state) 10562306a36Sopenharmony_ci * { 10662306a36Sopenharmony_ci * struct drm_shadow_plane_state *shadow_plane_state = 10762306a36Sopenharmony_ci * to_drm_shadow_plane_state(plane_state); 10862306a36Sopenharmony_ci * 10962306a36Sopenharmony_ci * // access shadow buffer via shadow_plane_state->map 11062306a36Sopenharmony_ci * } 11162306a36Sopenharmony_ci */ 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci/* 11462306a36Sopenharmony_ci * Plane Helpers 11562306a36Sopenharmony_ci */ 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci/** 11862306a36Sopenharmony_ci * drm_gem_plane_helper_prepare_fb() - Prepare a GEM backed framebuffer 11962306a36Sopenharmony_ci * @plane: Plane 12062306a36Sopenharmony_ci * @state: Plane state the fence will be attached to 12162306a36Sopenharmony_ci * 12262306a36Sopenharmony_ci * This function extracts the exclusive fence from &drm_gem_object.resv and 12362306a36Sopenharmony_ci * attaches it to plane state for the atomic helper to wait on. This is 12462306a36Sopenharmony_ci * necessary to correctly implement implicit synchronization for any buffers 12562306a36Sopenharmony_ci * shared as a struct &dma_buf. This function can be used as the 12662306a36Sopenharmony_ci * &drm_plane_helper_funcs.prepare_fb callback. 12762306a36Sopenharmony_ci * 12862306a36Sopenharmony_ci * There is no need for &drm_plane_helper_funcs.cleanup_fb hook for simple 12962306a36Sopenharmony_ci * GEM based framebuffer drivers which have their buffers always pinned in 13062306a36Sopenharmony_ci * memory. 13162306a36Sopenharmony_ci * 13262306a36Sopenharmony_ci * This function is the default implementation for GEM drivers of 13362306a36Sopenharmony_ci * &drm_plane_helper_funcs.prepare_fb if no callback is provided. 13462306a36Sopenharmony_ci */ 13562306a36Sopenharmony_ciint drm_gem_plane_helper_prepare_fb(struct drm_plane *plane, 13662306a36Sopenharmony_ci struct drm_plane_state *state) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci struct dma_fence *fence = dma_fence_get(state->fence); 13962306a36Sopenharmony_ci enum dma_resv_usage usage; 14062306a36Sopenharmony_ci size_t i; 14162306a36Sopenharmony_ci int ret; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci if (!state->fb) 14462306a36Sopenharmony_ci return 0; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci /* 14762306a36Sopenharmony_ci * Only add the kernel fences here if there is already a fence set via 14862306a36Sopenharmony_ci * explicit fencing interfaces on the atomic ioctl. 14962306a36Sopenharmony_ci * 15062306a36Sopenharmony_ci * This way explicit fencing can be used to overrule implicit fencing, 15162306a36Sopenharmony_ci * which is important to make explicit fencing use-cases work: One 15262306a36Sopenharmony_ci * example is using one buffer for 2 screens with different refresh 15362306a36Sopenharmony_ci * rates. Implicit fencing will clamp rendering to the refresh rate of 15462306a36Sopenharmony_ci * the slower screen, whereas explicit fence allows 2 independent 15562306a36Sopenharmony_ci * render and display loops on a single buffer. If a driver allows 15662306a36Sopenharmony_ci * obeys both implicit and explicit fences for plane updates, then it 15762306a36Sopenharmony_ci * will break all the benefits of explicit fencing. 15862306a36Sopenharmony_ci */ 15962306a36Sopenharmony_ci usage = fence ? DMA_RESV_USAGE_KERNEL : DMA_RESV_USAGE_WRITE; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci for (i = 0; i < state->fb->format->num_planes; ++i) { 16262306a36Sopenharmony_ci struct drm_gem_object *obj = drm_gem_fb_get_obj(state->fb, i); 16362306a36Sopenharmony_ci struct dma_fence *new; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci if (!obj) { 16662306a36Sopenharmony_ci ret = -EINVAL; 16762306a36Sopenharmony_ci goto error; 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci ret = dma_resv_get_singleton(obj->resv, usage, &new); 17162306a36Sopenharmony_ci if (ret) 17262306a36Sopenharmony_ci goto error; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci if (new && fence) { 17562306a36Sopenharmony_ci struct dma_fence_chain *chain = dma_fence_chain_alloc(); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci if (!chain) { 17862306a36Sopenharmony_ci ret = -ENOMEM; 17962306a36Sopenharmony_ci goto error; 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci dma_fence_chain_init(chain, fence, new, 1); 18362306a36Sopenharmony_ci fence = &chain->base; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci } else if (new) { 18662306a36Sopenharmony_ci fence = new; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci dma_fence_put(state->fence); 19162306a36Sopenharmony_ci state->fence = fence; 19262306a36Sopenharmony_ci return 0; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cierror: 19562306a36Sopenharmony_ci dma_fence_put(fence); 19662306a36Sopenharmony_ci return ret; 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(drm_gem_plane_helper_prepare_fb); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci/* 20162306a36Sopenharmony_ci * Shadow-buffered Planes 20262306a36Sopenharmony_ci */ 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci/** 20562306a36Sopenharmony_ci * __drm_gem_duplicate_shadow_plane_state - duplicates shadow-buffered plane state 20662306a36Sopenharmony_ci * @plane: the plane 20762306a36Sopenharmony_ci * @new_shadow_plane_state: the new shadow-buffered plane state 20862306a36Sopenharmony_ci * 20962306a36Sopenharmony_ci * This function duplicates shadow-buffered plane state. This is helpful for drivers 21062306a36Sopenharmony_ci * that subclass struct drm_shadow_plane_state. 21162306a36Sopenharmony_ci * 21262306a36Sopenharmony_ci * The function does not duplicate existing mappings of the shadow buffers. 21362306a36Sopenharmony_ci * Mappings are maintained during the atomic commit by the plane's prepare_fb 21462306a36Sopenharmony_ci * and cleanup_fb helpers. See drm_gem_prepare_shadow_fb() and drm_gem_cleanup_shadow_fb() 21562306a36Sopenharmony_ci * for corresponding helpers. 21662306a36Sopenharmony_ci */ 21762306a36Sopenharmony_civoid 21862306a36Sopenharmony_ci__drm_gem_duplicate_shadow_plane_state(struct drm_plane *plane, 21962306a36Sopenharmony_ci struct drm_shadow_plane_state *new_shadow_plane_state) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci __drm_atomic_helper_plane_duplicate_state(plane, &new_shadow_plane_state->base); 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ciEXPORT_SYMBOL(__drm_gem_duplicate_shadow_plane_state); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci/** 22662306a36Sopenharmony_ci * drm_gem_duplicate_shadow_plane_state - duplicates shadow-buffered plane state 22762306a36Sopenharmony_ci * @plane: the plane 22862306a36Sopenharmony_ci * 22962306a36Sopenharmony_ci * This function implements struct &drm_plane_funcs.atomic_duplicate_state for 23062306a36Sopenharmony_ci * shadow-buffered planes. It assumes the existing state to be of type 23162306a36Sopenharmony_ci * struct drm_shadow_plane_state and it allocates the new state to be of this 23262306a36Sopenharmony_ci * type. 23362306a36Sopenharmony_ci * 23462306a36Sopenharmony_ci * The function does not duplicate existing mappings of the shadow buffers. 23562306a36Sopenharmony_ci * Mappings are maintained during the atomic commit by the plane's prepare_fb 23662306a36Sopenharmony_ci * and cleanup_fb helpers. See drm_gem_prepare_shadow_fb() and drm_gem_cleanup_shadow_fb() 23762306a36Sopenharmony_ci * for corresponding helpers. 23862306a36Sopenharmony_ci * 23962306a36Sopenharmony_ci * Returns: 24062306a36Sopenharmony_ci * A pointer to a new plane state on success, or NULL otherwise. 24162306a36Sopenharmony_ci */ 24262306a36Sopenharmony_cistruct drm_plane_state * 24362306a36Sopenharmony_cidrm_gem_duplicate_shadow_plane_state(struct drm_plane *plane) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci struct drm_plane_state *plane_state = plane->state; 24662306a36Sopenharmony_ci struct drm_shadow_plane_state *new_shadow_plane_state; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci if (!plane_state) 24962306a36Sopenharmony_ci return NULL; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci new_shadow_plane_state = kzalloc(sizeof(*new_shadow_plane_state), GFP_KERNEL); 25262306a36Sopenharmony_ci if (!new_shadow_plane_state) 25362306a36Sopenharmony_ci return NULL; 25462306a36Sopenharmony_ci __drm_gem_duplicate_shadow_plane_state(plane, new_shadow_plane_state); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci return &new_shadow_plane_state->base; 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_duplicate_shadow_plane_state); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci/** 26162306a36Sopenharmony_ci * __drm_gem_destroy_shadow_plane_state - cleans up shadow-buffered plane state 26262306a36Sopenharmony_ci * @shadow_plane_state: the shadow-buffered plane state 26362306a36Sopenharmony_ci * 26462306a36Sopenharmony_ci * This function cleans up shadow-buffered plane state. Helpful for drivers that 26562306a36Sopenharmony_ci * subclass struct drm_shadow_plane_state. 26662306a36Sopenharmony_ci */ 26762306a36Sopenharmony_civoid __drm_gem_destroy_shadow_plane_state(struct drm_shadow_plane_state *shadow_plane_state) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci __drm_atomic_helper_plane_destroy_state(&shadow_plane_state->base); 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ciEXPORT_SYMBOL(__drm_gem_destroy_shadow_plane_state); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci/** 27462306a36Sopenharmony_ci * drm_gem_destroy_shadow_plane_state - deletes shadow-buffered plane state 27562306a36Sopenharmony_ci * @plane: the plane 27662306a36Sopenharmony_ci * @plane_state: the plane state of type struct drm_shadow_plane_state 27762306a36Sopenharmony_ci * 27862306a36Sopenharmony_ci * This function implements struct &drm_plane_funcs.atomic_destroy_state 27962306a36Sopenharmony_ci * for shadow-buffered planes. It expects that mappings of shadow buffers 28062306a36Sopenharmony_ci * have been released already. 28162306a36Sopenharmony_ci */ 28262306a36Sopenharmony_civoid drm_gem_destroy_shadow_plane_state(struct drm_plane *plane, 28362306a36Sopenharmony_ci struct drm_plane_state *plane_state) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci struct drm_shadow_plane_state *shadow_plane_state = 28662306a36Sopenharmony_ci to_drm_shadow_plane_state(plane_state); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci __drm_gem_destroy_shadow_plane_state(shadow_plane_state); 28962306a36Sopenharmony_ci kfree(shadow_plane_state); 29062306a36Sopenharmony_ci} 29162306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_destroy_shadow_plane_state); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci/** 29462306a36Sopenharmony_ci * __drm_gem_reset_shadow_plane - resets a shadow-buffered plane 29562306a36Sopenharmony_ci * @plane: the plane 29662306a36Sopenharmony_ci * @shadow_plane_state: the shadow-buffered plane state 29762306a36Sopenharmony_ci * 29862306a36Sopenharmony_ci * This function resets state for shadow-buffered planes. Helpful 29962306a36Sopenharmony_ci * for drivers that subclass struct drm_shadow_plane_state. 30062306a36Sopenharmony_ci */ 30162306a36Sopenharmony_civoid __drm_gem_reset_shadow_plane(struct drm_plane *plane, 30262306a36Sopenharmony_ci struct drm_shadow_plane_state *shadow_plane_state) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci __drm_atomic_helper_plane_reset(plane, &shadow_plane_state->base); 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ciEXPORT_SYMBOL(__drm_gem_reset_shadow_plane); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci/** 30962306a36Sopenharmony_ci * drm_gem_reset_shadow_plane - resets a shadow-buffered plane 31062306a36Sopenharmony_ci * @plane: the plane 31162306a36Sopenharmony_ci * 31262306a36Sopenharmony_ci * This function implements struct &drm_plane_funcs.reset_plane for 31362306a36Sopenharmony_ci * shadow-buffered planes. It assumes the current plane state to be 31462306a36Sopenharmony_ci * of type struct drm_shadow_plane and it allocates the new state of 31562306a36Sopenharmony_ci * this type. 31662306a36Sopenharmony_ci */ 31762306a36Sopenharmony_civoid drm_gem_reset_shadow_plane(struct drm_plane *plane) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci struct drm_shadow_plane_state *shadow_plane_state; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci if (plane->state) { 32262306a36Sopenharmony_ci drm_gem_destroy_shadow_plane_state(plane, plane->state); 32362306a36Sopenharmony_ci plane->state = NULL; /* must be set to NULL here */ 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci shadow_plane_state = kzalloc(sizeof(*shadow_plane_state), GFP_KERNEL); 32762306a36Sopenharmony_ci if (!shadow_plane_state) 32862306a36Sopenharmony_ci return; 32962306a36Sopenharmony_ci __drm_gem_reset_shadow_plane(plane, shadow_plane_state); 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_reset_shadow_plane); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci/** 33462306a36Sopenharmony_ci * drm_gem_begin_shadow_fb_access - prepares shadow framebuffers for CPU access 33562306a36Sopenharmony_ci * @plane: the plane 33662306a36Sopenharmony_ci * @plane_state: the plane state of type struct drm_shadow_plane_state 33762306a36Sopenharmony_ci * 33862306a36Sopenharmony_ci * This function implements struct &drm_plane_helper_funcs.begin_fb_access. It 33962306a36Sopenharmony_ci * maps all buffer objects of the plane's framebuffer into kernel address 34062306a36Sopenharmony_ci * space and stores them in struct &drm_shadow_plane_state.map. The first data 34162306a36Sopenharmony_ci * bytes are available in struct &drm_shadow_plane_state.data. 34262306a36Sopenharmony_ci * 34362306a36Sopenharmony_ci * See drm_gem_end_shadow_fb_access() for cleanup. 34462306a36Sopenharmony_ci * 34562306a36Sopenharmony_ci * Returns: 34662306a36Sopenharmony_ci * 0 on success, or a negative errno code otherwise. 34762306a36Sopenharmony_ci */ 34862306a36Sopenharmony_ciint drm_gem_begin_shadow_fb_access(struct drm_plane *plane, struct drm_plane_state *plane_state) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); 35162306a36Sopenharmony_ci struct drm_framebuffer *fb = plane_state->fb; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci if (!fb) 35462306a36Sopenharmony_ci return 0; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci return drm_gem_fb_vmap(fb, shadow_plane_state->map, shadow_plane_state->data); 35762306a36Sopenharmony_ci} 35862306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_begin_shadow_fb_access); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci/** 36162306a36Sopenharmony_ci * drm_gem_end_shadow_fb_access - releases shadow framebuffers from CPU access 36262306a36Sopenharmony_ci * @plane: the plane 36362306a36Sopenharmony_ci * @plane_state: the plane state of type struct drm_shadow_plane_state 36462306a36Sopenharmony_ci * 36562306a36Sopenharmony_ci * This function implements struct &drm_plane_helper_funcs.end_fb_access. It 36662306a36Sopenharmony_ci * undoes all effects of drm_gem_begin_shadow_fb_access() in reverse order. 36762306a36Sopenharmony_ci * 36862306a36Sopenharmony_ci * See drm_gem_begin_shadow_fb_access() for more information. 36962306a36Sopenharmony_ci */ 37062306a36Sopenharmony_civoid drm_gem_end_shadow_fb_access(struct drm_plane *plane, struct drm_plane_state *plane_state) 37162306a36Sopenharmony_ci{ 37262306a36Sopenharmony_ci struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); 37362306a36Sopenharmony_ci struct drm_framebuffer *fb = plane_state->fb; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci if (!fb) 37662306a36Sopenharmony_ci return; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci drm_gem_fb_vunmap(fb, shadow_plane_state->map); 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_end_shadow_fb_access); 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci/** 38362306a36Sopenharmony_ci * drm_gem_simple_kms_begin_shadow_fb_access - prepares shadow framebuffers for CPU access 38462306a36Sopenharmony_ci * @pipe: the simple display pipe 38562306a36Sopenharmony_ci * @plane_state: the plane state of type struct drm_shadow_plane_state 38662306a36Sopenharmony_ci * 38762306a36Sopenharmony_ci * This function implements struct drm_simple_display_funcs.begin_fb_access. 38862306a36Sopenharmony_ci * 38962306a36Sopenharmony_ci * See drm_gem_begin_shadow_fb_access() for details and 39062306a36Sopenharmony_ci * drm_gem_simple_kms_cleanup_shadow_fb() for cleanup. 39162306a36Sopenharmony_ci * 39262306a36Sopenharmony_ci * Returns: 39362306a36Sopenharmony_ci * 0 on success, or a negative errno code otherwise. 39462306a36Sopenharmony_ci */ 39562306a36Sopenharmony_ciint drm_gem_simple_kms_begin_shadow_fb_access(struct drm_simple_display_pipe *pipe, 39662306a36Sopenharmony_ci struct drm_plane_state *plane_state) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci return drm_gem_begin_shadow_fb_access(&pipe->plane, plane_state); 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_simple_kms_begin_shadow_fb_access); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci/** 40362306a36Sopenharmony_ci * drm_gem_simple_kms_end_shadow_fb_access - releases shadow framebuffers from CPU access 40462306a36Sopenharmony_ci * @pipe: the simple display pipe 40562306a36Sopenharmony_ci * @plane_state: the plane state of type struct drm_shadow_plane_state 40662306a36Sopenharmony_ci * 40762306a36Sopenharmony_ci * This function implements struct drm_simple_display_funcs.end_fb_access. 40862306a36Sopenharmony_ci * It undoes all effects of drm_gem_simple_kms_begin_shadow_fb_access() in 40962306a36Sopenharmony_ci * reverse order. 41062306a36Sopenharmony_ci * 41162306a36Sopenharmony_ci * See drm_gem_simple_kms_begin_shadow_fb_access(). 41262306a36Sopenharmony_ci */ 41362306a36Sopenharmony_civoid drm_gem_simple_kms_end_shadow_fb_access(struct drm_simple_display_pipe *pipe, 41462306a36Sopenharmony_ci struct drm_plane_state *plane_state) 41562306a36Sopenharmony_ci{ 41662306a36Sopenharmony_ci drm_gem_end_shadow_fb_access(&pipe->plane, plane_state); 41762306a36Sopenharmony_ci} 41862306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_simple_kms_end_shadow_fb_access); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci/** 42162306a36Sopenharmony_ci * drm_gem_simple_kms_reset_shadow_plane - resets a shadow-buffered plane 42262306a36Sopenharmony_ci * @pipe: the simple display pipe 42362306a36Sopenharmony_ci * 42462306a36Sopenharmony_ci * This function implements struct drm_simple_display_funcs.reset_plane 42562306a36Sopenharmony_ci * for shadow-buffered planes. 42662306a36Sopenharmony_ci */ 42762306a36Sopenharmony_civoid drm_gem_simple_kms_reset_shadow_plane(struct drm_simple_display_pipe *pipe) 42862306a36Sopenharmony_ci{ 42962306a36Sopenharmony_ci drm_gem_reset_shadow_plane(&pipe->plane); 43062306a36Sopenharmony_ci} 43162306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_simple_kms_reset_shadow_plane); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci/** 43462306a36Sopenharmony_ci * drm_gem_simple_kms_duplicate_shadow_plane_state - duplicates shadow-buffered plane state 43562306a36Sopenharmony_ci * @pipe: the simple display pipe 43662306a36Sopenharmony_ci * 43762306a36Sopenharmony_ci * This function implements struct drm_simple_display_funcs.duplicate_plane_state 43862306a36Sopenharmony_ci * for shadow-buffered planes. It does not duplicate existing mappings of the shadow 43962306a36Sopenharmony_ci * buffers. Mappings are maintained during the atomic commit by the plane's prepare_fb 44062306a36Sopenharmony_ci * and cleanup_fb helpers. 44162306a36Sopenharmony_ci * 44262306a36Sopenharmony_ci * Returns: 44362306a36Sopenharmony_ci * A pointer to a new plane state on success, or NULL otherwise. 44462306a36Sopenharmony_ci */ 44562306a36Sopenharmony_cistruct drm_plane_state * 44662306a36Sopenharmony_cidrm_gem_simple_kms_duplicate_shadow_plane_state(struct drm_simple_display_pipe *pipe) 44762306a36Sopenharmony_ci{ 44862306a36Sopenharmony_ci return drm_gem_duplicate_shadow_plane_state(&pipe->plane); 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_simple_kms_duplicate_shadow_plane_state); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci/** 45362306a36Sopenharmony_ci * drm_gem_simple_kms_destroy_shadow_plane_state - resets shadow-buffered plane state 45462306a36Sopenharmony_ci * @pipe: the simple display pipe 45562306a36Sopenharmony_ci * @plane_state: the plane state of type struct drm_shadow_plane_state 45662306a36Sopenharmony_ci * 45762306a36Sopenharmony_ci * This function implements struct drm_simple_display_funcs.destroy_plane_state 45862306a36Sopenharmony_ci * for shadow-buffered planes. It expects that mappings of shadow buffers 45962306a36Sopenharmony_ci * have been released already. 46062306a36Sopenharmony_ci */ 46162306a36Sopenharmony_civoid drm_gem_simple_kms_destroy_shadow_plane_state(struct drm_simple_display_pipe *pipe, 46262306a36Sopenharmony_ci struct drm_plane_state *plane_state) 46362306a36Sopenharmony_ci{ 46462306a36Sopenharmony_ci drm_gem_destroy_shadow_plane_state(&pipe->plane, plane_state); 46562306a36Sopenharmony_ci} 46662306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_simple_kms_destroy_shadow_plane_state); 467