xref: /openbmc/linux/drivers/gpu/drm/vkms/vkms_plane.c (revision 9aab6601)
1 // SPDX-License-Identifier: GPL-2.0+
2 
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>
8 #include <drm/drm_gem_shmem_helper.h>
9 
10 #include "vkms_drv.h"
11 
12 static const u32 vkms_formats[] = {
13 	DRM_FORMAT_XRGB8888,
14 };
15 
16 static const u32 vkms_cursor_formats[] = {
17 	DRM_FORMAT_ARGB8888,
18 };
19 
20 static struct drm_plane_state *
21 vkms_plane_duplicate_state(struct drm_plane *plane)
22 {
23 	struct vkms_plane_state *vkms_state;
24 	struct vkms_composer *composer;
25 
26 	vkms_state = kzalloc(sizeof(*vkms_state), GFP_KERNEL);
27 	if (!vkms_state)
28 		return NULL;
29 
30 	composer = kzalloc(sizeof(*composer), GFP_KERNEL);
31 	if (!composer) {
32 		DRM_DEBUG_KMS("Couldn't allocate composer\n");
33 		kfree(vkms_state);
34 		return NULL;
35 	}
36 
37 	vkms_state->composer = composer;
38 
39 	__drm_atomic_helper_plane_duplicate_state(plane,
40 						  &vkms_state->base);
41 
42 	return &vkms_state->base;
43 }
44 
45 static void vkms_plane_destroy_state(struct drm_plane *plane,
46 				     struct drm_plane_state *old_state)
47 {
48 	struct vkms_plane_state *vkms_state = to_vkms_plane_state(old_state);
49 	struct drm_crtc *crtc = vkms_state->base.crtc;
50 
51 	if (crtc) {
52 		/* dropping the reference we acquired in
53 		 * vkms_primary_plane_update()
54 		 */
55 		if (drm_framebuffer_read_refcount(&vkms_state->composer->fb))
56 			drm_framebuffer_put(&vkms_state->composer->fb);
57 	}
58 
59 	kfree(vkms_state->composer);
60 	vkms_state->composer = NULL;
61 
62 	__drm_atomic_helper_plane_destroy_state(old_state);
63 	kfree(vkms_state);
64 }
65 
66 static void vkms_plane_reset(struct drm_plane *plane)
67 {
68 	struct vkms_plane_state *vkms_state;
69 
70 	if (plane->state)
71 		vkms_plane_destroy_state(plane, plane->state);
72 
73 	vkms_state = kzalloc(sizeof(*vkms_state), GFP_KERNEL);
74 	if (!vkms_state) {
75 		DRM_ERROR("Cannot allocate vkms_plane_state\n");
76 		return;
77 	}
78 
79 	plane->state = &vkms_state->base;
80 	plane->state->plane = plane;
81 }
82 
83 static const struct drm_plane_funcs vkms_plane_funcs = {
84 	.update_plane		= drm_atomic_helper_update_plane,
85 	.disable_plane		= drm_atomic_helper_disable_plane,
86 	.destroy		= drm_plane_cleanup,
87 	.reset			= vkms_plane_reset,
88 	.atomic_duplicate_state = vkms_plane_duplicate_state,
89 	.atomic_destroy_state	= vkms_plane_destroy_state,
90 };
91 
92 static void vkms_plane_atomic_update(struct drm_plane *plane,
93 				     struct drm_plane_state *old_state)
94 {
95 	struct vkms_plane_state *vkms_plane_state;
96 	struct drm_framebuffer *fb = plane->state->fb;
97 	struct vkms_composer *composer;
98 
99 	if (!plane->state->crtc || !fb)
100 		return;
101 
102 	vkms_plane_state = to_vkms_plane_state(plane->state);
103 
104 	composer = vkms_plane_state->composer;
105 	memcpy(&composer->src, &plane->state->src, sizeof(struct drm_rect));
106 	memcpy(&composer->dst, &plane->state->dst, sizeof(struct drm_rect));
107 	memcpy(&composer->fb, fb, sizeof(struct drm_framebuffer));
108 	drm_framebuffer_get(&composer->fb);
109 	composer->offset = fb->offsets[0];
110 	composer->pitch = fb->pitches[0];
111 	composer->cpp = fb->format->cpp[0];
112 }
113 
114 static int vkms_plane_atomic_check(struct drm_plane *plane,
115 				   struct drm_plane_state *state)
116 {
117 	struct drm_crtc_state *crtc_state;
118 	bool can_position = false;
119 	int ret;
120 
121 	if (!state->fb || WARN_ON(!state->crtc))
122 		return 0;
123 
124 	crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
125 	if (IS_ERR(crtc_state))
126 		return PTR_ERR(crtc_state);
127 
128 	if (plane->type == DRM_PLANE_TYPE_CURSOR)
129 		can_position = true;
130 
131 	ret = drm_atomic_helper_check_plane_state(state, crtc_state,
132 						  DRM_PLANE_HELPER_NO_SCALING,
133 						  DRM_PLANE_HELPER_NO_SCALING,
134 						  can_position, true);
135 	if (ret != 0)
136 		return ret;
137 
138 	/* for now primary plane must be visible and full screen */
139 	if (!state->visible && !can_position)
140 		return -EINVAL;
141 
142 	return 0;
143 }
144 
145 static int vkms_prepare_fb(struct drm_plane *plane,
146 			   struct drm_plane_state *state)
147 {
148 	struct drm_gem_object *gem_obj;
149 	void *vaddr;
150 
151 	if (!state->fb)
152 		return 0;
153 
154 	gem_obj = drm_gem_fb_get_obj(state->fb, 0);
155 	vaddr = drm_gem_shmem_vmap(gem_obj);
156 	if (IS_ERR(vaddr))
157 		DRM_ERROR("vmap failed: %li\n", PTR_ERR(vaddr));
158 
159 	return drm_gem_fb_prepare_fb(plane, state);
160 }
161 
162 static void vkms_cleanup_fb(struct drm_plane *plane,
163 			    struct drm_plane_state *old_state)
164 {
165 	struct drm_gem_object *gem_obj;
166 	struct drm_gem_shmem_object *shmem_obj;
167 
168 	if (!old_state->fb)
169 		return;
170 
171 	gem_obj = drm_gem_fb_get_obj(old_state->fb, 0);
172 	shmem_obj = to_drm_gem_shmem_obj(drm_gem_fb_get_obj(old_state->fb, 0));
173 	drm_gem_shmem_vunmap(gem_obj, shmem_obj->vaddr);
174 }
175 
176 static const struct drm_plane_helper_funcs vkms_primary_helper_funcs = {
177 	.atomic_update		= vkms_plane_atomic_update,
178 	.atomic_check		= vkms_plane_atomic_check,
179 	.prepare_fb		= vkms_prepare_fb,
180 	.cleanup_fb		= vkms_cleanup_fb,
181 };
182 
183 struct drm_plane *vkms_plane_init(struct vkms_device *vkmsdev,
184 				  enum drm_plane_type type, int index)
185 {
186 	struct drm_device *dev = &vkmsdev->drm;
187 	const struct drm_plane_helper_funcs *funcs;
188 	struct drm_plane *plane;
189 	const u32 *formats;
190 	int ret, nformats;
191 
192 	plane = kzalloc(sizeof(*plane), GFP_KERNEL);
193 	if (!plane)
194 		return ERR_PTR(-ENOMEM);
195 
196 	if (type == DRM_PLANE_TYPE_CURSOR) {
197 		formats = vkms_cursor_formats;
198 		nformats = ARRAY_SIZE(vkms_cursor_formats);
199 		funcs = &vkms_primary_helper_funcs;
200 	} else {
201 		formats = vkms_formats;
202 		nformats = ARRAY_SIZE(vkms_formats);
203 		funcs = &vkms_primary_helper_funcs;
204 	}
205 
206 	ret = drm_universal_plane_init(dev, plane, 1 << index,
207 				       &vkms_plane_funcs,
208 				       formats, nformats,
209 				       NULL, type, NULL);
210 	if (ret) {
211 		kfree(plane);
212 		return ERR_PTR(ret);
213 	}
214 
215 	drm_plane_helper_add(plane, funcs);
216 
217 	return plane;
218 }
219