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