1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2016 Noralf Trønnes
6 #include <linux/module.h>
7 #include <linux/slab.h>
9 #include <drm/drm_atomic.h>
10 #include <drm/drm_atomic_helper.h>
11 #include <drm/drm_bridge.h>
12 #include <drm/drm_plane_helper.h>
13 #include <drm/drm_probe_helper.h>
14 #include <drm/drm_simple_kms_helper.h>
19 * This helper library provides helpers for drivers for simple display
22 * drm_simple_display_pipe_init() initializes a simple display pipeline
23 * which has only one full-screen scanout buffer feeding one output. The
24 * pipeline is represented by &struct drm_simple_display_pipe and binds
25 * together &drm_plane, &drm_crtc and &drm_encoder structures into one fixed
26 * entity. Some flexibility for code reuse is provided through a separately
27 * allocated &drm_connector object and supporting optional &drm_bridge
30 * Many drivers require only a very simple encoder that fulfills the minimum
31 * requirements of the display pipeline and does not add additional
32 * functionality. The function drm_simple_encoder_init() provides an
33 * implementation of such an encoder.
36 static const struct drm_encoder_funcs drm_simple_encoder_funcs_cleanup
= {
37 .destroy
= drm_encoder_cleanup
,
41 * drm_simple_encoder_init - Initialize a preallocated encoder with
42 * basic functionality.
44 * @encoder: the encoder to initialize
45 * @encoder_type: user visible type of the encoder
47 * Initialises a preallocated encoder that has no further functionality.
48 * Settings for possible CRTC and clones are left to their initial values.
49 * The encoder will be cleaned up automatically as part of the mode-setting
52 * The caller of drm_simple_encoder_init() is responsible for freeing
53 * the encoder's memory after the encoder has been cleaned up. At the
54 * moment this only works reliably if the encoder data structure is
55 * stored in the device structure. Free the encoder's memory as part of
56 * the device release function.
58 * FIXME: Later improvements to DRM's resource management may allow for
59 * an automated kfree() of the encoder's memory.
62 * Zero on success, error code on failure.
64 int drm_simple_encoder_init(struct drm_device
*dev
,
65 struct drm_encoder
*encoder
,
68 return drm_encoder_init(dev
, encoder
,
69 &drm_simple_encoder_funcs_cleanup
,
72 EXPORT_SYMBOL(drm_simple_encoder_init
);
74 static enum drm_mode_status
75 drm_simple_kms_crtc_mode_valid(struct drm_crtc
*crtc
,
76 const struct drm_display_mode
*mode
)
78 struct drm_simple_display_pipe
*pipe
;
80 pipe
= container_of(crtc
, struct drm_simple_display_pipe
, crtc
);
81 if (!pipe
->funcs
|| !pipe
->funcs
->mode_valid
)
85 return pipe
->funcs
->mode_valid(pipe
, mode
);
88 static int drm_simple_kms_crtc_check(struct drm_crtc
*crtc
,
89 struct drm_atomic_state
*state
)
91 struct drm_crtc_state
*crtc_state
= drm_atomic_get_new_crtc_state(state
,
93 bool has_primary
= crtc_state
->plane_mask
&
94 drm_plane_mask(crtc
->primary
);
96 /* We always want to have an active plane with an active CRTC */
97 if (has_primary
!= crtc_state
->enable
)
100 return drm_atomic_add_affected_planes(state
, crtc
);
103 static void drm_simple_kms_crtc_enable(struct drm_crtc
*crtc
,
104 struct drm_atomic_state
*state
)
106 struct drm_plane
*plane
;
107 struct drm_simple_display_pipe
*pipe
;
109 pipe
= container_of(crtc
, struct drm_simple_display_pipe
, crtc
);
110 if (!pipe
->funcs
|| !pipe
->funcs
->enable
)
113 plane
= &pipe
->plane
;
114 pipe
->funcs
->enable(pipe
, crtc
->state
, plane
->state
);
117 static void drm_simple_kms_crtc_disable(struct drm_crtc
*crtc
,
118 struct drm_atomic_state
*state
)
120 struct drm_simple_display_pipe
*pipe
;
122 pipe
= container_of(crtc
, struct drm_simple_display_pipe
, crtc
);
123 if (!pipe
->funcs
|| !pipe
->funcs
->disable
)
126 pipe
->funcs
->disable(pipe
);
129 static const struct drm_crtc_helper_funcs drm_simple_kms_crtc_helper_funcs
= {
130 .mode_valid
= drm_simple_kms_crtc_mode_valid
,
131 .atomic_check
= drm_simple_kms_crtc_check
,
132 .atomic_enable
= drm_simple_kms_crtc_enable
,
133 .atomic_disable
= drm_simple_kms_crtc_disable
,
136 static int drm_simple_kms_crtc_enable_vblank(struct drm_crtc
*crtc
)
138 struct drm_simple_display_pipe
*pipe
;
140 pipe
= container_of(crtc
, struct drm_simple_display_pipe
, crtc
);
141 if (!pipe
->funcs
|| !pipe
->funcs
->enable_vblank
)
144 return pipe
->funcs
->enable_vblank(pipe
);
147 static void drm_simple_kms_crtc_disable_vblank(struct drm_crtc
*crtc
)
149 struct drm_simple_display_pipe
*pipe
;
151 pipe
= container_of(crtc
, struct drm_simple_display_pipe
, crtc
);
152 if (!pipe
->funcs
|| !pipe
->funcs
->disable_vblank
)
155 pipe
->funcs
->disable_vblank(pipe
);
158 static const struct drm_crtc_funcs drm_simple_kms_crtc_funcs
= {
159 .reset
= drm_atomic_helper_crtc_reset
,
160 .destroy
= drm_crtc_cleanup
,
161 .set_config
= drm_atomic_helper_set_config
,
162 .page_flip
= drm_atomic_helper_page_flip
,
163 .atomic_duplicate_state
= drm_atomic_helper_crtc_duplicate_state
,
164 .atomic_destroy_state
= drm_atomic_helper_crtc_destroy_state
,
165 .enable_vblank
= drm_simple_kms_crtc_enable_vblank
,
166 .disable_vblank
= drm_simple_kms_crtc_disable_vblank
,
169 static int drm_simple_kms_plane_atomic_check(struct drm_plane
*plane
,
170 struct drm_plane_state
*plane_state
)
172 struct drm_simple_display_pipe
*pipe
;
173 struct drm_crtc_state
*crtc_state
;
176 pipe
= container_of(plane
, struct drm_simple_display_pipe
, plane
);
177 crtc_state
= drm_atomic_get_new_crtc_state(plane_state
->state
,
180 ret
= drm_atomic_helper_check_plane_state(plane_state
, crtc_state
,
181 DRM_PLANE_HELPER_NO_SCALING
,
182 DRM_PLANE_HELPER_NO_SCALING
,
187 if (!plane_state
->visible
)
190 if (!pipe
->funcs
|| !pipe
->funcs
->check
)
193 return pipe
->funcs
->check(pipe
, plane_state
, crtc_state
);
196 static void drm_simple_kms_plane_atomic_update(struct drm_plane
*plane
,
197 struct drm_plane_state
*old_pstate
)
199 struct drm_simple_display_pipe
*pipe
;
201 pipe
= container_of(plane
, struct drm_simple_display_pipe
, plane
);
202 if (!pipe
->funcs
|| !pipe
->funcs
->update
)
205 pipe
->funcs
->update(pipe
, old_pstate
);
208 static int drm_simple_kms_plane_prepare_fb(struct drm_plane
*plane
,
209 struct drm_plane_state
*state
)
211 struct drm_simple_display_pipe
*pipe
;
213 pipe
= container_of(plane
, struct drm_simple_display_pipe
, plane
);
214 if (!pipe
->funcs
|| !pipe
->funcs
->prepare_fb
)
217 return pipe
->funcs
->prepare_fb(pipe
, state
);
220 static void drm_simple_kms_plane_cleanup_fb(struct drm_plane
*plane
,
221 struct drm_plane_state
*state
)
223 struct drm_simple_display_pipe
*pipe
;
225 pipe
= container_of(plane
, struct drm_simple_display_pipe
, plane
);
226 if (!pipe
->funcs
|| !pipe
->funcs
->cleanup_fb
)
229 pipe
->funcs
->cleanup_fb(pipe
, state
);
232 static bool drm_simple_kms_format_mod_supported(struct drm_plane
*plane
,
236 return modifier
== DRM_FORMAT_MOD_LINEAR
;
239 static const struct drm_plane_helper_funcs drm_simple_kms_plane_helper_funcs
= {
240 .prepare_fb
= drm_simple_kms_plane_prepare_fb
,
241 .cleanup_fb
= drm_simple_kms_plane_cleanup_fb
,
242 .atomic_check
= drm_simple_kms_plane_atomic_check
,
243 .atomic_update
= drm_simple_kms_plane_atomic_update
,
246 static const struct drm_plane_funcs drm_simple_kms_plane_funcs
= {
247 .update_plane
= drm_atomic_helper_update_plane
,
248 .disable_plane
= drm_atomic_helper_disable_plane
,
249 .destroy
= drm_plane_cleanup
,
250 .reset
= drm_atomic_helper_plane_reset
,
251 .atomic_duplicate_state
= drm_atomic_helper_plane_duplicate_state
,
252 .atomic_destroy_state
= drm_atomic_helper_plane_destroy_state
,
253 .format_mod_supported
= drm_simple_kms_format_mod_supported
,
257 * drm_simple_display_pipe_attach_bridge - Attach a bridge to the display pipe
258 * @pipe: simple display pipe object
259 * @bridge: bridge to attach
261 * Makes it possible to still use the drm_simple_display_pipe helpers when
262 * a DRM bridge has to be used.
264 * Note that you probably want to initialize the pipe by passing a NULL
265 * connector to drm_simple_display_pipe_init().
268 * Zero on success, negative error code on failure.
270 int drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe
*pipe
,
271 struct drm_bridge
*bridge
)
273 return drm_bridge_attach(&pipe
->encoder
, bridge
, NULL
, 0);
275 EXPORT_SYMBOL(drm_simple_display_pipe_attach_bridge
);
278 * drm_simple_display_pipe_init - Initialize a simple display pipeline
280 * @pipe: simple display pipe object to initialize
281 * @funcs: callbacks for the display pipe (optional)
282 * @formats: array of supported formats (DRM_FORMAT\_\*)
283 * @format_count: number of elements in @formats
284 * @format_modifiers: array of formats modifiers
285 * @connector: connector to attach and register (optional)
287 * Sets up a display pipeline which consist of a really simple
288 * plane-crtc-encoder pipe.
290 * If a connector is supplied, the pipe will be coupled with the provided
291 * connector. You may supply a NULL connector when using drm bridges, that
292 * handle connectors themselves (see drm_simple_display_pipe_attach_bridge()).
294 * Teardown of a simple display pipe is all handled automatically by the drm
295 * core through calling drm_mode_config_cleanup(). Drivers afterwards need to
296 * release the memory for the structure themselves.
299 * Zero on success, negative error code on failure.
301 int drm_simple_display_pipe_init(struct drm_device
*dev
,
302 struct drm_simple_display_pipe
*pipe
,
303 const struct drm_simple_display_pipe_funcs
*funcs
,
304 const uint32_t *formats
, unsigned int format_count
,
305 const uint64_t *format_modifiers
,
306 struct drm_connector
*connector
)
308 struct drm_encoder
*encoder
= &pipe
->encoder
;
309 struct drm_plane
*plane
= &pipe
->plane
;
310 struct drm_crtc
*crtc
= &pipe
->crtc
;
313 pipe
->connector
= connector
;
316 drm_plane_helper_add(plane
, &drm_simple_kms_plane_helper_funcs
);
317 ret
= drm_universal_plane_init(dev
, plane
, 0,
318 &drm_simple_kms_plane_funcs
,
319 formats
, format_count
,
321 DRM_PLANE_TYPE_PRIMARY
, NULL
);
325 drm_crtc_helper_add(crtc
, &drm_simple_kms_crtc_helper_funcs
);
326 ret
= drm_crtc_init_with_planes(dev
, crtc
, plane
, NULL
,
327 &drm_simple_kms_crtc_funcs
, NULL
);
331 encoder
->possible_crtcs
= drm_crtc_mask(crtc
);
332 ret
= drm_simple_encoder_init(dev
, encoder
, DRM_MODE_ENCODER_NONE
);
333 if (ret
|| !connector
)
336 return drm_connector_attach_encoder(connector
, encoder
);
338 EXPORT_SYMBOL(drm_simple_display_pipe_init
);
340 MODULE_LICENSE("GPL");