1 // SPDX-License-Identifier: GPL-2.0+
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>
9 static const u32 vkms_formats[] = {
13 static const u32 vkms_cursor_formats[] = {
17 static struct drm_plane_state *
18 vkms_plane_duplicate_state(struct drm_plane *plane)
20 struct vkms_plane_state *vkms_state;
21 struct vkms_composer *composer;
23 vkms_state = kzalloc(sizeof(*vkms_state), GFP_KERNEL);
27 composer = kzalloc(sizeof(*composer), GFP_KERNEL);
29 DRM_DEBUG_KMS("Couldn't allocate composer\n");
34 vkms_state->composer = composer;
36 __drm_atomic_helper_plane_duplicate_state(plane,
39 return &vkms_state->base;
42 static void vkms_plane_destroy_state(struct drm_plane *plane,
43 struct drm_plane_state *old_state)
45 struct vkms_plane_state *vkms_state = to_vkms_plane_state(old_state);
46 struct drm_crtc *crtc = vkms_state->base.crtc;
49 /* dropping the reference we acquired in
50 * vkms_primary_plane_update()
52 if (drm_framebuffer_read_refcount(&vkms_state->composer->fb))
53 drm_framebuffer_put(&vkms_state->composer->fb);
56 kfree(vkms_state->composer);
57 vkms_state->composer = NULL;
59 __drm_atomic_helper_plane_destroy_state(old_state);
63 static void vkms_plane_reset(struct drm_plane *plane)
65 struct vkms_plane_state *vkms_state;
68 vkms_plane_destroy_state(plane, plane->state);
70 vkms_state = kzalloc(sizeof(*vkms_state), GFP_KERNEL);
72 DRM_ERROR("Cannot allocate vkms_plane_state\n");
76 plane->state = &vkms_state->base;
77 plane->state->plane = plane;
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,
89 static void vkms_plane_atomic_update(struct drm_plane *plane,
90 struct drm_plane_state *old_state)
92 struct vkms_plane_state *vkms_plane_state;
93 struct drm_framebuffer *fb = plane->state->fb;
94 struct vkms_composer *composer;
96 if (!plane->state->crtc || !fb)
99 vkms_plane_state = to_vkms_plane_state(plane->state);
101 composer = vkms_plane_state->composer;
102 memcpy(&composer->src, &plane->state->src, sizeof(struct drm_rect));
103 memcpy(&composer->dst, &plane->state->dst, sizeof(struct drm_rect));
104 memcpy(&composer->fb, fb, sizeof(struct drm_framebuffer));
105 drm_framebuffer_get(&composer->fb);
106 composer->offset = fb->offsets[0];
107 composer->pitch = fb->pitches[0];
108 composer->cpp = fb->format->cpp[0];
111 static int vkms_plane_atomic_check(struct drm_plane *plane,
112 struct drm_plane_state *state)
114 struct drm_crtc_state *crtc_state;
115 bool can_position = false;
118 if (!state->fb | !state->crtc)
121 crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
122 if (IS_ERR(crtc_state))
123 return PTR_ERR(crtc_state);
125 if (plane->type == DRM_PLANE_TYPE_CURSOR)
128 ret = drm_atomic_helper_check_plane_state(state, crtc_state,
129 DRM_PLANE_HELPER_NO_SCALING,
130 DRM_PLANE_HELPER_NO_SCALING,
135 /* for now primary plane must be visible and full screen */
136 if (!state->visible && !can_position)
142 static int vkms_prepare_fb(struct drm_plane *plane,
143 struct drm_plane_state *state)
145 struct drm_gem_object *gem_obj;
151 gem_obj = drm_gem_fb_get_obj(state->fb, 0);
152 ret = vkms_gem_vmap(gem_obj);
154 DRM_ERROR("vmap failed: %d\n", ret);
156 return drm_gem_fb_prepare_fb(plane, state);
159 static void vkms_cleanup_fb(struct drm_plane *plane,
160 struct drm_plane_state *old_state)
162 struct drm_gem_object *gem_obj;
167 gem_obj = drm_gem_fb_get_obj(old_state->fb, 0);
168 vkms_gem_vunmap(gem_obj);
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,
178 struct drm_plane *vkms_plane_init(struct vkms_device *vkmsdev,
179 enum drm_plane_type type, int index)
181 struct drm_device *dev = &vkmsdev->drm;
182 const struct drm_plane_helper_funcs *funcs;
183 struct drm_plane *plane;
187 plane = kzalloc(sizeof(*plane), GFP_KERNEL);
189 return ERR_PTR(-ENOMEM);
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;
196 formats = vkms_formats;
197 nformats = ARRAY_SIZE(vkms_formats);
198 funcs = &vkms_primary_helper_funcs;
201 ret = drm_universal_plane_init(dev, plane, 1 << index,
210 drm_plane_helper_add(plane, funcs);