Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / video / fbdev / omap2 / dss / manager.c
diff --git a/kernel/drivers/video/fbdev/omap2/dss/manager.c b/kernel/drivers/video/fbdev/omap2/dss/manager.c
new file mode 100644 (file)
index 0000000..1aac9b4
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * linux/drivers/video/omap2/dss/manager.c
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
+ *
+ * Some code and ideas taken from drivers/video/omap/ driver
+ * by Imre Deak.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define DSS_SUBSYS_NAME "MANAGER"
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/jiffies.h>
+
+#include <video/omapdss.h>
+
+#include "dss.h"
+#include "dss_features.h"
+
+static int num_managers;
+static struct omap_overlay_manager *managers;
+
+int dss_init_overlay_managers(void)
+{
+       int i;
+
+       num_managers = dss_feat_get_num_mgrs();
+
+       managers = kzalloc(sizeof(struct omap_overlay_manager) * num_managers,
+                       GFP_KERNEL);
+
+       BUG_ON(managers == NULL);
+
+       for (i = 0; i < num_managers; ++i) {
+               struct omap_overlay_manager *mgr = &managers[i];
+
+               switch (i) {
+               case 0:
+                       mgr->name = "lcd";
+                       mgr->id = OMAP_DSS_CHANNEL_LCD;
+                       break;
+               case 1:
+                       mgr->name = "tv";
+                       mgr->id = OMAP_DSS_CHANNEL_DIGIT;
+                       break;
+               case 2:
+                       mgr->name = "lcd2";
+                       mgr->id = OMAP_DSS_CHANNEL_LCD2;
+                       break;
+               case 3:
+                       mgr->name = "lcd3";
+                       mgr->id = OMAP_DSS_CHANNEL_LCD3;
+                       break;
+               }
+
+               mgr->caps = 0;
+               mgr->supported_displays =
+                       dss_feat_get_supported_displays(mgr->id);
+               mgr->supported_outputs =
+                       dss_feat_get_supported_outputs(mgr->id);
+
+               INIT_LIST_HEAD(&mgr->overlays);
+       }
+
+       return 0;
+}
+
+int dss_init_overlay_managers_sysfs(struct platform_device *pdev)
+{
+       int i, r;
+
+       for (i = 0; i < num_managers; ++i) {
+               struct omap_overlay_manager *mgr = &managers[i];
+
+               r = dss_manager_kobj_init(mgr, pdev);
+               if (r)
+                       DSSERR("failed to create sysfs file\n");
+       }
+
+       return 0;
+}
+
+void dss_uninit_overlay_managers(void)
+{
+       kfree(managers);
+       managers = NULL;
+       num_managers = 0;
+}
+
+void dss_uninit_overlay_managers_sysfs(struct platform_device *pdev)
+{
+       int i;
+
+       for (i = 0; i < num_managers; ++i) {
+               struct omap_overlay_manager *mgr = &managers[i];
+
+               dss_manager_kobj_uninit(mgr);
+       }
+}
+
+int omap_dss_get_num_overlay_managers(void)
+{
+       return num_managers;
+}
+EXPORT_SYMBOL(omap_dss_get_num_overlay_managers);
+
+struct omap_overlay_manager *omap_dss_get_overlay_manager(int num)
+{
+       if (num >= num_managers)
+               return NULL;
+
+       return &managers[num];
+}
+EXPORT_SYMBOL(omap_dss_get_overlay_manager);
+
+int dss_mgr_simple_check(struct omap_overlay_manager *mgr,
+               const struct omap_overlay_manager_info *info)
+{
+       if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) {
+               /*
+                * OMAP3 supports only graphics source transparency color key
+                * and alpha blending simultaneously. See TRM 15.4.2.4.2.2
+                * Alpha Mode.
+                */
+               if (info->partial_alpha_enabled && info->trans_enabled
+                       && info->trans_key_type != OMAP_DSS_COLOR_KEY_GFX_DST) {
+                       DSSERR("check_manager: illegal transparency key\n");
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+static int dss_mgr_check_zorder(struct omap_overlay_manager *mgr,
+               struct omap_overlay_info **overlay_infos)
+{
+       struct omap_overlay *ovl1, *ovl2;
+       struct omap_overlay_info *info1, *info2;
+
+       list_for_each_entry(ovl1, &mgr->overlays, list) {
+               info1 = overlay_infos[ovl1->id];
+
+               if (info1 == NULL)
+                       continue;
+
+               list_for_each_entry(ovl2, &mgr->overlays, list) {
+                       if (ovl1 == ovl2)
+                               continue;
+
+                       info2 = overlay_infos[ovl2->id];
+
+                       if (info2 == NULL)
+                               continue;
+
+                       if (info1->zorder == info2->zorder) {
+                               DSSERR("overlays %d and %d have the same "
+                                               "zorder %d\n",
+                                       ovl1->id, ovl2->id, info1->zorder);
+                               return -EINVAL;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+int dss_mgr_check_timings(struct omap_overlay_manager *mgr,
+               const struct omap_video_timings *timings)
+{
+       if (!dispc_mgr_timings_ok(mgr->id, timings)) {
+               DSSERR("check_manager: invalid timings\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int dss_mgr_check_lcd_config(struct omap_overlay_manager *mgr,
+               const struct dss_lcd_mgr_config *config)
+{
+       struct dispc_clock_info cinfo = config->clock_info;
+       int dl = config->video_port_width;
+       bool stallmode = config->stallmode;
+       bool fifohandcheck = config->fifohandcheck;
+
+       if (cinfo.lck_div < 1 || cinfo.lck_div > 255)
+               return -EINVAL;
+
+       if (cinfo.pck_div < 1 || cinfo.pck_div > 255)
+               return -EINVAL;
+
+       if (dl != 12 && dl != 16 && dl != 18 && dl != 24)
+               return -EINVAL;
+
+       /* fifohandcheck should be used only with stallmode */
+       if (stallmode == false && fifohandcheck == true)
+               return -EINVAL;
+
+       /*
+        * io pad mode can be only checked by using dssdev connected to the
+        * manager. Ignore checking these for now, add checks when manager
+        * is capable of holding information related to the connected interface
+        */
+
+       return 0;
+}
+
+int dss_mgr_check(struct omap_overlay_manager *mgr,
+               struct omap_overlay_manager_info *info,
+               const struct omap_video_timings *mgr_timings,
+               const struct dss_lcd_mgr_config *lcd_config,
+               struct omap_overlay_info **overlay_infos)
+{
+       struct omap_overlay *ovl;
+       int r;
+
+       if (dss_has_feature(FEAT_ALPHA_FREE_ZORDER)) {
+               r = dss_mgr_check_zorder(mgr, overlay_infos);
+               if (r)
+                       return r;
+       }
+
+       r = dss_mgr_check_timings(mgr, mgr_timings);
+       if (r)
+               return r;
+
+       r = dss_mgr_check_lcd_config(mgr, lcd_config);
+       if (r)
+               return r;
+
+       list_for_each_entry(ovl, &mgr->overlays, list) {
+               struct omap_overlay_info *oi;
+               int r;
+
+               oi = overlay_infos[ovl->id];
+
+               if (oi == NULL)
+                       continue;
+
+               r = dss_ovl_check(ovl, oi, mgr_timings);
+               if (r)
+                       return r;
+       }
+
+       return 0;
+}