16dd7b6ceSThomas Zimmermann // SPDX-License-Identifier: GPL-2.0-or-later
26dd7b6ceSThomas Zimmermann
3820c1707SThomas Zimmermann #include <linux/dma-resv.h>
41ea28bc5SChristian König #include <linux/dma-fence-chain.h>
5820c1707SThomas Zimmermann
66dd7b6ceSThomas Zimmermann #include <drm/drm_atomic_state_helper.h>
7820c1707SThomas Zimmermann #include <drm/drm_atomic_uapi.h>
8720cf96dSVille Syrjälä #include <drm/drm_framebuffer.h>
9820c1707SThomas Zimmermann #include <drm/drm_gem.h>
106dd7b6ceSThomas Zimmermann #include <drm/drm_gem_atomic_helper.h>
116dd7b6ceSThomas Zimmermann #include <drm/drm_gem_framebuffer_helper.h>
126dd7b6ceSThomas Zimmermann #include <drm/drm_simple_kms_helper.h>
136dd7b6ceSThomas Zimmermann
146dd7b6ceSThomas Zimmermann #include "drm_internal.h"
156dd7b6ceSThomas Zimmermann
166dd7b6ceSThomas Zimmermann /**
176dd7b6ceSThomas Zimmermann * DOC: overview
186dd7b6ceSThomas Zimmermann *
196dd7b6ceSThomas Zimmermann * The GEM atomic helpers library implements generic atomic-commit
206dd7b6ceSThomas Zimmermann * functions for drivers that use GEM objects. Currently, it provides
21820c1707SThomas Zimmermann * synchronization helpers, and plane state and framebuffer BO mappings
22820c1707SThomas Zimmermann * for planes with shadow buffers.
23820c1707SThomas Zimmermann *
24820c1707SThomas Zimmermann * Before scanout, a plane's framebuffer needs to be synchronized with
25820c1707SThomas Zimmermann * possible writers that draw into the framebuffer. All drivers should
26820c1707SThomas Zimmermann * call drm_gem_plane_helper_prepare_fb() from their implementation of
27820c1707SThomas Zimmermann * struct &drm_plane_helper.prepare_fb . It sets the plane's fence from
28820c1707SThomas Zimmermann * the framebuffer so that the DRM core can synchronize access automatically.
29820c1707SThomas Zimmermann * drm_gem_plane_helper_prepare_fb() can also be used directly as
3000b5497dSThomas Zimmermann * implementation of prepare_fb.
31820c1707SThomas Zimmermann *
32820c1707SThomas Zimmermann * .. code-block:: c
33820c1707SThomas Zimmermann *
34820c1707SThomas Zimmermann * #include <drm/drm_gem_atomic_helper.h>
35820c1707SThomas Zimmermann *
36820c1707SThomas Zimmermann * struct drm_plane_helper_funcs driver_plane_helper_funcs = {
37820c1707SThomas Zimmermann * ...,
38820c1707SThomas Zimmermann * . prepare_fb = drm_gem_plane_helper_prepare_fb,
39820c1707SThomas Zimmermann * };
40820c1707SThomas Zimmermann *
419dc9067dSThomas Zimmermann * A driver using a shadow buffer copies the content of the shadow buffers
429dc9067dSThomas Zimmermann * into the HW's framebuffer memory during an atomic update. This requires
439dc9067dSThomas Zimmermann * a mapping of the shadow buffer into kernel address space. The mappings
449dc9067dSThomas Zimmermann * cannot be established by commit-tail functions, such as atomic_update,
459dc9067dSThomas Zimmermann * as this would violate locking rules around dma_buf_vmap().
469dc9067dSThomas Zimmermann *
479dc9067dSThomas Zimmermann * The helpers for shadow-buffered planes establish and release mappings,
489dc9067dSThomas Zimmermann * and provide struct drm_shadow_plane_state, which stores the plane's mapping
490ae865efSCai Huoqing * for commit-tail functions.
509dc9067dSThomas Zimmermann *
519dc9067dSThomas Zimmermann * Shadow-buffered planes can easily be enabled by using the provided macros
529dc9067dSThomas Zimmermann * %DRM_GEM_SHADOW_PLANE_FUNCS and %DRM_GEM_SHADOW_PLANE_HELPER_FUNCS.
539dc9067dSThomas Zimmermann * These macros set up the plane and plane-helper callbacks to point to the
549dc9067dSThomas Zimmermann * shadow-buffer helpers.
559dc9067dSThomas Zimmermann *
569dc9067dSThomas Zimmermann * .. code-block:: c
579dc9067dSThomas Zimmermann *
58820c1707SThomas Zimmermann * #include <drm/drm_gem_atomic_helper.h>
599dc9067dSThomas Zimmermann *
609dc9067dSThomas Zimmermann * struct drm_plane_funcs driver_plane_funcs = {
619dc9067dSThomas Zimmermann * ...,
629dc9067dSThomas Zimmermann * DRM_GEM_SHADOW_PLANE_FUNCS,
639dc9067dSThomas Zimmermann * };
649dc9067dSThomas Zimmermann *
659dc9067dSThomas Zimmermann * struct drm_plane_helper_funcs driver_plane_helper_funcs = {
669dc9067dSThomas Zimmermann * ...,
679dc9067dSThomas Zimmermann * DRM_GEM_SHADOW_PLANE_HELPER_FUNCS,
689dc9067dSThomas Zimmermann * };
699dc9067dSThomas Zimmermann *
709dc9067dSThomas Zimmermann * In the driver's atomic-update function, shadow-buffer mappings are available
719dc9067dSThomas Zimmermann * from the plane state. Use to_drm_shadow_plane_state() to upcast from
729dc9067dSThomas Zimmermann * struct drm_plane_state.
739dc9067dSThomas Zimmermann *
749dc9067dSThomas Zimmermann * .. code-block:: c
759dc9067dSThomas Zimmermann *
769dc9067dSThomas Zimmermann * void driver_plane_atomic_update(struct drm_plane *plane,
779dc9067dSThomas Zimmermann * struct drm_plane_state *old_plane_state)
789dc9067dSThomas Zimmermann * {
799dc9067dSThomas Zimmermann * struct drm_plane_state *plane_state = plane->state;
809dc9067dSThomas Zimmermann * struct drm_shadow_plane_state *shadow_plane_state =
819dc9067dSThomas Zimmermann * to_drm_shadow_plane_state(plane_state);
829dc9067dSThomas Zimmermann *
839dc9067dSThomas Zimmermann * // access shadow buffer via shadow_plane_state->map
849dc9067dSThomas Zimmermann * }
859dc9067dSThomas Zimmermann *
869dc9067dSThomas Zimmermann * A mapping address for each of the framebuffer's buffer object is stored in
879dc9067dSThomas Zimmermann * struct &drm_shadow_plane_state.map. The mappings are valid while the state
889dc9067dSThomas Zimmermann * is being used.
899dc9067dSThomas Zimmermann *
909dc9067dSThomas Zimmermann * Drivers that use struct drm_simple_display_pipe can use
919dc9067dSThomas Zimmermann * %DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS to initialize the rsp
929dc9067dSThomas Zimmermann * callbacks. Access to shadow-buffer mappings is similar to regular
939dc9067dSThomas Zimmermann * atomic_update.
949dc9067dSThomas Zimmermann *
959dc9067dSThomas Zimmermann * .. code-block:: c
969dc9067dSThomas Zimmermann *
979dc9067dSThomas Zimmermann * struct drm_simple_display_pipe_funcs driver_pipe_funcs = {
989dc9067dSThomas Zimmermann * ...,
999dc9067dSThomas Zimmermann * DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS,
1009dc9067dSThomas Zimmermann * };
1019dc9067dSThomas Zimmermann *
1029dc9067dSThomas Zimmermann * void driver_pipe_enable(struct drm_simple_display_pipe *pipe,
1039dc9067dSThomas Zimmermann * struct drm_crtc_state *crtc_state,
1049dc9067dSThomas Zimmermann * struct drm_plane_state *plane_state)
1059dc9067dSThomas Zimmermann * {
1069dc9067dSThomas Zimmermann * struct drm_shadow_plane_state *shadow_plane_state =
1079dc9067dSThomas Zimmermann * to_drm_shadow_plane_state(plane_state);
1089dc9067dSThomas Zimmermann *
1099dc9067dSThomas Zimmermann * // access shadow buffer via shadow_plane_state->map
1109dc9067dSThomas Zimmermann * }
1116dd7b6ceSThomas Zimmermann */
1126dd7b6ceSThomas Zimmermann
1136dd7b6ceSThomas Zimmermann /*
114820c1707SThomas Zimmermann * Plane Helpers
115820c1707SThomas Zimmermann */
116820c1707SThomas Zimmermann
117820c1707SThomas Zimmermann /**
118820c1707SThomas Zimmermann * drm_gem_plane_helper_prepare_fb() - Prepare a GEM backed framebuffer
119820c1707SThomas Zimmermann * @plane: Plane
120820c1707SThomas Zimmermann * @state: Plane state the fence will be attached to
121820c1707SThomas Zimmermann *
122820c1707SThomas Zimmermann * This function extracts the exclusive fence from &drm_gem_object.resv and
123820c1707SThomas Zimmermann * attaches it to plane state for the atomic helper to wait on. This is
124820c1707SThomas Zimmermann * necessary to correctly implement implicit synchronization for any buffers
125820c1707SThomas Zimmermann * shared as a struct &dma_buf. This function can be used as the
126820c1707SThomas Zimmermann * &drm_plane_helper_funcs.prepare_fb callback.
127820c1707SThomas Zimmermann *
128820c1707SThomas Zimmermann * There is no need for &drm_plane_helper_funcs.cleanup_fb hook for simple
129820c1707SThomas Zimmermann * GEM based framebuffer drivers which have their buffers always pinned in
130820c1707SThomas Zimmermann * memory.
131820c1707SThomas Zimmermann *
1327d30963fSDaniel Vetter * This function is the default implementation for GEM drivers of
1337d30963fSDaniel Vetter * &drm_plane_helper_funcs.prepare_fb if no callback is provided.
134820c1707SThomas Zimmermann */
drm_gem_plane_helper_prepare_fb(struct drm_plane * plane,struct drm_plane_state * state)1351ea28bc5SChristian König int drm_gem_plane_helper_prepare_fb(struct drm_plane *plane,
1361ea28bc5SChristian König struct drm_plane_state *state)
137820c1707SThomas Zimmermann {
1381ea28bc5SChristian König struct dma_fence *fence = dma_fence_get(state->fence);
1391ea28bc5SChristian König enum dma_resv_usage usage;
1401ea28bc5SChristian König size_t i;
141c382df71SChristian König int ret;
142820c1707SThomas Zimmermann
143820c1707SThomas Zimmermann if (!state->fb)
144820c1707SThomas Zimmermann return 0;
145820c1707SThomas Zimmermann
1461ea28bc5SChristian König /*
1471ea28bc5SChristian König * Only add the kernel fences here if there is already a fence set via
1481ea28bc5SChristian König * explicit fencing interfaces on the atomic ioctl.
1491ea28bc5SChristian König *
1501ea28bc5SChristian König * This way explicit fencing can be used to overrule implicit fencing,
1511ea28bc5SChristian König * which is important to make explicit fencing use-cases work: One
1521ea28bc5SChristian König * example is using one buffer for 2 screens with different refresh
1531ea28bc5SChristian König * rates. Implicit fencing will clamp rendering to the refresh rate of
1541ea28bc5SChristian König * the slower screen, whereas explicit fence allows 2 independent
1551ea28bc5SChristian König * render and display loops on a single buffer. If a driver allows
1561ea28bc5SChristian König * obeys both implicit and explicit fences for plane updates, then it
1571ea28bc5SChristian König * will break all the benefits of explicit fencing.
158c382df71SChristian König */
1591ea28bc5SChristian König usage = fence ? DMA_RESV_USAGE_KERNEL : DMA_RESV_USAGE_WRITE;
1601ea28bc5SChristian König
1611ea28bc5SChristian König for (i = 0; i < state->fb->format->num_planes; ++i) {
1621ea28bc5SChristian König struct drm_gem_object *obj = drm_gem_fb_get_obj(state->fb, i);
1631ea28bc5SChristian König struct dma_fence *new;
1641ea28bc5SChristian König
165746b9c62SThomas Zimmermann if (!obj) {
166746b9c62SThomas Zimmermann ret = -EINVAL;
167746b9c62SThomas Zimmermann goto error;
168746b9c62SThomas Zimmermann }
1691ea28bc5SChristian König
1701ea28bc5SChristian König ret = dma_resv_get_singleton(obj->resv, usage, &new);
1711ea28bc5SChristian König if (ret)
1721ea28bc5SChristian König goto error;
1731ea28bc5SChristian König
1741ea28bc5SChristian König if (new && fence) {
1751ea28bc5SChristian König struct dma_fence_chain *chain = dma_fence_chain_alloc();
1761ea28bc5SChristian König
1771ea28bc5SChristian König if (!chain) {
1781ea28bc5SChristian König ret = -ENOMEM;
1791ea28bc5SChristian König goto error;
1801ea28bc5SChristian König }
1811ea28bc5SChristian König
1821ea28bc5SChristian König dma_fence_chain_init(chain, fence, new, 1);
1831ea28bc5SChristian König fence = &chain->base;
1841ea28bc5SChristian König
1851ea28bc5SChristian König } else if (new) {
1861ea28bc5SChristian König fence = new;
1871ea28bc5SChristian König }
1881ea28bc5SChristian König }
1891ea28bc5SChristian König
1901ea28bc5SChristian König dma_fence_put(state->fence);
1911ea28bc5SChristian König state->fence = fence;
192820c1707SThomas Zimmermann return 0;
1931ea28bc5SChristian König
1941ea28bc5SChristian König error:
1951ea28bc5SChristian König dma_fence_put(fence);
1961ea28bc5SChristian König return ret;
197820c1707SThomas Zimmermann }
198820c1707SThomas Zimmermann EXPORT_SYMBOL_GPL(drm_gem_plane_helper_prepare_fb);
199820c1707SThomas Zimmermann
200820c1707SThomas Zimmermann /*
2016dd7b6ceSThomas Zimmermann * Shadow-buffered Planes
2026dd7b6ceSThomas Zimmermann */
2036dd7b6ceSThomas Zimmermann
2049dc9067dSThomas Zimmermann /**
205b7156502SThomas Zimmermann * __drm_gem_duplicate_shadow_plane_state - duplicates shadow-buffered plane state
206b7156502SThomas Zimmermann * @plane: the plane
207b7156502SThomas Zimmermann * @new_shadow_plane_state: the new shadow-buffered plane state
208b7156502SThomas Zimmermann *
209b7156502SThomas Zimmermann * This function duplicates shadow-buffered plane state. This is helpful for drivers
210b7156502SThomas Zimmermann * that subclass struct drm_shadow_plane_state.
211b7156502SThomas Zimmermann *
212b7156502SThomas Zimmermann * The function does not duplicate existing mappings of the shadow buffers.
213b7156502SThomas Zimmermann * Mappings are maintained during the atomic commit by the plane's prepare_fb
214b7156502SThomas Zimmermann * and cleanup_fb helpers. See drm_gem_prepare_shadow_fb() and drm_gem_cleanup_shadow_fb()
215b7156502SThomas Zimmermann * for corresponding helpers.
216b7156502SThomas Zimmermann */
217b7156502SThomas Zimmermann void
__drm_gem_duplicate_shadow_plane_state(struct drm_plane * plane,struct drm_shadow_plane_state * new_shadow_plane_state)218b7156502SThomas Zimmermann __drm_gem_duplicate_shadow_plane_state(struct drm_plane *plane,
219b7156502SThomas Zimmermann struct drm_shadow_plane_state *new_shadow_plane_state)
220b7156502SThomas Zimmermann {
22190367458SThomas Zimmermann struct drm_plane_state *plane_state = plane->state;
22290367458SThomas Zimmermann struct drm_shadow_plane_state *shadow_plane_state =
22390367458SThomas Zimmermann to_drm_shadow_plane_state(plane_state);
22490367458SThomas Zimmermann
225b7156502SThomas Zimmermann __drm_atomic_helper_plane_duplicate_state(plane, &new_shadow_plane_state->base);
22690367458SThomas Zimmermann
227*a386c304SLucas Stach drm_format_conv_state_copy(&new_shadow_plane_state->fmtcnv_state,
228*a386c304SLucas Stach &shadow_plane_state->fmtcnv_state);
229b7156502SThomas Zimmermann }
230b7156502SThomas Zimmermann EXPORT_SYMBOL(__drm_gem_duplicate_shadow_plane_state);
231b7156502SThomas Zimmermann
232b7156502SThomas Zimmermann /**
2339dc9067dSThomas Zimmermann * drm_gem_duplicate_shadow_plane_state - duplicates shadow-buffered plane state
2349dc9067dSThomas Zimmermann * @plane: the plane
2359dc9067dSThomas Zimmermann *
2369dc9067dSThomas Zimmermann * This function implements struct &drm_plane_funcs.atomic_duplicate_state for
2379dc9067dSThomas Zimmermann * shadow-buffered planes. It assumes the existing state to be of type
2389dc9067dSThomas Zimmermann * struct drm_shadow_plane_state and it allocates the new state to be of this
2399dc9067dSThomas Zimmermann * type.
2409dc9067dSThomas Zimmermann *
2419dc9067dSThomas Zimmermann * The function does not duplicate existing mappings of the shadow buffers.
2429dc9067dSThomas Zimmermann * Mappings are maintained during the atomic commit by the plane's prepare_fb
2439dc9067dSThomas Zimmermann * and cleanup_fb helpers. See drm_gem_prepare_shadow_fb() and drm_gem_cleanup_shadow_fb()
2449dc9067dSThomas Zimmermann * for corresponding helpers.
2459dc9067dSThomas Zimmermann *
2469dc9067dSThomas Zimmermann * Returns:
2479dc9067dSThomas Zimmermann * A pointer to a new plane state on success, or NULL otherwise.
2489dc9067dSThomas Zimmermann */
2499dc9067dSThomas Zimmermann struct drm_plane_state *
drm_gem_duplicate_shadow_plane_state(struct drm_plane * plane)2506dd7b6ceSThomas Zimmermann drm_gem_duplicate_shadow_plane_state(struct drm_plane *plane)
2516dd7b6ceSThomas Zimmermann {
2526dd7b6ceSThomas Zimmermann struct drm_plane_state *plane_state = plane->state;
2536dd7b6ceSThomas Zimmermann struct drm_shadow_plane_state *new_shadow_plane_state;
2546dd7b6ceSThomas Zimmermann
2556dd7b6ceSThomas Zimmermann if (!plane_state)
2566dd7b6ceSThomas Zimmermann return NULL;
2576dd7b6ceSThomas Zimmermann
2586dd7b6ceSThomas Zimmermann new_shadow_plane_state = kzalloc(sizeof(*new_shadow_plane_state), GFP_KERNEL);
2596dd7b6ceSThomas Zimmermann if (!new_shadow_plane_state)
2606dd7b6ceSThomas Zimmermann return NULL;
261b7156502SThomas Zimmermann __drm_gem_duplicate_shadow_plane_state(plane, new_shadow_plane_state);
2626dd7b6ceSThomas Zimmermann
2636dd7b6ceSThomas Zimmermann return &new_shadow_plane_state->base;
2646dd7b6ceSThomas Zimmermann }
2659dc9067dSThomas Zimmermann EXPORT_SYMBOL(drm_gem_duplicate_shadow_plane_state);
2666dd7b6ceSThomas Zimmermann
2679dc9067dSThomas Zimmermann /**
268b7156502SThomas Zimmermann * __drm_gem_destroy_shadow_plane_state - cleans up shadow-buffered plane state
269b7156502SThomas Zimmermann * @shadow_plane_state: the shadow-buffered plane state
270b7156502SThomas Zimmermann *
271b7156502SThomas Zimmermann * This function cleans up shadow-buffered plane state. Helpful for drivers that
272b7156502SThomas Zimmermann * subclass struct drm_shadow_plane_state.
273b7156502SThomas Zimmermann */
__drm_gem_destroy_shadow_plane_state(struct drm_shadow_plane_state * shadow_plane_state)274b7156502SThomas Zimmermann void __drm_gem_destroy_shadow_plane_state(struct drm_shadow_plane_state *shadow_plane_state)
275b7156502SThomas Zimmermann {
27690367458SThomas Zimmermann drm_format_conv_state_release(&shadow_plane_state->fmtcnv_state);
277b7156502SThomas Zimmermann __drm_atomic_helper_plane_destroy_state(&shadow_plane_state->base);
278b7156502SThomas Zimmermann }
279b7156502SThomas Zimmermann EXPORT_SYMBOL(__drm_gem_destroy_shadow_plane_state);
280b7156502SThomas Zimmermann
281b7156502SThomas Zimmermann /**
2829dc9067dSThomas Zimmermann * drm_gem_destroy_shadow_plane_state - deletes shadow-buffered plane state
2839dc9067dSThomas Zimmermann * @plane: the plane
2849dc9067dSThomas Zimmermann * @plane_state: the plane state of type struct drm_shadow_plane_state
2859dc9067dSThomas Zimmermann *
2869dc9067dSThomas Zimmermann * This function implements struct &drm_plane_funcs.atomic_destroy_state
2879dc9067dSThomas Zimmermann * for shadow-buffered planes. It expects that mappings of shadow buffers
2889dc9067dSThomas Zimmermann * have been released already.
2899dc9067dSThomas Zimmermann */
drm_gem_destroy_shadow_plane_state(struct drm_plane * plane,struct drm_plane_state * plane_state)2909dc9067dSThomas Zimmermann void drm_gem_destroy_shadow_plane_state(struct drm_plane *plane,
2916dd7b6ceSThomas Zimmermann struct drm_plane_state *plane_state)
2926dd7b6ceSThomas Zimmermann {
2936dd7b6ceSThomas Zimmermann struct drm_shadow_plane_state *shadow_plane_state =
2946dd7b6ceSThomas Zimmermann to_drm_shadow_plane_state(plane_state);
2956dd7b6ceSThomas Zimmermann
296b7156502SThomas Zimmermann __drm_gem_destroy_shadow_plane_state(shadow_plane_state);
2976dd7b6ceSThomas Zimmermann kfree(shadow_plane_state);
2986dd7b6ceSThomas Zimmermann }
2999dc9067dSThomas Zimmermann EXPORT_SYMBOL(drm_gem_destroy_shadow_plane_state);
3006dd7b6ceSThomas Zimmermann
3019dc9067dSThomas Zimmermann /**
302b7156502SThomas Zimmermann * __drm_gem_reset_shadow_plane - resets a shadow-buffered plane
303b7156502SThomas Zimmermann * @plane: the plane
304b7156502SThomas Zimmermann * @shadow_plane_state: the shadow-buffered plane state
305b7156502SThomas Zimmermann *
306b7156502SThomas Zimmermann * This function resets state for shadow-buffered planes. Helpful
307b7156502SThomas Zimmermann * for drivers that subclass struct drm_shadow_plane_state.
308b7156502SThomas Zimmermann */
__drm_gem_reset_shadow_plane(struct drm_plane * plane,struct drm_shadow_plane_state * shadow_plane_state)309b7156502SThomas Zimmermann void __drm_gem_reset_shadow_plane(struct drm_plane *plane,
310b7156502SThomas Zimmermann struct drm_shadow_plane_state *shadow_plane_state)
311b7156502SThomas Zimmermann {
312b7156502SThomas Zimmermann __drm_atomic_helper_plane_reset(plane, &shadow_plane_state->base);
31390367458SThomas Zimmermann drm_format_conv_state_init(&shadow_plane_state->fmtcnv_state);
314b7156502SThomas Zimmermann }
315b7156502SThomas Zimmermann EXPORT_SYMBOL(__drm_gem_reset_shadow_plane);
316b7156502SThomas Zimmermann
317b7156502SThomas Zimmermann /**
3189dc9067dSThomas Zimmermann * drm_gem_reset_shadow_plane - resets a shadow-buffered plane
3199dc9067dSThomas Zimmermann * @plane: the plane
3209dc9067dSThomas Zimmermann *
3219dc9067dSThomas Zimmermann * This function implements struct &drm_plane_funcs.reset_plane for
3229dc9067dSThomas Zimmermann * shadow-buffered planes. It assumes the current plane state to be
3239dc9067dSThomas Zimmermann * of type struct drm_shadow_plane and it allocates the new state of
3249dc9067dSThomas Zimmermann * this type.
3259dc9067dSThomas Zimmermann */
drm_gem_reset_shadow_plane(struct drm_plane * plane)3269dc9067dSThomas Zimmermann void drm_gem_reset_shadow_plane(struct drm_plane *plane)
3276dd7b6ceSThomas Zimmermann {
3286dd7b6ceSThomas Zimmermann struct drm_shadow_plane_state *shadow_plane_state;
3296dd7b6ceSThomas Zimmermann
3306dd7b6ceSThomas Zimmermann if (plane->state) {
3316dd7b6ceSThomas Zimmermann drm_gem_destroy_shadow_plane_state(plane, plane->state);
3326dd7b6ceSThomas Zimmermann plane->state = NULL; /* must be set to NULL here */
3336dd7b6ceSThomas Zimmermann }
3346dd7b6ceSThomas Zimmermann
3356dd7b6ceSThomas Zimmermann shadow_plane_state = kzalloc(sizeof(*shadow_plane_state), GFP_KERNEL);
3366dd7b6ceSThomas Zimmermann if (!shadow_plane_state)
3376dd7b6ceSThomas Zimmermann return;
338b7156502SThomas Zimmermann __drm_gem_reset_shadow_plane(plane, shadow_plane_state);
3396dd7b6ceSThomas Zimmermann }
3409dc9067dSThomas Zimmermann EXPORT_SYMBOL(drm_gem_reset_shadow_plane);
3416dd7b6ceSThomas Zimmermann
3429dc9067dSThomas Zimmermann /**
343359c6649SThomas Zimmermann * drm_gem_begin_shadow_fb_access - prepares shadow framebuffers for CPU access
3449dc9067dSThomas Zimmermann * @plane: the plane
3459dc9067dSThomas Zimmermann * @plane_state: the plane state of type struct drm_shadow_plane_state
3469dc9067dSThomas Zimmermann *
347359c6649SThomas Zimmermann * This function implements struct &drm_plane_helper_funcs.begin_fb_access. It
3489dc9067dSThomas Zimmermann * maps all buffer objects of the plane's framebuffer into kernel address
349359c6649SThomas Zimmermann * space and stores them in struct &drm_shadow_plane_state.map. The first data
350359c6649SThomas Zimmermann * bytes are available in struct &drm_shadow_plane_state.data.
3519dc9067dSThomas Zimmermann *
352359c6649SThomas Zimmermann * See drm_gem_end_shadow_fb_access() for cleanup.
3539dc9067dSThomas Zimmermann *
3549dc9067dSThomas Zimmermann * Returns:
3559dc9067dSThomas Zimmermann * 0 on success, or a negative errno code otherwise.
3569dc9067dSThomas Zimmermann */
drm_gem_begin_shadow_fb_access(struct drm_plane * plane,struct drm_plane_state * plane_state)357359c6649SThomas Zimmermann int drm_gem_begin_shadow_fb_access(struct drm_plane *plane, struct drm_plane_state *plane_state)
3586dd7b6ceSThomas Zimmermann {
3596dd7b6ceSThomas Zimmermann struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
3606dd7b6ceSThomas Zimmermann struct drm_framebuffer *fb = plane_state->fb;
3616dd7b6ceSThomas Zimmermann
3626dd7b6ceSThomas Zimmermann if (!fb)
3636dd7b6ceSThomas Zimmermann return 0;
3646dd7b6ceSThomas Zimmermann
36543b36232SThomas Zimmermann return drm_gem_fb_vmap(fb, shadow_plane_state->map, shadow_plane_state->data);
3666dd7b6ceSThomas Zimmermann }
367359c6649SThomas Zimmermann EXPORT_SYMBOL(drm_gem_begin_shadow_fb_access);
3686dd7b6ceSThomas Zimmermann
3699dc9067dSThomas Zimmermann /**
370359c6649SThomas Zimmermann * drm_gem_end_shadow_fb_access - releases shadow framebuffers from CPU access
3719dc9067dSThomas Zimmermann * @plane: the plane
3729dc9067dSThomas Zimmermann * @plane_state: the plane state of type struct drm_shadow_plane_state
3739dc9067dSThomas Zimmermann *
374359c6649SThomas Zimmermann * This function implements struct &drm_plane_helper_funcs.end_fb_access. It
375359c6649SThomas Zimmermann * undoes all effects of drm_gem_begin_shadow_fb_access() in reverse order.
3769dc9067dSThomas Zimmermann *
377359c6649SThomas Zimmermann * See drm_gem_begin_shadow_fb_access() for more information.
3789dc9067dSThomas Zimmermann */
drm_gem_end_shadow_fb_access(struct drm_plane * plane,struct drm_plane_state * plane_state)379359c6649SThomas Zimmermann void drm_gem_end_shadow_fb_access(struct drm_plane *plane, struct drm_plane_state *plane_state)
3806dd7b6ceSThomas Zimmermann {
3816dd7b6ceSThomas Zimmermann struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
3826dd7b6ceSThomas Zimmermann struct drm_framebuffer *fb = plane_state->fb;
3836dd7b6ceSThomas Zimmermann
3846dd7b6ceSThomas Zimmermann if (!fb)
3856dd7b6ceSThomas Zimmermann return;
3866dd7b6ceSThomas Zimmermann
387f6424ecdSThomas Zimmermann drm_gem_fb_vunmap(fb, shadow_plane_state->map);
3886dd7b6ceSThomas Zimmermann }
389359c6649SThomas Zimmermann EXPORT_SYMBOL(drm_gem_end_shadow_fb_access);
3906dd7b6ceSThomas Zimmermann
3916dd7b6ceSThomas Zimmermann /**
39294d879eaSThomas Zimmermann * drm_gem_simple_kms_begin_shadow_fb_access - prepares shadow framebuffers for CPU access
3936dd7b6ceSThomas Zimmermann * @pipe: the simple display pipe
3946dd7b6ceSThomas Zimmermann * @plane_state: the plane state of type struct drm_shadow_plane_state
3956dd7b6ceSThomas Zimmermann *
39694d879eaSThomas Zimmermann * This function implements struct drm_simple_display_funcs.begin_fb_access.
3976dd7b6ceSThomas Zimmermann *
39894d879eaSThomas Zimmermann * See drm_gem_begin_shadow_fb_access() for details and
39994d879eaSThomas Zimmermann * drm_gem_simple_kms_cleanup_shadow_fb() for cleanup.
4006dd7b6ceSThomas Zimmermann *
4016dd7b6ceSThomas Zimmermann * Returns:
4026dd7b6ceSThomas Zimmermann * 0 on success, or a negative errno code otherwise.
4036dd7b6ceSThomas Zimmermann */
drm_gem_simple_kms_begin_shadow_fb_access(struct drm_simple_display_pipe * pipe,struct drm_plane_state * plane_state)404359c6649SThomas Zimmermann int drm_gem_simple_kms_begin_shadow_fb_access(struct drm_simple_display_pipe *pipe,
4056dd7b6ceSThomas Zimmermann struct drm_plane_state *plane_state)
4066dd7b6ceSThomas Zimmermann {
407359c6649SThomas Zimmermann return drm_gem_begin_shadow_fb_access(&pipe->plane, plane_state);
4086dd7b6ceSThomas Zimmermann }
409359c6649SThomas Zimmermann EXPORT_SYMBOL(drm_gem_simple_kms_begin_shadow_fb_access);
4106dd7b6ceSThomas Zimmermann
4116dd7b6ceSThomas Zimmermann /**
41294d879eaSThomas Zimmermann * drm_gem_simple_kms_end_shadow_fb_access - releases shadow framebuffers from CPU access
4136dd7b6ceSThomas Zimmermann * @pipe: the simple display pipe
4146dd7b6ceSThomas Zimmermann * @plane_state: the plane state of type struct drm_shadow_plane_state
4156dd7b6ceSThomas Zimmermann *
41694d879eaSThomas Zimmermann * This function implements struct drm_simple_display_funcs.end_fb_access.
41794d879eaSThomas Zimmermann * It undoes all effects of drm_gem_simple_kms_begin_shadow_fb_access() in
41894d879eaSThomas Zimmermann * reverse order.
4196dd7b6ceSThomas Zimmermann *
42094d879eaSThomas Zimmermann * See drm_gem_simple_kms_begin_shadow_fb_access().
4216dd7b6ceSThomas Zimmermann */
drm_gem_simple_kms_end_shadow_fb_access(struct drm_simple_display_pipe * pipe,struct drm_plane_state * plane_state)422359c6649SThomas Zimmermann void drm_gem_simple_kms_end_shadow_fb_access(struct drm_simple_display_pipe *pipe,
4236dd7b6ceSThomas Zimmermann struct drm_plane_state *plane_state)
4246dd7b6ceSThomas Zimmermann {
425359c6649SThomas Zimmermann drm_gem_end_shadow_fb_access(&pipe->plane, plane_state);
4266dd7b6ceSThomas Zimmermann }
427359c6649SThomas Zimmermann EXPORT_SYMBOL(drm_gem_simple_kms_end_shadow_fb_access);
4286dd7b6ceSThomas Zimmermann
4296dd7b6ceSThomas Zimmermann /**
4306dd7b6ceSThomas Zimmermann * drm_gem_simple_kms_reset_shadow_plane - resets a shadow-buffered plane
4316dd7b6ceSThomas Zimmermann * @pipe: the simple display pipe
4326dd7b6ceSThomas Zimmermann *
4336dd7b6ceSThomas Zimmermann * This function implements struct drm_simple_display_funcs.reset_plane
4346dd7b6ceSThomas Zimmermann * for shadow-buffered planes.
4356dd7b6ceSThomas Zimmermann */
drm_gem_simple_kms_reset_shadow_plane(struct drm_simple_display_pipe * pipe)4366dd7b6ceSThomas Zimmermann void drm_gem_simple_kms_reset_shadow_plane(struct drm_simple_display_pipe *pipe)
4376dd7b6ceSThomas Zimmermann {
4386dd7b6ceSThomas Zimmermann drm_gem_reset_shadow_plane(&pipe->plane);
4396dd7b6ceSThomas Zimmermann }
4406dd7b6ceSThomas Zimmermann EXPORT_SYMBOL(drm_gem_simple_kms_reset_shadow_plane);
4416dd7b6ceSThomas Zimmermann
4426dd7b6ceSThomas Zimmermann /**
4436dd7b6ceSThomas Zimmermann * drm_gem_simple_kms_duplicate_shadow_plane_state - duplicates shadow-buffered plane state
4446dd7b6ceSThomas Zimmermann * @pipe: the simple display pipe
4456dd7b6ceSThomas Zimmermann *
4466dd7b6ceSThomas Zimmermann * This function implements struct drm_simple_display_funcs.duplicate_plane_state
4476dd7b6ceSThomas Zimmermann * for shadow-buffered planes. It does not duplicate existing mappings of the shadow
4486dd7b6ceSThomas Zimmermann * buffers. Mappings are maintained during the atomic commit by the plane's prepare_fb
4496dd7b6ceSThomas Zimmermann * and cleanup_fb helpers.
4506dd7b6ceSThomas Zimmermann *
4516dd7b6ceSThomas Zimmermann * Returns:
4526dd7b6ceSThomas Zimmermann * A pointer to a new plane state on success, or NULL otherwise.
4536dd7b6ceSThomas Zimmermann */
4546dd7b6ceSThomas Zimmermann struct drm_plane_state *
drm_gem_simple_kms_duplicate_shadow_plane_state(struct drm_simple_display_pipe * pipe)4556dd7b6ceSThomas Zimmermann drm_gem_simple_kms_duplicate_shadow_plane_state(struct drm_simple_display_pipe *pipe)
4566dd7b6ceSThomas Zimmermann {
4576dd7b6ceSThomas Zimmermann return drm_gem_duplicate_shadow_plane_state(&pipe->plane);
4586dd7b6ceSThomas Zimmermann }
4596dd7b6ceSThomas Zimmermann EXPORT_SYMBOL(drm_gem_simple_kms_duplicate_shadow_plane_state);
4606dd7b6ceSThomas Zimmermann
4616dd7b6ceSThomas Zimmermann /**
4626dd7b6ceSThomas Zimmermann * drm_gem_simple_kms_destroy_shadow_plane_state - resets shadow-buffered plane state
4636dd7b6ceSThomas Zimmermann * @pipe: the simple display pipe
4646dd7b6ceSThomas Zimmermann * @plane_state: the plane state of type struct drm_shadow_plane_state
4656dd7b6ceSThomas Zimmermann *
4666dd7b6ceSThomas Zimmermann * This function implements struct drm_simple_display_funcs.destroy_plane_state
4676dd7b6ceSThomas Zimmermann * for shadow-buffered planes. It expects that mappings of shadow buffers
4686dd7b6ceSThomas Zimmermann * have been released already.
4696dd7b6ceSThomas Zimmermann */
drm_gem_simple_kms_destroy_shadow_plane_state(struct drm_simple_display_pipe * pipe,struct drm_plane_state * plane_state)4706dd7b6ceSThomas Zimmermann void drm_gem_simple_kms_destroy_shadow_plane_state(struct drm_simple_display_pipe *pipe,
4716dd7b6ceSThomas Zimmermann struct drm_plane_state *plane_state)
4726dd7b6ceSThomas Zimmermann {
4736dd7b6ceSThomas Zimmermann drm_gem_destroy_shadow_plane_state(&pipe->plane, plane_state);
4746dd7b6ceSThomas Zimmermann }
4756dd7b6ceSThomas Zimmermann EXPORT_SYMBOL(drm_gem_simple_kms_destroy_shadow_plane_state);
476