linux/drivers/gpu/drm/omapdrm/dss/display.c
<<
>>
Prefs
   1/*
   2 * linux/drivers/video/omap2/dss/display.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 "DISPLAY"
  24
  25#include <linux/kernel.h>
  26#include <linux/module.h>
  27#include <linux/jiffies.h>
  28#include <linux/platform_device.h>
  29#include <linux/of.h>
  30
  31#include "omapdss.h"
  32#include "dss.h"
  33#include "dss_features.h"
  34
  35void omapdss_default_get_resolution(struct omap_dss_device *dssdev,
  36                        u16 *xres, u16 *yres)
  37{
  38        *xres = dssdev->panel.timings.x_res;
  39        *yres = dssdev->panel.timings.y_res;
  40}
  41EXPORT_SYMBOL(omapdss_default_get_resolution);
  42
  43int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev)
  44{
  45        switch (dssdev->type) {
  46        case OMAP_DISPLAY_TYPE_DPI:
  47                if (dssdev->phy.dpi.data_lines == 24)
  48                        return 24;
  49                else
  50                        return 16;
  51
  52        case OMAP_DISPLAY_TYPE_DBI:
  53                if (dssdev->ctrl.pixel_size == 24)
  54                        return 24;
  55                else
  56                        return 16;
  57        case OMAP_DISPLAY_TYPE_DSI:
  58                if (dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) > 16)
  59                        return 24;
  60                else
  61                        return 16;
  62        case OMAP_DISPLAY_TYPE_VENC:
  63        case OMAP_DISPLAY_TYPE_SDI:
  64        case OMAP_DISPLAY_TYPE_HDMI:
  65        case OMAP_DISPLAY_TYPE_DVI:
  66                return 24;
  67        default:
  68                BUG();
  69                return 0;
  70        }
  71}
  72EXPORT_SYMBOL(omapdss_default_get_recommended_bpp);
  73
  74void omapdss_default_get_timings(struct omap_dss_device *dssdev,
  75                struct omap_video_timings *timings)
  76{
  77        *timings = dssdev->panel.timings;
  78}
  79EXPORT_SYMBOL(omapdss_default_get_timings);
  80
  81static LIST_HEAD(panel_list);
  82static DEFINE_MUTEX(panel_list_mutex);
  83static int disp_num_counter;
  84
  85int omapdss_register_display(struct omap_dss_device *dssdev)
  86{
  87        struct omap_dss_driver *drv = dssdev->driver;
  88        int id;
  89
  90        /*
  91         * Note: this presumes all the displays are either using DT or non-DT,
  92         * which normally should be the case. This also presumes that all
  93         * displays either have an DT alias, or none has.
  94         */
  95
  96        if (dssdev->dev->of_node) {
  97                id = of_alias_get_id(dssdev->dev->of_node, "display");
  98
  99                if (id < 0)
 100                        id = disp_num_counter++;
 101        } else {
 102                id = disp_num_counter++;
 103        }
 104
 105        snprintf(dssdev->alias, sizeof(dssdev->alias), "display%d", id);
 106
 107        /* Use 'label' property for name, if it exists */
 108        if (dssdev->dev->of_node)
 109                of_property_read_string(dssdev->dev->of_node, "label",
 110                        &dssdev->name);
 111
 112        if (dssdev->name == NULL)
 113                dssdev->name = dssdev->alias;
 114
 115        if (drv && drv->get_resolution == NULL)
 116                drv->get_resolution = omapdss_default_get_resolution;
 117        if (drv && drv->get_recommended_bpp == NULL)
 118                drv->get_recommended_bpp = omapdss_default_get_recommended_bpp;
 119        if (drv && drv->get_timings == NULL)
 120                drv->get_timings = omapdss_default_get_timings;
 121
 122        mutex_lock(&panel_list_mutex);
 123        list_add_tail(&dssdev->panel_list, &panel_list);
 124        mutex_unlock(&panel_list_mutex);
 125        return 0;
 126}
 127EXPORT_SYMBOL(omapdss_register_display);
 128
 129void omapdss_unregister_display(struct omap_dss_device *dssdev)
 130{
 131        mutex_lock(&panel_list_mutex);
 132        list_del(&dssdev->panel_list);
 133        mutex_unlock(&panel_list_mutex);
 134}
 135EXPORT_SYMBOL(omapdss_unregister_display);
 136
 137struct omap_dss_device *omap_dss_get_device(struct omap_dss_device *dssdev)
 138{
 139        if (!try_module_get(dssdev->owner))
 140                return NULL;
 141
 142        if (get_device(dssdev->dev) == NULL) {
 143                module_put(dssdev->owner);
 144                return NULL;
 145        }
 146
 147        return dssdev;
 148}
 149EXPORT_SYMBOL(omap_dss_get_device);
 150
 151void omap_dss_put_device(struct omap_dss_device *dssdev)
 152{
 153        put_device(dssdev->dev);
 154        module_put(dssdev->owner);
 155}
 156EXPORT_SYMBOL(omap_dss_put_device);
 157
 158/*
 159 * ref count of the found device is incremented.
 160 * ref count of from-device is decremented.
 161 */
 162struct omap_dss_device *omap_dss_get_next_device(struct omap_dss_device *from)
 163{
 164        struct list_head *l;
 165        struct omap_dss_device *dssdev;
 166
 167        mutex_lock(&panel_list_mutex);
 168
 169        if (list_empty(&panel_list)) {
 170                dssdev = NULL;
 171                goto out;
 172        }
 173
 174        if (from == NULL) {
 175                dssdev = list_first_entry(&panel_list, struct omap_dss_device,
 176                                panel_list);
 177                omap_dss_get_device(dssdev);
 178                goto out;
 179        }
 180
 181        omap_dss_put_device(from);
 182
 183        list_for_each(l, &panel_list) {
 184                dssdev = list_entry(l, struct omap_dss_device, panel_list);
 185                if (dssdev == from) {
 186                        if (list_is_last(l, &panel_list)) {
 187                                dssdev = NULL;
 188                                goto out;
 189                        }
 190
 191                        dssdev = list_entry(l->next, struct omap_dss_device,
 192                                        panel_list);
 193                        omap_dss_get_device(dssdev);
 194                        goto out;
 195                }
 196        }
 197
 198        WARN(1, "'from' dssdev not found\n");
 199
 200        dssdev = NULL;
 201out:
 202        mutex_unlock(&panel_list_mutex);
 203        return dssdev;
 204}
 205EXPORT_SYMBOL(omap_dss_get_next_device);
 206
 207struct omap_dss_device *omap_dss_find_device(void *data,
 208                int (*match)(struct omap_dss_device *dssdev, void *data))
 209{
 210        struct omap_dss_device *dssdev = NULL;
 211
 212        while ((dssdev = omap_dss_get_next_device(dssdev)) != NULL) {
 213                if (match(dssdev, data))
 214                        return dssdev;
 215        }
 216
 217        return NULL;
 218}
 219EXPORT_SYMBOL(omap_dss_find_device);
 220
 221void videomode_to_omap_video_timings(const struct videomode *vm,
 222                struct omap_video_timings *ovt)
 223{
 224        memset(ovt, 0, sizeof(*ovt));
 225
 226        ovt->pixelclock = vm->pixelclock;
 227        ovt->x_res = vm->hactive;
 228        ovt->hbp = vm->hback_porch;
 229        ovt->hfp = vm->hfront_porch;
 230        ovt->hsw = vm->hsync_len;
 231        ovt->y_res = vm->vactive;
 232        ovt->vbp = vm->vback_porch;
 233        ovt->vfp = vm->vfront_porch;
 234        ovt->vsw = vm->vsync_len;
 235
 236        ovt->vsync_level = vm->flags & DISPLAY_FLAGS_VSYNC_HIGH ?
 237                OMAPDSS_SIG_ACTIVE_HIGH :
 238                OMAPDSS_SIG_ACTIVE_LOW;
 239        ovt->hsync_level = vm->flags & DISPLAY_FLAGS_HSYNC_HIGH ?
 240                OMAPDSS_SIG_ACTIVE_HIGH :
 241                OMAPDSS_SIG_ACTIVE_LOW;
 242        ovt->de_level = vm->flags & DISPLAY_FLAGS_DE_HIGH ?
 243                OMAPDSS_SIG_ACTIVE_HIGH :
 244                OMAPDSS_SIG_ACTIVE_LOW;
 245        ovt->data_pclk_edge = vm->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE ?
 246                OMAPDSS_DRIVE_SIG_RISING_EDGE :
 247                OMAPDSS_DRIVE_SIG_FALLING_EDGE;
 248
 249        ovt->sync_pclk_edge = ovt->data_pclk_edge;
 250}
 251EXPORT_SYMBOL(videomode_to_omap_video_timings);
 252
 253void omap_video_timings_to_videomode(const struct omap_video_timings *ovt,
 254                struct videomode *vm)
 255{
 256        memset(vm, 0, sizeof(*vm));
 257
 258        vm->pixelclock = ovt->pixelclock;
 259
 260        vm->hactive = ovt->x_res;
 261        vm->hback_porch = ovt->hbp;
 262        vm->hfront_porch = ovt->hfp;
 263        vm->hsync_len = ovt->hsw;
 264        vm->vactive = ovt->y_res;
 265        vm->vback_porch = ovt->vbp;
 266        vm->vfront_porch = ovt->vfp;
 267        vm->vsync_len = ovt->vsw;
 268
 269        if (ovt->hsync_level == OMAPDSS_SIG_ACTIVE_HIGH)
 270                vm->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
 271        else
 272                vm->flags |= DISPLAY_FLAGS_HSYNC_LOW;
 273
 274        if (ovt->vsync_level == OMAPDSS_SIG_ACTIVE_HIGH)
 275                vm->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
 276        else
 277                vm->flags |= DISPLAY_FLAGS_VSYNC_LOW;
 278
 279        if (ovt->de_level == OMAPDSS_SIG_ACTIVE_HIGH)
 280                vm->flags |= DISPLAY_FLAGS_DE_HIGH;
 281        else
 282                vm->flags |= DISPLAY_FLAGS_DE_LOW;
 283
 284        if (ovt->data_pclk_edge == OMAPDSS_DRIVE_SIG_RISING_EDGE)
 285                vm->flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE;
 286        else
 287                vm->flags |= DISPLAY_FLAGS_PIXDATA_NEGEDGE;
 288}
 289EXPORT_SYMBOL(omap_video_timings_to_videomode);
 290