123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
- * Author: Benoit Parrot <[email protected]>
- */
- #include <drm/drm_atomic.h>
- #include <drm/drm_atomic_helper.h>
- #include "omap_dmm_tiler.h"
- #include "omap_drv.h"
- /*
- * overlay funcs
- */
- static const char * const overlay_id_to_name[] = {
- [OMAP_DSS_GFX] = "gfx",
- [OMAP_DSS_VIDEO1] = "vid1",
- [OMAP_DSS_VIDEO2] = "vid2",
- [OMAP_DSS_VIDEO3] = "vid3",
- };
- /*
- * Find a free overlay with the required caps and supported fourcc
- */
- static struct omap_hw_overlay *
- omap_plane_find_free_overlay(struct drm_device *dev, struct drm_plane *hwoverlay_to_plane[],
- u32 caps, u32 fourcc)
- {
- struct omap_drm_private *priv = dev->dev_private;
- int i;
- DBG("caps: %x fourcc: %x", caps, fourcc);
- for (i = 0; i < priv->num_ovls; i++) {
- struct omap_hw_overlay *cur = priv->overlays[i];
- DBG("%d: id: %d cur->caps: %x",
- cur->idx, cur->id, cur->caps);
- /* skip if already in-use */
- if (hwoverlay_to_plane[cur->idx])
- continue;
- /* skip if doesn't support some required caps: */
- if (caps & ~cur->caps)
- continue;
- /* check supported format */
- if (!dispc_ovl_color_mode_supported(priv->dispc,
- cur->id, fourcc))
- continue;
- return cur;
- }
- DBG("no match");
- return NULL;
- }
- /*
- * Assign a new overlay to a plane with the required caps and supported fourcc
- * If a plane need a new overlay, the previous one should have been released
- * with omap_overlay_release()
- * This should be called from the plane atomic_check() in order to prepare the
- * next global overlay_map to be enabled when atomic transaction is valid.
- */
- int omap_overlay_assign(struct drm_atomic_state *s, struct drm_plane *plane,
- u32 caps, u32 fourcc, struct omap_hw_overlay **overlay,
- struct omap_hw_overlay **r_overlay)
- {
- /* Get the global state of the current atomic transaction */
- struct omap_global_state *state = omap_get_global_state(s);
- struct drm_plane **overlay_map = state->hwoverlay_to_plane;
- struct omap_hw_overlay *ovl, *r_ovl;
- ovl = omap_plane_find_free_overlay(s->dev, overlay_map, caps, fourcc);
- if (!ovl)
- return -ENOMEM;
- overlay_map[ovl->idx] = plane;
- *overlay = ovl;
- if (r_overlay) {
- r_ovl = omap_plane_find_free_overlay(s->dev, overlay_map,
- caps, fourcc);
- if (!r_ovl) {
- overlay_map[ovl->idx] = NULL;
- *overlay = NULL;
- return -ENOMEM;
- }
- overlay_map[r_ovl->idx] = plane;
- *r_overlay = r_ovl;
- }
- DBG("%s: assign to plane %s caps %x", ovl->name, plane->name, caps);
- if (r_overlay) {
- DBG("%s: assign to right of plane %s caps %x",
- r_ovl->name, plane->name, caps);
- }
- return 0;
- }
- /*
- * Release an overlay from a plane if the plane gets not visible or the plane
- * need a new overlay if overlay caps changes.
- * This should be called from the plane atomic_check() in order to prepare the
- * next global overlay_map to be enabled when atomic transaction is valid.
- */
- void omap_overlay_release(struct drm_atomic_state *s, struct omap_hw_overlay *overlay)
- {
- /* Get the global state of the current atomic transaction */
- struct omap_global_state *state = omap_get_global_state(s);
- struct drm_plane **overlay_map = state->hwoverlay_to_plane;
- if (!overlay)
- return;
- if (WARN_ON(!overlay_map[overlay->idx]))
- return;
- DBG("%s: release from plane %s", overlay->name, overlay_map[overlay->idx]->name);
- overlay_map[overlay->idx] = NULL;
- }
- /*
- * Update an overlay state that was attached to a plane before the current atomic state.
- * This should be called from the plane atomic_update() or atomic_disable(),
- * where an overlay association to a plane could have changed between the old and current
- * atomic state.
- */
- void omap_overlay_update_state(struct omap_drm_private *priv,
- struct omap_hw_overlay *overlay)
- {
- struct omap_global_state *state = omap_get_existing_global_state(priv);
- struct drm_plane **overlay_map = state->hwoverlay_to_plane;
- /* Check if this overlay is not used anymore, then disable it */
- if (!overlay_map[overlay->idx]) {
- DBG("%s: disabled", overlay->name);
- /* disable the overlay */
- dispc_ovl_enable(priv->dispc, overlay->id, false);
- }
- }
- static void omap_overlay_destroy(struct omap_hw_overlay *overlay)
- {
- kfree(overlay);
- }
- static struct omap_hw_overlay *omap_overlay_init(enum omap_plane_id overlay_id,
- enum omap_overlay_caps caps)
- {
- struct omap_hw_overlay *overlay;
- overlay = kzalloc(sizeof(*overlay), GFP_KERNEL);
- if (!overlay)
- return ERR_PTR(-ENOMEM);
- overlay->name = overlay_id_to_name[overlay_id];
- overlay->id = overlay_id;
- overlay->caps = caps;
- return overlay;
- }
- int omap_hwoverlays_init(struct omap_drm_private *priv)
- {
- static const enum omap_plane_id hw_plane_ids[] = {
- OMAP_DSS_GFX, OMAP_DSS_VIDEO1,
- OMAP_DSS_VIDEO2, OMAP_DSS_VIDEO3,
- };
- u32 num_overlays = dispc_get_num_ovls(priv->dispc);
- enum omap_overlay_caps caps;
- int i, ret;
- for (i = 0; i < num_overlays; i++) {
- struct omap_hw_overlay *overlay;
- caps = dispc_ovl_get_caps(priv->dispc, hw_plane_ids[i]);
- overlay = omap_overlay_init(hw_plane_ids[i], caps);
- if (IS_ERR(overlay)) {
- ret = PTR_ERR(overlay);
- dev_err(priv->dev, "failed to construct overlay for %s (%d)\n",
- overlay_id_to_name[i], ret);
- omap_hwoverlays_destroy(priv);
- return ret;
- }
- overlay->idx = priv->num_ovls;
- priv->overlays[priv->num_ovls++] = overlay;
- }
- return 0;
- }
- void omap_hwoverlays_destroy(struct omap_drm_private *priv)
- {
- int i;
- for (i = 0; i < priv->num_ovls; i++) {
- omap_overlay_destroy(priv->overlays[i]);
- priv->overlays[i] = NULL;
- }
- priv->num_ovls = 0;
- }
|