1 // SPDX-License-Identifier: GPL-2.0+ 2 3 #include <linux/iosys-map.h> 4 5 #include <drm/drm_atomic.h> 6 #include <drm/drm_atomic_helper.h> 7 #include <drm/drm_fourcc.h> 8 #include <drm/drm_gem_atomic_helper.h> 9 #include <drm/drm_gem_framebuffer_helper.h> 10 11 #include "vkms_drv.h" 12 #include "vkms_formats.h" 13 14 static const u32 vkms_formats[] = { 15 DRM_FORMAT_XRGB8888, 16 DRM_FORMAT_XRGB16161616, 17 DRM_FORMAT_RGB565 18 }; 19 20 static const u32 vkms_plane_formats[] = { 21 DRM_FORMAT_ARGB8888, 22 DRM_FORMAT_XRGB8888, 23 DRM_FORMAT_XRGB16161616, 24 DRM_FORMAT_ARGB16161616, 25 DRM_FORMAT_RGB565 26 }; 27 28 static struct drm_plane_state * 29 vkms_plane_duplicate_state(struct drm_plane *plane) 30 { 31 struct vkms_plane_state *vkms_state; 32 struct vkms_frame_info *frame_info; 33 34 vkms_state = kzalloc(sizeof(*vkms_state), GFP_KERNEL); 35 if (!vkms_state) 36 return NULL; 37 38 frame_info = kzalloc(sizeof(*frame_info), GFP_KERNEL); 39 if (!frame_info) { 40 DRM_DEBUG_KMS("Couldn't allocate frame_info\n"); 41 kfree(vkms_state); 42 return NULL; 43 } 44 45 vkms_state->frame_info = frame_info; 46 47 __drm_gem_duplicate_shadow_plane_state(plane, &vkms_state->base); 48 49 return &vkms_state->base.base; 50 } 51 52 static void vkms_plane_destroy_state(struct drm_plane *plane, 53 struct drm_plane_state *old_state) 54 { 55 struct vkms_plane_state *vkms_state = to_vkms_plane_state(old_state); 56 struct drm_crtc *crtc = vkms_state->base.base.crtc; 57 58 if (crtc && vkms_state->frame_info->fb) { 59 /* dropping the reference we acquired in 60 * vkms_primary_plane_update() 61 */ 62 if (drm_framebuffer_read_refcount(vkms_state->frame_info->fb)) 63 drm_framebuffer_put(vkms_state->frame_info->fb); 64 } 65 66 kfree(vkms_state->frame_info); 67 vkms_state->frame_info = NULL; 68 69 __drm_gem_destroy_shadow_plane_state(&vkms_state->base); 70 kfree(vkms_state); 71 } 72 73 static void vkms_plane_reset(struct drm_plane *plane) 74 { 75 struct vkms_plane_state *vkms_state; 76 77 if (plane->state) { 78 vkms_plane_destroy_state(plane, plane->state); 79 plane->state = NULL; /* must be set to NULL here */ 80 } 81 82 vkms_state = kzalloc(sizeof(*vkms_state), GFP_KERNEL); 83 if (!vkms_state) { 84 DRM_ERROR("Cannot allocate vkms_plane_state\n"); 85 return; 86 } 87 88 __drm_gem_reset_shadow_plane(plane, &vkms_state->base); 89 } 90 91 static const struct drm_plane_funcs vkms_plane_funcs = { 92 .update_plane = drm_atomic_helper_update_plane, 93 .disable_plane = drm_atomic_helper_disable_plane, 94 .reset = vkms_plane_reset, 95 .atomic_duplicate_state = vkms_plane_duplicate_state, 96 .atomic_destroy_state = vkms_plane_destroy_state, 97 }; 98 99 static void vkms_plane_atomic_update(struct drm_plane *plane, 100 struct drm_atomic_state *state) 101 { 102 struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, 103 plane); 104 struct vkms_plane_state *vkms_plane_state; 105 struct drm_shadow_plane_state *shadow_plane_state; 106 struct drm_framebuffer *fb = new_state->fb; 107 struct vkms_frame_info *frame_info; 108 u32 fmt; 109 110 if (!new_state->crtc || !fb) 111 return; 112 113 fmt = fb->format->format; 114 vkms_plane_state = to_vkms_plane_state(new_state); 115 shadow_plane_state = &vkms_plane_state->base; 116 117 frame_info = vkms_plane_state->frame_info; 118 memcpy(&frame_info->src, &new_state->src, sizeof(struct drm_rect)); 119 memcpy(&frame_info->dst, &new_state->dst, sizeof(struct drm_rect)); 120 frame_info->fb = fb; 121 memcpy(&frame_info->map, &shadow_plane_state->data, sizeof(frame_info->map)); 122 drm_framebuffer_get(frame_info->fb); 123 frame_info->offset = fb->offsets[0]; 124 frame_info->pitch = fb->pitches[0]; 125 frame_info->cpp = fb->format->cpp[0]; 126 vkms_plane_state->plane_read = get_frame_to_line_function(fmt); 127 } 128 129 static int vkms_plane_atomic_check(struct drm_plane *plane, 130 struct drm_atomic_state *state) 131 { 132 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, 133 plane); 134 struct drm_crtc_state *crtc_state; 135 int ret; 136 137 if (!new_plane_state->fb || WARN_ON(!new_plane_state->crtc)) 138 return 0; 139 140 crtc_state = drm_atomic_get_crtc_state(state, 141 new_plane_state->crtc); 142 if (IS_ERR(crtc_state)) 143 return PTR_ERR(crtc_state); 144 145 ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state, 146 DRM_PLANE_NO_SCALING, 147 DRM_PLANE_NO_SCALING, 148 true, true); 149 if (ret != 0) 150 return ret; 151 152 return 0; 153 } 154 155 static int vkms_prepare_fb(struct drm_plane *plane, 156 struct drm_plane_state *state) 157 { 158 struct drm_shadow_plane_state *shadow_plane_state; 159 struct drm_framebuffer *fb = state->fb; 160 int ret; 161 162 if (!fb) 163 return 0; 164 165 shadow_plane_state = to_drm_shadow_plane_state(state); 166 167 ret = drm_gem_plane_helper_prepare_fb(plane, state); 168 if (ret) 169 return ret; 170 171 return drm_gem_fb_vmap(fb, shadow_plane_state->map, shadow_plane_state->data); 172 } 173 174 static void vkms_cleanup_fb(struct drm_plane *plane, 175 struct drm_plane_state *state) 176 { 177 struct drm_shadow_plane_state *shadow_plane_state; 178 struct drm_framebuffer *fb = state->fb; 179 180 if (!fb) 181 return; 182 183 shadow_plane_state = to_drm_shadow_plane_state(state); 184 185 drm_gem_fb_vunmap(fb, shadow_plane_state->map); 186 } 187 188 static const struct drm_plane_helper_funcs vkms_primary_helper_funcs = { 189 .atomic_update = vkms_plane_atomic_update, 190 .atomic_check = vkms_plane_atomic_check, 191 .prepare_fb = vkms_prepare_fb, 192 .cleanup_fb = vkms_cleanup_fb, 193 }; 194 195 struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev, 196 enum drm_plane_type type, int index) 197 { 198 struct drm_device *dev = &vkmsdev->drm; 199 const struct drm_plane_helper_funcs *funcs; 200 struct vkms_plane *plane; 201 const u32 *formats; 202 int nformats; 203 204 switch (type) { 205 case DRM_PLANE_TYPE_PRIMARY: 206 formats = vkms_formats; 207 nformats = ARRAY_SIZE(vkms_formats); 208 funcs = &vkms_primary_helper_funcs; 209 break; 210 case DRM_PLANE_TYPE_CURSOR: 211 case DRM_PLANE_TYPE_OVERLAY: 212 formats = vkms_plane_formats; 213 nformats = ARRAY_SIZE(vkms_plane_formats); 214 funcs = &vkms_primary_helper_funcs; 215 break; 216 default: 217 formats = vkms_formats; 218 nformats = ARRAY_SIZE(vkms_formats); 219 funcs = &vkms_primary_helper_funcs; 220 break; 221 } 222 223 plane = drmm_universal_plane_alloc(dev, struct vkms_plane, base, 1 << index, 224 &vkms_plane_funcs, 225 formats, nformats, 226 NULL, type, NULL); 227 if (IS_ERR(plane)) 228 return plane; 229 230 drm_plane_helper_add(&plane->base, funcs); 231 232 return plane; 233 } 234