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_crtc_helper.h>
14 #include <drm/drm_plane_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 int drm_simple_kms_crtc_check(struct drm_crtc
*crtc
,
38 struct drm_crtc_state
*state
)
40 return drm_atomic_add_affected_planes(state
->state
, crtc
);
43 static void drm_simple_kms_crtc_enable(struct drm_crtc
*crtc
)
45 struct drm_simple_display_pipe
*pipe
;
47 pipe
= container_of(crtc
, struct drm_simple_display_pipe
, crtc
);
48 if (!pipe
->funcs
|| !pipe
->funcs
->enable
)
51 pipe
->funcs
->enable(pipe
, crtc
->state
);
54 static void drm_simple_kms_crtc_disable(struct drm_crtc
*crtc
)
56 struct drm_simple_display_pipe
*pipe
;
58 pipe
= container_of(crtc
, struct drm_simple_display_pipe
, crtc
);
59 if (!pipe
->funcs
|| !pipe
->funcs
->disable
)
62 pipe
->funcs
->disable(pipe
);
65 static const struct drm_crtc_helper_funcs drm_simple_kms_crtc_helper_funcs
= {
66 .atomic_check
= drm_simple_kms_crtc_check
,
67 .disable
= drm_simple_kms_crtc_disable
,
68 .enable
= drm_simple_kms_crtc_enable
,
71 static const struct drm_crtc_funcs drm_simple_kms_crtc_funcs
= {
72 .reset
= drm_atomic_helper_crtc_reset
,
73 .destroy
= drm_crtc_cleanup
,
74 .set_config
= drm_atomic_helper_set_config
,
75 .page_flip
= drm_atomic_helper_page_flip
,
76 .atomic_duplicate_state
= drm_atomic_helper_crtc_duplicate_state
,
77 .atomic_destroy_state
= drm_atomic_helper_crtc_destroy_state
,
80 static int drm_simple_kms_plane_atomic_check(struct drm_plane
*plane
,
81 struct drm_plane_state
*plane_state
)
83 struct drm_rect clip
= { 0 };
84 struct drm_simple_display_pipe
*pipe
;
85 struct drm_crtc_state
*crtc_state
;
88 pipe
= container_of(plane
, struct drm_simple_display_pipe
, plane
);
89 crtc_state
= drm_atomic_get_existing_crtc_state(plane_state
->state
,
91 if (crtc_state
->enable
!= !!plane_state
->crtc
)
92 return -EINVAL
; /* plane must match crtc enable state */
94 if (!crtc_state
->enable
)
95 return 0; /* nothing to check when disabling or disabled */
97 clip
.x2
= crtc_state
->adjusted_mode
.hdisplay
;
98 clip
.y2
= crtc_state
->adjusted_mode
.vdisplay
;
100 ret
= drm_plane_helper_check_state(plane_state
, &clip
,
101 DRM_PLANE_HELPER_NO_SCALING
,
102 DRM_PLANE_HELPER_NO_SCALING
,
107 if (!plane_state
->visible
)
110 if (!pipe
->funcs
|| !pipe
->funcs
->check
)
113 return pipe
->funcs
->check(pipe
, plane_state
, crtc_state
);
116 static void drm_simple_kms_plane_atomic_update(struct drm_plane
*plane
,
117 struct drm_plane_state
*pstate
)
119 struct drm_simple_display_pipe
*pipe
;
121 pipe
= container_of(plane
, struct drm_simple_display_pipe
, plane
);
122 if (!pipe
->funcs
|| !pipe
->funcs
->update
)
125 pipe
->funcs
->update(pipe
, pstate
);
128 static const struct drm_plane_helper_funcs drm_simple_kms_plane_helper_funcs
= {
129 .atomic_check
= drm_simple_kms_plane_atomic_check
,
130 .atomic_update
= drm_simple_kms_plane_atomic_update
,
133 static const struct drm_plane_funcs drm_simple_kms_plane_funcs
= {
134 .update_plane
= drm_atomic_helper_update_plane
,
135 .disable_plane
= drm_atomic_helper_disable_plane
,
136 .destroy
= drm_plane_cleanup
,
137 .reset
= drm_atomic_helper_plane_reset
,
138 .atomic_duplicate_state
= drm_atomic_helper_plane_duplicate_state
,
139 .atomic_destroy_state
= drm_atomic_helper_plane_destroy_state
,
143 * drm_simple_display_pipe_attach_bridge - Attach a bridge to the display pipe
144 * @pipe: simple display pipe object
145 * @bridge: bridge to attach
147 * Makes it possible to still use the drm_simple_display_pipe helpers when
148 * a DRM bridge has to be used.
150 * Note that you probably want to initialize the pipe by passing a NULL
151 * connector to drm_simple_display_pipe_init().
154 * Zero on success, negative error code on failure.
156 int drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe
*pipe
,
157 struct drm_bridge
*bridge
)
159 bridge
->encoder
= &pipe
->encoder
;
160 pipe
->encoder
.bridge
= bridge
;
161 return drm_bridge_attach(pipe
->encoder
.dev
, bridge
);
163 EXPORT_SYMBOL(drm_simple_display_pipe_attach_bridge
);
166 * drm_simple_display_pipe_detach_bridge - Detach the bridge from the display pipe
167 * @pipe: simple display pipe object
169 * Detaches the drm bridge previously attached with
170 * drm_simple_display_pipe_attach_bridge()
172 void drm_simple_display_pipe_detach_bridge(struct drm_simple_display_pipe
*pipe
)
174 if (WARN_ON(!pipe
->encoder
.bridge
))
177 drm_bridge_detach(pipe
->encoder
.bridge
);
178 pipe
->encoder
.bridge
= NULL
;
180 EXPORT_SYMBOL(drm_simple_display_pipe_detach_bridge
);
183 * drm_simple_display_pipe_init - Initialize a simple display pipeline
185 * @pipe: simple display pipe object to initialize
186 * @funcs: callbacks for the display pipe (optional)
187 * @formats: array of supported formats (DRM_FORMAT\_\*)
188 * @format_count: number of elements in @formats
189 * @connector: connector to attach and register (optional)
191 * Sets up a display pipeline which consist of a really simple
192 * plane-crtc-encoder pipe.
194 * If a connector is supplied, the pipe will be coupled with the provided
195 * connector. You may supply a NULL connector when using drm bridges, that
196 * handle connectors themselves (see drm_simple_display_pipe_attach_bridge()).
198 * Teardown of a simple display pipe is all handled automatically by the drm
199 * core through calling drm_mode_config_cleanup(). Drivers afterwards need to
200 * release the memory for the structure themselves.
203 * Zero on success, negative error code on failure.
205 int drm_simple_display_pipe_init(struct drm_device
*dev
,
206 struct drm_simple_display_pipe
*pipe
,
207 const struct drm_simple_display_pipe_funcs
*funcs
,
208 const uint32_t *formats
, unsigned int format_count
,
209 struct drm_connector
*connector
)
211 struct drm_encoder
*encoder
= &pipe
->encoder
;
212 struct drm_plane
*plane
= &pipe
->plane
;
213 struct drm_crtc
*crtc
= &pipe
->crtc
;
216 pipe
->connector
= connector
;
219 drm_plane_helper_add(plane
, &drm_simple_kms_plane_helper_funcs
);
220 ret
= drm_universal_plane_init(dev
, plane
, 0,
221 &drm_simple_kms_plane_funcs
,
222 formats
, format_count
,
223 DRM_PLANE_TYPE_PRIMARY
, NULL
);
227 drm_crtc_helper_add(crtc
, &drm_simple_kms_crtc_helper_funcs
);
228 ret
= drm_crtc_init_with_planes(dev
, crtc
, plane
, NULL
,
229 &drm_simple_kms_crtc_funcs
, NULL
);
233 encoder
->possible_crtcs
= 1 << drm_crtc_index(crtc
);
234 ret
= drm_encoder_init(dev
, encoder
, &drm_simple_kms_encoder_funcs
,
235 DRM_MODE_ENCODER_NONE
, NULL
);
236 if (ret
|| !connector
)
239 return drm_mode_connector_attach_encoder(connector
, encoder
);
241 EXPORT_SYMBOL(drm_simple_display_pipe_init
);
243 MODULE_LICENSE("GPL");