xref: /linux/drivers/gpu/drm/vkms/vkms_plane.c (revision 815e260a18a3af4dab59025ee99a7156c0e8b5e0)
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_blend.h>
8 #include <drm/drm_fourcc.h>
9 #include <drm/drm_gem_atomic_helper.h>
10 #include <drm/drm_gem_framebuffer_helper.h>
11 #include <drm/drm_print.h>
12 
13 #include "vkms_drv.h"
14 #include "vkms_formats.h"
15 
16 static const u32 vkms_formats[] = {
17 	DRM_FORMAT_ARGB8888,
18 	DRM_FORMAT_ABGR8888,
19 	DRM_FORMAT_BGRA8888,
20 	DRM_FORMAT_RGBA8888,
21 	DRM_FORMAT_XRGB8888,
22 	DRM_FORMAT_XBGR8888,
23 	DRM_FORMAT_RGB888,
24 	DRM_FORMAT_BGR888,
25 	DRM_FORMAT_XRGB16161616,
26 	DRM_FORMAT_XBGR16161616,
27 	DRM_FORMAT_ARGB16161616,
28 	DRM_FORMAT_ABGR16161616,
29 	DRM_FORMAT_RGB565,
30 	DRM_FORMAT_BGR565,
31 	DRM_FORMAT_NV12,
32 	DRM_FORMAT_NV16,
33 	DRM_FORMAT_NV24,
34 	DRM_FORMAT_NV21,
35 	DRM_FORMAT_NV61,
36 	DRM_FORMAT_NV42,
37 	DRM_FORMAT_YUV420,
38 	DRM_FORMAT_YUV422,
39 	DRM_FORMAT_YUV444,
40 	DRM_FORMAT_YVU420,
41 	DRM_FORMAT_YVU422,
42 	DRM_FORMAT_YVU444,
43 	DRM_FORMAT_P010,
44 	DRM_FORMAT_P012,
45 	DRM_FORMAT_P016,
46 	DRM_FORMAT_R1,
47 	DRM_FORMAT_R2,
48 	DRM_FORMAT_R4,
49 	DRM_FORMAT_R8,
50 };
51 
52 static struct drm_plane_state *
53 vkms_plane_duplicate_state(struct drm_plane *plane)
54 {
55 	struct vkms_plane_state *vkms_state;
56 	struct vkms_frame_info *frame_info;
57 
58 	vkms_state = kzalloc(sizeof(*vkms_state), GFP_KERNEL);
59 	if (!vkms_state)
60 		return NULL;
61 
62 	frame_info = kzalloc(sizeof(*frame_info), GFP_KERNEL);
63 	if (!frame_info) {
64 		DRM_DEBUG_KMS("Couldn't allocate frame_info\n");
65 		kfree(vkms_state);
66 		return NULL;
67 	}
68 
69 	vkms_state->frame_info = frame_info;
70 
71 	__drm_gem_duplicate_shadow_plane_state(plane, &vkms_state->base);
72 
73 	return &vkms_state->base.base;
74 }
75 
76 static void vkms_plane_destroy_state(struct drm_plane *plane,
77 				     struct drm_plane_state *old_state)
78 {
79 	struct vkms_plane_state *vkms_state = to_vkms_plane_state(old_state);
80 	struct drm_crtc *crtc = vkms_state->base.base.crtc;
81 
82 	if (crtc && vkms_state->frame_info->fb) {
83 		/* dropping the reference we acquired in
84 		 * vkms_primary_plane_update()
85 		 */
86 		if (drm_framebuffer_read_refcount(vkms_state->frame_info->fb))
87 			drm_framebuffer_put(vkms_state->frame_info->fb);
88 	}
89 
90 	kfree(vkms_state->frame_info);
91 	vkms_state->frame_info = NULL;
92 
93 	__drm_gem_destroy_shadow_plane_state(&vkms_state->base);
94 	kfree(vkms_state);
95 }
96 
97 static void vkms_plane_reset(struct drm_plane *plane)
98 {
99 	struct vkms_plane_state *vkms_state;
100 
101 	if (plane->state) {
102 		vkms_plane_destroy_state(plane, plane->state);
103 		plane->state = NULL; /* must be set to NULL here */
104 	}
105 
106 	vkms_state = kzalloc(sizeof(*vkms_state), GFP_KERNEL);
107 	if (!vkms_state) {
108 		DRM_ERROR("Cannot allocate vkms_plane_state\n");
109 		return;
110 	}
111 
112 	__drm_gem_reset_shadow_plane(plane, &vkms_state->base);
113 }
114 
115 static const struct drm_plane_funcs vkms_plane_funcs = {
116 	.update_plane		= drm_atomic_helper_update_plane,
117 	.disable_plane		= drm_atomic_helper_disable_plane,
118 	.reset			= vkms_plane_reset,
119 	.atomic_duplicate_state = vkms_plane_duplicate_state,
120 	.atomic_destroy_state	= vkms_plane_destroy_state,
121 };
122 
123 static void vkms_plane_atomic_update(struct drm_plane *plane,
124 				     struct drm_atomic_state *state)
125 {
126 	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
127 									   plane);
128 	struct vkms_plane_state *vkms_plane_state;
129 	struct drm_shadow_plane_state *shadow_plane_state;
130 	struct drm_framebuffer *fb = new_state->fb;
131 	struct vkms_frame_info *frame_info;
132 	u32 fmt;
133 
134 	if (!new_state->crtc || !fb)
135 		return;
136 
137 	fmt = fb->format->format;
138 	vkms_plane_state = to_vkms_plane_state(new_state);
139 	shadow_plane_state = &vkms_plane_state->base;
140 
141 	frame_info = vkms_plane_state->frame_info;
142 	memcpy(&frame_info->src, &new_state->src, sizeof(struct drm_rect));
143 	memcpy(&frame_info->dst, &new_state->dst, sizeof(struct drm_rect));
144 	frame_info->fb = fb;
145 	memcpy(&frame_info->map, &shadow_plane_state->data, sizeof(frame_info->map));
146 	drm_framebuffer_get(frame_info->fb);
147 	frame_info->rotation = new_state->rotation;
148 
149 	vkms_plane_state->pixel_read_line = get_pixel_read_line_function(fmt);
150 	get_conversion_matrix_to_argb_u16(fmt, new_state->color_encoding, new_state->color_range,
151 					  &vkms_plane_state->conversion_matrix);
152 }
153 
154 static int vkms_plane_atomic_check(struct drm_plane *plane,
155 				   struct drm_atomic_state *state)
156 {
157 	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
158 										 plane);
159 	struct drm_crtc_state *crtc_state;
160 	int ret;
161 
162 	if (!new_plane_state->fb || WARN_ON(!new_plane_state->crtc))
163 		return 0;
164 
165 	crtc_state = drm_atomic_get_crtc_state(state,
166 					       new_plane_state->crtc);
167 	if (IS_ERR(crtc_state))
168 		return PTR_ERR(crtc_state);
169 
170 	ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
171 						  DRM_PLANE_NO_SCALING,
172 						  DRM_PLANE_NO_SCALING,
173 						  true, true);
174 	if (ret != 0)
175 		return ret;
176 
177 	return 0;
178 }
179 
180 static int vkms_prepare_fb(struct drm_plane *plane,
181 			   struct drm_plane_state *state)
182 {
183 	struct drm_shadow_plane_state *shadow_plane_state;
184 	struct drm_framebuffer *fb = state->fb;
185 	int ret;
186 
187 	if (!fb)
188 		return 0;
189 
190 	shadow_plane_state = to_drm_shadow_plane_state(state);
191 
192 	ret = drm_gem_plane_helper_prepare_fb(plane, state);
193 	if (ret)
194 		return ret;
195 
196 	return drm_gem_fb_vmap(fb, shadow_plane_state->map, shadow_plane_state->data);
197 }
198 
199 static void vkms_cleanup_fb(struct drm_plane *plane,
200 			    struct drm_plane_state *state)
201 {
202 	struct drm_shadow_plane_state *shadow_plane_state;
203 	struct drm_framebuffer *fb = state->fb;
204 
205 	if (!fb)
206 		return;
207 
208 	shadow_plane_state = to_drm_shadow_plane_state(state);
209 
210 	drm_gem_fb_vunmap(fb, shadow_plane_state->map);
211 }
212 
213 static const struct drm_plane_helper_funcs vkms_plane_helper_funcs = {
214 	.atomic_update		= vkms_plane_atomic_update,
215 	.atomic_check		= vkms_plane_atomic_check,
216 	.prepare_fb		= vkms_prepare_fb,
217 	.cleanup_fb		= vkms_cleanup_fb,
218 };
219 
220 struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev,
221 				   enum drm_plane_type type)
222 {
223 	struct drm_device *dev = &vkmsdev->drm;
224 	struct vkms_plane *plane;
225 
226 	plane = drmm_universal_plane_alloc(dev, struct vkms_plane, base, 0,
227 					   &vkms_plane_funcs,
228 					   vkms_formats, ARRAY_SIZE(vkms_formats),
229 					   NULL, type, NULL);
230 	if (IS_ERR(plane))
231 		return plane;
232 
233 	drm_plane_helper_add(&plane->base, &vkms_plane_helper_funcs);
234 
235 	drm_plane_create_rotation_property(&plane->base, DRM_MODE_ROTATE_0,
236 					   DRM_MODE_ROTATE_MASK | DRM_MODE_REFLECT_MASK);
237 
238 	drm_plane_create_color_properties(&plane->base,
239 					  BIT(DRM_COLOR_YCBCR_BT601) |
240 					  BIT(DRM_COLOR_YCBCR_BT709) |
241 					  BIT(DRM_COLOR_YCBCR_BT2020),
242 					  BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
243 					  BIT(DRM_COLOR_YCBCR_FULL_RANGE),
244 					  DRM_COLOR_YCBCR_BT601,
245 					  DRM_COLOR_YCBCR_FULL_RANGE);
246 
247 	return plane;
248 }
249