Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

drm/omap: dynamically assign hw overlays to planes

(re)assign the hw overlays to planes based on required caps, and to
handle situations where we could not modify an in-use plane.

This means all planes advertise the superset of formats and properties.
Userspace must (as always) use atomic TEST_ONLY step for atomic updates,
as not all planes may be available for use on every frame.

The mapping of hwoverlays to plane is stored in omap_global_state, so
that state updates are atomically committed in the same way that
plane/etc state updates are managed. This is needed because the
omap_plane_state keeps a pointer to the hwoverlay, and we don't want
global state to become out of sync with the plane state if an atomic
update fails, we hit deadlock/ backoff scenario, etc. The use of
global_state_lock keeps multiple parallel updates which both re-assign
hwoverlays properly serialized.

Signed-off-by: Benoit Parrot <bparrot@ti.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20211117141928.771082-8-narmstrong@baylibre.com

authored by

Benoit Parrot and committed by
Tomi Valkeinen
2e54ff0e 6e42201b

+220 -23
+3
drivers/gpu/drm/omapdrm/omap_drv.h
··· 50 50 51 51 struct omap_global_state { 52 52 struct drm_private_state base; 53 + 54 + /* global atomic state of assignment between overlays and planes */ 55 + struct drm_plane *hwoverlay_to_plane[8]; 53 56 }; 54 57 55 58 struct omap_drm_private {
+109
drivers/gpu/drm/omapdrm/omap_overlay.c
··· 21 21 [OMAP_DSS_VIDEO3] = "vid3", 22 22 }; 23 23 24 + /* 25 + * Find a free overlay with the required caps and supported fourcc 26 + */ 27 + static struct omap_hw_overlay * 28 + omap_plane_find_free_overlay(struct drm_device *dev, struct drm_plane *hwoverlay_to_plane[], 29 + u32 caps, u32 fourcc) 30 + { 31 + struct omap_drm_private *priv = dev->dev_private; 32 + int i; 33 + 34 + DBG("caps: %x fourcc: %x", caps, fourcc); 35 + 36 + for (i = 0; i < priv->num_ovls; i++) { 37 + struct omap_hw_overlay *cur = priv->overlays[i]; 38 + 39 + DBG("%d: id: %d cur->caps: %x", 40 + cur->idx, cur->id, cur->caps); 41 + 42 + /* skip if already in-use */ 43 + if (hwoverlay_to_plane[cur->idx]) 44 + continue; 45 + 46 + /* skip if doesn't support some required caps: */ 47 + if (caps & ~cur->caps) 48 + continue; 49 + 50 + /* check supported format */ 51 + if (!dispc_ovl_color_mode_supported(priv->dispc, 52 + cur->id, fourcc)) 53 + continue; 54 + 55 + return cur; 56 + } 57 + 58 + DBG("no match"); 59 + return NULL; 60 + } 61 + 62 + /* 63 + * Assign a new overlay to a plane with the required caps and supported fourcc 64 + * If a plane need a new overlay, the previous one should have been released 65 + * with omap_overlay_release() 66 + * This should be called from the plane atomic_check() in order to prepare the 67 + * next global overlay_map to be enabled when atomic transaction is valid. 68 + */ 69 + int omap_overlay_assign(struct drm_atomic_state *s, struct drm_plane *plane, 70 + u32 caps, u32 fourcc, struct omap_hw_overlay **overlay) 71 + { 72 + /* Get the global state of the current atomic transaction */ 73 + struct omap_global_state *state = omap_get_global_state(s); 74 + struct drm_plane **overlay_map = state->hwoverlay_to_plane; 75 + struct omap_hw_overlay *ovl; 76 + 77 + ovl = omap_plane_find_free_overlay(s->dev, overlay_map, caps, fourcc); 78 + if (!ovl) 79 + return -ENOMEM; 80 + 81 + overlay_map[ovl->idx] = plane; 82 + *overlay = ovl; 83 + 84 + DBG("%s: assign to plane %s caps %x", ovl->name, plane->name, caps); 85 + 86 + return 0; 87 + } 88 + 89 + /* 90 + * Release an overlay from a plane if the plane gets not visible or the plane 91 + * need a new overlay if overlay caps changes. 92 + * This should be called from the plane atomic_check() in order to prepare the 93 + * next global overlay_map to be enabled when atomic transaction is valid. 94 + */ 95 + void omap_overlay_release(struct drm_atomic_state *s, struct omap_hw_overlay *overlay) 96 + { 97 + /* Get the global state of the current atomic transaction */ 98 + struct omap_global_state *state = omap_get_global_state(s); 99 + struct drm_plane **overlay_map = state->hwoverlay_to_plane; 100 + 101 + if (!overlay) 102 + return; 103 + 104 + if (WARN_ON(!overlay_map[overlay->idx])) 105 + return; 106 + 107 + DBG("%s: release from plane %s", overlay->name, overlay_map[overlay->idx]->name); 108 + 109 + overlay_map[overlay->idx] = NULL; 110 + } 111 + 112 + /* 113 + * Update an overlay state that was attached to a plane before the current atomic state. 114 + * This should be called from the plane atomic_update() or atomic_disable(), 115 + * where an overlay association to a plane could have changed between the old and current 116 + * atomic state. 117 + */ 118 + void omap_overlay_update_state(struct omap_drm_private *priv, 119 + struct omap_hw_overlay *overlay) 120 + { 121 + struct omap_global_state *state = omap_get_existing_global_state(priv); 122 + struct drm_plane **overlay_map = state->hwoverlay_to_plane; 123 + 124 + /* Check if this overlay is not used anymore, then disable it */ 125 + if (!overlay_map[overlay->idx]) { 126 + DBG("%s: disabled", overlay->name); 127 + 128 + /* disable the overlay */ 129 + dispc_ovl_enable(priv->dispc, overlay->id, false); 130 + } 131 + } 132 + 24 133 static void omap_overlay_destroy(struct omap_hw_overlay *overlay) 25 134 { 26 135 kfree(overlay);
+4
drivers/gpu/drm/omapdrm/omap_overlay.h
··· 27 27 28 28 int omap_hwoverlays_init(struct omap_drm_private *priv); 29 29 void omap_hwoverlays_destroy(struct omap_drm_private *priv); 30 + int omap_overlay_assign(struct drm_atomic_state *s, struct drm_plane *plane, 31 + u32 caps, u32 fourcc, struct omap_hw_overlay **overlay); 32 + void omap_overlay_release(struct drm_atomic_state *s, struct omap_hw_overlay *overlay); 33 + void omap_overlay_update_state(struct omap_drm_private *priv, struct omap_hw_overlay *overlay); 30 34 #endif /* __OMAPDRM_OVERLAY_H__ */
+104 -23
drivers/gpu/drm/omapdrm/omap_plane.c
··· 8 8 #include <drm/drm_atomic_helper.h> 9 9 #include <drm/drm_gem_atomic_helper.h> 10 10 #include <drm/drm_plane_helper.h> 11 + #include <drm/drm_fourcc.h> 11 12 12 13 #include "omap_dmm_tiler.h" 13 14 #include "omap_drv.h" ··· 22 21 struct omap_plane_state { 23 22 /* Must be first. */ 24 23 struct drm_plane_state base; 24 + 25 + struct omap_hw_overlay *overlay; 25 26 }; 26 27 27 28 #define to_omap_plane(x) container_of(x, struct omap_plane, base) ··· 31 28 struct omap_plane { 32 29 struct drm_plane base; 33 30 enum omap_plane_id id; 34 - 35 - struct omap_hw_overlay *overlay; 36 31 }; 37 32 38 33 static int omap_plane_prepare_fb(struct drm_plane *plane, ··· 55 54 struct drm_atomic_state *state) 56 55 { 57 56 struct omap_drm_private *priv = plane->dev->dev_private; 58 - struct omap_plane *omap_plane = to_omap_plane(plane); 59 57 struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, 60 58 plane); 61 - enum omap_plane_id ovl_id = omap_plane->overlay->id; 59 + struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, 60 + plane); 61 + struct omap_plane_state *new_omap_state; 62 + struct omap_plane_state *old_omap_state; 62 63 struct omap_overlay_info info; 64 + enum omap_plane_id ovl_id; 63 65 int ret; 64 66 67 + new_omap_state = to_omap_plane_state(new_state); 68 + old_omap_state = to_omap_plane_state(old_state); 69 + 70 + /* Cleanup previously held overlay if needed */ 71 + if (old_omap_state->overlay) 72 + omap_overlay_update_state(priv, old_omap_state->overlay); 73 + 74 + if (!new_omap_state->overlay) { 75 + DBG("[PLANE:%d:%s] no overlay attached", plane->base.id, plane->name); 76 + return; 77 + } 78 + 79 + ovl_id = new_omap_state->overlay->id; 65 80 DBG("%s, crtc=%p fb=%p", plane->name, new_state->crtc, 66 81 new_state->fb); 67 82 ··· 96 79 /* update scanout: */ 97 80 omap_framebuffer_update_scanout(new_state->fb, new_state, &info); 98 81 99 - DBG("%dx%d -> %dx%d (%d)", info.width, info.height, 100 - info.out_width, info.out_height, 101 - info.screen_width); 82 + DBG("%s: %dx%d -> %dx%d (%d)", 83 + new_omap_state->overlay->name, info.width, info.height, 84 + info.out_width, info.out_height, info.screen_width); 102 85 DBG("%d,%d %pad %pad", info.pos_x, info.pos_y, 103 86 &info.paddr, &info.p_uv_addr); 104 87 ··· 119 102 static void omap_plane_atomic_disable(struct drm_plane *plane, 120 103 struct drm_atomic_state *state) 121 104 { 122 - struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, 123 - plane); 124 105 struct omap_drm_private *priv = plane->dev->dev_private; 125 106 struct omap_plane *omap_plane = to_omap_plane(plane); 126 - enum omap_plane_id ovl_id = omap_plane->overlay->id; 107 + struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, 108 + plane); 109 + struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, 110 + plane); 111 + struct omap_plane_state *new_omap_state; 112 + struct omap_plane_state *old_omap_state; 113 + 114 + new_omap_state = to_omap_plane_state(new_state); 115 + old_omap_state = to_omap_plane_state(old_state); 116 + 117 + if (!old_omap_state->overlay) 118 + return; 127 119 128 120 new_state->rotation = DRM_MODE_ROTATE_0; 129 121 new_state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY ? 0 : omap_plane->id; 130 122 131 - dispc_ovl_enable(priv->dispc, ovl_id, false); 123 + omap_overlay_update_state(priv, old_omap_state->overlay); 124 + new_omap_state->overlay = NULL; 132 125 } 133 126 134 127 #define FRAC_16_16(mult, div) (((mult) << 16) / (div)) ··· 148 121 { 149 122 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, 150 123 plane); 124 + struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, 125 + plane); 151 126 struct omap_drm_private *priv = plane->dev->dev_private; 127 + struct omap_plane_state *omap_state = to_omap_plane_state(new_plane_state); 128 + struct omap_global_state *omap_overlay_global_state; 152 129 struct drm_crtc_state *crtc_state; 130 + bool new_hw_overlay = false; 153 131 u32 max_width, max_height; 132 + struct drm_crtc *crtc; 154 133 u16 width, height; 134 + u32 caps = 0; 135 + u32 fourcc; 155 136 int ret; 156 137 157 - if (!new_plane_state->fb) 158 - return 0; 138 + omap_overlay_global_state = omap_get_global_state(state); 139 + if (IS_ERR(omap_overlay_global_state)) 140 + return PTR_ERR(omap_overlay_global_state); 159 141 160 142 dispc_ovl_get_max_size(priv->dispc, &width, &height); 161 143 max_width = width << 16; 162 144 max_height = height << 16; 163 145 164 - /* crtc should only be NULL when disabling (i.e., !new_plane_state->fb) */ 165 - if (WARN_ON(!new_plane_state->crtc)) 146 + crtc = new_plane_state->crtc ? new_plane_state->crtc : plane->state->crtc; 147 + if (!crtc) 166 148 return 0; 167 149 168 - crtc_state = drm_atomic_get_existing_crtc_state(state, 169 - new_plane_state->crtc); 150 + crtc_state = drm_atomic_get_existing_crtc_state(state, crtc); 170 151 /* we should have a crtc state if the plane is attached to a crtc */ 171 152 if (WARN_ON(!crtc_state)) 172 - return 0; 173 - 174 - if (!crtc_state->enable) 175 153 return 0; 176 154 177 155 /* ··· 190 158 true, true); 191 159 if (ret) 192 160 return ret; 161 + 162 + DBG("%s: visible %d -> %d", plane->name, 163 + old_plane_state->visible, new_plane_state->visible); 164 + 165 + if (!new_plane_state->visible) { 166 + omap_overlay_release(state, omap_state->overlay); 167 + omap_state->overlay = NULL; 168 + return 0; 169 + } 193 170 194 171 if (new_plane_state->crtc_x < 0 || new_plane_state->crtc_y < 0) 195 172 return -EINVAL; ··· 219 178 if (new_plane_state->rotation != DRM_MODE_ROTATE_0 && 220 179 !omap_framebuffer_supports_rotation(new_plane_state->fb)) 221 180 return -EINVAL; 181 + 182 + if ((new_plane_state->src_w >> 16) != new_plane_state->crtc_w || 183 + (new_plane_state->src_h >> 16) != new_plane_state->crtc_h) 184 + caps |= OMAP_DSS_OVL_CAP_SCALE; 185 + 186 + fourcc = new_plane_state->fb->format->format; 187 + 188 + /* 189 + * (re)allocate hw overlay if we don't have one or 190 + * there is a caps mismatch 191 + */ 192 + if (!omap_state->overlay || (caps & ~omap_state->overlay->caps)) { 193 + new_hw_overlay = true; 194 + } else { 195 + /* check supported format */ 196 + if (!dispc_ovl_color_mode_supported(priv->dispc, omap_state->overlay->id, 197 + fourcc)) 198 + new_hw_overlay = true; 199 + } 200 + 201 + if (new_hw_overlay) { 202 + struct omap_hw_overlay *old_ovl = omap_state->overlay; 203 + struct omap_hw_overlay *new_ovl = NULL; 204 + 205 + omap_overlay_release(state, old_ovl); 206 + 207 + ret = omap_overlay_assign(state, plane, caps, fourcc, &new_ovl); 208 + if (ret) { 209 + DBG("%s: failed to assign hw_overlay", plane->name); 210 + omap_state->overlay = NULL; 211 + return ret; 212 + } 213 + 214 + omap_state->overlay = new_ovl; 215 + } 216 + 217 + DBG("plane: %s overlay_id: %d", plane->name, omap_state->overlay->id); 222 218 223 219 return 0; 224 220 } ··· 330 252 static struct drm_plane_state * 331 253 omap_plane_atomic_duplicate_state(struct drm_plane *plane) 332 254 { 333 - struct omap_plane_state *state; 255 + struct omap_plane_state *state, *current_state; 334 256 335 257 if (WARN_ON(!plane->state)) 336 258 return NULL; 259 + 260 + current_state = to_omap_plane_state(plane->state); 337 261 338 262 state = kmalloc(sizeof(*state), GFP_KERNEL); 339 263 if (!state) 340 264 return NULL; 341 265 342 266 __drm_atomic_helper_plane_duplicate_state(plane, &state->base); 267 + 268 + state->overlay = current_state->overlay; 343 269 344 270 return &state->base; 345 271 } ··· 426 344 return ERR_PTR(-ENOMEM); 427 345 428 346 omap_plane->id = idx; 429 - omap_plane->overlay = priv->overlays[idx]; 430 347 431 348 DBG("%d: type=%d", omap_plane->id, type); 432 349 DBG(" crtc_mask: 0x%04x", possible_crtcs); 433 350 434 - formats = dispc_ovl_get_color_modes(priv->dispc, omap_plane->overlay->id); 351 + formats = dispc_ovl_get_color_modes(priv->dispc, omap_plane->id); 435 352 for (nformats = 0; formats[nformats]; ++nformats) 436 353 ; 437 354