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