Line data Source code
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 :
28 : #include <drm/drm_atomic.h>
29 : #include <drm/drm_atomic_helper.h>
30 : #include <drm/drm_atomic_uapi.h>
31 : #include <drm/drm_crtc_helper.h>
32 : #include <drm/drm_device.h>
33 : #include <drm/drm_encoder.h>
34 : #include <drm/drm_plane_helper.h>
35 : #include <drm/drm_rect.h>
36 :
37 : #define SUBPIXEL_MASK 0xffff
38 :
39 : /**
40 : * DOC: overview
41 : *
42 : * This helper library has two parts. The first part has support to implement
43 : * primary plane support on top of the normal CRTC configuration interface.
44 : * Since the legacy &drm_mode_config_funcs.set_config interface ties the primary
45 : * plane together with the CRTC state this does not allow userspace to disable
46 : * the primary plane itself. The default primary plane only expose XRBG8888 and
47 : * ARGB8888 as valid pixel formats for the attached framebuffer.
48 : *
49 : * Drivers are highly recommended to implement proper support for primary
50 : * planes, and newly merged drivers must not rely upon these transitional
51 : * helpers.
52 : *
53 : * The second part also implements transitional helpers which allow drivers to
54 : * gradually switch to the atomic helper infrastructure for plane updates. Once
55 : * that switch is complete drivers shouldn't use these any longer, instead using
56 : * the proper legacy implementations for update and disable plane hooks provided
57 : * by the atomic helpers.
58 : *
59 : * Again drivers are strongly urged to switch to the new interfaces.
60 : *
61 : * The plane helpers share the function table structures with other helpers,
62 : * specifically also the atomic helpers. See &struct drm_plane_helper_funcs for
63 : * the details.
64 : */
65 :
66 : /*
67 : * Returns the connectors currently associated with a CRTC. This function
68 : * should be called twice: once with a NULL connector list to retrieve
69 : * the list size, and once with the properly allocated list to be filled in.
70 : */
71 0 : static int get_connectors_for_crtc(struct drm_crtc *crtc,
72 : struct drm_connector **connector_list,
73 : int num_connectors)
74 : {
75 0 : struct drm_device *dev = crtc->dev;
76 : struct drm_connector *connector;
77 : struct drm_connector_list_iter conn_iter;
78 0 : int count = 0;
79 :
80 : /*
81 : * Note: Once we change the plane hooks to more fine-grained locking we
82 : * need to grab the connection_mutex here to be able to make these
83 : * checks.
84 : */
85 0 : WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
86 :
87 0 : drm_connector_list_iter_begin(dev, &conn_iter);
88 0 : drm_for_each_connector_iter(connector, &conn_iter) {
89 0 : if (connector->encoder && connector->encoder->crtc == crtc) {
90 0 : if (connector_list != NULL && count < num_connectors)
91 0 : *(connector_list++) = connector;
92 :
93 0 : count++;
94 : }
95 : }
96 0 : drm_connector_list_iter_end(&conn_iter);
97 :
98 0 : return count;
99 : }
100 :
101 0 : static int drm_plane_helper_check_update(struct drm_plane *plane,
102 : struct drm_crtc *crtc,
103 : struct drm_framebuffer *fb,
104 : struct drm_rect *src,
105 : struct drm_rect *dst,
106 : unsigned int rotation,
107 : int min_scale,
108 : int max_scale,
109 : bool can_position,
110 : bool can_update_disabled,
111 : bool *visible)
112 : {
113 0 : struct drm_plane_state plane_state = {
114 : .plane = plane,
115 : .crtc = crtc,
116 : .fb = fb,
117 0 : .src_x = src->x1,
118 0 : .src_y = src->y1,
119 0 : .src_w = drm_rect_width(src),
120 0 : .src_h = drm_rect_height(src),
121 0 : .crtc_x = dst->x1,
122 0 : .crtc_y = dst->y1,
123 0 : .crtc_w = drm_rect_width(dst),
124 0 : .crtc_h = drm_rect_height(dst),
125 : .rotation = rotation,
126 : };
127 0 : struct drm_crtc_state crtc_state = {
128 : .crtc = crtc,
129 0 : .enable = crtc->enabled,
130 : .mode = crtc->mode,
131 : };
132 : int ret;
133 :
134 0 : ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
135 : min_scale, max_scale,
136 : can_position,
137 : can_update_disabled);
138 0 : if (ret)
139 : return ret;
140 :
141 0 : *src = plane_state.src;
142 0 : *dst = plane_state.dst;
143 0 : *visible = plane_state.visible;
144 :
145 0 : return 0;
146 : }
147 :
148 0 : static int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
149 : struct drm_framebuffer *fb,
150 : int crtc_x, int crtc_y,
151 : unsigned int crtc_w, unsigned int crtc_h,
152 : uint32_t src_x, uint32_t src_y,
153 : uint32_t src_w, uint32_t src_h,
154 : struct drm_modeset_acquire_ctx *ctx)
155 : {
156 0 : struct drm_mode_set set = {
157 : .crtc = crtc,
158 : .fb = fb,
159 0 : .mode = &crtc->mode,
160 0 : .x = src_x >> 16,
161 0 : .y = src_y >> 16,
162 : };
163 0 : struct drm_rect src = {
164 : .x1 = src_x,
165 : .y1 = src_y,
166 0 : .x2 = src_x + src_w,
167 0 : .y2 = src_y + src_h,
168 : };
169 0 : struct drm_rect dest = {
170 : .x1 = crtc_x,
171 : .y1 = crtc_y,
172 0 : .x2 = crtc_x + crtc_w,
173 0 : .y2 = crtc_y + crtc_h,
174 : };
175 : struct drm_connector **connector_list;
176 : int num_connectors, ret;
177 : bool visible;
178 :
179 0 : ret = drm_plane_helper_check_update(plane, crtc, fb,
180 : &src, &dest,
181 : DRM_MODE_ROTATE_0,
182 : DRM_PLANE_HELPER_NO_SCALING,
183 : DRM_PLANE_HELPER_NO_SCALING,
184 : false, false, &visible);
185 0 : if (ret)
186 : return ret;
187 :
188 0 : if (!visible)
189 : /*
190 : * Primary plane isn't visible. Note that unless a driver
191 : * provides their own disable function, this will just
192 : * wind up returning -EINVAL to userspace.
193 : */
194 0 : return plane->funcs->disable_plane(plane, ctx);
195 :
196 : /* Find current connectors for CRTC */
197 0 : num_connectors = get_connectors_for_crtc(crtc, NULL, 0);
198 0 : BUG_ON(num_connectors == 0);
199 0 : connector_list = kcalloc(num_connectors, sizeof(*connector_list),
200 : GFP_KERNEL);
201 0 : if (!connector_list)
202 : return -ENOMEM;
203 0 : get_connectors_for_crtc(crtc, connector_list, num_connectors);
204 :
205 0 : set.connectors = connector_list;
206 0 : set.num_connectors = num_connectors;
207 :
208 : /*
209 : * We call set_config() directly here rather than using
210 : * drm_mode_set_config_internal. We're reprogramming the same
211 : * connectors that were already in use, so we shouldn't need the extra
212 : * cross-CRTC fb refcounting to accommodate stealing connectors.
213 : * drm_mode_setplane() already handles the basic refcounting for the
214 : * framebuffers involved in this operation.
215 : */
216 0 : ret = crtc->funcs->set_config(&set, ctx);
217 :
218 0 : kfree(connector_list);
219 0 : return ret;
220 : }
221 :
222 0 : static int drm_primary_helper_disable(struct drm_plane *plane,
223 : struct drm_modeset_acquire_ctx *ctx)
224 : {
225 0 : return -EINVAL;
226 : }
227 :
228 : /**
229 : * drm_primary_helper_destroy() - Helper for primary plane destruction
230 : * @plane: plane to destroy
231 : *
232 : * Provides a default plane destroy handler for primary planes. This handler
233 : * is called during CRTC destruction. We disable the primary plane, remove
234 : * it from the DRM plane list, and deallocate the plane structure.
235 : */
236 0 : void drm_primary_helper_destroy(struct drm_plane *plane)
237 : {
238 0 : drm_plane_cleanup(plane);
239 0 : kfree(plane);
240 0 : }
241 : EXPORT_SYMBOL(drm_primary_helper_destroy);
242 :
243 : const struct drm_plane_funcs drm_primary_helper_funcs = {
244 : .update_plane = drm_primary_helper_update,
245 : .disable_plane = drm_primary_helper_disable,
246 : .destroy = drm_primary_helper_destroy,
247 : };
248 : EXPORT_SYMBOL(drm_primary_helper_funcs);
|