1 // SPDX-License-Identifier: GPL-2.0+
3 #include <linux/dma-buf-map.h>
5 #include <drm/drm_atomic.h>
6 #include <drm/drm_atomic_helper.h>
7 #include <drm/drm_fourcc.h>
8 #include <drm/drm_gem_framebuffer_helper.h>
9 #include <drm/drm_plane_helper.h>
10 #include <drm/drm_gem_shmem_helper.h>
14 static const u32 vkms_formats
[] = {
18 static const u32 vkms_cursor_formats
[] = {
22 static struct drm_plane_state
*
23 vkms_plane_duplicate_state(struct drm_plane
*plane
)
25 struct vkms_plane_state
*vkms_state
;
26 struct vkms_composer
*composer
;
28 vkms_state
= kzalloc(sizeof(*vkms_state
), GFP_KERNEL
);
32 composer
= kzalloc(sizeof(*composer
), GFP_KERNEL
);
34 DRM_DEBUG_KMS("Couldn't allocate composer\n");
39 vkms_state
->composer
= composer
;
41 __drm_atomic_helper_plane_duplicate_state(plane
,
44 return &vkms_state
->base
;
47 static void vkms_plane_destroy_state(struct drm_plane
*plane
,
48 struct drm_plane_state
*old_state
)
50 struct vkms_plane_state
*vkms_state
= to_vkms_plane_state(old_state
);
51 struct drm_crtc
*crtc
= vkms_state
->base
.crtc
;
54 /* dropping the reference we acquired in
55 * vkms_primary_plane_update()
57 if (drm_framebuffer_read_refcount(&vkms_state
->composer
->fb
))
58 drm_framebuffer_put(&vkms_state
->composer
->fb
);
61 kfree(vkms_state
->composer
);
62 vkms_state
->composer
= NULL
;
64 __drm_atomic_helper_plane_destroy_state(old_state
);
68 static void vkms_plane_reset(struct drm_plane
*plane
)
70 struct vkms_plane_state
*vkms_state
;
73 vkms_plane_destroy_state(plane
, plane
->state
);
75 vkms_state
= kzalloc(sizeof(*vkms_state
), GFP_KERNEL
);
77 DRM_ERROR("Cannot allocate vkms_plane_state\n");
81 plane
->state
= &vkms_state
->base
;
82 plane
->state
->plane
= plane
;
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 .destroy
= drm_plane_cleanup
,
89 .reset
= vkms_plane_reset
,
90 .atomic_duplicate_state
= vkms_plane_duplicate_state
,
91 .atomic_destroy_state
= vkms_plane_destroy_state
,
94 static void vkms_plane_atomic_update(struct drm_plane
*plane
,
95 struct drm_plane_state
*old_state
)
97 struct vkms_plane_state
*vkms_plane_state
;
98 struct drm_framebuffer
*fb
= plane
->state
->fb
;
99 struct vkms_composer
*composer
;
101 if (!plane
->state
->crtc
|| !fb
)
104 vkms_plane_state
= to_vkms_plane_state(plane
->state
);
106 composer
= vkms_plane_state
->composer
;
107 memcpy(&composer
->src
, &plane
->state
->src
, sizeof(struct drm_rect
));
108 memcpy(&composer
->dst
, &plane
->state
->dst
, sizeof(struct drm_rect
));
109 memcpy(&composer
->fb
, fb
, sizeof(struct drm_framebuffer
));
110 drm_framebuffer_get(&composer
->fb
);
111 composer
->offset
= fb
->offsets
[0];
112 composer
->pitch
= fb
->pitches
[0];
113 composer
->cpp
= fb
->format
->cpp
[0];
116 static int vkms_plane_atomic_check(struct drm_plane
*plane
,
117 struct drm_plane_state
*state
)
119 struct drm_crtc_state
*crtc_state
;
120 bool can_position
= false;
123 if (!state
->fb
|| WARN_ON(!state
->crtc
))
126 crtc_state
= drm_atomic_get_crtc_state(state
->state
, state
->crtc
);
127 if (IS_ERR(crtc_state
))
128 return PTR_ERR(crtc_state
);
130 if (plane
->type
== DRM_PLANE_TYPE_CURSOR
)
133 ret
= drm_atomic_helper_check_plane_state(state
, crtc_state
,
134 DRM_PLANE_HELPER_NO_SCALING
,
135 DRM_PLANE_HELPER_NO_SCALING
,
140 /* for now primary plane must be visible and full screen */
141 if (!state
->visible
&& !can_position
)
147 static int vkms_prepare_fb(struct drm_plane
*plane
,
148 struct drm_plane_state
*state
)
150 struct drm_gem_object
*gem_obj
;
151 struct dma_buf_map map
;
157 gem_obj
= drm_gem_fb_get_obj(state
->fb
, 0);
158 ret
= drm_gem_shmem_vmap(gem_obj
, &map
);
160 DRM_ERROR("vmap failed: %d\n", ret
);
162 return drm_gem_fb_prepare_fb(plane
, state
);
165 static void vkms_cleanup_fb(struct drm_plane
*plane
,
166 struct drm_plane_state
*old_state
)
168 struct drm_gem_object
*gem_obj
;
169 struct drm_gem_shmem_object
*shmem_obj
;
170 struct dma_buf_map map
;
175 gem_obj
= drm_gem_fb_get_obj(old_state
->fb
, 0);
176 shmem_obj
= to_drm_gem_shmem_obj(drm_gem_fb_get_obj(old_state
->fb
, 0));
177 dma_buf_map_set_vaddr(&map
, shmem_obj
->vaddr
);
178 drm_gem_shmem_vunmap(gem_obj
, &map
);
181 static const struct drm_plane_helper_funcs vkms_primary_helper_funcs
= {
182 .atomic_update
= vkms_plane_atomic_update
,
183 .atomic_check
= vkms_plane_atomic_check
,
184 .prepare_fb
= vkms_prepare_fb
,
185 .cleanup_fb
= vkms_cleanup_fb
,
188 struct drm_plane
*vkms_plane_init(struct vkms_device
*vkmsdev
,
189 enum drm_plane_type type
, int index
)
191 struct drm_device
*dev
= &vkmsdev
->drm
;
192 const struct drm_plane_helper_funcs
*funcs
;
193 struct drm_plane
*plane
;
197 plane
= kzalloc(sizeof(*plane
), GFP_KERNEL
);
199 return ERR_PTR(-ENOMEM
);
201 if (type
== DRM_PLANE_TYPE_CURSOR
) {
202 formats
= vkms_cursor_formats
;
203 nformats
= ARRAY_SIZE(vkms_cursor_formats
);
204 funcs
= &vkms_primary_helper_funcs
;
206 formats
= vkms_formats
;
207 nformats
= ARRAY_SIZE(vkms_formats
);
208 funcs
= &vkms_primary_helper_funcs
;
211 ret
= drm_universal_plane_init(dev
, plane
, 1 << index
,
220 drm_plane_helper_add(plane
, funcs
);