0001
0002
0003
0004
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
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
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
0043 if (hwoverlay_to_plane[cur->idx])
0044 continue;
0045
0046
0047 if (caps & ~cur->caps)
0048 continue;
0049
0050
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
0064
0065
0066
0067
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
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
0110
0111
0112
0113
0114 void omap_overlay_release(struct drm_atomic_state *s, struct omap_hw_overlay *overlay)
0115 {
0116
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
0133
0134
0135
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
0144 if (!overlay_map[overlay->idx]) {
0145 DBG("%s: disabled", overlay->name);
0146
0147
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 }