1 // SPDX-License-Identifier: GPL-2.0+
3 #include <drm/drm_atomic.h>
4 #include <drm/drm_atomic_helper.h>
5 #include <drm/drm_fourcc.h>
6 #include <drm/drm_gem_framebuffer_helper.h>
7 #include <drm/drm_plane_helper.h>
11 static const u32 vkms_formats
[] = {
15 static const u32 vkms_cursor_formats
[] = {
19 static struct drm_plane_state
*
20 vkms_plane_duplicate_state(struct drm_plane
*plane
)
22 struct vkms_plane_state
*vkms_state
;
23 struct vkms_composer
*composer
;
25 vkms_state
= kzalloc(sizeof(*vkms_state
), GFP_KERNEL
);
29 composer
= kzalloc(sizeof(*composer
), GFP_KERNEL
);
31 DRM_DEBUG_KMS("Couldn't allocate composer\n");
36 vkms_state
->composer
= composer
;
38 __drm_atomic_helper_plane_duplicate_state(plane
,
41 return &vkms_state
->base
;
44 static void vkms_plane_destroy_state(struct drm_plane
*plane
,
45 struct drm_plane_state
*old_state
)
47 struct vkms_plane_state
*vkms_state
= to_vkms_plane_state(old_state
);
48 struct drm_crtc
*crtc
= vkms_state
->base
.crtc
;
51 /* dropping the reference we acquired in
52 * vkms_primary_plane_update()
54 if (drm_framebuffer_read_refcount(&vkms_state
->composer
->fb
))
55 drm_framebuffer_put(&vkms_state
->composer
->fb
);
58 kfree(vkms_state
->composer
);
59 vkms_state
->composer
= NULL
;
61 __drm_atomic_helper_plane_destroy_state(old_state
);
65 static void vkms_plane_reset(struct drm_plane
*plane
)
67 struct vkms_plane_state
*vkms_state
;
70 vkms_plane_destroy_state(plane
, plane
->state
);
72 vkms_state
= kzalloc(sizeof(*vkms_state
), GFP_KERNEL
);
74 DRM_ERROR("Cannot allocate vkms_plane_state\n");
78 plane
->state
= &vkms_state
->base
;
79 plane
->state
->plane
= plane
;
82 static const struct drm_plane_funcs vkms_plane_funcs
= {
83 .update_plane
= drm_atomic_helper_update_plane
,
84 .disable_plane
= drm_atomic_helper_disable_plane
,
85 .destroy
= drm_plane_cleanup
,
86 .reset
= vkms_plane_reset
,
87 .atomic_duplicate_state
= vkms_plane_duplicate_state
,
88 .atomic_destroy_state
= vkms_plane_destroy_state
,
91 static void vkms_plane_atomic_update(struct drm_plane
*plane
,
92 struct drm_plane_state
*old_state
)
94 struct vkms_plane_state
*vkms_plane_state
;
95 struct drm_framebuffer
*fb
= plane
->state
->fb
;
96 struct vkms_composer
*composer
;
98 if (!plane
->state
->crtc
|| !fb
)
101 vkms_plane_state
= to_vkms_plane_state(plane
->state
);
103 composer
= vkms_plane_state
->composer
;
104 memcpy(&composer
->src
, &plane
->state
->src
, sizeof(struct drm_rect
));
105 memcpy(&composer
->dst
, &plane
->state
->dst
, sizeof(struct drm_rect
));
106 memcpy(&composer
->fb
, fb
, sizeof(struct drm_framebuffer
));
107 drm_framebuffer_get(&composer
->fb
);
108 composer
->offset
= fb
->offsets
[0];
109 composer
->pitch
= fb
->pitches
[0];
110 composer
->cpp
= fb
->format
->cpp
[0];
113 static int vkms_plane_atomic_check(struct drm_plane
*plane
,
114 struct drm_plane_state
*state
)
116 struct drm_crtc_state
*crtc_state
;
117 bool can_position
= false;
120 if (!state
->fb
| !state
->crtc
)
123 crtc_state
= drm_atomic_get_crtc_state(state
->state
, state
->crtc
);
124 if (IS_ERR(crtc_state
))
125 return PTR_ERR(crtc_state
);
127 if (plane
->type
== DRM_PLANE_TYPE_CURSOR
)
130 ret
= drm_atomic_helper_check_plane_state(state
, crtc_state
,
131 DRM_PLANE_HELPER_NO_SCALING
,
132 DRM_PLANE_HELPER_NO_SCALING
,
137 /* for now primary plane must be visible and full screen */
138 if (!state
->visible
&& !can_position
)
144 static int vkms_prepare_fb(struct drm_plane
*plane
,
145 struct drm_plane_state
*state
)
147 struct drm_gem_object
*gem_obj
;
153 gem_obj
= drm_gem_fb_get_obj(state
->fb
, 0);
154 ret
= vkms_gem_vmap(gem_obj
);
156 DRM_ERROR("vmap failed: %d\n", ret
);
158 return drm_gem_fb_prepare_fb(plane
, state
);
161 static void vkms_cleanup_fb(struct drm_plane
*plane
,
162 struct drm_plane_state
*old_state
)
164 struct drm_gem_object
*gem_obj
;
169 gem_obj
= drm_gem_fb_get_obj(old_state
->fb
, 0);
170 vkms_gem_vunmap(gem_obj
);
173 static const struct drm_plane_helper_funcs vkms_primary_helper_funcs
= {
174 .atomic_update
= vkms_plane_atomic_update
,
175 .atomic_check
= vkms_plane_atomic_check
,
176 .prepare_fb
= vkms_prepare_fb
,
177 .cleanup_fb
= vkms_cleanup_fb
,
180 struct drm_plane
*vkms_plane_init(struct vkms_device
*vkmsdev
,
181 enum drm_plane_type type
, int index
)
183 struct drm_device
*dev
= &vkmsdev
->drm
;
184 const struct drm_plane_helper_funcs
*funcs
;
185 struct drm_plane
*plane
;
189 plane
= kzalloc(sizeof(*plane
), GFP_KERNEL
);
191 return ERR_PTR(-ENOMEM
);
193 if (type
== DRM_PLANE_TYPE_CURSOR
) {
194 formats
= vkms_cursor_formats
;
195 nformats
= ARRAY_SIZE(vkms_cursor_formats
);
196 funcs
= &vkms_primary_helper_funcs
;
198 formats
= vkms_formats
;
199 nformats
= ARRAY_SIZE(vkms_formats
);
200 funcs
= &vkms_primary_helper_funcs
;
203 ret
= drm_universal_plane_init(dev
, plane
, 1 << index
,
212 drm_plane_helper_add(plane
, funcs
);