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_device.h> 32 #include <drm/drm_drv.h> 33 #include <drm/drm_encoder.h> 34 #include <drm/drm_plane_helper.h> 35 #include <drm/drm_print.h> 36 #include <drm/drm_rect.h> 37 38 #define SUBPIXEL_MASK 0xffff 39 40 /** 41 * DOC: overview 42 * 43 * This helper library contains helpers to implement primary plane support on 44 * top of the normal CRTC configuration interface. 45 * Since the legacy &drm_mode_config_funcs.set_config interface ties the primary 46 * plane together with the CRTC state this does not allow userspace to disable 47 * the primary plane itself. The default primary plane only expose XRBG8888 and 48 * ARGB8888 as valid pixel formats for the attached framebuffer. 49 * 50 * Drivers are highly recommended to implement proper support for primary 51 * planes, and newly merged drivers must not rely upon these transitional 52 * helpers. 53 * 54 * The plane helpers share the function table structures with other helpers, 55 * specifically also the atomic helpers. See &struct drm_plane_helper_funcs for 56 * the details. 57 */ 58 59 /* 60 * Returns the connectors currently associated with a CRTC. This function 61 * should be called twice: once with a NULL connector list to retrieve 62 * the list size, and once with the properly allocated list to be filled in. 63 */ 64 static int get_connectors_for_crtc(struct drm_crtc *crtc, 65 struct drm_connector **connector_list, 66 int num_connectors) 67 { 68 struct drm_device *dev = crtc->dev; 69 struct drm_connector *connector; 70 struct drm_connector_list_iter conn_iter; 71 int count = 0; 72 73 /* 74 * Note: Once we change the plane hooks to more fine-grained locking we 75 * need to grab the connection_mutex here to be able to make these 76 * checks. 77 */ 78 WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); 79 80 drm_connector_list_iter_begin(dev, &conn_iter); 81 drm_for_each_connector_iter(connector, &conn_iter) { 82 if (connector->encoder && connector->encoder->crtc == crtc) { 83 if (connector_list != NULL && count < num_connectors) 84 *(connector_list++) = connector; 85 86 count++; 87 } 88 } 89 drm_connector_list_iter_end(&conn_iter); 90 91 return count; 92 } 93 94 static int drm_plane_helper_check_update(struct drm_plane *plane, 95 struct drm_crtc *crtc, 96 struct drm_framebuffer *fb, 97 struct drm_rect *src, 98 struct drm_rect *dst, 99 unsigned int rotation, 100 int min_scale, 101 int max_scale, 102 bool can_position, 103 bool can_update_disabled, 104 bool *visible) 105 { 106 struct drm_plane_state plane_state = { 107 .plane = plane, 108 .crtc = crtc, 109 .fb = fb, 110 .src_x = src->x1, 111 .src_y = src->y1, 112 .src_w = drm_rect_width(src), 113 .src_h = drm_rect_height(src), 114 .crtc_x = dst->x1, 115 .crtc_y = dst->y1, 116 .crtc_w = drm_rect_width(dst), 117 .crtc_h = drm_rect_height(dst), 118 .rotation = rotation, 119 }; 120 struct drm_crtc_state crtc_state = { 121 .crtc = crtc, 122 .enable = crtc->enabled, 123 .mode = crtc->mode, 124 }; 125 int ret; 126 127 ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 128 min_scale, max_scale, 129 can_position, 130 can_update_disabled); 131 if (ret) 132 return ret; 133 134 *src = plane_state.src; 135 *dst = plane_state.dst; 136 *visible = plane_state.visible; 137 138 return 0; 139 } 140 141 /** 142 * drm_plane_helper_update_primary - Helper for updating primary planes 143 * @plane: plane to update 144 * @crtc: the plane's new CRTC 145 * @fb: the plane's new framebuffer 146 * @crtc_x: x coordinate within CRTC 147 * @crtc_y: y coordinate within CRTC 148 * @crtc_w: width coordinate within CRTC 149 * @crtc_h: height coordinate within CRTC 150 * @src_x: x coordinate within source 151 * @src_y: y coordinate within source 152 * @src_w: width coordinate within source 153 * @src_h: height coordinate within source 154 * @ctx: modeset locking context 155 * 156 * This helper validates the given parameters and updates the primary plane. 157 * 158 * This function is only useful for non-atomic modesetting. Don't use 159 * it in new drivers. 160 * 161 * Returns: 162 * Zero on success, or an errno code otherwise. 163 */ 164 int drm_plane_helper_update_primary(struct drm_plane *plane, struct drm_crtc *crtc, 165 struct drm_framebuffer *fb, 166 int crtc_x, int crtc_y, 167 unsigned int crtc_w, unsigned int crtc_h, 168 uint32_t src_x, uint32_t src_y, 169 uint32_t src_w, uint32_t src_h, 170 struct drm_modeset_acquire_ctx *ctx) 171 { 172 struct drm_mode_set set = { 173 .crtc = crtc, 174 .fb = fb, 175 .mode = &crtc->mode, 176 .x = src_x >> 16, 177 .y = src_y >> 16, 178 }; 179 struct drm_rect src = { 180 .x1 = src_x, 181 .y1 = src_y, 182 .x2 = src_x + src_w, 183 .y2 = src_y + src_h, 184 }; 185 struct drm_rect dest = { 186 .x1 = crtc_x, 187 .y1 = crtc_y, 188 .x2 = crtc_x + crtc_w, 189 .y2 = crtc_y + crtc_h, 190 }; 191 struct drm_device *dev = plane->dev; 192 struct drm_connector **connector_list; 193 int num_connectors, ret; 194 bool visible; 195 196 if (drm_WARN_ON_ONCE(dev, drm_drv_uses_atomic_modeset(dev))) 197 return -EINVAL; 198 199 ret = drm_plane_helper_check_update(plane, crtc, fb, 200 &src, &dest, 201 DRM_MODE_ROTATE_0, 202 DRM_PLANE_NO_SCALING, 203 DRM_PLANE_NO_SCALING, 204 false, false, &visible); 205 if (ret) 206 return ret; 207 208 if (!visible) 209 /* 210 * Primary plane isn't visible. Note that unless a driver 211 * provides their own disable function, this will just 212 * wind up returning -EINVAL to userspace. 213 */ 214 return plane->funcs->disable_plane(plane, ctx); 215 216 /* Find current connectors for CRTC */ 217 num_connectors = get_connectors_for_crtc(crtc, NULL, 0); 218 BUG_ON(num_connectors == 0); 219 connector_list = kcalloc(num_connectors, sizeof(*connector_list), 220 GFP_KERNEL); 221 if (!connector_list) 222 return -ENOMEM; 223 get_connectors_for_crtc(crtc, connector_list, num_connectors); 224 225 set.connectors = connector_list; 226 set.num_connectors = num_connectors; 227 228 /* 229 * We call set_config() directly here rather than using 230 * drm_mode_set_config_internal. We're reprogramming the same 231 * connectors that were already in use, so we shouldn't need the extra 232 * cross-CRTC fb refcounting to accommodate stealing connectors. 233 * drm_mode_setplane() already handles the basic refcounting for the 234 * framebuffers involved in this operation. 235 */ 236 ret = crtc->funcs->set_config(&set, ctx); 237 238 kfree(connector_list); 239 return ret; 240 } 241 EXPORT_SYMBOL(drm_plane_helper_update_primary); 242 243 /** 244 * drm_plane_helper_disable_primary - Helper for disabling primary planes 245 * @plane: plane to disable 246 * @ctx: modeset locking context 247 * 248 * This helper returns an error when trying to disable the primary 249 * plane. 250 * 251 * This function is only useful for non-atomic modesetting. Don't use 252 * it in new drivers. 253 * 254 * Returns: 255 * An errno code. 256 */ 257 int drm_plane_helper_disable_primary(struct drm_plane *plane, 258 struct drm_modeset_acquire_ctx *ctx) 259 { 260 struct drm_device *dev = plane->dev; 261 262 drm_WARN_ON_ONCE(dev, drm_drv_uses_atomic_modeset(dev)); 263 264 return -EINVAL; 265 } 266 EXPORT_SYMBOL(drm_plane_helper_disable_primary); 267 268 /** 269 * drm_plane_helper_destroy() - Helper for primary plane destruction 270 * @plane: plane to destroy 271 * 272 * Provides a default plane destroy handler for primary planes. This handler 273 * is called during CRTC destruction. We disable the primary plane, remove 274 * it from the DRM plane list, and deallocate the plane structure. 275 */ 276 void drm_plane_helper_destroy(struct drm_plane *plane) 277 { 278 drm_plane_cleanup(plane); 279 kfree(plane); 280 } 281 EXPORT_SYMBOL(drm_plane_helper_destroy); 282 283 /** 284 * drm_plane_helper_atomic_check() - Helper to check plane atomic-state 285 * @plane: plane to check 286 * @state: atomic state object 287 * 288 * Provides a default plane-state check handler for planes whose atomic-state 289 * scale and positioning are not expected to change since the plane is always 290 * a fullscreen scanout buffer. 291 * 292 * This is often the case for the primary plane of simple framebuffers. See 293 * also drm_crtc_helper_atomic_check() for the respective CRTC-state check 294 * helper function. 295 * 296 * RETURNS: 297 * Zero on success, or an errno code otherwise. 298 */ 299 int drm_plane_helper_atomic_check(struct drm_plane *plane, struct drm_atomic_state *state) 300 { 301 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane); 302 struct drm_crtc *new_crtc = new_plane_state->crtc; 303 struct drm_crtc_state *new_crtc_state = NULL; 304 305 if (new_crtc) 306 new_crtc_state = drm_atomic_get_new_crtc_state(state, new_crtc); 307 308 return drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state, 309 DRM_PLANE_NO_SCALING, 310 DRM_PLANE_NO_SCALING, 311 false, false); 312 } 313 EXPORT_SYMBOL(drm_plane_helper_atomic_check); 314