diff options
-rw-r--r-- | drivers/gpu/drm/Makefile | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_plane_helper.c | 312 | ||||
-rw-r--r-- | include/drm/drm_plane_helper.h | 49 |
3 files changed, 363 insertions, 1 deletions
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 5e792b0a5f75..9d25dbbe6771 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile | |||
@@ -13,7 +13,8 @@ drm-y := drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \ | |||
13 | drm_crtc.o drm_modes.o drm_edid.o \ | 13 | drm_crtc.o drm_modes.o drm_edid.o \ |
14 | drm_info.o drm_debugfs.o drm_encoder_slave.o \ | 14 | drm_info.o drm_debugfs.o drm_encoder_slave.o \ |
15 | drm_trace_points.o drm_global.o drm_prime.o \ | 15 | drm_trace_points.o drm_global.o drm_prime.o \ |
16 | drm_rect.o drm_vma_manager.o drm_flip_work.o | 16 | drm_rect.o drm_vma_manager.o drm_flip_work.o \ |
17 | drm_plane_helper.o | ||
17 | 18 | ||
18 | drm-$(CONFIG_COMPAT) += drm_ioc32.o | 19 | drm-$(CONFIG_COMPAT) += drm_ioc32.o |
19 | drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o | 20 | drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o |
diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c new file mode 100644 index 000000000000..2f2374aba42e --- /dev/null +++ b/drivers/gpu/drm/drm_plane_helper.c | |||
@@ -0,0 +1,312 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 Intel Corporation | ||
3 | * | ||
4 | * DRM universal plane helper functions | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
7 | * copy of this software and associated documentation files (the "Software"), | ||
8 | * to deal in the Software without restriction, including without limitation | ||
9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
10 | * and/or sell copies of the Software, and to permit persons to whom the | ||
11 | * Software is furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice (including the next | ||
14 | * paragraph) shall be included in all copies or substantial portions of the | ||
15 | * Software. | ||
16 | * | ||
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
23 | * SOFTWARE. | ||
24 | */ | ||
25 | |||
26 | #include <linux/list.h> | ||
27 | #include <drm/drmP.h> | ||
28 | #include <drm/drm_rect.h> | ||
29 | |||
30 | #define SUBPIXEL_MASK 0xffff | ||
31 | |||
32 | /* | ||
33 | * This is the minimal list of formats that seem to be safe for modeset use | ||
34 | * with all current DRM drivers. Most hardware can actually support more | ||
35 | * formats than this and drivers may specify a more accurate list when | ||
36 | * creating the primary plane. However drivers that still call | ||
37 | * drm_plane_init() will use this minimal format list as the default. | ||
38 | */ | ||
39 | const static uint32_t safe_modeset_formats[] = { | ||
40 | DRM_FORMAT_XRGB8888, | ||
41 | DRM_FORMAT_ARGB8888, | ||
42 | }; | ||
43 | |||
44 | /* | ||
45 | * Returns the connectors currently associated with a CRTC. This function | ||
46 | * should be called twice: once with a NULL connector list to retrieve | ||
47 | * the list size, and once with the properly allocated list to be filled in. | ||
48 | */ | ||
49 | static int get_connectors_for_crtc(struct drm_crtc *crtc, | ||
50 | struct drm_connector **connector_list, | ||
51 | int num_connectors) | ||
52 | { | ||
53 | struct drm_device *dev = crtc->dev; | ||
54 | struct drm_connector *connector; | ||
55 | int count = 0; | ||
56 | |||
57 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) | ||
58 | if (connector->encoder && connector->encoder->crtc == crtc) { | ||
59 | if (connector_list != NULL && count < num_connectors) | ||
60 | *(connector_list++) = connector; | ||
61 | |||
62 | count++; | ||
63 | } | ||
64 | |||
65 | return count; | ||
66 | } | ||
67 | |||
68 | /** | ||
69 | * drm_primary_helper_update() - Helper for primary plane update | ||
70 | * @plane: plane object to update | ||
71 | * @crtc: owning CRTC of owning plane | ||
72 | * @fb: framebuffer to flip onto plane | ||
73 | * @crtc_x: x offset of primary plane on crtc | ||
74 | * @crtc_y: y offset of primary plane on crtc | ||
75 | * @crtc_w: width of primary plane rectangle on crtc | ||
76 | * @crtc_h: height of primary plane rectangle on crtc | ||
77 | * @src_x: x offset of @fb for panning | ||
78 | * @src_y: y offset of @fb for panning | ||
79 | * @src_w: width of source rectangle in @fb | ||
80 | * @src_h: height of source rectangle in @fb | ||
81 | * | ||
82 | * Provides a default plane update handler for primary planes. This is handler | ||
83 | * is called in response to a userspace SetPlane operation on the plane with a | ||
84 | * non-NULL framebuffer. We call the driver's modeset handler to update the | ||
85 | * framebuffer. | ||
86 | * | ||
87 | * SetPlane() on a primary plane of a disabled CRTC is not supported, and will | ||
88 | * return an error. | ||
89 | * | ||
90 | * Note that we make some assumptions about hardware limitations that may not be | ||
91 | * true for all hardware -- | ||
92 | * 1) Primary plane cannot be repositioned. | ||
93 | * 2) Primary plane cannot be scaled. | ||
94 | * 3) Primary plane must cover the entire CRTC. | ||
95 | * 4) Subpixel positioning is not supported. | ||
96 | * Drivers for hardware that don't have these restrictions can provide their | ||
97 | * own implementation rather than using this helper. | ||
98 | * | ||
99 | * RETURNS: | ||
100 | * Zero on success, error code on failure | ||
101 | */ | ||
102 | int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc, | ||
103 | struct drm_framebuffer *fb, | ||
104 | int crtc_x, int crtc_y, | ||
105 | unsigned int crtc_w, unsigned int crtc_h, | ||
106 | uint32_t src_x, uint32_t src_y, | ||
107 | uint32_t src_w, uint32_t src_h) | ||
108 | { | ||
109 | struct drm_mode_set set = { | ||
110 | .crtc = crtc, | ||
111 | .fb = fb, | ||
112 | .mode = &crtc->mode, | ||
113 | .x = src_x >> 16, | ||
114 | .y = src_y >> 16, | ||
115 | }; | ||
116 | struct drm_rect dest = { | ||
117 | .x1 = crtc_x, | ||
118 | .y1 = crtc_y, | ||
119 | .x2 = crtc_x + crtc_w, | ||
120 | .y2 = crtc_y + crtc_h, | ||
121 | }; | ||
122 | struct drm_rect clip = { | ||
123 | .x2 = crtc->mode.hdisplay, | ||
124 | .y2 = crtc->mode.vdisplay, | ||
125 | }; | ||
126 | struct drm_connector **connector_list; | ||
127 | struct drm_framebuffer *tmpfb; | ||
128 | int num_connectors, ret; | ||
129 | |||
130 | if (!crtc->enabled) { | ||
131 | DRM_DEBUG_KMS("Cannot update primary plane of a disabled CRTC.\n"); | ||
132 | return -EINVAL; | ||
133 | } | ||
134 | |||
135 | /* Disallow subpixel positioning */ | ||
136 | if ((src_x | src_y | src_w | src_h) & SUBPIXEL_MASK) { | ||
137 | DRM_DEBUG_KMS("Primary plane does not support subpixel positioning\n"); | ||
138 | return -EINVAL; | ||
139 | } | ||
140 | |||
141 | /* Primary planes are locked to their owning CRTC */ | ||
142 | if (plane->possible_crtcs != drm_crtc_mask(crtc)) { | ||
143 | DRM_DEBUG_KMS("Cannot change primary plane CRTC\n"); | ||
144 | return -EINVAL; | ||
145 | } | ||
146 | |||
147 | /* Disallow scaling */ | ||
148 | if (crtc_w != src_w || crtc_h != src_h) { | ||
149 | DRM_DEBUG_KMS("Can't scale primary plane\n"); | ||
150 | return -EINVAL; | ||
151 | } | ||
152 | |||
153 | /* Make sure primary plane covers entire CRTC */ | ||
154 | drm_rect_intersect(&dest, &clip); | ||
155 | if (dest.x1 != 0 || dest.y1 != 0 || | ||
156 | dest.x2 != crtc->mode.hdisplay || dest.y2 != crtc->mode.vdisplay) { | ||
157 | DRM_DEBUG_KMS("Primary plane must cover entire CRTC\n"); | ||
158 | return -EINVAL; | ||
159 | } | ||
160 | |||
161 | /* Framebuffer must be big enough to cover entire plane */ | ||
162 | ret = drm_crtc_check_viewport(crtc, crtc_x, crtc_y, &crtc->mode, fb); | ||
163 | if (ret) | ||
164 | return ret; | ||
165 | |||
166 | /* Find current connectors for CRTC */ | ||
167 | num_connectors = get_connectors_for_crtc(crtc, NULL, 0); | ||
168 | BUG_ON(num_connectors == 0); | ||
169 | connector_list = kzalloc(num_connectors * sizeof(*connector_list), | ||
170 | GFP_KERNEL); | ||
171 | if (!connector_list) | ||
172 | return -ENOMEM; | ||
173 | get_connectors_for_crtc(crtc, connector_list, num_connectors); | ||
174 | |||
175 | set.connectors = connector_list; | ||
176 | set.num_connectors = num_connectors; | ||
177 | |||
178 | /* | ||
179 | * set_config() adjusts crtc->primary->fb; however the DRM setplane | ||
180 | * code that called us expects to handle the framebuffer update and | ||
181 | * reference counting; save and restore the current fb before | ||
182 | * calling it. | ||
183 | * | ||
184 | * N.B., we call set_config() directly here rather than using | ||
185 | * drm_mode_set_config_internal. We're reprogramming the same | ||
186 | * connectors that were already in use, so we shouldn't need the extra | ||
187 | * cross-CRTC fb refcounting to accomodate stealing connectors. | ||
188 | * drm_mode_setplane() already handles the basic refcounting for the | ||
189 | * framebuffers involved in this operation. | ||
190 | */ | ||
191 | tmpfb = plane->fb; | ||
192 | ret = crtc->funcs->set_config(&set); | ||
193 | plane->fb = tmpfb; | ||
194 | |||
195 | kfree(connector_list); | ||
196 | return ret; | ||
197 | } | ||
198 | EXPORT_SYMBOL(drm_primary_helper_update); | ||
199 | |||
200 | /** | ||
201 | * drm_primary_helper_disable() - Helper for primary plane disable | ||
202 | * @plane: plane to disable | ||
203 | * | ||
204 | * Provides a default plane disable handler for primary planes. This is handler | ||
205 | * is called in response to a userspace SetPlane operation on the plane with a | ||
206 | * NULL framebuffer parameter. We call the driver's modeset handler with a NULL | ||
207 | * framebuffer to disable the CRTC if no other planes are currently enabled. | ||
208 | * If other planes are still enabled on the same CRTC, we return -EBUSY. | ||
209 | * | ||
210 | * Note that some hardware may be able to disable the primary plane without | ||
211 | * disabling the whole CRTC. Drivers for such hardware should provide their | ||
212 | * own disable handler that disables just the primary plane (and they'll likely | ||
213 | * need to provide their own update handler as well to properly re-enable a | ||
214 | * disabled primary plane). | ||
215 | * | ||
216 | * RETURNS: | ||
217 | * Zero on success, error code on failure | ||
218 | */ | ||
219 | int drm_primary_helper_disable(struct drm_plane *plane) | ||
220 | { | ||
221 | struct drm_plane *p; | ||
222 | struct drm_mode_set set = { | ||
223 | .crtc = plane->crtc, | ||
224 | .fb = NULL, | ||
225 | }; | ||
226 | |||
227 | if (plane->crtc == NULL || plane->fb == NULL) | ||
228 | /* Already disabled */ | ||
229 | return 0; | ||
230 | |||
231 | list_for_each_entry(p, &plane->dev->mode_config.plane_list, head) | ||
232 | if (p != plane && p->fb) { | ||
233 | DRM_DEBUG_KMS("Cannot disable primary plane while other planes are still active on CRTC.\n"); | ||
234 | return -EBUSY; | ||
235 | } | ||
236 | |||
237 | /* | ||
238 | * N.B. We call set_config() directly here rather than | ||
239 | * drm_mode_set_config_internal() since drm_mode_setplane() already | ||
240 | * handles the basic refcounting and we don't need the special | ||
241 | * cross-CRTC refcounting (no chance of stealing connectors from | ||
242 | * other CRTC's with this update). | ||
243 | */ | ||
244 | return plane->crtc->funcs->set_config(&set); | ||
245 | } | ||
246 | EXPORT_SYMBOL(drm_primary_helper_disable); | ||
247 | |||
248 | /** | ||
249 | * drm_primary_helper_destroy() - Helper for primary plane destruction | ||
250 | * @plane: plane to destroy | ||
251 | * | ||
252 | * Provides a default plane destroy handler for primary planes. This handler | ||
253 | * is called during CRTC destruction. We disable the primary plane, remove | ||
254 | * it from the DRM plane list, and deallocate the plane structure. | ||
255 | */ | ||
256 | void drm_primary_helper_destroy(struct drm_plane *plane) | ||
257 | { | ||
258 | plane->funcs->disable_plane(plane); | ||
259 | drm_plane_cleanup(plane); | ||
260 | kfree(plane); | ||
261 | } | ||
262 | EXPORT_SYMBOL(drm_primary_helper_destroy); | ||
263 | |||
264 | const struct drm_plane_funcs drm_primary_helper_funcs = { | ||
265 | .update_plane = drm_primary_helper_update, | ||
266 | .disable_plane = drm_primary_helper_disable, | ||
267 | .destroy = drm_primary_helper_destroy, | ||
268 | }; | ||
269 | EXPORT_SYMBOL(drm_primary_helper_funcs); | ||
270 | |||
271 | /** | ||
272 | * drm_primary_helper_create_plane() - Create a generic primary plane | ||
273 | * @dev: drm device | ||
274 | * @formats: pixel formats supported, or NULL for a default safe list | ||
275 | * @num_formats: size of @formats; ignored if @formats is NULL | ||
276 | * | ||
277 | * Allocates and initializes a primary plane that can be used with the primary | ||
278 | * plane helpers. Drivers that wish to use driver-specific plane structures or | ||
279 | * provide custom handler functions may perform their own allocation and | ||
280 | * initialization rather than calling this function. | ||
281 | */ | ||
282 | struct drm_plane *drm_primary_helper_create_plane(struct drm_device *dev, | ||
283 | const uint32_t *formats, | ||
284 | int num_formats) | ||
285 | { | ||
286 | struct drm_plane *primary; | ||
287 | int ret; | ||
288 | |||
289 | primary = kzalloc(sizeof(*primary), GFP_KERNEL); | ||
290 | if (primary == NULL) { | ||
291 | DRM_DEBUG_KMS("Failed to allocate primary plane\n"); | ||
292 | return NULL; | ||
293 | } | ||
294 | |||
295 | if (formats == NULL) { | ||
296 | formats = safe_modeset_formats; | ||
297 | num_formats = ARRAY_SIZE(safe_modeset_formats); | ||
298 | } | ||
299 | |||
300 | /* possible_crtc's will be filled in later by crtc_init */ | ||
301 | ret = drm_plane_init(dev, primary, 0, &drm_primary_helper_funcs, | ||
302 | formats, num_formats, | ||
303 | DRM_PLANE_TYPE_PRIMARY); | ||
304 | if (ret) { | ||
305 | kfree(primary); | ||
306 | primary = NULL; | ||
307 | } | ||
308 | |||
309 | return primary; | ||
310 | } | ||
311 | EXPORT_SYMBOL(drm_primary_helper_create_plane); | ||
312 | |||
diff --git a/include/drm/drm_plane_helper.h b/include/drm/drm_plane_helper.h new file mode 100644 index 000000000000..09824becee3e --- /dev/null +++ b/include/drm/drm_plane_helper.h | |||
@@ -0,0 +1,49 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2011-2013 Intel Corporation | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
21 | * SOFTWARE. | ||
22 | */ | ||
23 | |||
24 | #ifndef DRM_PLANE_HELPER_H | ||
25 | #define DRM_PLANE_HELPER_H | ||
26 | |||
27 | /** | ||
28 | * DOC: plane helpers | ||
29 | * | ||
30 | * Helper functions to assist with creation and handling of CRTC primary | ||
31 | * planes. | ||
32 | */ | ||
33 | |||
34 | extern int drm_primary_helper_update(struct drm_plane *plane, | ||
35 | struct drm_crtc *crtc, | ||
36 | struct drm_framebuffer *fb, | ||
37 | int crtc_x, int crtc_y, | ||
38 | unsigned int crtc_w, unsigned int crtc_h, | ||
39 | uint32_t src_x, uint32_t src_y, | ||
40 | uint32_t src_w, uint32_t src_h); | ||
41 | extern int drm_primary_helper_disable(struct drm_plane *plane); | ||
42 | extern void drm_primary_helper_destroy(struct drm_plane *plane); | ||
43 | extern const struct drm_plane_funcs drm_primary_helper_funcs; | ||
44 | extern struct drm_plane *drm_primary_helper_create_plane(struct drm_device *dev, | ||
45 | uint32_t *formats, | ||
46 | int num_formats); | ||
47 | |||
48 | |||
49 | #endif | ||