Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0-or-later
2 : /*
3 : * Copyright (C) 2016 Noralf Trønnes
4 : */
5 :
6 : #include <linux/module.h>
7 : #include <linux/slab.h>
8 :
9 : #include <drm/drm_atomic.h>
10 : #include <drm/drm_atomic_helper.h>
11 : #include <drm/drm_bridge.h>
12 : #include <drm/drm_drv.h>
13 : #include <drm/drm_gem_atomic_helper.h>
14 : #include <drm/drm_managed.h>
15 : #include <drm/drm_plane_helper.h>
16 : #include <drm/drm_probe_helper.h>
17 : #include <drm/drm_simple_kms_helper.h>
18 :
19 : /**
20 : * DOC: overview
21 : *
22 : * This helper library provides helpers for drivers for simple display
23 : * hardware.
24 : *
25 : * drm_simple_display_pipe_init() initializes a simple display pipeline
26 : * which has only one full-screen scanout buffer feeding one output. The
27 : * pipeline is represented by &struct drm_simple_display_pipe and binds
28 : * together &drm_plane, &drm_crtc and &drm_encoder structures into one fixed
29 : * entity. Some flexibility for code reuse is provided through a separately
30 : * allocated &drm_connector object and supporting optional &drm_bridge
31 : * encoder drivers.
32 : *
33 : * Many drivers require only a very simple encoder that fulfills the minimum
34 : * requirements of the display pipeline and does not add additional
35 : * functionality. The function drm_simple_encoder_init() provides an
36 : * implementation of such an encoder.
37 : */
38 :
39 : static const struct drm_encoder_funcs drm_simple_encoder_funcs_cleanup = {
40 : .destroy = drm_encoder_cleanup,
41 : };
42 :
43 : /**
44 : * drm_simple_encoder_init - Initialize a preallocated encoder with
45 : * basic functionality.
46 : * @dev: drm device
47 : * @encoder: the encoder to initialize
48 : * @encoder_type: user visible type of the encoder
49 : *
50 : * Initialises a preallocated encoder that has no further functionality.
51 : * Settings for possible CRTC and clones are left to their initial values.
52 : * The encoder will be cleaned up automatically as part of the mode-setting
53 : * cleanup.
54 : *
55 : * The caller of drm_simple_encoder_init() is responsible for freeing
56 : * the encoder's memory after the encoder has been cleaned up. At the
57 : * moment this only works reliably if the encoder data structure is
58 : * stored in the device structure. Free the encoder's memory as part of
59 : * the device release function.
60 : *
61 : * Note: consider using drmm_simple_encoder_alloc() instead of
62 : * drm_simple_encoder_init() to let the DRM managed resource infrastructure
63 : * take care of cleanup and deallocation.
64 : *
65 : * Returns:
66 : * Zero on success, error code on failure.
67 : */
68 0 : int drm_simple_encoder_init(struct drm_device *dev,
69 : struct drm_encoder *encoder,
70 : int encoder_type)
71 : {
72 0 : return drm_encoder_init(dev, encoder,
73 : &drm_simple_encoder_funcs_cleanup,
74 : encoder_type, NULL);
75 : }
76 : EXPORT_SYMBOL(drm_simple_encoder_init);
77 :
78 0 : void *__drmm_simple_encoder_alloc(struct drm_device *dev, size_t size,
79 : size_t offset, int encoder_type)
80 : {
81 0 : return __drmm_encoder_alloc(dev, size, offset, NULL, encoder_type,
82 : NULL);
83 : }
84 : EXPORT_SYMBOL(__drmm_simple_encoder_alloc);
85 :
86 : static enum drm_mode_status
87 0 : drm_simple_kms_crtc_mode_valid(struct drm_crtc *crtc,
88 : const struct drm_display_mode *mode)
89 : {
90 : struct drm_simple_display_pipe *pipe;
91 :
92 0 : pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
93 0 : if (!pipe->funcs || !pipe->funcs->mode_valid)
94 : /* Anything goes */
95 : return MODE_OK;
96 :
97 0 : return pipe->funcs->mode_valid(pipe, mode);
98 : }
99 :
100 0 : static int drm_simple_kms_crtc_check(struct drm_crtc *crtc,
101 : struct drm_atomic_state *state)
102 : {
103 0 : struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
104 : crtc);
105 0 : bool has_primary = crtc_state->plane_mask &
106 0 : drm_plane_mask(crtc->primary);
107 :
108 : /* We always want to have an active plane with an active CRTC */
109 0 : if (has_primary != crtc_state->enable)
110 : return -EINVAL;
111 :
112 0 : return drm_atomic_add_affected_planes(state, crtc);
113 : }
114 :
115 0 : static void drm_simple_kms_crtc_enable(struct drm_crtc *crtc,
116 : struct drm_atomic_state *state)
117 : {
118 : struct drm_plane *plane;
119 : struct drm_simple_display_pipe *pipe;
120 :
121 0 : pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
122 0 : if (!pipe->funcs || !pipe->funcs->enable)
123 : return;
124 :
125 0 : plane = &pipe->plane;
126 0 : pipe->funcs->enable(pipe, crtc->state, plane->state);
127 : }
128 :
129 0 : static void drm_simple_kms_crtc_disable(struct drm_crtc *crtc,
130 : struct drm_atomic_state *state)
131 : {
132 : struct drm_simple_display_pipe *pipe;
133 :
134 0 : pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
135 0 : if (!pipe->funcs || !pipe->funcs->disable)
136 : return;
137 :
138 0 : pipe->funcs->disable(pipe);
139 : }
140 :
141 : static const struct drm_crtc_helper_funcs drm_simple_kms_crtc_helper_funcs = {
142 : .mode_valid = drm_simple_kms_crtc_mode_valid,
143 : .atomic_check = drm_simple_kms_crtc_check,
144 : .atomic_enable = drm_simple_kms_crtc_enable,
145 : .atomic_disable = drm_simple_kms_crtc_disable,
146 : };
147 :
148 0 : static void drm_simple_kms_crtc_reset(struct drm_crtc *crtc)
149 : {
150 : struct drm_simple_display_pipe *pipe;
151 :
152 0 : pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
153 0 : if (!pipe->funcs || !pipe->funcs->reset_crtc)
154 0 : return drm_atomic_helper_crtc_reset(crtc);
155 :
156 0 : return pipe->funcs->reset_crtc(pipe);
157 : }
158 :
159 0 : static struct drm_crtc_state *drm_simple_kms_crtc_duplicate_state(struct drm_crtc *crtc)
160 : {
161 : struct drm_simple_display_pipe *pipe;
162 :
163 0 : pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
164 0 : if (!pipe->funcs || !pipe->funcs->duplicate_crtc_state)
165 0 : return drm_atomic_helper_crtc_duplicate_state(crtc);
166 :
167 0 : return pipe->funcs->duplicate_crtc_state(pipe);
168 : }
169 :
170 0 : static void drm_simple_kms_crtc_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *state)
171 : {
172 : struct drm_simple_display_pipe *pipe;
173 :
174 0 : pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
175 0 : if (!pipe->funcs || !pipe->funcs->destroy_crtc_state)
176 0 : drm_atomic_helper_crtc_destroy_state(crtc, state);
177 : else
178 0 : pipe->funcs->destroy_crtc_state(pipe, state);
179 0 : }
180 :
181 0 : static int drm_simple_kms_crtc_enable_vblank(struct drm_crtc *crtc)
182 : {
183 : struct drm_simple_display_pipe *pipe;
184 :
185 0 : pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
186 0 : if (!pipe->funcs || !pipe->funcs->enable_vblank)
187 : return 0;
188 :
189 0 : return pipe->funcs->enable_vblank(pipe);
190 : }
191 :
192 0 : static void drm_simple_kms_crtc_disable_vblank(struct drm_crtc *crtc)
193 : {
194 : struct drm_simple_display_pipe *pipe;
195 :
196 0 : pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
197 0 : if (!pipe->funcs || !pipe->funcs->disable_vblank)
198 : return;
199 :
200 0 : pipe->funcs->disable_vblank(pipe);
201 : }
202 :
203 : static const struct drm_crtc_funcs drm_simple_kms_crtc_funcs = {
204 : .reset = drm_simple_kms_crtc_reset,
205 : .destroy = drm_crtc_cleanup,
206 : .set_config = drm_atomic_helper_set_config,
207 : .page_flip = drm_atomic_helper_page_flip,
208 : .atomic_duplicate_state = drm_simple_kms_crtc_duplicate_state,
209 : .atomic_destroy_state = drm_simple_kms_crtc_destroy_state,
210 : .enable_vblank = drm_simple_kms_crtc_enable_vblank,
211 : .disable_vblank = drm_simple_kms_crtc_disable_vblank,
212 : };
213 :
214 0 : static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane,
215 : struct drm_atomic_state *state)
216 : {
217 0 : struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state,
218 : plane);
219 : struct drm_simple_display_pipe *pipe;
220 : struct drm_crtc_state *crtc_state;
221 : int ret;
222 :
223 0 : pipe = container_of(plane, struct drm_simple_display_pipe, plane);
224 0 : crtc_state = drm_atomic_get_new_crtc_state(state,
225 : &pipe->crtc);
226 :
227 0 : ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state,
228 : DRM_PLANE_HELPER_NO_SCALING,
229 : DRM_PLANE_HELPER_NO_SCALING,
230 : false, true);
231 0 : if (ret)
232 : return ret;
233 :
234 0 : if (!plane_state->visible)
235 : return 0;
236 :
237 0 : if (!pipe->funcs || !pipe->funcs->check)
238 : return 0;
239 :
240 0 : return pipe->funcs->check(pipe, plane_state, crtc_state);
241 : }
242 :
243 0 : static void drm_simple_kms_plane_atomic_update(struct drm_plane *plane,
244 : struct drm_atomic_state *state)
245 : {
246 0 : struct drm_plane_state *old_pstate = drm_atomic_get_old_plane_state(state,
247 : plane);
248 : struct drm_simple_display_pipe *pipe;
249 :
250 0 : pipe = container_of(plane, struct drm_simple_display_pipe, plane);
251 0 : if (!pipe->funcs || !pipe->funcs->update)
252 : return;
253 :
254 0 : pipe->funcs->update(pipe, old_pstate);
255 : }
256 :
257 0 : static int drm_simple_kms_plane_prepare_fb(struct drm_plane *plane,
258 : struct drm_plane_state *state)
259 : {
260 : struct drm_simple_display_pipe *pipe;
261 :
262 0 : pipe = container_of(plane, struct drm_simple_display_pipe, plane);
263 0 : if (!pipe->funcs || !pipe->funcs->prepare_fb) {
264 0 : if (WARN_ON_ONCE(!drm_core_check_feature(plane->dev, DRIVER_GEM)))
265 : return 0;
266 :
267 0 : WARN_ON_ONCE(pipe->funcs && pipe->funcs->cleanup_fb);
268 :
269 0 : return drm_gem_simple_display_pipe_prepare_fb(pipe, state);
270 : }
271 :
272 0 : return pipe->funcs->prepare_fb(pipe, state);
273 : }
274 :
275 0 : static void drm_simple_kms_plane_cleanup_fb(struct drm_plane *plane,
276 : struct drm_plane_state *state)
277 : {
278 : struct drm_simple_display_pipe *pipe;
279 :
280 0 : pipe = container_of(plane, struct drm_simple_display_pipe, plane);
281 0 : if (!pipe->funcs || !pipe->funcs->cleanup_fb)
282 : return;
283 :
284 0 : pipe->funcs->cleanup_fb(pipe, state);
285 : }
286 :
287 0 : static bool drm_simple_kms_format_mod_supported(struct drm_plane *plane,
288 : uint32_t format,
289 : uint64_t modifier)
290 : {
291 0 : return modifier == DRM_FORMAT_MOD_LINEAR;
292 : }
293 :
294 : static const struct drm_plane_helper_funcs drm_simple_kms_plane_helper_funcs = {
295 : .prepare_fb = drm_simple_kms_plane_prepare_fb,
296 : .cleanup_fb = drm_simple_kms_plane_cleanup_fb,
297 : .atomic_check = drm_simple_kms_plane_atomic_check,
298 : .atomic_update = drm_simple_kms_plane_atomic_update,
299 : };
300 :
301 0 : static void drm_simple_kms_plane_reset(struct drm_plane *plane)
302 : {
303 : struct drm_simple_display_pipe *pipe;
304 :
305 0 : pipe = container_of(plane, struct drm_simple_display_pipe, plane);
306 0 : if (!pipe->funcs || !pipe->funcs->reset_plane)
307 0 : return drm_atomic_helper_plane_reset(plane);
308 :
309 0 : return pipe->funcs->reset_plane(pipe);
310 : }
311 :
312 0 : static struct drm_plane_state *drm_simple_kms_plane_duplicate_state(struct drm_plane *plane)
313 : {
314 : struct drm_simple_display_pipe *pipe;
315 :
316 0 : pipe = container_of(plane, struct drm_simple_display_pipe, plane);
317 0 : if (!pipe->funcs || !pipe->funcs->duplicate_plane_state)
318 0 : return drm_atomic_helper_plane_duplicate_state(plane);
319 :
320 0 : return pipe->funcs->duplicate_plane_state(pipe);
321 : }
322 :
323 0 : static void drm_simple_kms_plane_destroy_state(struct drm_plane *plane,
324 : struct drm_plane_state *state)
325 : {
326 : struct drm_simple_display_pipe *pipe;
327 :
328 0 : pipe = container_of(plane, struct drm_simple_display_pipe, plane);
329 0 : if (!pipe->funcs || !pipe->funcs->destroy_plane_state)
330 0 : drm_atomic_helper_plane_destroy_state(plane, state);
331 : else
332 0 : pipe->funcs->destroy_plane_state(pipe, state);
333 0 : }
334 :
335 : static const struct drm_plane_funcs drm_simple_kms_plane_funcs = {
336 : .update_plane = drm_atomic_helper_update_plane,
337 : .disable_plane = drm_atomic_helper_disable_plane,
338 : .destroy = drm_plane_cleanup,
339 : .reset = drm_simple_kms_plane_reset,
340 : .atomic_duplicate_state = drm_simple_kms_plane_duplicate_state,
341 : .atomic_destroy_state = drm_simple_kms_plane_destroy_state,
342 : .format_mod_supported = drm_simple_kms_format_mod_supported,
343 : };
344 :
345 : /**
346 : * drm_simple_display_pipe_attach_bridge - Attach a bridge to the display pipe
347 : * @pipe: simple display pipe object
348 : * @bridge: bridge to attach
349 : *
350 : * Makes it possible to still use the drm_simple_display_pipe helpers when
351 : * a DRM bridge has to be used.
352 : *
353 : * Note that you probably want to initialize the pipe by passing a NULL
354 : * connector to drm_simple_display_pipe_init().
355 : *
356 : * Returns:
357 : * Zero on success, negative error code on failure.
358 : */
359 0 : int drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe *pipe,
360 : struct drm_bridge *bridge)
361 : {
362 0 : return drm_bridge_attach(&pipe->encoder, bridge, NULL, 0);
363 : }
364 : EXPORT_SYMBOL(drm_simple_display_pipe_attach_bridge);
365 :
366 : /**
367 : * drm_simple_display_pipe_init - Initialize a simple display pipeline
368 : * @dev: DRM device
369 : * @pipe: simple display pipe object to initialize
370 : * @funcs: callbacks for the display pipe (optional)
371 : * @formats: array of supported formats (DRM_FORMAT\_\*)
372 : * @format_count: number of elements in @formats
373 : * @format_modifiers: array of formats modifiers
374 : * @connector: connector to attach and register (optional)
375 : *
376 : * Sets up a display pipeline which consist of a really simple
377 : * plane-crtc-encoder pipe.
378 : *
379 : * If a connector is supplied, the pipe will be coupled with the provided
380 : * connector. You may supply a NULL connector when using drm bridges, that
381 : * handle connectors themselves (see drm_simple_display_pipe_attach_bridge()).
382 : *
383 : * Teardown of a simple display pipe is all handled automatically by the drm
384 : * core through calling drm_mode_config_cleanup(). Drivers afterwards need to
385 : * release the memory for the structure themselves.
386 : *
387 : * Returns:
388 : * Zero on success, negative error code on failure.
389 : */
390 0 : int drm_simple_display_pipe_init(struct drm_device *dev,
391 : struct drm_simple_display_pipe *pipe,
392 : const struct drm_simple_display_pipe_funcs *funcs,
393 : const uint32_t *formats, unsigned int format_count,
394 : const uint64_t *format_modifiers,
395 : struct drm_connector *connector)
396 : {
397 0 : struct drm_encoder *encoder = &pipe->encoder;
398 0 : struct drm_plane *plane = &pipe->plane;
399 0 : struct drm_crtc *crtc = &pipe->crtc;
400 : int ret;
401 :
402 0 : pipe->connector = connector;
403 0 : pipe->funcs = funcs;
404 :
405 0 : drm_plane_helper_add(plane, &drm_simple_kms_plane_helper_funcs);
406 0 : ret = drm_universal_plane_init(dev, plane, 0,
407 : &drm_simple_kms_plane_funcs,
408 : formats, format_count,
409 : format_modifiers,
410 : DRM_PLANE_TYPE_PRIMARY, NULL);
411 0 : if (ret)
412 : return ret;
413 :
414 0 : drm_crtc_helper_add(crtc, &drm_simple_kms_crtc_helper_funcs);
415 0 : ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL,
416 : &drm_simple_kms_crtc_funcs, NULL);
417 0 : if (ret)
418 : return ret;
419 :
420 0 : encoder->possible_crtcs = drm_crtc_mask(crtc);
421 0 : ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_NONE);
422 0 : if (ret || !connector)
423 : return ret;
424 :
425 0 : return drm_connector_attach_encoder(connector, encoder);
426 : }
427 : EXPORT_SYMBOL(drm_simple_display_pipe_init);
428 :
429 : MODULE_LICENSE("GPL");
|