282 lines · c
1/*2 * Copyright (C) 2014 Intel Corporation3 *4 * DRM universal plane helper functions5 *6 * Permission is hereby granted, free of charge, to any person obtaining a7 * copy of this software and associated documentation files (the "Software"),8 * to deal in the Software without restriction, including without limitation9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,10 * and/or sell copies of the Software, and to permit persons to whom the11 * Software is furnished to do so, subject to the following conditions:12 *13 * The above copyright notice and this permission notice (including the next14 * paragraph) shall be included in all copies or substantial portions of the15 * Software.16 *17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER21 * 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 THE23 * 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 0xffff39 40/**41 * DOC: overview42 *43 * This helper library contains helpers to implement primary plane support on44 * top of the normal CRTC configuration interface.45 * Since the legacy &drm_mode_config_funcs.set_config interface ties the primary46 * plane together with the CRTC state this does not allow userspace to disable47 * the primary plane itself. The default primary plane only expose XRBG8888 and48 * ARGB8888 as valid pixel formats for the attached framebuffer.49 *50 * Drivers are highly recommended to implement proper support for primary51 * planes, and newly merged drivers must not rely upon these transitional52 * 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 for56 * the details.57 */58 59/*60 * Returns the connectors currently associated with a CRTC. This function61 * should be called twice: once with a NULL connector list to retrieve62 * the list size, and once with the properly allocated list to be filled in.63 */64static 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 we75 * need to grab the connection_mutex here to be able to make these76 * 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 94static 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 planes143 * @plane: plane to update144 * @crtc: the plane's new CRTC145 * @fb: the plane's new framebuffer146 * @crtc_x: x coordinate within CRTC147 * @crtc_y: y coordinate within CRTC148 * @crtc_w: width coordinate within CRTC149 * @crtc_h: height coordinate within CRTC150 * @src_x: x coordinate within source151 * @src_y: y coordinate within source152 * @src_w: width coordinate within source153 * @src_h: height coordinate within source154 * @ctx: modeset locking context155 *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 use159 * it in new drivers.160 *161 * Returns:162 * Zero on success, or an errno code otherwise.163 */164int 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 driver211 * provides their own disable function, this will just212 * 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 using230 * drm_mode_set_config_internal. We're reprogramming the same231 * connectors that were already in use, so we shouldn't need the extra232 * cross-CRTC fb refcounting to accommodate stealing connectors.233 * drm_mode_setplane() already handles the basic refcounting for the234 * framebuffers involved in this operation.235 */236 ret = crtc->funcs->set_config(&set, ctx);237 238 kfree(connector_list);239 return ret;240}241EXPORT_SYMBOL(drm_plane_helper_update_primary);242 243/**244 * drm_plane_helper_disable_primary - Helper for disabling primary planes245 * @plane: plane to disable246 * @ctx: modeset locking context247 *248 * This helper returns an error when trying to disable the primary249 * plane.250 *251 * This function is only useful for non-atomic modesetting. Don't use252 * it in new drivers.253 *254 * Returns:255 * An errno code.256 */257int 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}266EXPORT_SYMBOL(drm_plane_helper_disable_primary);267 268/**269 * drm_plane_helper_destroy() - Helper for primary plane destruction270 * @plane: plane to destroy271 *272 * Provides a default plane destroy handler for primary planes. This handler273 * is called during CRTC destruction. We disable the primary plane, remove274 * it from the DRM plane list, and deallocate the plane structure.275 */276void drm_plane_helper_destroy(struct drm_plane *plane)277{278 drm_plane_cleanup(plane);279 kfree(plane);280}281EXPORT_SYMBOL(drm_plane_helper_destroy);282