1 // SPDX-License-Identifier: GPL-2.0+ 2 3 #include "vkms_drv.h" 4 #include <drm/drm_plane_helper.h> 5 #include <drm/drm_atomic.h> 6 #include <drm/drm_atomic_helper.h> 7 #include <drm/drm_gem_framebuffer_helper.h> 8 9 static const u32 vkms_formats[] = { 10 DRM_FORMAT_XRGB8888, 11 }; 12 13 static const u32 vkms_cursor_formats[] = { 14 DRM_FORMAT_ARGB8888, 15 }; 16 17 static struct drm_plane_state * 18 vkms_plane_duplicate_state(struct drm_plane *plane) 19 { 20 struct vkms_plane_state *vkms_state; 21 struct vkms_crc_data *crc_data; 22 23 vkms_state = kzalloc(sizeof(*vkms_state), GFP_KERNEL); 24 if (!vkms_state) 25 return NULL; 26 27 crc_data = kzalloc(sizeof(*crc_data), GFP_KERNEL); 28 if (!crc_data) { 29 DRM_DEBUG_KMS("Couldn't allocate crc_data\n"); 30 kfree(vkms_state); 31 return NULL; 32 } 33 34 vkms_state->crc_data = crc_data; 35 36 __drm_atomic_helper_plane_duplicate_state(plane, 37 &vkms_state->base); 38 39 return &vkms_state->base; 40 } 41 42 static void vkms_plane_destroy_state(struct drm_plane *plane, 43 struct drm_plane_state *old_state) 44 { 45 struct vkms_plane_state *vkms_state = to_vkms_plane_state(old_state); 46 struct drm_crtc *crtc = vkms_state->base.crtc; 47 48 if (crtc) { 49 /* dropping the reference we acquired in 50 * vkms_primary_plane_update() 51 */ 52 if (drm_framebuffer_read_refcount(&vkms_state->crc_data->fb)) 53 drm_framebuffer_put(&vkms_state->crc_data->fb); 54 } 55 56 kfree(vkms_state->crc_data); 57 vkms_state->crc_data = NULL; 58 59 __drm_atomic_helper_plane_destroy_state(old_state); 60 kfree(vkms_state); 61 } 62 63 static void vkms_plane_reset(struct drm_plane *plane) 64 { 65 struct vkms_plane_state *vkms_state; 66 67 if (plane->state) 68 vkms_plane_destroy_state(plane, plane->state); 69 70 vkms_state = kzalloc(sizeof(*vkms_state), GFP_KERNEL); 71 if (!vkms_state) { 72 DRM_ERROR("Cannot allocate vkms_plane_state\n"); 73 return; 74 } 75 76 plane->state = &vkms_state->base; 77 plane->state->plane = plane; 78 } 79 80 static const struct drm_plane_funcs vkms_plane_funcs = { 81 .update_plane = drm_atomic_helper_update_plane, 82 .disable_plane = drm_atomic_helper_disable_plane, 83 .destroy = drm_plane_cleanup, 84 .reset = vkms_plane_reset, 85 .atomic_duplicate_state = vkms_plane_duplicate_state, 86 .atomic_destroy_state = vkms_plane_destroy_state, 87 }; 88 89 static void vkms_plane_atomic_update(struct drm_plane *plane, 90 struct drm_plane_state *old_state) 91 { 92 struct vkms_plane_state *vkms_plane_state; 93 struct drm_framebuffer *fb = plane->state->fb; 94 struct vkms_crc_data *crc_data; 95 96 if (!plane->state->crtc || !fb) 97 return; 98 99 vkms_plane_state = to_vkms_plane_state(plane->state); 100 101 crc_data = vkms_plane_state->crc_data; 102 memcpy(&crc_data->src, &plane->state->src, sizeof(struct drm_rect)); 103 memcpy(&crc_data->dst, &plane->state->dst, sizeof(struct drm_rect)); 104 memcpy(&crc_data->fb, fb, sizeof(struct drm_framebuffer)); 105 drm_framebuffer_get(&crc_data->fb); 106 crc_data->offset = fb->offsets[0]; 107 crc_data->pitch = fb->pitches[0]; 108 crc_data->cpp = fb->format->cpp[0]; 109 } 110 111 static int vkms_plane_atomic_check(struct drm_plane *plane, 112 struct drm_plane_state *state) 113 { 114 struct drm_crtc_state *crtc_state; 115 bool can_position = false; 116 int ret; 117 118 if (!state->fb | !state->crtc) 119 return 0; 120 121 crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc); 122 if (IS_ERR(crtc_state)) 123 return PTR_ERR(crtc_state); 124 125 if (plane->type == DRM_PLANE_TYPE_CURSOR) 126 can_position = true; 127 128 ret = drm_atomic_helper_check_plane_state(state, crtc_state, 129 DRM_PLANE_HELPER_NO_SCALING, 130 DRM_PLANE_HELPER_NO_SCALING, 131 can_position, true); 132 if (ret != 0) 133 return ret; 134 135 /* for now primary plane must be visible and full screen */ 136 if (!state->visible && !can_position) 137 return -EINVAL; 138 139 return 0; 140 } 141 142 static int vkms_prepare_fb(struct drm_plane *plane, 143 struct drm_plane_state *state) 144 { 145 struct drm_gem_object *gem_obj; 146 int ret; 147 148 if (!state->fb) 149 return 0; 150 151 gem_obj = drm_gem_fb_get_obj(state->fb, 0); 152 ret = vkms_gem_vmap(gem_obj); 153 if (ret) 154 DRM_ERROR("vmap failed: %d\n", ret); 155 156 return drm_gem_fb_prepare_fb(plane, state); 157 } 158 159 static void vkms_cleanup_fb(struct drm_plane *plane, 160 struct drm_plane_state *old_state) 161 { 162 struct drm_gem_object *gem_obj; 163 164 if (!old_state->fb) 165 return; 166 167 gem_obj = drm_gem_fb_get_obj(old_state->fb, 0); 168 vkms_gem_vunmap(gem_obj); 169 } 170 171 static const struct drm_plane_helper_funcs vkms_primary_helper_funcs = { 172 .atomic_update = vkms_plane_atomic_update, 173 .atomic_check = vkms_plane_atomic_check, 174 .prepare_fb = vkms_prepare_fb, 175 .cleanup_fb = vkms_cleanup_fb, 176 }; 177 178 struct drm_plane *vkms_plane_init(struct vkms_device *vkmsdev, 179 enum drm_plane_type type) 180 { 181 struct drm_device *dev = &vkmsdev->drm; 182 const struct drm_plane_helper_funcs *funcs; 183 struct drm_plane *plane; 184 const u32 *formats; 185 int ret, nformats; 186 187 plane = kzalloc(sizeof(*plane), GFP_KERNEL); 188 if (!plane) 189 return ERR_PTR(-ENOMEM); 190 191 if (type == DRM_PLANE_TYPE_CURSOR) { 192 formats = vkms_cursor_formats; 193 nformats = ARRAY_SIZE(vkms_cursor_formats); 194 funcs = &vkms_primary_helper_funcs; 195 } else { 196 formats = vkms_formats; 197 nformats = ARRAY_SIZE(vkms_formats); 198 funcs = &vkms_primary_helper_funcs; 199 } 200 201 ret = drm_universal_plane_init(dev, plane, 0, 202 &vkms_plane_funcs, 203 formats, nformats, 204 NULL, type, NULL); 205 if (ret) { 206 kfree(plane); 207 return ERR_PTR(ret); 208 } 209 210 drm_plane_helper_add(plane, funcs); 211 212 return plane; 213 } 214