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 bool can_position = false; 136 int ret; 137 138 if (!new_plane_state->fb || WARN_ON(!new_plane_state->crtc)) 139 return 0; 140 141 crtc_state = drm_atomic_get_crtc_state(state, 142 new_plane_state->crtc); 143 if (IS_ERR(crtc_state)) 144 return PTR_ERR(crtc_state); 145 146 if (plane->type != DRM_PLANE_TYPE_PRIMARY) 147 can_position = true; 148 149 ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state, 150 DRM_PLANE_NO_SCALING, 151 DRM_PLANE_NO_SCALING, 152 can_position, true); 153 if (ret != 0) 154 return ret; 155 156 /* for now primary plane must be visible and full screen */ 157 if (!new_plane_state->visible && !can_position) 158 return -EINVAL; 159 160 return 0; 161 } 162 163 static const struct drm_plane_helper_funcs vkms_primary_helper_funcs = { 164 .atomic_update = vkms_plane_atomic_update, 165 .atomic_check = vkms_plane_atomic_check, 166 DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, 167 }; 168 169 struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev, 170 enum drm_plane_type type, int index) 171 { 172 struct drm_device *dev = &vkmsdev->drm; 173 const struct drm_plane_helper_funcs *funcs; 174 struct vkms_plane *plane; 175 const u32 *formats; 176 int nformats; 177 178 switch (type) { 179 case DRM_PLANE_TYPE_PRIMARY: 180 formats = vkms_formats; 181 nformats = ARRAY_SIZE(vkms_formats); 182 funcs = &vkms_primary_helper_funcs; 183 break; 184 case DRM_PLANE_TYPE_CURSOR: 185 case DRM_PLANE_TYPE_OVERLAY: 186 formats = vkms_plane_formats; 187 nformats = ARRAY_SIZE(vkms_plane_formats); 188 funcs = &vkms_primary_helper_funcs; 189 break; 190 default: 191 formats = vkms_formats; 192 nformats = ARRAY_SIZE(vkms_formats); 193 funcs = &vkms_primary_helper_funcs; 194 break; 195 } 196 197 plane = drmm_universal_plane_alloc(dev, struct vkms_plane, base, 1 << index, 198 &vkms_plane_funcs, 199 formats, nformats, 200 NULL, type, NULL); 201 if (IS_ERR(plane)) 202 return plane; 203 204 drm_plane_helper_add(&plane->base, funcs); 205 206 return plane; 207 } 208