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 #include <drm/drm_plane_helper.h> 11 12 #include "vkms_drv.h" 13 14 static const u32 vkms_formats[] = { 15 DRM_FORMAT_XRGB8888, 16 }; 17 18 static const u32 vkms_plane_formats[] = { 19 DRM_FORMAT_ARGB8888, 20 DRM_FORMAT_XRGB8888 21 }; 22 23 static struct drm_plane_state * 24 vkms_plane_duplicate_state(struct drm_plane *plane) 25 { 26 struct vkms_plane_state *vkms_state; 27 struct vkms_composer *composer; 28 29 vkms_state = kzalloc(sizeof(*vkms_state), GFP_KERNEL); 30 if (!vkms_state) 31 return NULL; 32 33 composer = kzalloc(sizeof(*composer), GFP_KERNEL); 34 if (!composer) { 35 DRM_DEBUG_KMS("Couldn't allocate composer\n"); 36 kfree(vkms_state); 37 return NULL; 38 } 39 40 vkms_state->composer = composer; 41 42 __drm_gem_duplicate_shadow_plane_state(plane, &vkms_state->base); 43 44 return &vkms_state->base.base; 45 } 46 47 static void vkms_plane_destroy_state(struct drm_plane *plane, 48 struct drm_plane_state *old_state) 49 { 50 struct vkms_plane_state *vkms_state = to_vkms_plane_state(old_state); 51 struct drm_crtc *crtc = vkms_state->base.base.crtc; 52 53 if (crtc) { 54 /* dropping the reference we acquired in 55 * vkms_primary_plane_update() 56 */ 57 if (drm_framebuffer_read_refcount(&vkms_state->composer->fb)) 58 drm_framebuffer_put(&vkms_state->composer->fb); 59 } 60 61 kfree(vkms_state->composer); 62 vkms_state->composer = NULL; 63 64 __drm_gem_destroy_shadow_plane_state(&vkms_state->base); 65 kfree(vkms_state); 66 } 67 68 static void vkms_plane_reset(struct drm_plane *plane) 69 { 70 struct vkms_plane_state *vkms_state; 71 72 if (plane->state) { 73 vkms_plane_destroy_state(plane, plane->state); 74 plane->state = NULL; /* must be set to NULL here */ 75 } 76 77 vkms_state = kzalloc(sizeof(*vkms_state), GFP_KERNEL); 78 if (!vkms_state) { 79 DRM_ERROR("Cannot allocate vkms_plane_state\n"); 80 return; 81 } 82 83 __drm_gem_reset_shadow_plane(plane, &vkms_state->base); 84 } 85 86 static const struct drm_plane_funcs vkms_plane_funcs = { 87 .update_plane = drm_atomic_helper_update_plane, 88 .disable_plane = drm_atomic_helper_disable_plane, 89 .reset = vkms_plane_reset, 90 .atomic_duplicate_state = vkms_plane_duplicate_state, 91 .atomic_destroy_state = vkms_plane_destroy_state, 92 }; 93 94 static void vkms_plane_atomic_update(struct drm_plane *plane, 95 struct drm_atomic_state *state) 96 { 97 struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, 98 plane); 99 struct vkms_plane_state *vkms_plane_state; 100 struct drm_shadow_plane_state *shadow_plane_state; 101 struct drm_framebuffer *fb = new_state->fb; 102 struct vkms_composer *composer; 103 104 if (!new_state->crtc || !fb) 105 return; 106 107 vkms_plane_state = to_vkms_plane_state(new_state); 108 shadow_plane_state = &vkms_plane_state->base; 109 110 composer = vkms_plane_state->composer; 111 memcpy(&composer->src, &new_state->src, sizeof(struct drm_rect)); 112 memcpy(&composer->dst, &new_state->dst, sizeof(struct drm_rect)); 113 memcpy(&composer->fb, fb, sizeof(struct drm_framebuffer)); 114 memcpy(&composer->map, &shadow_plane_state->data, sizeof(composer->map)); 115 drm_framebuffer_get(&composer->fb); 116 composer->offset = fb->offsets[0]; 117 composer->pitch = fb->pitches[0]; 118 composer->cpp = fb->format->cpp[0]; 119 } 120 121 static int vkms_plane_atomic_check(struct drm_plane *plane, 122 struct drm_atomic_state *state) 123 { 124 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, 125 plane); 126 struct drm_crtc_state *crtc_state; 127 bool can_position = false; 128 int ret; 129 130 if (!new_plane_state->fb || WARN_ON(!new_plane_state->crtc)) 131 return 0; 132 133 crtc_state = drm_atomic_get_crtc_state(state, 134 new_plane_state->crtc); 135 if (IS_ERR(crtc_state)) 136 return PTR_ERR(crtc_state); 137 138 if (plane->type != DRM_PLANE_TYPE_PRIMARY) 139 can_position = true; 140 141 ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state, 142 DRM_PLANE_HELPER_NO_SCALING, 143 DRM_PLANE_HELPER_NO_SCALING, 144 can_position, true); 145 if (ret != 0) 146 return ret; 147 148 /* for now primary plane must be visible and full screen */ 149 if (!new_plane_state->visible && !can_position) 150 return -EINVAL; 151 152 return 0; 153 } 154 155 static const struct drm_plane_helper_funcs vkms_primary_helper_funcs = { 156 .atomic_update = vkms_plane_atomic_update, 157 .atomic_check = vkms_plane_atomic_check, 158 DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, 159 }; 160 161 struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev, 162 enum drm_plane_type type, int index) 163 { 164 struct drm_device *dev = &vkmsdev->drm; 165 const struct drm_plane_helper_funcs *funcs; 166 struct vkms_plane *plane; 167 const u32 *formats; 168 int nformats; 169 170 switch (type) { 171 case DRM_PLANE_TYPE_PRIMARY: 172 formats = vkms_formats; 173 nformats = ARRAY_SIZE(vkms_formats); 174 funcs = &vkms_primary_helper_funcs; 175 break; 176 case DRM_PLANE_TYPE_CURSOR: 177 case DRM_PLANE_TYPE_OVERLAY: 178 formats = vkms_plane_formats; 179 nformats = ARRAY_SIZE(vkms_plane_formats); 180 funcs = &vkms_primary_helper_funcs; 181 break; 182 default: 183 formats = vkms_formats; 184 nformats = ARRAY_SIZE(vkms_formats); 185 funcs = &vkms_primary_helper_funcs; 186 break; 187 } 188 189 plane = drmm_universal_plane_alloc(dev, struct vkms_plane, base, 1 << index, 190 &vkms_plane_funcs, 191 formats, nformats, 192 NULL, type, NULL); 193 if (IS_ERR(plane)) 194 return plane; 195 196 drm_plane_helper_add(&plane->base, funcs); 197 198 return plane; 199 } 200