OMAPDSS: DISPC: zorder support for DSS overlays
authorArchit Taneja <archit@ti.com>
Thu, 8 Sep 2011 05:59:17 +0000 (11:29 +0530)
committerTomi Valkeinen <tomi.valkeinen@ti.com>
Mon, 3 Oct 2011 13:51:55 +0000 (16:51 +0300)
Add zorder support on OMAP4, this feature allows deciding the visibility order
of the overlays based on the zorder value provided as an overlay info parameter
or a sysfs attribute of the overlay object.

Use the overlay cap OMAP_DSS_OVL_CAP_ZORDER to determine whether zorder is
supported for the overlay or not. Use dss feature FEAT_ALPHA_FREE_ZORDER
if the caps are not available.

Ensure that all overlays that are enabled and connected to the same manager
have different zorders. Swapping zorders of 2 enabled overlays currently
requires disabling one of the overlays.

Signed-off-by: Archit Taneja <archit@ti.com>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
drivers/video/omap2/dss/dispc.c
drivers/video/omap2/dss/overlay.c
include/video/omapdss.h

index fa7aadfec7b81c4200d31f455736d85331824d66..6892cfd2e3b7043755441165c8554245cb425a6d 100644 (file)
@@ -739,6 +739,27 @@ static void dispc_ovl_set_vid_size(enum omap_plane plane, int width, int height)
        dispc_write_reg(DISPC_OVL_SIZE(plane), val);
 }
 
+static void dispc_ovl_set_zorder(enum omap_plane plane, u8 zorder)
+{
+       struct omap_overlay *ovl = omap_dss_get_overlay(plane);
+
+       if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0)
+               return;
+
+       REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), zorder, 27, 26);
+}
+
+static void dispc_ovl_enable_zorder_planes(void)
+{
+       int i;
+
+       if (!dss_has_feature(FEAT_ALPHA_FREE_ZORDER))
+               return;
+
+       for (i = 0; i < dss_feat_get_num_ovls(); i++)
+               REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i), 1, 25, 25);
+}
+
 static void dispc_ovl_set_pre_mult_alpha(enum omap_plane plane, bool enable)
 {
        struct omap_overlay *ovl = omap_dss_get_overlay(plane);
@@ -1866,6 +1887,7 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
        dispc_ovl_set_rotation_attrs(plane, oi->rotation, oi->mirror,
                        oi->color_mode);
 
+       dispc_ovl_set_zorder(plane, oi->zorder);
        dispc_ovl_set_pre_mult_alpha(plane, oi->pre_mult_alpha);
        dispc_ovl_setup_global_alpha(plane, oi->global_alpha);
 
@@ -3317,6 +3339,8 @@ static void _omap_dispc_initial_config(void)
        dispc_read_plane_fifo_sizes();
 
        dispc_configure_burst_sizes();
+
+       dispc_ovl_enable_zorder_planes();
 }
 
 /* DISPC HW IP initialisation */
index 11d21e3347ad3473e7a0c33d14f784380bd12f7a..ab8e40e48759969671bc6025a4ef610ef3f61272 100644 (file)
@@ -311,6 +311,42 @@ static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl,
        return size;
 }
 
+static ssize_t overlay_zorder_show(struct omap_overlay *ovl, char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.zorder);
+}
+
+static ssize_t overlay_zorder_store(struct omap_overlay *ovl,
+               const char *buf, size_t size)
+{
+       int r;
+       u8 zorder;
+       struct omap_overlay_info info;
+
+       if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0)
+               return -ENODEV;
+
+       r = kstrtou8(buf, 0, &zorder);
+       if (r)
+               return r;
+
+       ovl->get_overlay_info(ovl, &info);
+
+       info.zorder = zorder;
+
+       r = ovl->set_overlay_info(ovl, &info);
+       if (r)
+               return r;
+
+       if (ovl->manager) {
+               r = ovl->manager->apply(ovl->manager);
+               if (r)
+                       return r;
+       }
+
+       return size;
+}
+
 struct overlay_attribute {
        struct attribute attr;
        ssize_t (*show)(struct omap_overlay *, char *);
@@ -337,6 +373,8 @@ static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR,
 static OVERLAY_ATTR(pre_mult_alpha, S_IRUGO|S_IWUSR,
                overlay_pre_mult_alpha_show,
                overlay_pre_mult_alpha_store);
+static OVERLAY_ATTR(zorder, S_IRUGO|S_IWUSR,
+               overlay_zorder_show, overlay_zorder_store);
 
 static struct attribute *overlay_sysfs_attrs[] = {
        &overlay_attr_name.attr,
@@ -348,6 +386,7 @@ static struct attribute *overlay_sysfs_attrs[] = {
        &overlay_attr_enabled.attr,
        &overlay_attr_global_alpha.attr,
        &overlay_attr_pre_mult_alpha.attr,
+       &overlay_attr_zorder.attr,
        NULL
 };
 
@@ -397,6 +436,7 @@ int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev)
        struct omap_overlay_info *info;
        u16 outw, outh;
        u16 dw, dh;
+       int i;
 
        if (!dssdev)
                return 0;
@@ -452,6 +492,31 @@ int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev)
                return -EINVAL;
        }
 
+       if (ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) {
+               if (info->zorder < 0 || info->zorder > 3) {
+                       DSSERR("zorder out of range: %d\n",
+                               info->zorder);
+                       return -EINVAL;
+               }
+               /*
+                * Check that zorder doesn't match with zorder of any other
+                * overlay which is enabled and is also connected to the same
+                * manager
+                */
+               for (i = 0; i < omap_dss_get_num_overlays(); i++) {
+                       struct omap_overlay *tmp_ovl = omap_dss_get_overlay(i);
+
+                       if (tmp_ovl->id != ovl->id &&
+                                       tmp_ovl->manager == ovl->manager &&
+                                       tmp_ovl->info.enabled == true &&
+                                       tmp_ovl->info.zorder == info->zorder) {
+                               DSSERR("%s and %s have same zorder: %d\n",
+                                       ovl->name, tmp_ovl->name, info->zorder);
+                               return -EINVAL;
+                       }
+               }
+       }
+
        return 0;
 }
 
@@ -604,21 +669,28 @@ void dss_init_overlays(struct platform_device *pdev)
                        ovl->name = "gfx";
                        ovl->id = OMAP_DSS_GFX;
                        ovl->info.global_alpha = 255;
+                       ovl->info.zorder = 0;
                        break;
                case 1:
                        ovl->name = "vid1";
                        ovl->id = OMAP_DSS_VIDEO1;
                        ovl->info.global_alpha = 255;
+                       ovl->info.zorder =
+                               dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 3 : 0;
                        break;
                case 2:
                        ovl->name = "vid2";
                        ovl->id = OMAP_DSS_VIDEO2;
                        ovl->info.global_alpha = 255;
+                       ovl->info.zorder =
+                               dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 2 : 0;
                        break;
                case 3:
                        ovl->name = "vid3";
                        ovl->id = OMAP_DSS_VIDEO3;
                        ovl->info.global_alpha = 255;
+                       ovl->info.zorder =
+                               dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 1 : 0;
                        break;
                }
 
index 27d9cce259182b46a66454a5cbc4e62ab534c9f2..b66ebb2032c6d6b87c928876cab69c235d2425f3 100644 (file)
@@ -377,6 +377,7 @@ struct omap_overlay_info {
        u16 out_height; /* if 0, out_height == height */
        u8 global_alpha;
        u8 pre_mult_alpha;
+       u8 zorder;
 };
 
 struct omap_overlay {