linux/drivers/video/fbdev/omap2/omapfb/dss/manager.c
<<
>>
Prefs
   1/*
   2 * linux/drivers/video/omap2/dss/manager.c
   3 *
   4 * Copyright (C) 2009 Nokia Corporation
   5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
   6 *
   7 * Some code and ideas taken from drivers/video/omap/ driver
   8 * by Imre Deak.
   9 *
  10 * This program is free software; you can redistribute it and/or modify it
  11 * under the terms of the GNU General Public License version 2 as published by
  12 * the Free Software Foundation.
  13 *
  14 * This program is distributed in the hope that it will be useful, but WITHOUT
  15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  16 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  17 * more details.
  18 *
  19 * You should have received a copy of the GNU General Public License along with
  20 * this program.  If not, see <http://www.gnu.org/licenses/>.
  21 */
  22
  23#define DSS_SUBSYS_NAME "MANAGER"
  24
  25#include <linux/kernel.h>
  26#include <linux/slab.h>
  27#include <linux/module.h>
  28#include <linux/platform_device.h>
  29#include <linux/jiffies.h>
  30
  31#include <video/omapfb_dss.h>
  32
  33#include "dss.h"
  34#include "dss_features.h"
  35
  36static int num_managers;
  37static struct omap_overlay_manager *managers;
  38
  39int dss_init_overlay_managers(void)
  40{
  41        int i;
  42
  43        num_managers = dss_feat_get_num_mgrs();
  44
  45        managers = kzalloc(sizeof(struct omap_overlay_manager) * num_managers,
  46                        GFP_KERNEL);
  47
  48        BUG_ON(managers == NULL);
  49
  50        for (i = 0; i < num_managers; ++i) {
  51                struct omap_overlay_manager *mgr = &managers[i];
  52
  53                switch (i) {
  54                case 0:
  55                        mgr->name = "lcd";
  56                        mgr->id = OMAP_DSS_CHANNEL_LCD;
  57                        break;
  58                case 1:
  59                        mgr->name = "tv";
  60                        mgr->id = OMAP_DSS_CHANNEL_DIGIT;
  61                        break;
  62                case 2:
  63                        mgr->name = "lcd2";
  64                        mgr->id = OMAP_DSS_CHANNEL_LCD2;
  65                        break;
  66                case 3:
  67                        mgr->name = "lcd3";
  68                        mgr->id = OMAP_DSS_CHANNEL_LCD3;
  69                        break;
  70                }
  71
  72                mgr->supported_displays =
  73                        dss_feat_get_supported_displays(mgr->id);
  74                mgr->supported_outputs =
  75                        dss_feat_get_supported_outputs(mgr->id);
  76
  77                INIT_LIST_HEAD(&mgr->overlays);
  78        }
  79
  80        return 0;
  81}
  82
  83int dss_init_overlay_managers_sysfs(struct platform_device *pdev)
  84{
  85        int i, r;
  86
  87        for (i = 0; i < num_managers; ++i) {
  88                struct omap_overlay_manager *mgr = &managers[i];
  89
  90                r = dss_manager_kobj_init(mgr, pdev);
  91                if (r)
  92                        DSSERR("failed to create sysfs file\n");
  93        }
  94
  95        return 0;
  96}
  97
  98void dss_uninit_overlay_managers(void)
  99{
 100        kfree(managers);
 101        managers = NULL;
 102        num_managers = 0;
 103}
 104
 105void dss_uninit_overlay_managers_sysfs(struct platform_device *pdev)
 106{
 107        int i;
 108
 109        for (i = 0; i < num_managers; ++i) {
 110                struct omap_overlay_manager *mgr = &managers[i];
 111
 112                dss_manager_kobj_uninit(mgr);
 113        }
 114}
 115
 116int omap_dss_get_num_overlay_managers(void)
 117{
 118        return num_managers;
 119}
 120EXPORT_SYMBOL(omap_dss_get_num_overlay_managers);
 121
 122struct omap_overlay_manager *omap_dss_get_overlay_manager(int num)
 123{
 124        if (num >= num_managers)
 125                return NULL;
 126
 127        return &managers[num];
 128}
 129EXPORT_SYMBOL(omap_dss_get_overlay_manager);
 130
 131int dss_mgr_simple_check(struct omap_overlay_manager *mgr,
 132                const struct omap_overlay_manager_info *info)
 133{
 134        if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) {
 135                /*
 136                 * OMAP3 supports only graphics source transparency color key
 137                 * and alpha blending simultaneously. See TRM 15.4.2.4.2.2
 138                 * Alpha Mode.
 139                 */
 140                if (info->partial_alpha_enabled && info->trans_enabled
 141                        && info->trans_key_type != OMAP_DSS_COLOR_KEY_GFX_DST) {
 142                        DSSERR("check_manager: illegal transparency key\n");
 143                        return -EINVAL;
 144                }
 145        }
 146
 147        return 0;
 148}
 149
 150static int dss_mgr_check_zorder(struct omap_overlay_manager *mgr,
 151                struct omap_overlay_info **overlay_infos)
 152{
 153        struct omap_overlay *ovl1, *ovl2;
 154        struct omap_overlay_info *info1, *info2;
 155
 156        list_for_each_entry(ovl1, &mgr->overlays, list) {
 157                info1 = overlay_infos[ovl1->id];
 158
 159                if (info1 == NULL)
 160                        continue;
 161
 162                list_for_each_entry(ovl2, &mgr->overlays, list) {
 163                        if (ovl1 == ovl2)
 164                                continue;
 165
 166                        info2 = overlay_infos[ovl2->id];
 167
 168                        if (info2 == NULL)
 169                                continue;
 170
 171                        if (info1->zorder == info2->zorder) {
 172                                DSSERR("overlays %d and %d have the same "
 173                                                "zorder %d\n",
 174                                        ovl1->id, ovl2->id, info1->zorder);
 175                                return -EINVAL;
 176                        }
 177                }
 178        }
 179
 180        return 0;
 181}
 182
 183int dss_mgr_check_timings(struct omap_overlay_manager *mgr,
 184                const struct omap_video_timings *timings)
 185{
 186        if (!dispc_mgr_timings_ok(mgr->id, timings)) {
 187                DSSERR("check_manager: invalid timings\n");
 188                return -EINVAL;
 189        }
 190
 191        return 0;
 192}
 193
 194static int dss_mgr_check_lcd_config(struct omap_overlay_manager *mgr,
 195                const struct dss_lcd_mgr_config *config)
 196{
 197        struct dispc_clock_info cinfo = config->clock_info;
 198        int dl = config->video_port_width;
 199        bool stallmode = config->stallmode;
 200        bool fifohandcheck = config->fifohandcheck;
 201
 202        if (cinfo.lck_div < 1 || cinfo.lck_div > 255)
 203                return -EINVAL;
 204
 205        if (cinfo.pck_div < 1 || cinfo.pck_div > 255)
 206                return -EINVAL;
 207
 208        if (dl != 12 && dl != 16 && dl != 18 && dl != 24)
 209                return -EINVAL;
 210
 211        /* fifohandcheck should be used only with stallmode */
 212        if (!stallmode && fifohandcheck)
 213                return -EINVAL;
 214
 215        /*
 216         * io pad mode can be only checked by using dssdev connected to the
 217         * manager. Ignore checking these for now, add checks when manager
 218         * is capable of holding information related to the connected interface
 219         */
 220
 221        return 0;
 222}
 223
 224int dss_mgr_check(struct omap_overlay_manager *mgr,
 225                struct omap_overlay_manager_info *info,
 226                const struct omap_video_timings *mgr_timings,
 227                const struct dss_lcd_mgr_config *lcd_config,
 228                struct omap_overlay_info **overlay_infos)
 229{
 230        struct omap_overlay *ovl;
 231        int r;
 232
 233        if (dss_has_feature(FEAT_ALPHA_FREE_ZORDER)) {
 234                r = dss_mgr_check_zorder(mgr, overlay_infos);
 235                if (r)
 236                        return r;
 237        }
 238
 239        r = dss_mgr_check_timings(mgr, mgr_timings);
 240        if (r)
 241                return r;
 242
 243        r = dss_mgr_check_lcd_config(mgr, lcd_config);
 244        if (r)
 245                return r;
 246
 247        list_for_each_entry(ovl, &mgr->overlays, list) {
 248                struct omap_overlay_info *oi;
 249                int r;
 250
 251                oi = overlay_infos[ovl->id];
 252
 253                if (oi == NULL)
 254                        continue;
 255
 256                r = dss_ovl_check(ovl, oi, mgr_timings);
 257                if (r)
 258                        return r;
 259        }
 260
 261        return 0;
 262}
 263