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
31 static const struct drm_encoder_funcs drm_simple_kms_encoder_funcs
= {
32 .destroy
= drm_encoder_cleanup
,
35 static enum drm_mode_status
36 drm_simple_kms_crtc_mode_valid(struct drm_crtc
*crtc
,
37 const struct drm_display_mode
*mode
)
39 struct drm_simple_display_pipe
*pipe
;
41 pipe
= container_of(crtc
, struct drm_simple_display_pipe
, crtc
);
42 if (!pipe
->funcs
|| !pipe
->funcs
->mode_valid
)
46 return pipe
->funcs
->mode_valid(pipe
, mode
);
49 static int drm_simple_kms_crtc_check(struct drm_crtc
*crtc
,
50 struct drm_crtc_state
*state
)
52 bool has_primary
= state
->plane_mask
&
53 drm_plane_mask(crtc
->primary
);
55 /* We always want to have an active plane with an active CRTC */
56 if (has_primary
!= state
->enable
)
59 return drm_atomic_add_affected_planes(state
->state
, crtc
);
62 static void drm_simple_kms_crtc_enable(struct drm_crtc
*crtc
,
63 struct drm_crtc_state
*old_state
)
65 struct drm_plane
*plane
;
66 struct drm_simple_display_pipe
*pipe
;
68 pipe
= container_of(crtc
, struct drm_simple_display_pipe
, crtc
);
69 if (!pipe
->funcs
|| !pipe
->funcs
->enable
)
73 pipe
->funcs
->enable(pipe
, crtc
->state
, plane
->state
);
76 static void drm_simple_kms_crtc_disable(struct drm_crtc
*crtc
,
77 struct drm_crtc_state
*old_state
)
79 struct drm_simple_display_pipe
*pipe
;
81 pipe
= container_of(crtc
, struct drm_simple_display_pipe
, crtc
);
82 if (!pipe
->funcs
|| !pipe
->funcs
->disable
)
85 pipe
->funcs
->disable(pipe
);
88 static const struct drm_crtc_helper_funcs drm_simple_kms_crtc_helper_funcs
= {
89 .mode_valid
= drm_simple_kms_crtc_mode_valid
,
90 .atomic_check
= drm_simple_kms_crtc_check
,
91 .atomic_enable
= drm_simple_kms_crtc_enable
,
92 .atomic_disable
= drm_simple_kms_crtc_disable
,
95 static int drm_simple_kms_crtc_enable_vblank(struct drm_crtc
*crtc
)
97 struct drm_simple_display_pipe
*pipe
;
99 pipe
= container_of(crtc
, struct drm_simple_display_pipe
, crtc
);
100 if (!pipe
->funcs
|| !pipe
->funcs
->enable_vblank
)
103 return pipe
->funcs
->enable_vblank(pipe
);
106 static void drm_simple_kms_crtc_disable_vblank(struct drm_crtc
*crtc
)
108 struct drm_simple_display_pipe
*pipe
;
110 pipe
= container_of(crtc
, struct drm_simple_display_pipe
, crtc
);
111 if (!pipe
->funcs
|| !pipe
->funcs
->disable_vblank
)
114 pipe
->funcs
->disable_vblank(pipe
);
117 static const struct drm_crtc_funcs drm_simple_kms_crtc_funcs
= {
118 .reset
= drm_atomic_helper_crtc_reset
,
119 .destroy
= drm_crtc_cleanup
,
120 .set_config
= drm_atomic_helper_set_config
,
121 .page_flip
= drm_atomic_helper_page_flip
,
122 .atomic_duplicate_state
= drm_atomic_helper_crtc_duplicate_state
,
123 .atomic_destroy_state
= drm_atomic_helper_crtc_destroy_state
,
124 .enable_vblank
= drm_simple_kms_crtc_enable_vblank
,
125 .disable_vblank
= drm_simple_kms_crtc_disable_vblank
,
128 static int drm_simple_kms_plane_atomic_check(struct drm_plane
*plane
,
129 struct drm_plane_state
*plane_state
)
131 struct drm_simple_display_pipe
*pipe
;
132 struct drm_crtc_state
*crtc_state
;
135 pipe
= container_of(plane
, struct drm_simple_display_pipe
, plane
);
136 crtc_state
= drm_atomic_get_new_crtc_state(plane_state
->state
,
139 ret
= drm_atomic_helper_check_plane_state(plane_state
, crtc_state
,
140 DRM_PLANE_HELPER_NO_SCALING
,
141 DRM_PLANE_HELPER_NO_SCALING
,
146 if (!plane_state
->visible
)
149 if (!pipe
->funcs
|| !pipe
->funcs
->check
)
152 return pipe
->funcs
->check(pipe
, plane_state
, crtc_state
);
155 static void drm_simple_kms_plane_atomic_update(struct drm_plane
*plane
,
156 struct drm_plane_state
*old_pstate
)
158 struct drm_simple_display_pipe
*pipe
;
160 pipe
= container_of(plane
, struct drm_simple_display_pipe
, plane
);
161 if (!pipe
->funcs
|| !pipe
->funcs
->update
)
164 pipe
->funcs
->update(pipe
, old_pstate
);
167 static int drm_simple_kms_plane_prepare_fb(struct drm_plane
*plane
,
168 struct drm_plane_state
*state
)
170 struct drm_simple_display_pipe
*pipe
;
172 pipe
= container_of(plane
, struct drm_simple_display_pipe
, plane
);
173 if (!pipe
->funcs
|| !pipe
->funcs
->prepare_fb
)
176 return pipe
->funcs
->prepare_fb(pipe
, state
);
179 static void drm_simple_kms_plane_cleanup_fb(struct drm_plane
*plane
,
180 struct drm_plane_state
*state
)
182 struct drm_simple_display_pipe
*pipe
;
184 pipe
= container_of(plane
, struct drm_simple_display_pipe
, plane
);
185 if (!pipe
->funcs
|| !pipe
->funcs
->cleanup_fb
)
188 pipe
->funcs
->cleanup_fb(pipe
, state
);
191 static bool drm_simple_kms_format_mod_supported(struct drm_plane
*plane
,
195 return modifier
== DRM_FORMAT_MOD_LINEAR
;
198 static const struct drm_plane_helper_funcs drm_simple_kms_plane_helper_funcs
= {
199 .prepare_fb
= drm_simple_kms_plane_prepare_fb
,
200 .cleanup_fb
= drm_simple_kms_plane_cleanup_fb
,
201 .atomic_check
= drm_simple_kms_plane_atomic_check
,
202 .atomic_update
= drm_simple_kms_plane_atomic_update
,
205 static const struct drm_plane_funcs drm_simple_kms_plane_funcs
= {
206 .update_plane
= drm_atomic_helper_update_plane
,
207 .disable_plane
= drm_atomic_helper_disable_plane
,
208 .destroy
= drm_plane_cleanup
,
209 .reset
= drm_atomic_helper_plane_reset
,
210 .atomic_duplicate_state
= drm_atomic_helper_plane_duplicate_state
,
211 .atomic_destroy_state
= drm_atomic_helper_plane_destroy_state
,
212 .format_mod_supported
= drm_simple_kms_format_mod_supported
,
216 * drm_simple_display_pipe_attach_bridge - Attach a bridge to the display pipe
217 * @pipe: simple display pipe object
218 * @bridge: bridge to attach
220 * Makes it possible to still use the drm_simple_display_pipe helpers when
221 * a DRM bridge has to be used.
223 * Note that you probably want to initialize the pipe by passing a NULL
224 * connector to drm_simple_display_pipe_init().
227 * Zero on success, negative error code on failure.
229 int drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe
*pipe
,
230 struct drm_bridge
*bridge
)
232 return drm_bridge_attach(&pipe
->encoder
, bridge
, NULL
);
234 EXPORT_SYMBOL(drm_simple_display_pipe_attach_bridge
);
237 * drm_simple_display_pipe_init - Initialize a simple display pipeline
239 * @pipe: simple display pipe object to initialize
240 * @funcs: callbacks for the display pipe (optional)
241 * @formats: array of supported formats (DRM_FORMAT\_\*)
242 * @format_count: number of elements in @formats
243 * @format_modifiers: array of formats modifiers
244 * @connector: connector to attach and register (optional)
246 * Sets up a display pipeline which consist of a really simple
247 * plane-crtc-encoder pipe.
249 * If a connector is supplied, the pipe will be coupled with the provided
250 * connector. You may supply a NULL connector when using drm bridges, that
251 * handle connectors themselves (see drm_simple_display_pipe_attach_bridge()).
253 * Teardown of a simple display pipe is all handled automatically by the drm
254 * core through calling drm_mode_config_cleanup(). Drivers afterwards need to
255 * release the memory for the structure themselves.
258 * Zero on success, negative error code on failure.
260 int drm_simple_display_pipe_init(struct drm_device
*dev
,
261 struct drm_simple_display_pipe
*pipe
,
262 const struct drm_simple_display_pipe_funcs
*funcs
,
263 const uint32_t *formats
, unsigned int format_count
,
264 const uint64_t *format_modifiers
,
265 struct drm_connector
*connector
)
267 struct drm_encoder
*encoder
= &pipe
->encoder
;
268 struct drm_plane
*plane
= &pipe
->plane
;
269 struct drm_crtc
*crtc
= &pipe
->crtc
;
272 pipe
->connector
= connector
;
275 drm_plane_helper_add(plane
, &drm_simple_kms_plane_helper_funcs
);
276 ret
= drm_universal_plane_init(dev
, plane
, 0,
277 &drm_simple_kms_plane_funcs
,
278 formats
, format_count
,
280 DRM_PLANE_TYPE_PRIMARY
, NULL
);
284 drm_crtc_helper_add(crtc
, &drm_simple_kms_crtc_helper_funcs
);
285 ret
= drm_crtc_init_with_planes(dev
, crtc
, plane
, NULL
,
286 &drm_simple_kms_crtc_funcs
, NULL
);
290 encoder
->possible_crtcs
= drm_crtc_mask(crtc
);
291 ret
= drm_encoder_init(dev
, encoder
, &drm_simple_kms_encoder_funcs
,
292 DRM_MODE_ENCODER_NONE
, NULL
);
293 if (ret
|| !connector
)
296 return drm_connector_attach_encoder(connector
, encoder
);
298 EXPORT_SYMBOL(drm_simple_display_pipe_init
);
300 MODULE_LICENSE("GPL");