xref: /linux/drivers/gpu/drm/drm_simple_kms_helper.c (revision 40286d6379aacfcc053253ef78dc78b09addffda)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) 2016 Noralf Trønnes
4  */
5 
6 #include <linux/export.h>
7 #include <linux/module.h>
8 #include <linux/slab.h>
9 
10 #include <drm/drm_atomic.h>
11 #include <drm/drm_atomic_helper.h>
12 #include <drm/drm_bridge.h>
13 #include <drm/drm_drv.h>
14 #include <drm/drm_gem_atomic_helper.h>
15 #include <drm/drm_managed.h>
16 #include <drm/drm_probe_helper.h>
17 #include <drm/drm_simple_kms_helper.h>
18 
19 static const struct drm_encoder_funcs drm_simple_encoder_funcs_cleanup = {
20 	.destroy = drm_encoder_cleanup,
21 };
22 
23 int drm_simple_encoder_init(struct drm_device *dev,
24 			    struct drm_encoder *encoder,
25 			    int encoder_type)
26 {
27 	return drm_encoder_init(dev, encoder,
28 				&drm_simple_encoder_funcs_cleanup,
29 				encoder_type, NULL);
30 }
31 EXPORT_SYMBOL(drm_simple_encoder_init);
32 
33 void *__drmm_simple_encoder_alloc(struct drm_device *dev, size_t size,
34 				  size_t offset, int encoder_type)
35 {
36 	return __drmm_encoder_alloc(dev, size, offset, NULL, encoder_type,
37 				    NULL);
38 }
39 EXPORT_SYMBOL(__drmm_simple_encoder_alloc);
40 
41 static enum drm_mode_status
42 drm_simple_kms_crtc_mode_valid(struct drm_crtc *crtc,
43 			       const struct drm_display_mode *mode)
44 {
45 	struct drm_simple_display_pipe *pipe;
46 
47 	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
48 	if (!pipe->funcs || !pipe->funcs->mode_valid)
49 		/* Anything goes */
50 		return MODE_OK;
51 
52 	return pipe->funcs->mode_valid(pipe, mode);
53 }
54 
55 static int drm_simple_kms_crtc_check(struct drm_crtc *crtc,
56 				     struct drm_atomic_state *state)
57 {
58 	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
59 	int ret;
60 
61 	if (!crtc_state->enable)
62 		goto out;
63 
64 	ret = drm_atomic_helper_check_crtc_primary_plane(crtc_state);
65 	if (ret)
66 		return ret;
67 
68 out:
69 	return drm_atomic_add_affected_planes(state, crtc);
70 }
71 
72 static void drm_simple_kms_crtc_enable(struct drm_crtc *crtc,
73 				       struct drm_atomic_state *state)
74 {
75 	struct drm_plane *plane;
76 	struct drm_simple_display_pipe *pipe;
77 
78 	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
79 	if (!pipe->funcs || !pipe->funcs->enable)
80 		return;
81 
82 	plane = &pipe->plane;
83 	pipe->funcs->enable(pipe, crtc->state, plane->state);
84 }
85 
86 static void drm_simple_kms_crtc_disable(struct drm_crtc *crtc,
87 					struct drm_atomic_state *state)
88 {
89 	struct drm_simple_display_pipe *pipe;
90 
91 	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
92 	if (!pipe->funcs || !pipe->funcs->disable)
93 		return;
94 
95 	pipe->funcs->disable(pipe);
96 }
97 
98 static const struct drm_crtc_helper_funcs drm_simple_kms_crtc_helper_funcs = {
99 	.mode_valid = drm_simple_kms_crtc_mode_valid,
100 	.atomic_check = drm_simple_kms_crtc_check,
101 	.atomic_enable = drm_simple_kms_crtc_enable,
102 	.atomic_disable = drm_simple_kms_crtc_disable,
103 };
104 
105 static void drm_simple_kms_crtc_reset(struct drm_crtc *crtc)
106 {
107 	struct drm_simple_display_pipe *pipe;
108 
109 	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
110 	if (!pipe->funcs || !pipe->funcs->reset_crtc)
111 		return drm_atomic_helper_crtc_reset(crtc);
112 
113 	return pipe->funcs->reset_crtc(pipe);
114 }
115 
116 static struct drm_crtc_state *drm_simple_kms_crtc_duplicate_state(struct drm_crtc *crtc)
117 {
118 	struct drm_simple_display_pipe *pipe;
119 
120 	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
121 	if (!pipe->funcs || !pipe->funcs->duplicate_crtc_state)
122 		return drm_atomic_helper_crtc_duplicate_state(crtc);
123 
124 	return pipe->funcs->duplicate_crtc_state(pipe);
125 }
126 
127 static void drm_simple_kms_crtc_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *state)
128 {
129 	struct drm_simple_display_pipe *pipe;
130 
131 	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
132 	if (!pipe->funcs || !pipe->funcs->destroy_crtc_state)
133 		drm_atomic_helper_crtc_destroy_state(crtc, state);
134 	else
135 		pipe->funcs->destroy_crtc_state(pipe, state);
136 }
137 
138 static int drm_simple_kms_crtc_enable_vblank(struct drm_crtc *crtc)
139 {
140 	struct drm_simple_display_pipe *pipe;
141 
142 	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
143 	if (!pipe->funcs || !pipe->funcs->enable_vblank)
144 		return 0;
145 
146 	return pipe->funcs->enable_vblank(pipe);
147 }
148 
149 static void drm_simple_kms_crtc_disable_vblank(struct drm_crtc *crtc)
150 {
151 	struct drm_simple_display_pipe *pipe;
152 
153 	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
154 	if (!pipe->funcs || !pipe->funcs->disable_vblank)
155 		return;
156 
157 	pipe->funcs->disable_vblank(pipe);
158 }
159 
160 static const struct drm_crtc_funcs drm_simple_kms_crtc_funcs = {
161 	.reset = drm_simple_kms_crtc_reset,
162 	.destroy = drm_crtc_cleanup,
163 	.set_config = drm_atomic_helper_set_config,
164 	.page_flip = drm_atomic_helper_page_flip,
165 	.atomic_duplicate_state = drm_simple_kms_crtc_duplicate_state,
166 	.atomic_destroy_state = drm_simple_kms_crtc_destroy_state,
167 	.enable_vblank = drm_simple_kms_crtc_enable_vblank,
168 	.disable_vblank = drm_simple_kms_crtc_disable_vblank,
169 };
170 
171 static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane,
172 					struct drm_atomic_state *state)
173 {
174 	struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state,
175 									     plane);
176 	struct drm_simple_display_pipe *pipe;
177 	struct drm_crtc_state *crtc_state;
178 	int ret;
179 
180 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
181 	crtc_state = drm_atomic_get_new_crtc_state(state,
182 						   &pipe->crtc);
183 
184 	ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state,
185 						  DRM_PLANE_NO_SCALING,
186 						  DRM_PLANE_NO_SCALING,
187 						  false, false);
188 	if (ret)
189 		return ret;
190 
191 	if (!plane_state->visible)
192 		return 0;
193 
194 	if (!pipe->funcs || !pipe->funcs->check)
195 		return 0;
196 
197 	return pipe->funcs->check(pipe, plane_state, crtc_state);
198 }
199 
200 static void drm_simple_kms_plane_atomic_update(struct drm_plane *plane,
201 					struct drm_atomic_state *state)
202 {
203 	struct drm_plane_state *old_pstate = drm_atomic_get_old_plane_state(state,
204 									    plane);
205 	struct drm_simple_display_pipe *pipe;
206 
207 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
208 	if (!pipe->funcs || !pipe->funcs->update)
209 		return;
210 
211 	pipe->funcs->update(pipe, old_pstate);
212 }
213 
214 static int drm_simple_kms_plane_prepare_fb(struct drm_plane *plane,
215 					   struct drm_plane_state *state)
216 {
217 	struct drm_simple_display_pipe *pipe;
218 
219 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
220 	if (!pipe->funcs || !pipe->funcs->prepare_fb) {
221 		if (WARN_ON_ONCE(!drm_core_check_feature(plane->dev, DRIVER_GEM)))
222 			return 0;
223 
224 		WARN_ON_ONCE(pipe->funcs && pipe->funcs->cleanup_fb);
225 
226 		return drm_gem_plane_helper_prepare_fb(plane, state);
227 	}
228 
229 	return pipe->funcs->prepare_fb(pipe, state);
230 }
231 
232 static void drm_simple_kms_plane_cleanup_fb(struct drm_plane *plane,
233 					    struct drm_plane_state *state)
234 {
235 	struct drm_simple_display_pipe *pipe;
236 
237 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
238 	if (!pipe->funcs || !pipe->funcs->cleanup_fb)
239 		return;
240 
241 	pipe->funcs->cleanup_fb(pipe, state);
242 }
243 
244 static int drm_simple_kms_plane_begin_fb_access(struct drm_plane *plane,
245 						struct drm_plane_state *new_plane_state)
246 {
247 	struct drm_simple_display_pipe *pipe;
248 
249 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
250 	if (!pipe->funcs || !pipe->funcs->begin_fb_access)
251 		return 0;
252 
253 	return pipe->funcs->begin_fb_access(pipe, new_plane_state);
254 }
255 
256 static void drm_simple_kms_plane_end_fb_access(struct drm_plane *plane,
257 					       struct drm_plane_state *new_plane_state)
258 {
259 	struct drm_simple_display_pipe *pipe;
260 
261 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
262 	if (!pipe->funcs || !pipe->funcs->end_fb_access)
263 		return;
264 
265 	pipe->funcs->end_fb_access(pipe, new_plane_state);
266 }
267 
268 static bool drm_simple_kms_format_mod_supported(struct drm_plane *plane,
269 						uint32_t format,
270 						uint64_t modifier)
271 {
272 	return modifier == DRM_FORMAT_MOD_LINEAR;
273 }
274 
275 static const struct drm_plane_helper_funcs drm_simple_kms_plane_helper_funcs = {
276 	.prepare_fb = drm_simple_kms_plane_prepare_fb,
277 	.cleanup_fb = drm_simple_kms_plane_cleanup_fb,
278 	.begin_fb_access = drm_simple_kms_plane_begin_fb_access,
279 	.end_fb_access = drm_simple_kms_plane_end_fb_access,
280 	.atomic_check = drm_simple_kms_plane_atomic_check,
281 	.atomic_update = drm_simple_kms_plane_atomic_update,
282 };
283 
284 static void drm_simple_kms_plane_reset(struct drm_plane *plane)
285 {
286 	struct drm_simple_display_pipe *pipe;
287 
288 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
289 	if (!pipe->funcs || !pipe->funcs->reset_plane)
290 		return drm_atomic_helper_plane_reset(plane);
291 
292 	return pipe->funcs->reset_plane(pipe);
293 }
294 
295 static struct drm_plane_state *drm_simple_kms_plane_duplicate_state(struct drm_plane *plane)
296 {
297 	struct drm_simple_display_pipe *pipe;
298 
299 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
300 	if (!pipe->funcs || !pipe->funcs->duplicate_plane_state)
301 		return drm_atomic_helper_plane_duplicate_state(plane);
302 
303 	return pipe->funcs->duplicate_plane_state(pipe);
304 }
305 
306 static void drm_simple_kms_plane_destroy_state(struct drm_plane *plane,
307 					       struct drm_plane_state *state)
308 {
309 	struct drm_simple_display_pipe *pipe;
310 
311 	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
312 	if (!pipe->funcs || !pipe->funcs->destroy_plane_state)
313 		drm_atomic_helper_plane_destroy_state(plane, state);
314 	else
315 		pipe->funcs->destroy_plane_state(pipe, state);
316 }
317 
318 static const struct drm_plane_funcs drm_simple_kms_plane_funcs = {
319 	.update_plane		= drm_atomic_helper_update_plane,
320 	.disable_plane		= drm_atomic_helper_disable_plane,
321 	.destroy		= drm_plane_cleanup,
322 	.reset			= drm_simple_kms_plane_reset,
323 	.atomic_duplicate_state	= drm_simple_kms_plane_duplicate_state,
324 	.atomic_destroy_state	= drm_simple_kms_plane_destroy_state,
325 	.format_mod_supported   = drm_simple_kms_format_mod_supported,
326 };
327 
328 int drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe *pipe,
329 					  struct drm_bridge *bridge)
330 {
331 	return drm_bridge_attach(&pipe->encoder, bridge, NULL, 0);
332 }
333 EXPORT_SYMBOL(drm_simple_display_pipe_attach_bridge);
334 
335 int drm_simple_display_pipe_init(struct drm_device *dev,
336 			struct drm_simple_display_pipe *pipe,
337 			const struct drm_simple_display_pipe_funcs *funcs,
338 			const uint32_t *formats, unsigned int format_count,
339 			const uint64_t *format_modifiers,
340 			struct drm_connector *connector)
341 {
342 	struct drm_encoder *encoder = &pipe->encoder;
343 	struct drm_plane *plane = &pipe->plane;
344 	struct drm_crtc *crtc = &pipe->crtc;
345 	int ret;
346 
347 	pipe->connector = connector;
348 	pipe->funcs = funcs;
349 
350 	drm_plane_helper_add(plane, &drm_simple_kms_plane_helper_funcs);
351 	ret = drm_universal_plane_init(dev, plane, 0,
352 				       &drm_simple_kms_plane_funcs,
353 				       formats, format_count,
354 				       format_modifiers,
355 				       DRM_PLANE_TYPE_PRIMARY, NULL);
356 	if (ret)
357 		return ret;
358 
359 	drm_crtc_helper_add(crtc, &drm_simple_kms_crtc_helper_funcs);
360 	ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL,
361 					&drm_simple_kms_crtc_funcs, NULL);
362 	if (ret)
363 		return ret;
364 
365 	encoder->possible_crtcs = drm_crtc_mask(crtc);
366 	ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_NONE);
367 	if (ret || !connector)
368 		return ret;
369 
370 	return drm_connector_attach_encoder(connector, encoder);
371 }
372 EXPORT_SYMBOL(drm_simple_display_pipe_init);
373 
374 MODULE_DESCRIPTION("Helpers for drivers for simple display hardware");
375 MODULE_LICENSE("GPL");
376