Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2018 Texas Instruments Incorporated -  http://www.ti.com/
0004  * Author: Benoit Parrot <bparrot@ti.com>
0005  */
0006 
0007 #include <drm/drm_atomic.h>
0008 #include <drm/drm_atomic_helper.h>
0009 #include <drm/drm_plane_helper.h>
0010 
0011 #include "omap_dmm_tiler.h"
0012 #include "omap_drv.h"
0013 
0014 /*
0015  * overlay funcs
0016  */
0017 static const char * const overlay_id_to_name[] = {
0018     [OMAP_DSS_GFX] = "gfx",
0019     [OMAP_DSS_VIDEO1] = "vid1",
0020     [OMAP_DSS_VIDEO2] = "vid2",
0021     [OMAP_DSS_VIDEO3] = "vid3",
0022 };
0023 
0024 /*
0025  * Find a free overlay with the required caps and supported fourcc
0026  */
0027 static struct omap_hw_overlay *
0028 omap_plane_find_free_overlay(struct drm_device *dev, struct drm_plane *hwoverlay_to_plane[],
0029                  u32 caps, u32 fourcc)
0030 {
0031     struct omap_drm_private *priv = dev->dev_private;
0032     int i;
0033 
0034     DBG("caps: %x fourcc: %x", caps, fourcc);
0035 
0036     for (i = 0; i < priv->num_ovls; i++) {
0037         struct omap_hw_overlay *cur = priv->overlays[i];
0038 
0039         DBG("%d: id: %d cur->caps: %x",
0040             cur->idx, cur->id, cur->caps);
0041 
0042         /* skip if already in-use */
0043         if (hwoverlay_to_plane[cur->idx])
0044             continue;
0045 
0046         /* skip if doesn't support some required caps: */
0047         if (caps & ~cur->caps)
0048             continue;
0049 
0050         /* check supported format */
0051         if (!dispc_ovl_color_mode_supported(priv->dispc,
0052                             cur->id, fourcc))
0053             continue;
0054 
0055         return cur;
0056     }
0057 
0058     DBG("no match");
0059     return NULL;
0060 }
0061 
0062 /*
0063  * Assign a new overlay to a plane with the required caps and supported fourcc
0064  * If a plane need a new overlay, the previous one should have been released
0065  * with omap_overlay_release()
0066  * This should be called from the plane atomic_check() in order to prepare the
0067  * next global overlay_map to be enabled when atomic transaction is valid.
0068  */
0069 int omap_overlay_assign(struct drm_atomic_state *s, struct drm_plane *plane,
0070             u32 caps, u32 fourcc, struct omap_hw_overlay **overlay,
0071             struct omap_hw_overlay **r_overlay)
0072 {
0073     /* Get the global state of the current atomic transaction */
0074     struct omap_global_state *state = omap_get_global_state(s);
0075     struct drm_plane **overlay_map = state->hwoverlay_to_plane;
0076     struct omap_hw_overlay *ovl, *r_ovl;
0077 
0078     ovl = omap_plane_find_free_overlay(s->dev, overlay_map, caps, fourcc);
0079     if (!ovl)
0080         return -ENOMEM;
0081 
0082     overlay_map[ovl->idx] = plane;
0083     *overlay = ovl;
0084 
0085     if (r_overlay) {
0086         r_ovl = omap_plane_find_free_overlay(s->dev, overlay_map,
0087                              caps, fourcc);
0088         if (!r_ovl) {
0089             overlay_map[ovl->idx] = NULL;
0090             *overlay = NULL;
0091             return -ENOMEM;
0092         }
0093 
0094         overlay_map[r_ovl->idx] = plane;
0095         *r_overlay = r_ovl;
0096     }
0097 
0098     DBG("%s: assign to plane %s caps %x", ovl->name, plane->name, caps);
0099 
0100     if (r_overlay) {
0101         DBG("%s: assign to right of plane %s caps %x",
0102             r_ovl->name, plane->name, caps);
0103     }
0104 
0105     return 0;
0106 }
0107 
0108 /*
0109  * Release an overlay from a plane if the plane gets not visible or the plane
0110  * need a new overlay if overlay caps changes.
0111  * This should be called from the plane atomic_check() in order to prepare the
0112  * next global overlay_map to be enabled when atomic transaction is valid.
0113  */
0114 void omap_overlay_release(struct drm_atomic_state *s, struct omap_hw_overlay *overlay)
0115 {
0116     /* Get the global state of the current atomic transaction */
0117     struct omap_global_state *state = omap_get_global_state(s);
0118     struct drm_plane **overlay_map = state->hwoverlay_to_plane;
0119 
0120     if (!overlay)
0121         return;
0122 
0123     if (WARN_ON(!overlay_map[overlay->idx]))
0124         return;
0125 
0126     DBG("%s: release from plane %s", overlay->name, overlay_map[overlay->idx]->name);
0127 
0128     overlay_map[overlay->idx] = NULL;
0129 }
0130 
0131 /*
0132  * Update an overlay state that was attached to a plane before the current atomic state.
0133  * This should be called from the plane atomic_update() or atomic_disable(),
0134  * where an overlay association to a plane could have changed between the old and current
0135  * atomic state.
0136  */
0137 void omap_overlay_update_state(struct omap_drm_private *priv,
0138                    struct omap_hw_overlay *overlay)
0139 {
0140     struct omap_global_state *state = omap_get_existing_global_state(priv);
0141     struct drm_plane **overlay_map = state->hwoverlay_to_plane;
0142 
0143     /* Check if this overlay is not used anymore, then disable it */
0144     if (!overlay_map[overlay->idx]) {
0145         DBG("%s: disabled", overlay->name);
0146 
0147         /* disable the overlay */
0148         dispc_ovl_enable(priv->dispc, overlay->id, false);
0149     }
0150 }
0151 
0152 static void omap_overlay_destroy(struct omap_hw_overlay *overlay)
0153 {
0154     kfree(overlay);
0155 }
0156 
0157 static struct omap_hw_overlay *omap_overlay_init(enum omap_plane_id overlay_id,
0158                          enum omap_overlay_caps caps)
0159 {
0160     struct omap_hw_overlay *overlay;
0161 
0162     overlay = kzalloc(sizeof(*overlay), GFP_KERNEL);
0163     if (!overlay)
0164         return ERR_PTR(-ENOMEM);
0165 
0166     overlay->name = overlay_id_to_name[overlay_id];
0167     overlay->id = overlay_id;
0168     overlay->caps = caps;
0169 
0170     return overlay;
0171 }
0172 
0173 int omap_hwoverlays_init(struct omap_drm_private *priv)
0174 {
0175     static const enum omap_plane_id hw_plane_ids[] = {
0176             OMAP_DSS_GFX, OMAP_DSS_VIDEO1,
0177             OMAP_DSS_VIDEO2, OMAP_DSS_VIDEO3,
0178     };
0179     u32 num_overlays = dispc_get_num_ovls(priv->dispc);
0180     enum omap_overlay_caps caps;
0181     int i, ret;
0182 
0183     for (i = 0; i < num_overlays; i++) {
0184         struct omap_hw_overlay *overlay;
0185 
0186         caps = dispc_ovl_get_caps(priv->dispc, hw_plane_ids[i]);
0187         overlay = omap_overlay_init(hw_plane_ids[i], caps);
0188         if (IS_ERR(overlay)) {
0189             ret = PTR_ERR(overlay);
0190             dev_err(priv->dev, "failed to construct overlay for %s (%d)\n",
0191                 overlay_id_to_name[i], ret);
0192             omap_hwoverlays_destroy(priv);
0193             return ret;
0194         }
0195         overlay->idx = priv->num_ovls;
0196         priv->overlays[priv->num_ovls++] = overlay;
0197     }
0198 
0199     return 0;
0200 }
0201 
0202 void omap_hwoverlays_destroy(struct omap_drm_private *priv)
0203 {
0204     int i;
0205 
0206     for (i = 0; i < priv->num_ovls; i++) {
0207         omap_overlay_destroy(priv->overlays[i]);
0208         priv->overlays[i] = NULL;
0209     }
0210 
0211     priv->num_ovls = 0;
0212 }