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 = fb->format->format; 109 110 if (!new_state->crtc || !fb) 111 return; 112 113 vkms_plane_state = to_vkms_plane_state(new_state); 114 shadow_plane_state = &vkms_plane_state->base; 115 116 frame_info = vkms_plane_state->frame_info; 117 memcpy(&frame_info->src, &new_state->src, sizeof(struct drm_rect)); 118 memcpy(&frame_info->dst, &new_state->dst, sizeof(struct drm_rect)); 119 frame_info->fb = fb; 120 memcpy(&frame_info->map, &shadow_plane_state->data, sizeof(frame_info->map)); 121 drm_framebuffer_get(frame_info->fb); 122 frame_info->offset = fb->offsets[0]; 123 frame_info->pitch = fb->pitches[0]; 124 frame_info->cpp = fb->format->cpp[0]; 125 vkms_plane_state->plane_read = get_frame_to_line_function(fmt); 126 } 127 128 static int vkms_plane_atomic_check(struct drm_plane *plane, 129 struct drm_atomic_state *state) 130 { 131 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, 132 plane); 133 struct drm_crtc_state *crtc_state; 134 bool can_position = false; 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 if (plane->type != DRM_PLANE_TYPE_PRIMARY) 146 can_position = true; 147 148 ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state, 149 DRM_PLANE_NO_SCALING, 150 DRM_PLANE_NO_SCALING, 151 can_position, true); 152 if (ret != 0) 153 return ret; 154 155 /* for now primary plane must be visible and full screen */ 156 if (!new_plane_state->visible && !can_position) 157 return -EINVAL; 158 159 return 0; 160 } 161 162 static const struct drm_plane_helper_funcs vkms_primary_helper_funcs = { 163 .atomic_update = vkms_plane_atomic_update, 164 .atomic_check = vkms_plane_atomic_check, 165 DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, 166 }; 167 168 struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev, 169 enum drm_plane_type type, int index) 170 { 171 struct drm_device *dev = &vkmsdev->drm; 172 const struct drm_plane_helper_funcs *funcs; 173 struct vkms_plane *plane; 174 const u32 *formats; 175 int nformats; 176 177 switch (type) { 178 case DRM_PLANE_TYPE_PRIMARY: 179 formats = vkms_formats; 180 nformats = ARRAY_SIZE(vkms_formats); 181 funcs = &vkms_primary_helper_funcs; 182 break; 183 case DRM_PLANE_TYPE_CURSOR: 184 case DRM_PLANE_TYPE_OVERLAY: 185 formats = vkms_plane_formats; 186 nformats = ARRAY_SIZE(vkms_plane_formats); 187 funcs = &vkms_primary_helper_funcs; 188 break; 189 default: 190 formats = vkms_formats; 191 nformats = ARRAY_SIZE(vkms_formats); 192 funcs = &vkms_primary_helper_funcs; 193 break; 194 } 195 196 plane = drmm_universal_plane_alloc(dev, struct vkms_plane, base, 1 << index, 197 &vkms_plane_funcs, 198 formats, nformats, 199 NULL, type, NULL); 200 if (IS_ERR(plane)) 201 return plane; 202 203 drm_plane_helper_add(&plane->base, funcs); 204 205 return plane; 206 } 207