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 19 /* 20 * Shadow-buffered Planes 21 */ 22 23 static struct drm_plane_state * 24 drm_gem_duplicate_shadow_plane_state(struct drm_plane *plane) 25 { 26 struct drm_plane_state *plane_state = plane->state; 27 struct drm_shadow_plane_state *new_shadow_plane_state; 28 29 if (!plane_state) 30 return NULL; 31 32 new_shadow_plane_state = kzalloc(sizeof(*new_shadow_plane_state), GFP_KERNEL); 33 if (!new_shadow_plane_state) 34 return NULL; 35 __drm_atomic_helper_plane_duplicate_state(plane, &new_shadow_plane_state->base); 36 37 return &new_shadow_plane_state->base; 38 } 39 40 static void drm_gem_destroy_shadow_plane_state(struct drm_plane *plane, 41 struct drm_plane_state *plane_state) 42 { 43 struct drm_shadow_plane_state *shadow_plane_state = 44 to_drm_shadow_plane_state(plane_state); 45 46 __drm_atomic_helper_plane_destroy_state(&shadow_plane_state->base); 47 kfree(shadow_plane_state); 48 } 49 50 static void drm_gem_reset_shadow_plane(struct drm_plane *plane) 51 { 52 struct drm_shadow_plane_state *shadow_plane_state; 53 54 if (plane->state) { 55 drm_gem_destroy_shadow_plane_state(plane, plane->state); 56 plane->state = NULL; /* must be set to NULL here */ 57 } 58 59 shadow_plane_state = kzalloc(sizeof(*shadow_plane_state), GFP_KERNEL); 60 if (!shadow_plane_state) 61 return; 62 __drm_atomic_helper_plane_reset(plane, &shadow_plane_state->base); 63 } 64 65 static int drm_gem_prepare_shadow_fb(struct drm_plane *plane, struct drm_plane_state *plane_state) 66 { 67 struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); 68 struct drm_framebuffer *fb = plane_state->fb; 69 struct drm_gem_object *obj; 70 struct dma_buf_map map; 71 int ret; 72 size_t i; 73 74 if (!fb) 75 return 0; 76 77 ret = drm_gem_fb_prepare_fb(plane, plane_state); 78 if (ret) 79 return ret; 80 81 for (i = 0; i < ARRAY_SIZE(shadow_plane_state->map); ++i) { 82 obj = drm_gem_fb_get_obj(fb, i); 83 if (!obj) 84 continue; 85 ret = drm_gem_vmap(obj, &map); 86 if (ret) 87 goto err_drm_gem_vunmap; 88 shadow_plane_state->map[i] = map; 89 } 90 91 return 0; 92 93 err_drm_gem_vunmap: 94 while (i) { 95 --i; 96 obj = drm_gem_fb_get_obj(fb, i); 97 if (!obj) 98 continue; 99 drm_gem_vunmap(obj, &shadow_plane_state->map[i]); 100 } 101 return ret; 102 } 103 104 static void drm_gem_cleanup_shadow_fb(struct drm_plane *plane, struct drm_plane_state *plane_state) 105 { 106 struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); 107 struct drm_framebuffer *fb = plane_state->fb; 108 size_t i = ARRAY_SIZE(shadow_plane_state->map); 109 struct drm_gem_object *obj; 110 111 if (!fb) 112 return; 113 114 while (i) { 115 --i; 116 obj = drm_gem_fb_get_obj(fb, i); 117 if (!obj) 118 continue; 119 drm_gem_vunmap(obj, &shadow_plane_state->map[i]); 120 } 121 } 122 123 /** 124 * drm_gem_simple_kms_prepare_shadow_fb - prepares shadow framebuffers 125 * @pipe: the simple display pipe 126 * @plane_state: the plane state of type struct drm_shadow_plane_state 127 * 128 * This function implements struct drm_simple_display_funcs.prepare_fb. It 129 * maps all buffer objects of the plane's framebuffer into kernel address 130 * space and stores them in struct drm_shadow_plane_state.map. The 131 * framebuffer will be synchronized as part of the atomic commit. 132 * 133 * See drm_gem_simple_kms_cleanup_shadow_fb() for cleanup. 134 * 135 * Returns: 136 * 0 on success, or a negative errno code otherwise. 137 */ 138 int drm_gem_simple_kms_prepare_shadow_fb(struct drm_simple_display_pipe *pipe, 139 struct drm_plane_state *plane_state) 140 { 141 return drm_gem_prepare_shadow_fb(&pipe->plane, plane_state); 142 } 143 EXPORT_SYMBOL(drm_gem_simple_kms_prepare_shadow_fb); 144 145 /** 146 * drm_gem_simple_kms_cleanup_shadow_fb - releases shadow framebuffers 147 * @pipe: the simple display pipe 148 * @plane_state: the plane state of type struct drm_shadow_plane_state 149 * 150 * This function implements struct drm_simple_display_funcs.cleanup_fb. 151 * This function unmaps all buffer objects of the plane's framebuffer. 152 * 153 * See drm_gem_simple_kms_prepare_shadow_fb(). 154 */ 155 void drm_gem_simple_kms_cleanup_shadow_fb(struct drm_simple_display_pipe *pipe, 156 struct drm_plane_state *plane_state) 157 { 158 drm_gem_cleanup_shadow_fb(&pipe->plane, plane_state); 159 } 160 EXPORT_SYMBOL(drm_gem_simple_kms_cleanup_shadow_fb); 161 162 /** 163 * drm_gem_simple_kms_reset_shadow_plane - resets a shadow-buffered plane 164 * @pipe: the simple display pipe 165 * 166 * This function implements struct drm_simple_display_funcs.reset_plane 167 * for shadow-buffered planes. 168 */ 169 void drm_gem_simple_kms_reset_shadow_plane(struct drm_simple_display_pipe *pipe) 170 { 171 drm_gem_reset_shadow_plane(&pipe->plane); 172 } 173 EXPORT_SYMBOL(drm_gem_simple_kms_reset_shadow_plane); 174 175 /** 176 * drm_gem_simple_kms_duplicate_shadow_plane_state - duplicates shadow-buffered plane state 177 * @pipe: the simple display pipe 178 * 179 * This function implements struct drm_simple_display_funcs.duplicate_plane_state 180 * for shadow-buffered planes. It does not duplicate existing mappings of the shadow 181 * buffers. Mappings are maintained during the atomic commit by the plane's prepare_fb 182 * and cleanup_fb helpers. 183 * 184 * Returns: 185 * A pointer to a new plane state on success, or NULL otherwise. 186 */ 187 struct drm_plane_state * 188 drm_gem_simple_kms_duplicate_shadow_plane_state(struct drm_simple_display_pipe *pipe) 189 { 190 return drm_gem_duplicate_shadow_plane_state(&pipe->plane); 191 } 192 EXPORT_SYMBOL(drm_gem_simple_kms_duplicate_shadow_plane_state); 193 194 /** 195 * drm_gem_simple_kms_destroy_shadow_plane_state - resets shadow-buffered plane state 196 * @pipe: the simple display pipe 197 * @plane_state: the plane state of type struct drm_shadow_plane_state 198 * 199 * This function implements struct drm_simple_display_funcs.destroy_plane_state 200 * for shadow-buffered planes. It expects that mappings of shadow buffers 201 * have been released already. 202 */ 203 void drm_gem_simple_kms_destroy_shadow_plane_state(struct drm_simple_display_pipe *pipe, 204 struct drm_plane_state *plane_state) 205 { 206 drm_gem_destroy_shadow_plane_state(&pipe->plane, plane_state); 207 } 208 EXPORT_SYMBOL(drm_gem_simple_kms_destroy_shadow_plane_state); 209