Branch data 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 : 0 : struct drm_connector *connector;
77 : 0 : 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 : 0 : .visible = *visible,
127 : : };
128 : 0 : struct drm_crtc_state crtc_state = {
129 : : .crtc = crtc,
130 : 0 : .enable = crtc->enabled,
131 : : .mode = crtc->mode,
132 : : };
133 : 0 : int ret;
134 : :
135 : 0 : ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
136 : : min_scale, max_scale,
137 : : can_position,
138 : : can_update_disabled);
139 [ # # ]: 0 : if (ret)
140 : : return ret;
141 : :
142 : 0 : *src = plane_state.src;
143 : 0 : *dst = plane_state.dst;
144 : 0 : *visible = plane_state.visible;
145 : :
146 : 0 : return 0;
147 : : }
148 : :
149 : 0 : static int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
150 : : struct drm_framebuffer *fb,
151 : : int crtc_x, int crtc_y,
152 : : unsigned int crtc_w, unsigned int crtc_h,
153 : : uint32_t src_x, uint32_t src_y,
154 : : uint32_t src_w, uint32_t src_h,
155 : : struct drm_modeset_acquire_ctx *ctx)
156 : : {
157 : 0 : struct drm_mode_set set = {
158 : : .crtc = crtc,
159 : : .fb = fb,
160 : 0 : .mode = &crtc->mode,
161 : 0 : .x = src_x >> 16,
162 : 0 : .y = src_y >> 16,
163 : : };
164 : 0 : struct drm_rect src = {
165 : : .x1 = src_x,
166 : : .y1 = src_y,
167 : 0 : .x2 = src_x + src_w,
168 : 0 : .y2 = src_y + src_h,
169 : : };
170 : 0 : struct drm_rect dest = {
171 : : .x1 = crtc_x,
172 : : .y1 = crtc_y,
173 : 0 : .x2 = crtc_x + crtc_w,
174 : 0 : .y2 = crtc_y + crtc_h,
175 : : };
176 : 0 : struct drm_connector **connector_list;
177 : 0 : int num_connectors, ret;
178 : 0 : bool visible;
179 : :
180 : 0 : ret = drm_plane_helper_check_update(plane, crtc, fb,
181 : : &src, &dest,
182 : : DRM_MODE_ROTATE_0,
183 : : DRM_PLANE_HELPER_NO_SCALING,
184 : : DRM_PLANE_HELPER_NO_SCALING,
185 : : false, false, &visible);
186 [ # # ]: 0 : if (ret)
187 : : return ret;
188 : :
189 [ # # ]: 0 : if (!visible)
190 : : /*
191 : : * Primary plane isn't visible. Note that unless a driver
192 : : * provides their own disable function, this will just
193 : : * wind up returning -EINVAL to userspace.
194 : : */
195 : 0 : return plane->funcs->disable_plane(plane, ctx);
196 : :
197 : : /* Find current connectors for CRTC */
198 : 0 : num_connectors = get_connectors_for_crtc(crtc, NULL, 0);
199 [ # # ]: 0 : BUG_ON(num_connectors == 0);
200 : 0 : connector_list = kcalloc(num_connectors, sizeof(*connector_list),
201 : : GFP_KERNEL);
202 [ # # ]: 0 : if (!connector_list)
203 : : return -ENOMEM;
204 : 0 : get_connectors_for_crtc(crtc, connector_list, num_connectors);
205 : :
206 : 0 : set.connectors = connector_list;
207 : 0 : set.num_connectors = num_connectors;
208 : :
209 : : /*
210 : : * We call set_config() directly here rather than using
211 : : * drm_mode_set_config_internal. We're reprogramming the same
212 : : * connectors that were already in use, so we shouldn't need the extra
213 : : * cross-CRTC fb refcounting to accomodate stealing connectors.
214 : : * drm_mode_setplane() already handles the basic refcounting for the
215 : : * framebuffers involved in this operation.
216 : : */
217 : 0 : ret = crtc->funcs->set_config(&set, ctx);
218 : :
219 : 0 : kfree(connector_list);
220 : 0 : return ret;
221 : : }
222 : :
223 : 0 : static int drm_primary_helper_disable(struct drm_plane *plane,
224 : : struct drm_modeset_acquire_ctx *ctx)
225 : : {
226 : 0 : return -EINVAL;
227 : : }
228 : :
229 : : /**
230 : : * drm_primary_helper_destroy() - Helper for primary plane destruction
231 : : * @plane: plane to destroy
232 : : *
233 : : * Provides a default plane destroy handler for primary planes. This handler
234 : : * is called during CRTC destruction. We disable the primary plane, remove
235 : : * it from the DRM plane list, and deallocate the plane structure.
236 : : */
237 : 0 : void drm_primary_helper_destroy(struct drm_plane *plane)
238 : : {
239 : 0 : drm_plane_cleanup(plane);
240 : 0 : kfree(plane);
241 : 0 : }
242 : : EXPORT_SYMBOL(drm_primary_helper_destroy);
243 : :
244 : : const struct drm_plane_funcs drm_primary_helper_funcs = {
245 : : .update_plane = drm_primary_helper_update,
246 : : .disable_plane = drm_primary_helper_disable,
247 : : .destroy = drm_primary_helper_destroy,
248 : : };
249 : : EXPORT_SYMBOL(drm_primary_helper_funcs);
|