2 * Copyright (C) 2016 Noralf Trønnes
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
11 #include <drm/drm_atomic.h>
12 #include <drm/drm_atomic_helper.h>
13 #include <drm/drm_plane_helper.h>
14 #include <drm/drm_probe_helper.h>
15 #include <drm/drm_simple_kms_helper.h>
16 #include <linux/slab.h>
21 * This helper library provides helpers for drivers for simple display
24 * drm_simple_display_pipe_init() initializes a simple display pipeline
25 * which has only one full-screen scanout buffer feeding one output. The
26 * pipeline is represented by &struct drm_simple_display_pipe and binds
27 * together &drm_plane, &drm_crtc and &drm_encoder structures into one fixed
28 * entity. Some flexibility for code reuse is provided through a separately
29 * allocated &drm_connector object and supporting optional &drm_bridge
33 static const struct drm_encoder_funcs drm_simple_kms_encoder_funcs
= {
34 .destroy
= drm_encoder_cleanup
,
37 static enum drm_mode_status
38 drm_simple_kms_crtc_mode_valid(struct drm_crtc
*crtc
,
39 const struct drm_display_mode
*mode
)
41 struct drm_simple_display_pipe
*pipe
;
43 pipe
= container_of(crtc
, struct drm_simple_display_pipe
, crtc
);
44 if (!pipe
->funcs
|| !pipe
->funcs
->mode_valid
)
48 return pipe
->funcs
->mode_valid(crtc
, mode
);
51 static int drm_simple_kms_crtc_check(struct drm_crtc
*crtc
,
52 struct drm_crtc_state
*state
)
54 bool has_primary
= state
->plane_mask
&
55 drm_plane_mask(crtc
->primary
);
57 /* We always want to have an active plane with an active CRTC */
58 if (has_primary
!= state
->enable
)
61 return drm_atomic_add_affected_planes(state
->state
, crtc
);
64 static void drm_simple_kms_crtc_enable(struct drm_crtc
*crtc
,
65 struct drm_crtc_state
*old_state
)
67 struct drm_plane
*plane
;
68 struct drm_simple_display_pipe
*pipe
;
70 pipe
= container_of(crtc
, struct drm_simple_display_pipe
, crtc
);
71 if (!pipe
->funcs
|| !pipe
->funcs
->enable
)
75 pipe
->funcs
->enable(pipe
, crtc
->state
, plane
->state
);
78 static void drm_simple_kms_crtc_disable(struct drm_crtc
*crtc
,
79 struct drm_crtc_state
*old_state
)
81 struct drm_simple_display_pipe
*pipe
;
83 pipe
= container_of(crtc
, struct drm_simple_display_pipe
, crtc
);
84 if (!pipe
->funcs
|| !pipe
->funcs
->disable
)
87 pipe
->funcs
->disable(pipe
);
90 static const struct drm_crtc_helper_funcs drm_simple_kms_crtc_helper_funcs
= {
91 .mode_valid
= drm_simple_kms_crtc_mode_valid
,
92 .atomic_check
= drm_simple_kms_crtc_check
,
93 .atomic_enable
= drm_simple_kms_crtc_enable
,
94 .atomic_disable
= drm_simple_kms_crtc_disable
,
97 static int drm_simple_kms_crtc_enable_vblank(struct drm_crtc
*crtc
)
99 struct drm_simple_display_pipe
*pipe
;
101 pipe
= container_of(crtc
, struct drm_simple_display_pipe
, crtc
);
102 if (!pipe
->funcs
|| !pipe
->funcs
->enable_vblank
)
105 return pipe
->funcs
->enable_vblank(pipe
);
108 static void drm_simple_kms_crtc_disable_vblank(struct drm_crtc
*crtc
)
110 struct drm_simple_display_pipe
*pipe
;
112 pipe
= container_of(crtc
, struct drm_simple_display_pipe
, crtc
);
113 if (!pipe
->funcs
|| !pipe
->funcs
->disable_vblank
)
116 pipe
->funcs
->disable_vblank(pipe
);
119 static const struct drm_crtc_funcs drm_simple_kms_crtc_funcs
= {
120 .reset
= drm_atomic_helper_crtc_reset
,
121 .destroy
= drm_crtc_cleanup
,
122 .set_config
= drm_atomic_helper_set_config
,
123 .page_flip
= drm_atomic_helper_page_flip
,
124 .atomic_duplicate_state
= drm_atomic_helper_crtc_duplicate_state
,
125 .atomic_destroy_state
= drm_atomic_helper_crtc_destroy_state
,
126 .enable_vblank
= drm_simple_kms_crtc_enable_vblank
,
127 .disable_vblank
= drm_simple_kms_crtc_disable_vblank
,
130 static int drm_simple_kms_plane_atomic_check(struct drm_plane
*plane
,
131 struct drm_plane_state
*plane_state
)
133 struct drm_simple_display_pipe
*pipe
;
134 struct drm_crtc_state
*crtc_state
;
137 pipe
= container_of(plane
, struct drm_simple_display_pipe
, plane
);
138 crtc_state
= drm_atomic_get_new_crtc_state(plane_state
->state
,
141 ret
= drm_atomic_helper_check_plane_state(plane_state
, crtc_state
,
142 DRM_PLANE_HELPER_NO_SCALING
,
143 DRM_PLANE_HELPER_NO_SCALING
,
148 if (!plane_state
->visible
)
151 if (!pipe
->funcs
|| !pipe
->funcs
->check
)
154 return pipe
->funcs
->check(pipe
, plane_state
, crtc_state
);
157 static void drm_simple_kms_plane_atomic_update(struct drm_plane
*plane
,
158 struct drm_plane_state
*old_pstate
)
160 struct drm_simple_display_pipe
*pipe
;
162 pipe
= container_of(plane
, struct drm_simple_display_pipe
, plane
);
163 if (!pipe
->funcs
|| !pipe
->funcs
->update
)
166 pipe
->funcs
->update(pipe
, old_pstate
);
169 static int drm_simple_kms_plane_prepare_fb(struct drm_plane
*plane
,
170 struct drm_plane_state
*state
)
172 struct drm_simple_display_pipe
*pipe
;
174 pipe
= container_of(plane
, struct drm_simple_display_pipe
, plane
);
175 if (!pipe
->funcs
|| !pipe
->funcs
->prepare_fb
)
178 return pipe
->funcs
->prepare_fb(pipe
, state
);
181 static void drm_simple_kms_plane_cleanup_fb(struct drm_plane
*plane
,
182 struct drm_plane_state
*state
)
184 struct drm_simple_display_pipe
*pipe
;
186 pipe
= container_of(plane
, struct drm_simple_display_pipe
, plane
);
187 if (!pipe
->funcs
|| !pipe
->funcs
->cleanup_fb
)
190 pipe
->funcs
->cleanup_fb(pipe
, state
);
193 static bool drm_simple_kms_format_mod_supported(struct drm_plane
*plane
,
197 return modifier
== DRM_FORMAT_MOD_LINEAR
;
200 static const struct drm_plane_helper_funcs drm_simple_kms_plane_helper_funcs
= {
201 .prepare_fb
= drm_simple_kms_plane_prepare_fb
,
202 .cleanup_fb
= drm_simple_kms_plane_cleanup_fb
,
203 .atomic_check
= drm_simple_kms_plane_atomic_check
,
204 .atomic_update
= drm_simple_kms_plane_atomic_update
,
207 static const struct drm_plane_funcs drm_simple_kms_plane_funcs
= {
208 .update_plane
= drm_atomic_helper_update_plane
,
209 .disable_plane
= drm_atomic_helper_disable_plane
,
210 .destroy
= drm_plane_cleanup
,
211 .reset
= drm_atomic_helper_plane_reset
,
212 .atomic_duplicate_state
= drm_atomic_helper_plane_duplicate_state
,
213 .atomic_destroy_state
= drm_atomic_helper_plane_destroy_state
,
214 .format_mod_supported
= drm_simple_kms_format_mod_supported
,
218 * drm_simple_display_pipe_attach_bridge - Attach a bridge to the display pipe
219 * @pipe: simple display pipe object
220 * @bridge: bridge to attach
222 * Makes it possible to still use the drm_simple_display_pipe helpers when
223 * a DRM bridge has to be used.
225 * Note that you probably want to initialize the pipe by passing a NULL
226 * connector to drm_simple_display_pipe_init().
229 * Zero on success, negative error code on failure.
231 int drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe
*pipe
,
232 struct drm_bridge
*bridge
)
234 return drm_bridge_attach(&pipe
->encoder
, bridge
, NULL
);
236 EXPORT_SYMBOL(drm_simple_display_pipe_attach_bridge
);
239 * drm_simple_display_pipe_init - Initialize a simple display pipeline
241 * @pipe: simple display pipe object to initialize
242 * @funcs: callbacks for the display pipe (optional)
243 * @formats: array of supported formats (DRM_FORMAT\_\*)
244 * @format_count: number of elements in @formats
245 * @format_modifiers: array of formats modifiers
246 * @connector: connector to attach and register (optional)
248 * Sets up a display pipeline which consist of a really simple
249 * plane-crtc-encoder pipe.
251 * If a connector is supplied, the pipe will be coupled with the provided
252 * connector. You may supply a NULL connector when using drm bridges, that
253 * handle connectors themselves (see drm_simple_display_pipe_attach_bridge()).
255 * Teardown of a simple display pipe is all handled automatically by the drm
256 * core through calling drm_mode_config_cleanup(). Drivers afterwards need to
257 * release the memory for the structure themselves.
260 * Zero on success, negative error code on failure.
262 int drm_simple_display_pipe_init(struct drm_device
*dev
,
263 struct drm_simple_display_pipe
*pipe
,
264 const struct drm_simple_display_pipe_funcs
*funcs
,
265 const uint32_t *formats
, unsigned int format_count
,
266 const uint64_t *format_modifiers
,
267 struct drm_connector
*connector
)
269 struct drm_encoder
*encoder
= &pipe
->encoder
;
270 struct drm_plane
*plane
= &pipe
->plane
;
271 struct drm_crtc
*crtc
= &pipe
->crtc
;
274 pipe
->connector
= connector
;
277 drm_plane_helper_add(plane
, &drm_simple_kms_plane_helper_funcs
);
278 ret
= drm_universal_plane_init(dev
, plane
, 0,
279 &drm_simple_kms_plane_funcs
,
280 formats
, format_count
,
282 DRM_PLANE_TYPE_PRIMARY
, NULL
);
286 drm_crtc_helper_add(crtc
, &drm_simple_kms_crtc_helper_funcs
);
287 ret
= drm_crtc_init_with_planes(dev
, crtc
, plane
, NULL
,
288 &drm_simple_kms_crtc_funcs
, NULL
);
292 encoder
->possible_crtcs
= drm_crtc_mask(crtc
);
293 ret
= drm_encoder_init(dev
, encoder
, &drm_simple_kms_encoder_funcs
,
294 DRM_MODE_ENCODER_NONE
, NULL
);
295 if (ret
|| !connector
)
298 return drm_connector_attach_encoder(connector
, encoder
);
300 EXPORT_SYMBOL(drm_simple_display_pipe_init
);
302 MODULE_LICENSE("GPL");