xref: /openbmc/linux/drivers/gpu/drm/vkms/vkms_plane.c (revision 5e8bf00e)
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_fourcc.h>
8 #include <drm/drm_gem_atomic_helper.h>
9 #include <drm/drm_gem_framebuffer_helper.h>
10 
11 #include "vkms_drv.h"
12 
13 static const u32 vkms_formats[] = {
14 	DRM_FORMAT_XRGB8888,
15 };
16 
17 static const u32 vkms_plane_formats[] = {
18 	DRM_FORMAT_ARGB8888,
19 	DRM_FORMAT_XRGB8888
20 };
21 
22 static struct drm_plane_state *
23 vkms_plane_duplicate_state(struct drm_plane *plane)
24 {
25 	struct vkms_plane_state *vkms_state;
26 	struct vkms_composer *composer;
27 
28 	vkms_state = kzalloc(sizeof(*vkms_state), GFP_KERNEL);
29 	if (!vkms_state)
30 		return NULL;
31 
32 	composer = kzalloc(sizeof(*composer), GFP_KERNEL);
33 	if (!composer) {
34 		DRM_DEBUG_KMS("Couldn't allocate composer\n");
35 		kfree(vkms_state);
36 		return NULL;
37 	}
38 
39 	vkms_state->composer = composer;
40 
41 	__drm_gem_duplicate_shadow_plane_state(plane, &vkms_state->base);
42 
43 	return &vkms_state->base.base;
44 }
45 
46 static void vkms_plane_destroy_state(struct drm_plane *plane,
47 				     struct drm_plane_state *old_state)
48 {
49 	struct vkms_plane_state *vkms_state = to_vkms_plane_state(old_state);
50 	struct drm_crtc *crtc = vkms_state->base.base.crtc;
51 
52 	if (crtc) {
53 		/* dropping the reference we acquired in
54 		 * vkms_primary_plane_update()
55 		 */
56 		if (drm_framebuffer_read_refcount(&vkms_state->composer->fb))
57 			drm_framebuffer_put(&vkms_state->composer->fb);
58 	}
59 
60 	kfree(vkms_state->composer);
61 	vkms_state->composer = NULL;
62 
63 	__drm_gem_destroy_shadow_plane_state(&vkms_state->base);
64 	kfree(vkms_state);
65 }
66 
67 static void vkms_plane_reset(struct drm_plane *plane)
68 {
69 	struct vkms_plane_state *vkms_state;
70 
71 	if (plane->state) {
72 		vkms_plane_destroy_state(plane, plane->state);
73 		plane->state = NULL; /* must be set to NULL here */
74 	}
75 
76 	vkms_state = kzalloc(sizeof(*vkms_state), GFP_KERNEL);
77 	if (!vkms_state) {
78 		DRM_ERROR("Cannot allocate vkms_plane_state\n");
79 		return;
80 	}
81 
82 	__drm_gem_reset_shadow_plane(plane, &vkms_state->base);
83 }
84 
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 	.reset			= vkms_plane_reset,
89 	.atomic_duplicate_state = vkms_plane_duplicate_state,
90 	.atomic_destroy_state	= vkms_plane_destroy_state,
91 };
92 
93 static void vkms_plane_atomic_update(struct drm_plane *plane,
94 				     struct drm_atomic_state *state)
95 {
96 	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
97 									   plane);
98 	struct vkms_plane_state *vkms_plane_state;
99 	struct drm_shadow_plane_state *shadow_plane_state;
100 	struct drm_framebuffer *fb = new_state->fb;
101 	struct vkms_composer *composer;
102 
103 	if (!new_state->crtc || !fb)
104 		return;
105 
106 	vkms_plane_state = to_vkms_plane_state(new_state);
107 	shadow_plane_state = &vkms_plane_state->base;
108 
109 	composer = vkms_plane_state->composer;
110 	memcpy(&composer->src, &new_state->src, sizeof(struct drm_rect));
111 	memcpy(&composer->dst, &new_state->dst, sizeof(struct drm_rect));
112 	memcpy(&composer->fb, fb, sizeof(struct drm_framebuffer));
113 	memcpy(&composer->map, &shadow_plane_state->data, sizeof(composer->map));
114 	drm_framebuffer_get(&composer->fb);
115 	composer->offset = fb->offsets[0];
116 	composer->pitch = fb->pitches[0];
117 	composer->cpp = fb->format->cpp[0];
118 }
119 
120 static int vkms_plane_atomic_check(struct drm_plane *plane,
121 				   struct drm_atomic_state *state)
122 {
123 	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
124 										 plane);
125 	struct drm_crtc_state *crtc_state;
126 	bool can_position = false;
127 	int ret;
128 
129 	if (!new_plane_state->fb || WARN_ON(!new_plane_state->crtc))
130 		return 0;
131 
132 	crtc_state = drm_atomic_get_crtc_state(state,
133 					       new_plane_state->crtc);
134 	if (IS_ERR(crtc_state))
135 		return PTR_ERR(crtc_state);
136 
137 	if (plane->type != DRM_PLANE_TYPE_PRIMARY)
138 		can_position = true;
139 
140 	ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
141 						  DRM_PLANE_NO_SCALING,
142 						  DRM_PLANE_NO_SCALING,
143 						  can_position, true);
144 	if (ret != 0)
145 		return ret;
146 
147 	/* for now primary plane must be visible and full screen */
148 	if (!new_plane_state->visible && !can_position)
149 		return -EINVAL;
150 
151 	return 0;
152 }
153 
154 static const struct drm_plane_helper_funcs vkms_primary_helper_funcs = {
155 	.atomic_update		= vkms_plane_atomic_update,
156 	.atomic_check		= vkms_plane_atomic_check,
157 	DRM_GEM_SHADOW_PLANE_HELPER_FUNCS,
158 };
159 
160 struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev,
161 				   enum drm_plane_type type, int index)
162 {
163 	struct drm_device *dev = &vkmsdev->drm;
164 	const struct drm_plane_helper_funcs *funcs;
165 	struct vkms_plane *plane;
166 	const u32 *formats;
167 	int nformats;
168 
169 	switch (type) {
170 	case DRM_PLANE_TYPE_PRIMARY:
171 		formats = vkms_formats;
172 		nformats = ARRAY_SIZE(vkms_formats);
173 		funcs = &vkms_primary_helper_funcs;
174 		break;
175 	case DRM_PLANE_TYPE_CURSOR:
176 	case DRM_PLANE_TYPE_OVERLAY:
177 		formats = vkms_plane_formats;
178 		nformats = ARRAY_SIZE(vkms_plane_formats);
179 		funcs = &vkms_primary_helper_funcs;
180 		break;
181 	default:
182 		formats = vkms_formats;
183 		nformats = ARRAY_SIZE(vkms_formats);
184 		funcs = &vkms_primary_helper_funcs;
185 		break;
186 	}
187 
188 	plane = drmm_universal_plane_alloc(dev, struct vkms_plane, base, 1 << index,
189 					   &vkms_plane_funcs,
190 					   formats, nformats,
191 					   NULL, type, NULL);
192 	if (IS_ERR(plane))
193 		return plane;
194 
195 	drm_plane_helper_add(&plane->base, funcs);
196 
197 	return plane;
198 }
199