1 // SPDX-License-Identifier: GPL-2.0-or-later 2 3 #include <drm/drm_atomic_state_helper.h> 4 #include <drm/drm_gem_atomic_helper.h> 5 #include <drm/drm_gem_framebuffer_helper.h> 6 #include <drm/drm_simple_kms_helper.h> 7 8 #include "drm_internal.h" 9 10 /** 11 * DOC: overview 12 * 13 * The GEM atomic helpers library implements generic atomic-commit 14 * functions for drivers that use GEM objects. Currently, it provides 15 * plane state and framebuffer BO mappings for planes with shadow 16 * buffers. 17 * 18 * A driver using a shadow buffer copies the content of the shadow buffers 19 * into the HW's framebuffer memory during an atomic update. This requires 20 * a mapping of the shadow buffer into kernel address space. The mappings 21 * cannot be established by commit-tail functions, such as atomic_update, 22 * as this would violate locking rules around dma_buf_vmap(). 23 * 24 * The helpers for shadow-buffered planes establish and release mappings, 25 * and provide struct drm_shadow_plane_state, which stores the plane's mapping 26 * for commit-tail functons. 27 * 28 * Shadow-buffered planes can easily be enabled by using the provided macros 29 * %DRM_GEM_SHADOW_PLANE_FUNCS and %DRM_GEM_SHADOW_PLANE_HELPER_FUNCS. 30 * These macros set up the plane and plane-helper callbacks to point to the 31 * shadow-buffer helpers. 32 * 33 * .. code-block:: c 34 * 35 * #include <drm/drm/gem_atomic_helper.h> 36 * 37 * struct drm_plane_funcs driver_plane_funcs = { 38 * ..., 39 * DRM_GEM_SHADOW_PLANE_FUNCS, 40 * }; 41 * 42 * struct drm_plane_helper_funcs driver_plane_helper_funcs = { 43 * ..., 44 * DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, 45 * }; 46 * 47 * In the driver's atomic-update function, shadow-buffer mappings are available 48 * from the plane state. Use to_drm_shadow_plane_state() to upcast from 49 * struct drm_plane_state. 50 * 51 * .. code-block:: c 52 * 53 * void driver_plane_atomic_update(struct drm_plane *plane, 54 * struct drm_plane_state *old_plane_state) 55 * { 56 * struct drm_plane_state *plane_state = plane->state; 57 * struct drm_shadow_plane_state *shadow_plane_state = 58 * to_drm_shadow_plane_state(plane_state); 59 * 60 * // access shadow buffer via shadow_plane_state->map 61 * } 62 * 63 * A mapping address for each of the framebuffer's buffer object is stored in 64 * struct &drm_shadow_plane_state.map. The mappings are valid while the state 65 * is being used. 66 * 67 * Drivers that use struct drm_simple_display_pipe can use 68 * %DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS to initialize the rsp 69 * callbacks. Access to shadow-buffer mappings is similar to regular 70 * atomic_update. 71 * 72 * .. code-block:: c 73 * 74 * struct drm_simple_display_pipe_funcs driver_pipe_funcs = { 75 * ..., 76 * DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS, 77 * }; 78 * 79 * void driver_pipe_enable(struct drm_simple_display_pipe *pipe, 80 * struct drm_crtc_state *crtc_state, 81 * struct drm_plane_state *plane_state) 82 * { 83 * struct drm_shadow_plane_state *shadow_plane_state = 84 * to_drm_shadow_plane_state(plane_state); 85 * 86 * // access shadow buffer via shadow_plane_state->map 87 * } 88 */ 89 90 /* 91 * Shadow-buffered Planes 92 */ 93 94 /** 95 * drm_gem_duplicate_shadow_plane_state - duplicates shadow-buffered plane state 96 * @plane: the plane 97 * 98 * This function implements struct &drm_plane_funcs.atomic_duplicate_state for 99 * shadow-buffered planes. It assumes the existing state to be of type 100 * struct drm_shadow_plane_state and it allocates the new state to be of this 101 * type. 102 * 103 * The function does not duplicate existing mappings of the shadow buffers. 104 * Mappings are maintained during the atomic commit by the plane's prepare_fb 105 * and cleanup_fb helpers. See drm_gem_prepare_shadow_fb() and drm_gem_cleanup_shadow_fb() 106 * for corresponding helpers. 107 * 108 * Returns: 109 * A pointer to a new plane state on success, or NULL otherwise. 110 */ 111 struct drm_plane_state * 112 drm_gem_duplicate_shadow_plane_state(struct drm_plane *plane) 113 { 114 struct drm_plane_state *plane_state = plane->state; 115 struct drm_shadow_plane_state *new_shadow_plane_state; 116 117 if (!plane_state) 118 return NULL; 119 120 new_shadow_plane_state = kzalloc(sizeof(*new_shadow_plane_state), GFP_KERNEL); 121 if (!new_shadow_plane_state) 122 return NULL; 123 __drm_atomic_helper_plane_duplicate_state(plane, &new_shadow_plane_state->base); 124 125 return &new_shadow_plane_state->base; 126 } 127 EXPORT_SYMBOL(drm_gem_duplicate_shadow_plane_state); 128 129 /** 130 * drm_gem_destroy_shadow_plane_state - deletes shadow-buffered plane state 131 * @plane: the plane 132 * @plane_state: the plane state of type struct drm_shadow_plane_state 133 * 134 * This function implements struct &drm_plane_funcs.atomic_destroy_state 135 * for shadow-buffered planes. It expects that mappings of shadow buffers 136 * have been released already. 137 */ 138 void drm_gem_destroy_shadow_plane_state(struct drm_plane *plane, 139 struct drm_plane_state *plane_state) 140 { 141 struct drm_shadow_plane_state *shadow_plane_state = 142 to_drm_shadow_plane_state(plane_state); 143 144 __drm_atomic_helper_plane_destroy_state(&shadow_plane_state->base); 145 kfree(shadow_plane_state); 146 } 147 EXPORT_SYMBOL(drm_gem_destroy_shadow_plane_state); 148 149 /** 150 * drm_gem_reset_shadow_plane - resets a shadow-buffered plane 151 * @plane: the plane 152 * 153 * This function implements struct &drm_plane_funcs.reset_plane for 154 * shadow-buffered planes. It assumes the current plane state to be 155 * of type struct drm_shadow_plane and it allocates the new state of 156 * this type. 157 */ 158 void drm_gem_reset_shadow_plane(struct drm_plane *plane) 159 { 160 struct drm_shadow_plane_state *shadow_plane_state; 161 162 if (plane->state) { 163 drm_gem_destroy_shadow_plane_state(plane, plane->state); 164 plane->state = NULL; /* must be set to NULL here */ 165 } 166 167 shadow_plane_state = kzalloc(sizeof(*shadow_plane_state), GFP_KERNEL); 168 if (!shadow_plane_state) 169 return; 170 __drm_atomic_helper_plane_reset(plane, &shadow_plane_state->base); 171 } 172 EXPORT_SYMBOL(drm_gem_reset_shadow_plane); 173 174 /** 175 * drm_gem_prepare_shadow_fb - prepares shadow framebuffers 176 * @plane: the plane 177 * @plane_state: the plane state of type struct drm_shadow_plane_state 178 * 179 * This function implements struct &drm_plane_helper_funcs.prepare_fb. It 180 * maps all buffer objects of the plane's framebuffer into kernel address 181 * space and stores them in &struct drm_shadow_plane_state.map. The 182 * framebuffer will be synchronized as part of the atomic commit. 183 * 184 * See drm_gem_cleanup_shadow_fb() for cleanup. 185 * 186 * Returns: 187 * 0 on success, or a negative errno code otherwise. 188 */ 189 int drm_gem_prepare_shadow_fb(struct drm_plane *plane, struct drm_plane_state *plane_state) 190 { 191 struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); 192 struct drm_framebuffer *fb = plane_state->fb; 193 struct drm_gem_object *obj; 194 struct dma_buf_map map; 195 int ret; 196 size_t i; 197 198 if (!fb) 199 return 0; 200 201 ret = drm_gem_fb_prepare_fb(plane, plane_state); 202 if (ret) 203 return ret; 204 205 for (i = 0; i < ARRAY_SIZE(shadow_plane_state->map); ++i) { 206 obj = drm_gem_fb_get_obj(fb, i); 207 if (!obj) 208 continue; 209 ret = drm_gem_vmap(obj, &map); 210 if (ret) 211 goto err_drm_gem_vunmap; 212 shadow_plane_state->map[i] = map; 213 } 214 215 return 0; 216 217 err_drm_gem_vunmap: 218 while (i) { 219 --i; 220 obj = drm_gem_fb_get_obj(fb, i); 221 if (!obj) 222 continue; 223 drm_gem_vunmap(obj, &shadow_plane_state->map[i]); 224 } 225 return ret; 226 } 227 EXPORT_SYMBOL(drm_gem_prepare_shadow_fb); 228 229 /** 230 * drm_gem_cleanup_shadow_fb - releases shadow framebuffers 231 * @plane: the plane 232 * @plane_state: the plane state of type struct drm_shadow_plane_state 233 * 234 * This function implements struct &drm_plane_helper_funcs.cleanup_fb. 235 * This function unmaps all buffer objects of the plane's framebuffer. 236 * 237 * See drm_gem_prepare_shadow_fb() for more inforamtion. 238 */ 239 void drm_gem_cleanup_shadow_fb(struct drm_plane *plane, struct drm_plane_state *plane_state) 240 { 241 struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); 242 struct drm_framebuffer *fb = plane_state->fb; 243 size_t i = ARRAY_SIZE(shadow_plane_state->map); 244 struct drm_gem_object *obj; 245 246 if (!fb) 247 return; 248 249 while (i) { 250 --i; 251 obj = drm_gem_fb_get_obj(fb, i); 252 if (!obj) 253 continue; 254 drm_gem_vunmap(obj, &shadow_plane_state->map[i]); 255 } 256 } 257 EXPORT_SYMBOL(drm_gem_cleanup_shadow_fb); 258 259 /** 260 * drm_gem_simple_kms_prepare_shadow_fb - prepares shadow framebuffers 261 * @pipe: the simple display pipe 262 * @plane_state: the plane state of type struct drm_shadow_plane_state 263 * 264 * This function implements struct drm_simple_display_funcs.prepare_fb. It 265 * maps all buffer objects of the plane's framebuffer into kernel address 266 * space and stores them in struct drm_shadow_plane_state.map. The 267 * framebuffer will be synchronized as part of the atomic commit. 268 * 269 * See drm_gem_simple_kms_cleanup_shadow_fb() for cleanup. 270 * 271 * Returns: 272 * 0 on success, or a negative errno code otherwise. 273 */ 274 int drm_gem_simple_kms_prepare_shadow_fb(struct drm_simple_display_pipe *pipe, 275 struct drm_plane_state *plane_state) 276 { 277 return drm_gem_prepare_shadow_fb(&pipe->plane, plane_state); 278 } 279 EXPORT_SYMBOL(drm_gem_simple_kms_prepare_shadow_fb); 280 281 /** 282 * drm_gem_simple_kms_cleanup_shadow_fb - releases shadow framebuffers 283 * @pipe: the simple display pipe 284 * @plane_state: the plane state of type struct drm_shadow_plane_state 285 * 286 * This function implements struct drm_simple_display_funcs.cleanup_fb. 287 * This function unmaps all buffer objects of the plane's framebuffer. 288 * 289 * See drm_gem_simple_kms_prepare_shadow_fb(). 290 */ 291 void drm_gem_simple_kms_cleanup_shadow_fb(struct drm_simple_display_pipe *pipe, 292 struct drm_plane_state *plane_state) 293 { 294 drm_gem_cleanup_shadow_fb(&pipe->plane, plane_state); 295 } 296 EXPORT_SYMBOL(drm_gem_simple_kms_cleanup_shadow_fb); 297 298 /** 299 * drm_gem_simple_kms_reset_shadow_plane - resets a shadow-buffered plane 300 * @pipe: the simple display pipe 301 * 302 * This function implements struct drm_simple_display_funcs.reset_plane 303 * for shadow-buffered planes. 304 */ 305 void drm_gem_simple_kms_reset_shadow_plane(struct drm_simple_display_pipe *pipe) 306 { 307 drm_gem_reset_shadow_plane(&pipe->plane); 308 } 309 EXPORT_SYMBOL(drm_gem_simple_kms_reset_shadow_plane); 310 311 /** 312 * drm_gem_simple_kms_duplicate_shadow_plane_state - duplicates shadow-buffered plane state 313 * @pipe: the simple display pipe 314 * 315 * This function implements struct drm_simple_display_funcs.duplicate_plane_state 316 * for shadow-buffered planes. It does not duplicate existing mappings of the shadow 317 * buffers. Mappings are maintained during the atomic commit by the plane's prepare_fb 318 * and cleanup_fb helpers. 319 * 320 * Returns: 321 * A pointer to a new plane state on success, or NULL otherwise. 322 */ 323 struct drm_plane_state * 324 drm_gem_simple_kms_duplicate_shadow_plane_state(struct drm_simple_display_pipe *pipe) 325 { 326 return drm_gem_duplicate_shadow_plane_state(&pipe->plane); 327 } 328 EXPORT_SYMBOL(drm_gem_simple_kms_duplicate_shadow_plane_state); 329 330 /** 331 * drm_gem_simple_kms_destroy_shadow_plane_state - resets shadow-buffered plane state 332 * @pipe: the simple display pipe 333 * @plane_state: the plane state of type struct drm_shadow_plane_state 334 * 335 * This function implements struct drm_simple_display_funcs.destroy_plane_state 336 * for shadow-buffered planes. It expects that mappings of shadow buffers 337 * have been released already. 338 */ 339 void drm_gem_simple_kms_destroy_shadow_plane_state(struct drm_simple_display_pipe *pipe, 340 struct drm_plane_state *plane_state) 341 { 342 drm_gem_destroy_shadow_plane_state(&pipe->plane, plane_state); 343 } 344 EXPORT_SYMBOL(drm_gem_simple_kms_destroy_shadow_plane_state); 345