1 /* 2 * Copyright (C) 2016 Samsung Electronics Co.Ltd 3 * Authors: 4 * Marek Szyprowski <m.szyprowski@samsung.com> 5 * 6 * DRM core plane blending related functions 7 * 8 * Permission to use, copy, modify, distribute, and sell this software and its 9 * documentation for any purpose is hereby granted without fee, provided that 10 * the above copyright notice appear in all copies and that both that copyright 11 * notice and this permission notice appear in supporting documentation, and 12 * that the name of the copyright holders not be used in advertising or 13 * publicity pertaining to distribution of the software without specific, 14 * written prior permission. The copyright holders make no representations 15 * about the suitability of this software for any purpose. It is provided "as 16 * is" without express or implied warranty. 17 * 18 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 19 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 20 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 21 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 22 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 23 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 24 * OF THIS SOFTWARE. 25 */ 26 #include <drm/drmP.h> 27 #include <drm/drm_atomic.h> 28 #include <drm/drm_crtc.h> 29 #include <linux/export.h> 30 #include <linux/slab.h> 31 #include <linux/sort.h> 32 33 #include "drm_internal.h" 34 35 /** 36 * drm_plane_create_zpos_property - create mutable zpos property 37 * @plane: drm plane 38 * @zpos: initial value of zpos property 39 * @min: minimal possible value of zpos property 40 * @max: maximal possible value of zpos property 41 * 42 * This function initializes generic mutable zpos property and enables support 43 * for it in drm core. Drivers can then attach this property to planes to enable 44 * support for configurable planes arrangement during blending operation. 45 * Once mutable zpos property has been enabled, the DRM core will automatically 46 * calculate drm_plane_state->normalized_zpos values. Usually min should be set 47 * to 0 and max to maximal number of planes for given crtc - 1. 48 * 49 * If zpos of some planes cannot be changed (like fixed background or 50 * cursor/topmost planes), driver should adjust min/max values and assign those 51 * planes immutable zpos property with lower or higher values (for more 52 * information, see drm_mode_create_zpos_immutable_property() function). In such 53 * case driver should also assign proper initial zpos values for all planes in 54 * its plane_reset() callback, so the planes will be always sorted properly. 55 * 56 * Returns: 57 * Zero on success, negative errno on failure. 58 */ 59 int drm_plane_create_zpos_property(struct drm_plane *plane, 60 unsigned int zpos, 61 unsigned int min, unsigned int max) 62 { 63 struct drm_property *prop; 64 65 prop = drm_property_create_range(plane->dev, 0, "zpos", min, max); 66 if (!prop) 67 return -ENOMEM; 68 69 drm_object_attach_property(&plane->base, prop, zpos); 70 71 plane->zpos_property = prop; 72 73 if (plane->state) { 74 plane->state->zpos = zpos; 75 plane->state->normalized_zpos = zpos; 76 } 77 78 return 0; 79 } 80 EXPORT_SYMBOL(drm_plane_create_zpos_property); 81 82 /** 83 * drm_plane_create_zpos_immutable_property - create immuttable zpos property 84 * @plane: drm plane 85 * @zpos: value of zpos property 86 * 87 * This function initializes generic immutable zpos property and enables 88 * support for it in drm core. Using this property driver lets userspace 89 * to get the arrangement of the planes for blending operation and notifies 90 * it that the hardware (or driver) doesn't support changing of the planes' 91 * order. 92 * 93 * Returns: 94 * Zero on success, negative errno on failure. 95 */ 96 int drm_plane_create_zpos_immutable_property(struct drm_plane *plane, 97 unsigned int zpos) 98 { 99 struct drm_property *prop; 100 101 prop = drm_property_create_range(plane->dev, DRM_MODE_PROP_IMMUTABLE, 102 "zpos", zpos, zpos); 103 if (!prop) 104 return -ENOMEM; 105 106 drm_object_attach_property(&plane->base, prop, zpos); 107 108 plane->zpos_property = prop; 109 110 if (plane->state) { 111 plane->state->zpos = zpos; 112 plane->state->normalized_zpos = zpos; 113 } 114 115 return 0; 116 } 117 EXPORT_SYMBOL(drm_plane_create_zpos_immutable_property); 118 119 static int drm_atomic_state_zpos_cmp(const void *a, const void *b) 120 { 121 const struct drm_plane_state *sa = *(struct drm_plane_state **)a; 122 const struct drm_plane_state *sb = *(struct drm_plane_state **)b; 123 124 if (sa->zpos != sb->zpos) 125 return sa->zpos - sb->zpos; 126 else 127 return sa->plane->base.id - sb->plane->base.id; 128 } 129 130 /** 131 * drm_atomic_helper_crtc_normalize_zpos - calculate normalized zpos values 132 * @crtc: crtc with planes, which have to be considered for normalization 133 * @crtc_state: new atomic state to apply 134 * 135 * This function checks new states of all planes assigned to given crtc and 136 * calculates normalized zpos value for them. Planes are compared first by their 137 * zpos values, then by plane id (if zpos equals). Plane with lowest zpos value 138 * is at the bottom. The plane_state->normalized_zpos is then filled with unique 139 * values from 0 to number of active planes in crtc minus one. 140 * 141 * RETURNS 142 * Zero for success or -errno 143 */ 144 static int drm_atomic_helper_crtc_normalize_zpos(struct drm_crtc *crtc, 145 struct drm_crtc_state *crtc_state) 146 { 147 struct drm_atomic_state *state = crtc_state->state; 148 struct drm_device *dev = crtc->dev; 149 int total_planes = dev->mode_config.num_total_plane; 150 struct drm_plane_state **states; 151 struct drm_plane *plane; 152 int i, n = 0; 153 int ret = 0; 154 155 DRM_DEBUG_ATOMIC("[CRTC:%d:%s] calculating normalized zpos values\n", 156 crtc->base.id, crtc->name); 157 158 states = kmalloc_array(total_planes, sizeof(*states), GFP_TEMPORARY); 159 if (!states) 160 return -ENOMEM; 161 162 /* 163 * Normalization process might create new states for planes which 164 * normalized_zpos has to be recalculated. 165 */ 166 drm_for_each_plane_mask(plane, dev, crtc_state->plane_mask) { 167 struct drm_plane_state *plane_state = 168 drm_atomic_get_plane_state(state, plane); 169 if (IS_ERR(plane_state)) { 170 ret = PTR_ERR(plane_state); 171 goto done; 172 } 173 states[n++] = plane_state; 174 DRM_DEBUG_ATOMIC("[PLANE:%d:%s] processing zpos value %d\n", 175 plane->base.id, plane->name, 176 plane_state->zpos); 177 } 178 179 sort(states, n, sizeof(*states), drm_atomic_state_zpos_cmp, NULL); 180 181 for (i = 0; i < n; i++) { 182 plane = states[i]->plane; 183 184 states[i]->normalized_zpos = i; 185 DRM_DEBUG_ATOMIC("[PLANE:%d:%s] normalized zpos value %d\n", 186 plane->base.id, plane->name, i); 187 } 188 crtc_state->zpos_changed = true; 189 190 done: 191 kfree(states); 192 return ret; 193 } 194 195 /** 196 * drm_atomic_helper_normalize_zpos - calculate normalized zpos values for all 197 * crtcs 198 * @dev: DRM device 199 * @state: atomic state of DRM device 200 * 201 * This function calculates normalized zpos value for all modified planes in 202 * the provided atomic state of DRM device. For more information, see 203 * drm_atomic_helper_crtc_normalize_zpos() function. 204 * 205 * RETURNS 206 * Zero for success or -errno 207 */ 208 int drm_atomic_helper_normalize_zpos(struct drm_device *dev, 209 struct drm_atomic_state *state) 210 { 211 struct drm_crtc *crtc; 212 struct drm_crtc_state *crtc_state; 213 struct drm_plane *plane; 214 struct drm_plane_state *plane_state; 215 int i, ret = 0; 216 217 for_each_plane_in_state(state, plane, plane_state, i) { 218 crtc = plane_state->crtc; 219 if (!crtc) 220 continue; 221 if (plane->state->zpos != plane_state->zpos) { 222 crtc_state = 223 drm_atomic_get_existing_crtc_state(state, crtc); 224 crtc_state->zpos_changed = true; 225 } 226 } 227 228 for_each_crtc_in_state(state, crtc, crtc_state, i) { 229 if (crtc_state->plane_mask != crtc->state->plane_mask || 230 crtc_state->zpos_changed) { 231 ret = drm_atomic_helper_crtc_normalize_zpos(crtc, 232 crtc_state); 233 if (ret) 234 return ret; 235 } 236 } 237 return 0; 238 } 239