linux/drivers/gpu/drm/omapdrm/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/omapdss.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->caps = 0;
  73                mgr->supported_displays =
  74                        dss_feat_get_supported_displays(mgr->id);
  75                mgr->supported_outputs =
  76                        dss_feat_get_supported_outputs(mgr->id);
  77
  78                INIT_LIST_HEAD(&mgr->overlays);
  79        }
  80
  81        return 0;
  82}
  83
  84int dss_init_overlay_managers_sysfs(struct platform_device *pdev)
  85{
  86        int i, r;
  87
  88        for (i = 0; i < num_managers; ++i) {
  89                struct omap_overlay_manager *mgr = &managers[i];
  90
  91                r = dss_manager_kobj_init(mgr, pdev);
  92                if (r)
  93                        DSSERR("failed to create sysfs file\n");
  94        }
  95
  96        return 0;
  97}
  98
  99void dss_uninit_overlay_managers(void)
 100{
 101        kfree(managers);
 102        managers = NULL;
 103        num_managers = 0;
 104}
 105
 106void dss_uninit_overlay_managers_sysfs(struct platform_device *pdev)
 107{
 108        int i;
 109
 110        for (i = 0; i < num_managers; ++i) {
 111                struct omap_overlay_manager *mgr = &managers[i];
 112
 113                dss_manager_kobj_uninit(mgr);
 114        }
 115}
 116
 117int omap_dss_get_num_overlay_managers(void)
 118{
 119        return num_managers;
 120}
 121EXPORT_SYMBOL(omap_dss_get_num_overlay_managers);
 122
 123struct omap_overlay_manager *omap_dss_get_overlay_manager(int num)
 124{
 125        if (num >= num_managers)
 126                return NULL;
 127
 128        return &managers[num];
 129}
 130EXPORT_SYMBOL(omap_dss_get_overlay_manager);
 131
 132int dss_mgr_simple_check(struct omap_overlay_manager *mgr,
 133                const struct omap_overlay_manager_info *info)
 134{
 135        if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) {
 136                /*
 137                 * OMAP3 supports only graphics source transparency color key
 138                 * and alpha blending simultaneously. See TRM 15.4.2.4.2.2
 139                 * Alpha Mode.
 140                 */
 141                if (info->partial_alpha_enabled && info->trans_enabled
 142                        && info->trans_key_type != OMAP_DSS_COLOR_KEY_GFX_DST) {
 143                        DSSERR("check_manager: illegal transparency key\n");
 144                        return -EINVAL;
 145                }
 146        }
 147
 148        return 0;
 149}
 150
 151static int dss_mgr_check_zorder(struct omap_overlay_manager *mgr,
 152                struct omap_overlay_info **overlay_infos)
 153{
 154        struct omap_overlay *ovl1, *ovl2;
 155        struct omap_overlay_info *info1, *info2;
 156
 157        list_for_each_entry(ovl1, &mgr->overlays, list) {
 158                info1 = overlay_infos[ovl1->id];
 159
 160                if (info1 == NULL)
 161                        continue;
 162
 163                list_for_each_entry(ovl2, &mgr->overlays, list) {
 164                        if (ovl1 == ovl2)
 165                                continue;
 166
 167                        info2 = overlay_infos[ovl2->id];
 168
 169                        if (info2 == NULL)
 170                                continue;
 171
 172                        if (info1->zorder == info2->zorder) {
 173                                DSSERR("overlays %d and %d have the same "
 174                                                "zorder %d\n",
 175                                        ovl1->id, ovl2->id, info1->zorder);
 176                                return -EINVAL;
 177                        }
 178                }
 179        }
 180
 181        return 0;
 182}
 183
 184int dss_mgr_check_timings(struct omap_overlay_manager *mgr,
 185                const struct omap_video_timings *timings)
 186{
 187        if (!dispc_mgr_timings_ok(mgr->id, timings)) {
 188                DSSERR("check_manager: invalid timings\n");
 189                return -EINVAL;
 190        }
 191
 192        return 0;
 193}
 194
 195static int dss_mgr_check_lcd_config(struct omap_overlay_manager *mgr,
 196                const struct dss_lcd_mgr_config *config)
 197{
 198        struct dispc_clock_info cinfo = config->clock_info;
 199        int dl = config->video_port_width;
 200        bool stallmode = config->stallmode;
 201        bool fifohandcheck = config->fifohandcheck;
 202
 203        if (cinfo.lck_div < 1 || cinfo.lck_div > 255)
 204                return -EINVAL;
 205
 206        if (cinfo.pck_div < 1 || cinfo.pck_div > 255)
 207                return -EINVAL;
 208
 209        if (dl != 12 && dl != 16 && dl != 18 && dl != 24)
 210                return -EINVAL;
 211
 212        /* fifohandcheck should be used only with stallmode */
 213        if (!stallmode && fifohandcheck)
 214                return -EINVAL;
 215
 216        /*
 217         * io pad mode can be only checked by using dssdev connected to the
 218         * manager. Ignore checking these for now, add checks when manager
 219         * is capable of holding information related to the connected interface
 220         */
 221
 222        return 0;
 223}
 224
 225int dss_mgr_check(struct omap_overlay_manager *mgr,
 226                struct omap_overlay_manager_info *info,
 227                const struct omap_video_timings *mgr_timings,
 228                const struct dss_lcd_mgr_config *lcd_config,
 229                struct omap_overlay_info **overlay_infos)
 230{
 231        struct omap_overlay *ovl;
 232        int r;
 233
 234        if (dss_has_feature(FEAT_ALPHA_FREE_ZORDER)) {
 235                r = dss_mgr_check_zorder(mgr, overlay_infos);
 236                if (r)
 237                        return r;
 238        }
 239
 240        r = dss_mgr_check_timings(mgr, mgr_timings);
 241        if (r)
 242                return r;
 243
 244        r = dss_mgr_check_lcd_config(mgr, lcd_config);
 245        if (r)
 246                return r;
 247
 248        list_for_each_entry(ovl, &mgr->overlays, list) {
 249                struct omap_overlay_info *oi;
 250                int r;
 251
 252                oi = overlay_infos[ovl->id];
 253
 254                if (oi == NULL)
 255                        continue;
 256
 257                r = dss_ovl_check(ovl, oi, mgr_timings);
 258                if (r)
 259                        return r;
 260        }
 261
 262        return 0;
 263}
 264