1ba55f2f5SFrançois Tigeot /* 2ba55f2f5SFrançois Tigeot * Copyright (C) 2014 Intel Corporation 3ba55f2f5SFrançois Tigeot * 4ba55f2f5SFrançois Tigeot * DRM universal plane helper functions 5ba55f2f5SFrançois Tigeot * 6ba55f2f5SFrançois Tigeot * Permission is hereby granted, free of charge, to any person obtaining a 7ba55f2f5SFrançois Tigeot * copy of this software and associated documentation files (the "Software"), 8ba55f2f5SFrançois Tigeot * to deal in the Software without restriction, including without limitation 9ba55f2f5SFrançois Tigeot * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10ba55f2f5SFrançois Tigeot * and/or sell copies of the Software, and to permit persons to whom the 11ba55f2f5SFrançois Tigeot * Software is furnished to do so, subject to the following conditions: 12ba55f2f5SFrançois Tigeot * 13ba55f2f5SFrançois Tigeot * The above copyright notice and this permission notice (including the next 14ba55f2f5SFrançois Tigeot * paragraph) shall be included in all copies or substantial portions of the 15ba55f2f5SFrançois Tigeot * Software. 16ba55f2f5SFrançois Tigeot * 17ba55f2f5SFrançois Tigeot * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18ba55f2f5SFrançois Tigeot * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19ba55f2f5SFrançois Tigeot * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20ba55f2f5SFrançois Tigeot * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21ba55f2f5SFrançois Tigeot * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22ba55f2f5SFrançois Tigeot * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23ba55f2f5SFrançois Tigeot * SOFTWARE. 24ba55f2f5SFrançois Tigeot */ 25ba55f2f5SFrançois Tigeot 26ba55f2f5SFrançois Tigeot #include <linux/list.h> 27ba55f2f5SFrançois Tigeot #include <drm/drmP.h> 28ba55f2f5SFrançois Tigeot #include <drm/drm_plane_helper.h> 292c9916cdSFrançois Tigeot #include <drm/drm_rect.h> 302c9916cdSFrançois Tigeot #include <drm/drm_atomic.h> 312c9916cdSFrançois Tigeot #include <drm/drm_crtc_helper.h> 322c9916cdSFrançois Tigeot #include <drm/drm_atomic_helper.h> 33ba55f2f5SFrançois Tigeot 34ba55f2f5SFrançois Tigeot #define SUBPIXEL_MASK 0xffff 35ba55f2f5SFrançois Tigeot 362c9916cdSFrançois Tigeot /** 372c9916cdSFrançois Tigeot * DOC: overview 382c9916cdSFrançois Tigeot * 392c9916cdSFrançois Tigeot * This helper library has two parts. The first part has support to implement 402c9916cdSFrançois Tigeot * primary plane support on top of the normal CRTC configuration interface. 412c9916cdSFrançois Tigeot * Since the legacy ->set_config interface ties the primary plane together with 422c9916cdSFrançois Tigeot * the CRTC state this does not allow userspace to disable the primary plane 432c9916cdSFrançois Tigeot * itself. To avoid too much duplicated code use 442c9916cdSFrançois Tigeot * drm_plane_helper_check_update() which can be used to enforce the same 452c9916cdSFrançois Tigeot * restrictions as primary planes had thus. The default primary plane only 462c9916cdSFrançois Tigeot * expose XRBG8888 and ARGB8888 as valid pixel formats for the attached 472c9916cdSFrançois Tigeot * framebuffer. 482c9916cdSFrançois Tigeot * 492c9916cdSFrançois Tigeot * Drivers are highly recommended to implement proper support for primary 502c9916cdSFrançois Tigeot * planes, and newly merged drivers must not rely upon these transitional 512c9916cdSFrançois Tigeot * helpers. 522c9916cdSFrançois Tigeot * 532c9916cdSFrançois Tigeot * The second part also implements transitional helpers which allow drivers to 542c9916cdSFrançois Tigeot * gradually switch to the atomic helper infrastructure for plane updates. Once 552c9916cdSFrançois Tigeot * that switch is complete drivers shouldn't use these any longer, instead using 562c9916cdSFrançois Tigeot * the proper legacy implementations for update and disable plane hooks provided 572c9916cdSFrançois Tigeot * by the atomic helpers. 582c9916cdSFrançois Tigeot * 592c9916cdSFrançois Tigeot * Again drivers are strongly urged to switch to the new interfaces. 602c9916cdSFrançois Tigeot */ 612c9916cdSFrançois Tigeot 62ba55f2f5SFrançois Tigeot /* 63ba55f2f5SFrançois Tigeot * This is the minimal list of formats that seem to be safe for modeset use 64ba55f2f5SFrançois Tigeot * with all current DRM drivers. Most hardware can actually support more 65ba55f2f5SFrançois Tigeot * formats than this and drivers may specify a more accurate list when 66ba55f2f5SFrançois Tigeot * creating the primary plane. However drivers that still call 67ba55f2f5SFrançois Tigeot * drm_plane_init() will use this minimal format list as the default. 68ba55f2f5SFrançois Tigeot */ 69ba55f2f5SFrançois Tigeot static const uint32_t safe_modeset_formats[] = { 70ba55f2f5SFrançois Tigeot DRM_FORMAT_XRGB8888, 71ba55f2f5SFrançois Tigeot DRM_FORMAT_ARGB8888, 72ba55f2f5SFrançois Tigeot }; 73ba55f2f5SFrançois Tigeot 74ba55f2f5SFrançois Tigeot /* 75ba55f2f5SFrançois Tigeot * Returns the connectors currently associated with a CRTC. This function 76ba55f2f5SFrançois Tigeot * should be called twice: once with a NULL connector list to retrieve 77ba55f2f5SFrançois Tigeot * the list size, and once with the properly allocated list to be filled in. 78ba55f2f5SFrançois Tigeot */ 79ba55f2f5SFrançois Tigeot static int get_connectors_for_crtc(struct drm_crtc *crtc, 80ba55f2f5SFrançois Tigeot struct drm_connector **connector_list, 81ba55f2f5SFrançois Tigeot int num_connectors) 82ba55f2f5SFrançois Tigeot { 83ba55f2f5SFrançois Tigeot struct drm_device *dev = crtc->dev; 84ba55f2f5SFrançois Tigeot struct drm_connector *connector; 85ba55f2f5SFrançois Tigeot int count = 0; 86ba55f2f5SFrançois Tigeot 87ba55f2f5SFrançois Tigeot /* 88ba55f2f5SFrançois Tigeot * Note: Once we change the plane hooks to more fine-grained locking we 89ba55f2f5SFrançois Tigeot * need to grab the connection_mutex here to be able to make these 90ba55f2f5SFrançois Tigeot * checks. 91ba55f2f5SFrançois Tigeot */ 92ba55f2f5SFrançois Tigeot WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); 93ba55f2f5SFrançois Tigeot 94ba55f2f5SFrançois Tigeot list_for_each_entry(connector, &dev->mode_config.connector_list, head) 95ba55f2f5SFrançois Tigeot if (connector->encoder && connector->encoder->crtc == crtc) { 96ba55f2f5SFrançois Tigeot if (connector_list != NULL && count < num_connectors) 97ba55f2f5SFrançois Tigeot *(connector_list++) = connector; 98ba55f2f5SFrançois Tigeot 99ba55f2f5SFrançois Tigeot count++; 100ba55f2f5SFrançois Tigeot } 101ba55f2f5SFrançois Tigeot 102ba55f2f5SFrançois Tigeot return count; 103ba55f2f5SFrançois Tigeot } 104ba55f2f5SFrançois Tigeot 105ba55f2f5SFrançois Tigeot /** 10624edb884SFrançois Tigeot * drm_plane_helper_check_update() - Check plane update for validity 10724edb884SFrançois Tigeot * @plane: plane object to update 10824edb884SFrançois Tigeot * @crtc: owning CRTC of owning plane 10924edb884SFrançois Tigeot * @fb: framebuffer to flip onto plane 11024edb884SFrançois Tigeot * @src: source coordinates in 16.16 fixed point 11124edb884SFrançois Tigeot * @dest: integer destination coordinates 11224edb884SFrançois Tigeot * @clip: integer clipping coordinates 11324edb884SFrançois Tigeot * @min_scale: minimum @src:@dest scaling factor in 16.16 fixed point 11424edb884SFrançois Tigeot * @max_scale: maximum @src:@dest scaling factor in 16.16 fixed point 11524edb884SFrançois Tigeot * @can_position: is it legal to position the plane such that it 11624edb884SFrançois Tigeot * doesn't cover the entire crtc? This will generally 11724edb884SFrançois Tigeot * only be false for primary planes. 11824edb884SFrançois Tigeot * @can_update_disabled: can the plane be updated while the crtc 11924edb884SFrançois Tigeot * is disabled? 12024edb884SFrançois Tigeot * @visible: output parameter indicating whether plane is still visible after 12124edb884SFrançois Tigeot * clipping 12224edb884SFrançois Tigeot * 12324edb884SFrançois Tigeot * Checks that a desired plane update is valid. Drivers that provide 12424edb884SFrançois Tigeot * their own plane handling rather than helper-provided implementations may 12524edb884SFrançois Tigeot * still wish to call this function to avoid duplication of error checking 12624edb884SFrançois Tigeot * code. 12724edb884SFrançois Tigeot * 12824edb884SFrançois Tigeot * RETURNS: 12924edb884SFrançois Tigeot * Zero if update appears valid, error code on failure 13024edb884SFrançois Tigeot */ 13124edb884SFrançois Tigeot int drm_plane_helper_check_update(struct drm_plane *plane, 13224edb884SFrançois Tigeot struct drm_crtc *crtc, 13324edb884SFrançois Tigeot struct drm_framebuffer *fb, 13424edb884SFrançois Tigeot struct drm_rect *src, 13524edb884SFrançois Tigeot struct drm_rect *dest, 13624edb884SFrançois Tigeot const struct drm_rect *clip, 13724edb884SFrançois Tigeot int min_scale, 13824edb884SFrançois Tigeot int max_scale, 13924edb884SFrançois Tigeot bool can_position, 14024edb884SFrançois Tigeot bool can_update_disabled, 14124edb884SFrançois Tigeot bool *visible) 14224edb884SFrançois Tigeot { 14324edb884SFrançois Tigeot int hscale, vscale; 14424edb884SFrançois Tigeot 1452c9916cdSFrançois Tigeot if (!fb) { 1462c9916cdSFrançois Tigeot *visible = false; 1472c9916cdSFrançois Tigeot return 0; 1482c9916cdSFrançois Tigeot } 1492c9916cdSFrançois Tigeot 1502c9916cdSFrançois Tigeot /* crtc should only be NULL when disabling (i.e., !fb) */ 1512c9916cdSFrançois Tigeot if (WARN_ON(!crtc)) { 1522c9916cdSFrançois Tigeot *visible = false; 1532c9916cdSFrançois Tigeot return 0; 1542c9916cdSFrançois Tigeot } 1552c9916cdSFrançois Tigeot 15624edb884SFrançois Tigeot if (!crtc->enabled && !can_update_disabled) { 15724edb884SFrançois Tigeot DRM_DEBUG_KMS("Cannot update plane of a disabled CRTC.\n"); 15824edb884SFrançois Tigeot return -EINVAL; 15924edb884SFrançois Tigeot } 16024edb884SFrançois Tigeot 16124edb884SFrançois Tigeot /* Check scaling */ 16224edb884SFrançois Tigeot hscale = drm_rect_calc_hscale(src, dest, min_scale, max_scale); 16324edb884SFrançois Tigeot vscale = drm_rect_calc_vscale(src, dest, min_scale, max_scale); 16424edb884SFrançois Tigeot if (hscale < 0 || vscale < 0) { 16524edb884SFrançois Tigeot DRM_DEBUG_KMS("Invalid scaling of plane\n"); 16624edb884SFrançois Tigeot return -ERANGE; 16724edb884SFrançois Tigeot } 16824edb884SFrançois Tigeot 16924edb884SFrançois Tigeot *visible = drm_rect_clip_scaled(src, dest, clip, hscale, vscale); 17024edb884SFrançois Tigeot if (!*visible) 17124edb884SFrançois Tigeot /* 17224edb884SFrançois Tigeot * Plane isn't visible; some drivers can handle this 17324edb884SFrançois Tigeot * so we just return success here. Drivers that can't 17424edb884SFrançois Tigeot * (including those that use the primary plane helper's 17524edb884SFrançois Tigeot * update function) will return an error from their 17624edb884SFrançois Tigeot * update_plane handler. 17724edb884SFrançois Tigeot */ 17824edb884SFrançois Tigeot return 0; 17924edb884SFrançois Tigeot 18024edb884SFrançois Tigeot if (!can_position && !drm_rect_equals(dest, clip)) { 18124edb884SFrançois Tigeot DRM_DEBUG_KMS("Plane must cover entire CRTC\n"); 18224edb884SFrançois Tigeot return -EINVAL; 18324edb884SFrançois Tigeot } 18424edb884SFrançois Tigeot 18524edb884SFrançois Tigeot return 0; 18624edb884SFrançois Tigeot } 18724edb884SFrançois Tigeot EXPORT_SYMBOL(drm_plane_helper_check_update); 18824edb884SFrançois Tigeot 18924edb884SFrançois Tigeot /** 190ba55f2f5SFrançois Tigeot * drm_primary_helper_update() - Helper for primary plane update 191ba55f2f5SFrançois Tigeot * @plane: plane object to update 192ba55f2f5SFrançois Tigeot * @crtc: owning CRTC of owning plane 193ba55f2f5SFrançois Tigeot * @fb: framebuffer to flip onto plane 194ba55f2f5SFrançois Tigeot * @crtc_x: x offset of primary plane on crtc 195ba55f2f5SFrançois Tigeot * @crtc_y: y offset of primary plane on crtc 196ba55f2f5SFrançois Tigeot * @crtc_w: width of primary plane rectangle on crtc 197ba55f2f5SFrançois Tigeot * @crtc_h: height of primary plane rectangle on crtc 198ba55f2f5SFrançois Tigeot * @src_x: x offset of @fb for panning 199ba55f2f5SFrançois Tigeot * @src_y: y offset of @fb for panning 200ba55f2f5SFrançois Tigeot * @src_w: width of source rectangle in @fb 201ba55f2f5SFrançois Tigeot * @src_h: height of source rectangle in @fb 202ba55f2f5SFrançois Tigeot * 203ba55f2f5SFrançois Tigeot * Provides a default plane update handler for primary planes. This is handler 204ba55f2f5SFrançois Tigeot * is called in response to a userspace SetPlane operation on the plane with a 205ba55f2f5SFrançois Tigeot * non-NULL framebuffer. We call the driver's modeset handler to update the 206ba55f2f5SFrançois Tigeot * framebuffer. 207ba55f2f5SFrançois Tigeot * 208ba55f2f5SFrançois Tigeot * SetPlane() on a primary plane of a disabled CRTC is not supported, and will 209ba55f2f5SFrançois Tigeot * return an error. 210ba55f2f5SFrançois Tigeot * 211ba55f2f5SFrançois Tigeot * Note that we make some assumptions about hardware limitations that may not be 212ba55f2f5SFrançois Tigeot * true for all hardware -- 213ba55f2f5SFrançois Tigeot * 1) Primary plane cannot be repositioned. 214ba55f2f5SFrançois Tigeot * 2) Primary plane cannot be scaled. 215ba55f2f5SFrançois Tigeot * 3) Primary plane must cover the entire CRTC. 216ba55f2f5SFrançois Tigeot * 4) Subpixel positioning is not supported. 217ba55f2f5SFrançois Tigeot * Drivers for hardware that don't have these restrictions can provide their 218ba55f2f5SFrançois Tigeot * own implementation rather than using this helper. 219ba55f2f5SFrançois Tigeot * 220ba55f2f5SFrançois Tigeot * RETURNS: 221ba55f2f5SFrançois Tigeot * Zero on success, error code on failure 222ba55f2f5SFrançois Tigeot */ 223ba55f2f5SFrançois Tigeot int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc, 224ba55f2f5SFrançois Tigeot struct drm_framebuffer *fb, 225ba55f2f5SFrançois Tigeot int crtc_x, int crtc_y, 226ba55f2f5SFrançois Tigeot unsigned int crtc_w, unsigned int crtc_h, 227ba55f2f5SFrançois Tigeot uint32_t src_x, uint32_t src_y, 228ba55f2f5SFrançois Tigeot uint32_t src_w, uint32_t src_h) 229ba55f2f5SFrançois Tigeot { 230ba55f2f5SFrançois Tigeot struct drm_mode_set set = { 231ba55f2f5SFrançois Tigeot .crtc = crtc, 232ba55f2f5SFrançois Tigeot .fb = fb, 233ba55f2f5SFrançois Tigeot .mode = &crtc->mode, 234ba55f2f5SFrançois Tigeot .x = src_x >> 16, 235ba55f2f5SFrançois Tigeot .y = src_y >> 16, 236ba55f2f5SFrançois Tigeot }; 2372c9916cdSFrançois Tigeot struct drm_rect src = { 2382c9916cdSFrançois Tigeot .x1 = src_x, 2392c9916cdSFrançois Tigeot .y1 = src_y, 2402c9916cdSFrançois Tigeot .x2 = src_x + src_w, 2412c9916cdSFrançois Tigeot .y2 = src_y + src_h, 2422c9916cdSFrançois Tigeot }; 243ba55f2f5SFrançois Tigeot struct drm_rect dest = { 244ba55f2f5SFrançois Tigeot .x1 = crtc_x, 245ba55f2f5SFrançois Tigeot .y1 = crtc_y, 246ba55f2f5SFrançois Tigeot .x2 = crtc_x + crtc_w, 247ba55f2f5SFrançois Tigeot .y2 = crtc_y + crtc_h, 248ba55f2f5SFrançois Tigeot }; 2492c9916cdSFrançois Tigeot const struct drm_rect clip = { 250ba55f2f5SFrançois Tigeot .x2 = crtc->mode.hdisplay, 251ba55f2f5SFrançois Tigeot .y2 = crtc->mode.vdisplay, 252ba55f2f5SFrançois Tigeot }; 253ba55f2f5SFrançois Tigeot struct drm_connector **connector_list; 254ba55f2f5SFrançois Tigeot int num_connectors, ret; 2552c9916cdSFrançois Tigeot bool visible; 256ba55f2f5SFrançois Tigeot 2572c9916cdSFrançois Tigeot ret = drm_plane_helper_check_update(plane, crtc, fb, 2582c9916cdSFrançois Tigeot &src, &dest, &clip, 2592c9916cdSFrançois Tigeot DRM_PLANE_HELPER_NO_SCALING, 2602c9916cdSFrançois Tigeot DRM_PLANE_HELPER_NO_SCALING, 2612c9916cdSFrançois Tigeot false, false, &visible); 262ba55f2f5SFrançois Tigeot if (ret) 263ba55f2f5SFrançois Tigeot return ret; 264ba55f2f5SFrançois Tigeot 2652c9916cdSFrançois Tigeot if (!visible) 2662c9916cdSFrançois Tigeot /* 2672c9916cdSFrançois Tigeot * Primary plane isn't visible. Note that unless a driver 2682c9916cdSFrançois Tigeot * provides their own disable function, this will just 2692c9916cdSFrançois Tigeot * wind up returning -EINVAL to userspace. 2702c9916cdSFrançois Tigeot */ 2712c9916cdSFrançois Tigeot return plane->funcs->disable_plane(plane); 2722c9916cdSFrançois Tigeot 273ba55f2f5SFrançois Tigeot /* Find current connectors for CRTC */ 274ba55f2f5SFrançois Tigeot num_connectors = get_connectors_for_crtc(crtc, NULL, 0); 275ba55f2f5SFrançois Tigeot BUG_ON(num_connectors == 0); 276ba55f2f5SFrançois Tigeot connector_list = kzalloc(num_connectors * sizeof(*connector_list), 277ba55f2f5SFrançois Tigeot GFP_KERNEL); 278ba55f2f5SFrançois Tigeot if (!connector_list) 279ba55f2f5SFrançois Tigeot return -ENOMEM; 280ba55f2f5SFrançois Tigeot get_connectors_for_crtc(crtc, connector_list, num_connectors); 281ba55f2f5SFrançois Tigeot 282ba55f2f5SFrançois Tigeot set.connectors = connector_list; 283ba55f2f5SFrançois Tigeot set.num_connectors = num_connectors; 284ba55f2f5SFrançois Tigeot 285ba55f2f5SFrançois Tigeot /* 286ba55f2f5SFrançois Tigeot * We call set_config() directly here rather than using 287ba55f2f5SFrançois Tigeot * drm_mode_set_config_internal. We're reprogramming the same 288ba55f2f5SFrançois Tigeot * connectors that were already in use, so we shouldn't need the extra 289ba55f2f5SFrançois Tigeot * cross-CRTC fb refcounting to accomodate stealing connectors. 290ba55f2f5SFrançois Tigeot * drm_mode_setplane() already handles the basic refcounting for the 291ba55f2f5SFrançois Tigeot * framebuffers involved in this operation. 292ba55f2f5SFrançois Tigeot */ 293ba55f2f5SFrançois Tigeot ret = crtc->funcs->set_config(&set); 294ba55f2f5SFrançois Tigeot 295ba55f2f5SFrançois Tigeot kfree(connector_list); 296ba55f2f5SFrançois Tigeot return ret; 297ba55f2f5SFrançois Tigeot } 298ba55f2f5SFrançois Tigeot EXPORT_SYMBOL(drm_primary_helper_update); 299ba55f2f5SFrançois Tigeot 300ba55f2f5SFrançois Tigeot /** 301ba55f2f5SFrançois Tigeot * drm_primary_helper_disable() - Helper for primary plane disable 302ba55f2f5SFrançois Tigeot * @plane: plane to disable 303ba55f2f5SFrançois Tigeot * 304ba55f2f5SFrançois Tigeot * Provides a default plane disable handler for primary planes. This is handler 305ba55f2f5SFrançois Tigeot * is called in response to a userspace SetPlane operation on the plane with a 3062c9916cdSFrançois Tigeot * NULL framebuffer parameter. It unconditionally fails the disable call with 3072c9916cdSFrançois Tigeot * -EINVAL the only way to disable the primary plane without driver support is 3082c9916cdSFrançois Tigeot * to disable the entier CRTC. Which does not match the plane ->disable hook. 309ba55f2f5SFrançois Tigeot * 310ba55f2f5SFrançois Tigeot * Note that some hardware may be able to disable the primary plane without 311ba55f2f5SFrançois Tigeot * disabling the whole CRTC. Drivers for such hardware should provide their 312ba55f2f5SFrançois Tigeot * own disable handler that disables just the primary plane (and they'll likely 313ba55f2f5SFrançois Tigeot * need to provide their own update handler as well to properly re-enable a 314ba55f2f5SFrançois Tigeot * disabled primary plane). 315ba55f2f5SFrançois Tigeot * 316ba55f2f5SFrançois Tigeot * RETURNS: 3172c9916cdSFrançois Tigeot * Unconditionally returns -EINVAL. 318ba55f2f5SFrançois Tigeot */ 319ba55f2f5SFrançois Tigeot int drm_primary_helper_disable(struct drm_plane *plane) 320ba55f2f5SFrançois Tigeot { 3212c9916cdSFrançois Tigeot return -EINVAL; 322ba55f2f5SFrançois Tigeot } 323ba55f2f5SFrançois Tigeot EXPORT_SYMBOL(drm_primary_helper_disable); 324ba55f2f5SFrançois Tigeot 325ba55f2f5SFrançois Tigeot /** 326ba55f2f5SFrançois Tigeot * drm_primary_helper_destroy() - Helper for primary plane destruction 327ba55f2f5SFrançois Tigeot * @plane: plane to destroy 328ba55f2f5SFrançois Tigeot * 329ba55f2f5SFrançois Tigeot * Provides a default plane destroy handler for primary planes. This handler 330ba55f2f5SFrançois Tigeot * is called during CRTC destruction. We disable the primary plane, remove 331ba55f2f5SFrançois Tigeot * it from the DRM plane list, and deallocate the plane structure. 332ba55f2f5SFrançois Tigeot */ 333ba55f2f5SFrançois Tigeot void drm_primary_helper_destroy(struct drm_plane *plane) 334ba55f2f5SFrançois Tigeot { 335ba55f2f5SFrançois Tigeot drm_plane_cleanup(plane); 336ba55f2f5SFrançois Tigeot kfree(plane); 337ba55f2f5SFrançois Tigeot } 338ba55f2f5SFrançois Tigeot EXPORT_SYMBOL(drm_primary_helper_destroy); 339ba55f2f5SFrançois Tigeot 340ba55f2f5SFrançois Tigeot const struct drm_plane_funcs drm_primary_helper_funcs = { 341ba55f2f5SFrançois Tigeot .update_plane = drm_primary_helper_update, 342ba55f2f5SFrançois Tigeot .disable_plane = drm_primary_helper_disable, 343ba55f2f5SFrançois Tigeot .destroy = drm_primary_helper_destroy, 344ba55f2f5SFrançois Tigeot }; 345ba55f2f5SFrançois Tigeot EXPORT_SYMBOL(drm_primary_helper_funcs); 346ba55f2f5SFrançois Tigeot 347*477eb7f9SFrançois Tigeot static struct drm_plane *create_primary_plane(struct drm_device *dev) 348ba55f2f5SFrançois Tigeot { 349ba55f2f5SFrançois Tigeot struct drm_plane *primary; 350ba55f2f5SFrançois Tigeot int ret; 351ba55f2f5SFrançois Tigeot 352ba55f2f5SFrançois Tigeot primary = kzalloc(sizeof(*primary), GFP_KERNEL); 353ba55f2f5SFrançois Tigeot if (primary == NULL) { 354ba55f2f5SFrançois Tigeot DRM_DEBUG_KMS("Failed to allocate primary plane\n"); 355ba55f2f5SFrançois Tigeot return NULL; 356ba55f2f5SFrançois Tigeot } 357ba55f2f5SFrançois Tigeot 358*477eb7f9SFrançois Tigeot /* 359*477eb7f9SFrançois Tigeot * Remove the format_default field from drm_plane when dropping 360*477eb7f9SFrançois Tigeot * this helper. 361*477eb7f9SFrançois Tigeot */ 362*477eb7f9SFrançois Tigeot primary->format_default = true; 363ba55f2f5SFrançois Tigeot 364ba55f2f5SFrançois Tigeot /* possible_crtc's will be filled in later by crtc_init */ 36524edb884SFrançois Tigeot ret = drm_universal_plane_init(dev, primary, 0, 36624edb884SFrançois Tigeot &drm_primary_helper_funcs, 367*477eb7f9SFrançois Tigeot safe_modeset_formats, 368*477eb7f9SFrançois Tigeot ARRAY_SIZE(safe_modeset_formats), 369ba55f2f5SFrançois Tigeot DRM_PLANE_TYPE_PRIMARY); 370ba55f2f5SFrançois Tigeot if (ret) { 371ba55f2f5SFrançois Tigeot kfree(primary); 372ba55f2f5SFrançois Tigeot primary = NULL; 373ba55f2f5SFrançois Tigeot } 374ba55f2f5SFrançois Tigeot 375ba55f2f5SFrançois Tigeot return primary; 376ba55f2f5SFrançois Tigeot } 377ba55f2f5SFrançois Tigeot 378ba55f2f5SFrançois Tigeot /** 379ba55f2f5SFrançois Tigeot * drm_crtc_init - Legacy CRTC initialization function 380ba55f2f5SFrançois Tigeot * @dev: DRM device 381ba55f2f5SFrançois Tigeot * @crtc: CRTC object to init 382ba55f2f5SFrançois Tigeot * @funcs: callbacks for the new CRTC 383ba55f2f5SFrançois Tigeot * 384ba55f2f5SFrançois Tigeot * Initialize a CRTC object with a default helper-provided primary plane and no 385ba55f2f5SFrançois Tigeot * cursor plane. 386ba55f2f5SFrançois Tigeot * 387ba55f2f5SFrançois Tigeot * Returns: 388ba55f2f5SFrançois Tigeot * Zero on success, error code on failure. 389ba55f2f5SFrançois Tigeot */ 390ba55f2f5SFrançois Tigeot int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, 391ba55f2f5SFrançois Tigeot const struct drm_crtc_funcs *funcs) 392ba55f2f5SFrançois Tigeot { 393ba55f2f5SFrançois Tigeot struct drm_plane *primary; 394ba55f2f5SFrançois Tigeot 395*477eb7f9SFrançois Tigeot primary = create_primary_plane(dev); 396ba55f2f5SFrançois Tigeot return drm_crtc_init_with_planes(dev, crtc, primary, NULL, funcs); 397ba55f2f5SFrançois Tigeot } 398ba55f2f5SFrançois Tigeot EXPORT_SYMBOL(drm_crtc_init); 3992c9916cdSFrançois Tigeot 4002c9916cdSFrançois Tigeot int drm_plane_helper_commit(struct drm_plane *plane, 4012c9916cdSFrançois Tigeot struct drm_plane_state *plane_state, 4022c9916cdSFrançois Tigeot struct drm_framebuffer *old_fb) 4032c9916cdSFrançois Tigeot { 404*477eb7f9SFrançois Tigeot const struct drm_plane_helper_funcs *plane_funcs; 4052c9916cdSFrançois Tigeot struct drm_crtc *crtc[2]; 406*477eb7f9SFrançois Tigeot const struct drm_crtc_helper_funcs *crtc_funcs[2]; 4072c9916cdSFrançois Tigeot int i, ret = 0; 4082c9916cdSFrançois Tigeot 4092c9916cdSFrançois Tigeot plane_funcs = plane->helper_private; 4102c9916cdSFrançois Tigeot 4112c9916cdSFrançois Tigeot /* Since this is a transitional helper we can't assume that plane->state 4122c9916cdSFrançois Tigeot * is always valid. Hence we need to use plane->crtc instead of 4132c9916cdSFrançois Tigeot * plane->state->crtc as the old crtc. */ 4142c9916cdSFrançois Tigeot crtc[0] = plane->crtc; 4152c9916cdSFrançois Tigeot crtc[1] = crtc[0] != plane_state->crtc ? plane_state->crtc : NULL; 4162c9916cdSFrançois Tigeot 4172c9916cdSFrançois Tigeot for (i = 0; i < 2; i++) 4182c9916cdSFrançois Tigeot crtc_funcs[i] = crtc[i] ? crtc[i]->helper_private : NULL; 4192c9916cdSFrançois Tigeot 4202c9916cdSFrançois Tigeot if (plane_funcs->atomic_check) { 4212c9916cdSFrançois Tigeot ret = plane_funcs->atomic_check(plane, plane_state); 4222c9916cdSFrançois Tigeot if (ret) 4232c9916cdSFrançois Tigeot goto out; 4242c9916cdSFrançois Tigeot } 4252c9916cdSFrançois Tigeot 426*477eb7f9SFrançois Tigeot if (plane_funcs->prepare_fb && plane_state->fb && 427*477eb7f9SFrançois Tigeot plane_state->fb != old_fb) { 428*477eb7f9SFrançois Tigeot ret = plane_funcs->prepare_fb(plane, plane_state->fb, 429*477eb7f9SFrançois Tigeot plane_state); 4302c9916cdSFrançois Tigeot if (ret) 4312c9916cdSFrançois Tigeot goto out; 4322c9916cdSFrançois Tigeot } 4332c9916cdSFrançois Tigeot 4342c9916cdSFrançois Tigeot /* Point of no return, commit sw state. */ 4352c9916cdSFrançois Tigeot swap(plane->state, plane_state); 4362c9916cdSFrançois Tigeot 4372c9916cdSFrançois Tigeot for (i = 0; i < 2; i++) { 4382c9916cdSFrançois Tigeot if (crtc_funcs[i] && crtc_funcs[i]->atomic_begin) 4392c9916cdSFrançois Tigeot crtc_funcs[i]->atomic_begin(crtc[i]); 4402c9916cdSFrançois Tigeot } 4412c9916cdSFrançois Tigeot 442*477eb7f9SFrançois Tigeot /* 443*477eb7f9SFrançois Tigeot * Drivers may optionally implement the ->atomic_disable callback, so 444*477eb7f9SFrançois Tigeot * special-case that here. 445*477eb7f9SFrançois Tigeot */ 446*477eb7f9SFrançois Tigeot if (drm_atomic_plane_disabling(plane, plane_state) && 447*477eb7f9SFrançois Tigeot plane_funcs->atomic_disable) 448*477eb7f9SFrançois Tigeot plane_funcs->atomic_disable(plane, plane_state); 449*477eb7f9SFrançois Tigeot else 4502c9916cdSFrançois Tigeot plane_funcs->atomic_update(plane, plane_state); 4512c9916cdSFrançois Tigeot 4522c9916cdSFrançois Tigeot for (i = 0; i < 2; i++) { 4532c9916cdSFrançois Tigeot if (crtc_funcs[i] && crtc_funcs[i]->atomic_flush) 4542c9916cdSFrançois Tigeot crtc_funcs[i]->atomic_flush(crtc[i]); 4552c9916cdSFrançois Tigeot } 4562c9916cdSFrançois Tigeot 457*477eb7f9SFrançois Tigeot /* 458*477eb7f9SFrançois Tigeot * If we only moved the plane and didn't change fb's, there's no need to 459*477eb7f9SFrançois Tigeot * wait for vblank. 460*477eb7f9SFrançois Tigeot */ 461*477eb7f9SFrançois Tigeot if (plane->state->fb == old_fb) 462*477eb7f9SFrançois Tigeot goto out; 463*477eb7f9SFrançois Tigeot 4642c9916cdSFrançois Tigeot for (i = 0; i < 2; i++) { 4652c9916cdSFrançois Tigeot if (!crtc[i]) 4662c9916cdSFrançois Tigeot continue; 4672c9916cdSFrançois Tigeot 468*477eb7f9SFrançois Tigeot if (crtc[i]->cursor == plane) 469*477eb7f9SFrançois Tigeot continue; 470*477eb7f9SFrançois Tigeot 471*477eb7f9SFrançois Tigeot /* There's no other way to figure out whether the crtc is running. */ 4722c9916cdSFrançois Tigeot ret = drm_crtc_vblank_get(crtc[i]); 4732c9916cdSFrançois Tigeot if (ret == 0) { 4742c9916cdSFrançois Tigeot drm_crtc_wait_one_vblank(crtc[i]); 4752c9916cdSFrançois Tigeot drm_crtc_vblank_put(crtc[i]); 4762c9916cdSFrançois Tigeot } 4772c9916cdSFrançois Tigeot 4782c9916cdSFrançois Tigeot ret = 0; 4792c9916cdSFrançois Tigeot } 4802c9916cdSFrançois Tigeot 4812c9916cdSFrançois Tigeot if (plane_funcs->cleanup_fb && old_fb) 482*477eb7f9SFrançois Tigeot plane_funcs->cleanup_fb(plane, old_fb, plane_state); 4832c9916cdSFrançois Tigeot out: 4842c9916cdSFrançois Tigeot if (plane_state) { 4852c9916cdSFrançois Tigeot if (plane->funcs->atomic_destroy_state) 4862c9916cdSFrançois Tigeot plane->funcs->atomic_destroy_state(plane, plane_state); 4872c9916cdSFrançois Tigeot else 4882c9916cdSFrançois Tigeot drm_atomic_helper_plane_destroy_state(plane, plane_state); 4892c9916cdSFrançois Tigeot } 4902c9916cdSFrançois Tigeot 4912c9916cdSFrançois Tigeot return ret; 4922c9916cdSFrançois Tigeot } 4932c9916cdSFrançois Tigeot 4942c9916cdSFrançois Tigeot /** 4952c9916cdSFrançois Tigeot * drm_plane_helper_update() - Transitional helper for plane update 4962c9916cdSFrançois Tigeot * @plane: plane object to update 4972c9916cdSFrançois Tigeot * @crtc: owning CRTC of owning plane 4982c9916cdSFrançois Tigeot * @fb: framebuffer to flip onto plane 4992c9916cdSFrançois Tigeot * @crtc_x: x offset of primary plane on crtc 5002c9916cdSFrançois Tigeot * @crtc_y: y offset of primary plane on crtc 5012c9916cdSFrançois Tigeot * @crtc_w: width of primary plane rectangle on crtc 5022c9916cdSFrançois Tigeot * @crtc_h: height of primary plane rectangle on crtc 5032c9916cdSFrançois Tigeot * @src_x: x offset of @fb for panning 5042c9916cdSFrançois Tigeot * @src_y: y offset of @fb for panning 5052c9916cdSFrançois Tigeot * @src_w: width of source rectangle in @fb 5062c9916cdSFrançois Tigeot * @src_h: height of source rectangle in @fb 5072c9916cdSFrançois Tigeot * 5082c9916cdSFrançois Tigeot * Provides a default plane update handler using the atomic plane update 5092c9916cdSFrançois Tigeot * functions. It is fully left to the driver to check plane constraints and 5102c9916cdSFrançois Tigeot * handle corner-cases like a fully occluded or otherwise invisible plane. 5112c9916cdSFrançois Tigeot * 5122c9916cdSFrançois Tigeot * This is useful for piecewise transitioning of a driver to the atomic helpers. 5132c9916cdSFrançois Tigeot * 5142c9916cdSFrançois Tigeot * RETURNS: 5152c9916cdSFrançois Tigeot * Zero on success, error code on failure 5162c9916cdSFrançois Tigeot */ 5172c9916cdSFrançois Tigeot int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc, 5182c9916cdSFrançois Tigeot struct drm_framebuffer *fb, 5192c9916cdSFrançois Tigeot int crtc_x, int crtc_y, 5202c9916cdSFrançois Tigeot unsigned int crtc_w, unsigned int crtc_h, 5212c9916cdSFrançois Tigeot uint32_t src_x, uint32_t src_y, 5222c9916cdSFrançois Tigeot uint32_t src_w, uint32_t src_h) 5232c9916cdSFrançois Tigeot { 5242c9916cdSFrançois Tigeot struct drm_plane_state *plane_state; 5252c9916cdSFrançois Tigeot 5262c9916cdSFrançois Tigeot if (plane->funcs->atomic_duplicate_state) 5272c9916cdSFrançois Tigeot plane_state = plane->funcs->atomic_duplicate_state(plane); 5282c9916cdSFrançois Tigeot else if (plane->state) 5292c9916cdSFrançois Tigeot plane_state = drm_atomic_helper_plane_duplicate_state(plane); 5302c9916cdSFrançois Tigeot else 5312c9916cdSFrançois Tigeot plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL); 5322c9916cdSFrançois Tigeot if (!plane_state) 5332c9916cdSFrançois Tigeot return -ENOMEM; 5342c9916cdSFrançois Tigeot plane_state->plane = plane; 5352c9916cdSFrançois Tigeot 5362c9916cdSFrançois Tigeot plane_state->crtc = crtc; 5372c9916cdSFrançois Tigeot drm_atomic_set_fb_for_plane(plane_state, fb); 5382c9916cdSFrançois Tigeot plane_state->crtc_x = crtc_x; 5392c9916cdSFrançois Tigeot plane_state->crtc_y = crtc_y; 5402c9916cdSFrançois Tigeot plane_state->crtc_h = crtc_h; 5412c9916cdSFrançois Tigeot plane_state->crtc_w = crtc_w; 5422c9916cdSFrançois Tigeot plane_state->src_x = src_x; 5432c9916cdSFrançois Tigeot plane_state->src_y = src_y; 5442c9916cdSFrançois Tigeot plane_state->src_h = src_h; 5452c9916cdSFrançois Tigeot plane_state->src_w = src_w; 5462c9916cdSFrançois Tigeot 5472c9916cdSFrançois Tigeot return drm_plane_helper_commit(plane, plane_state, plane->fb); 5482c9916cdSFrançois Tigeot } 5492c9916cdSFrançois Tigeot EXPORT_SYMBOL(drm_plane_helper_update); 5502c9916cdSFrançois Tigeot 5512c9916cdSFrançois Tigeot /** 5522c9916cdSFrançois Tigeot * drm_plane_helper_disable() - Helper for primary plane disable 5532c9916cdSFrançois Tigeot * @plane: plane to disable 5542c9916cdSFrançois Tigeot * 5552c9916cdSFrançois Tigeot * Provides a default plane disable handler using the atomic plane update 5562c9916cdSFrançois Tigeot * functions. It is fully left to the driver to check plane constraints and 5572c9916cdSFrançois Tigeot * handle corner-cases like a fully occluded or otherwise invisible plane. 5582c9916cdSFrançois Tigeot * 5592c9916cdSFrançois Tigeot * This is useful for piecewise transitioning of a driver to the atomic helpers. 5602c9916cdSFrançois Tigeot * 5612c9916cdSFrançois Tigeot * RETURNS: 5622c9916cdSFrançois Tigeot * Zero on success, error code on failure 5632c9916cdSFrançois Tigeot */ 5642c9916cdSFrançois Tigeot int drm_plane_helper_disable(struct drm_plane *plane) 5652c9916cdSFrançois Tigeot { 5662c9916cdSFrançois Tigeot struct drm_plane_state *plane_state; 5672c9916cdSFrançois Tigeot 5682c9916cdSFrançois Tigeot /* crtc helpers love to call disable functions for already disabled hw 5692c9916cdSFrançois Tigeot * functions. So cope with that. */ 5702c9916cdSFrançois Tigeot if (!plane->crtc) 5712c9916cdSFrançois Tigeot return 0; 5722c9916cdSFrançois Tigeot 5732c9916cdSFrançois Tigeot if (plane->funcs->atomic_duplicate_state) 5742c9916cdSFrançois Tigeot plane_state = plane->funcs->atomic_duplicate_state(plane); 5752c9916cdSFrançois Tigeot else if (plane->state) 5762c9916cdSFrançois Tigeot plane_state = drm_atomic_helper_plane_duplicate_state(plane); 5772c9916cdSFrançois Tigeot else 5782c9916cdSFrançois Tigeot plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL); 5792c9916cdSFrançois Tigeot if (!plane_state) 5802c9916cdSFrançois Tigeot return -ENOMEM; 5812c9916cdSFrançois Tigeot plane_state->plane = plane; 5822c9916cdSFrançois Tigeot 5832c9916cdSFrançois Tigeot plane_state->crtc = NULL; 5842c9916cdSFrançois Tigeot drm_atomic_set_fb_for_plane(plane_state, NULL); 5852c9916cdSFrançois Tigeot 5862c9916cdSFrançois Tigeot return drm_plane_helper_commit(plane, plane_state, plane->fb); 5872c9916cdSFrançois Tigeot } 5882c9916cdSFrançois Tigeot EXPORT_SYMBOL(drm_plane_helper_disable); 589