linux/drivers/video/fbdev/omap2/omapfb/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 <video/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
  81int dss_suspend_all_devices(void)
  82{
  83        struct omap_dss_device *dssdev = NULL;
  84
  85        for_each_dss_dev(dssdev) {
  86                if (!dssdev->driver)
  87                        continue;
  88
  89                if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
  90                        dssdev->driver->disable(dssdev);
  91                        dssdev->activate_after_resume = true;
  92                } else {
  93                        dssdev->activate_after_resume = false;
  94                }
  95        }
  96
  97        return 0;
  98}
  99
 100int dss_resume_all_devices(void)
 101{
 102        struct omap_dss_device *dssdev = NULL;
 103
 104        for_each_dss_dev(dssdev) {
 105                if (!dssdev->driver)
 106                        continue;
 107
 108                if (dssdev->activate_after_resume) {
 109                        dssdev->driver->enable(dssdev);
 110                        dssdev->activate_after_resume = false;
 111                }
 112        }
 113
 114        return 0;
 115}
 116
 117void dss_disable_all_devices(void)
 118{
 119        struct omap_dss_device *dssdev = NULL;
 120
 121        for_each_dss_dev(dssdev) {
 122                if (!dssdev->driver)
 123                        continue;
 124
 125                if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
 126                        dssdev->driver->disable(dssdev);
 127        }
 128}
 129
 130static LIST_HEAD(panel_list);
 131static DEFINE_MUTEX(panel_list_mutex);
 132static int disp_num_counter;
 133
 134int omapdss_register_display(struct omap_dss_device *dssdev)
 135{
 136        struct omap_dss_driver *drv = dssdev->driver;
 137        int id;
 138
 139        /*
 140         * Note: this presumes all the displays are either using DT or non-DT,
 141         * which normally should be the case. This also presumes that all
 142         * displays either have an DT alias, or none has.
 143         */
 144
 145        if (dssdev->dev->of_node) {
 146                id = of_alias_get_id(dssdev->dev->of_node, "display");
 147
 148                if (id < 0)
 149                        id = disp_num_counter++;
 150        } else {
 151                id = disp_num_counter++;
 152        }
 153
 154        snprintf(dssdev->alias, sizeof(dssdev->alias), "display%d", id);
 155
 156        /* Use 'label' property for name, if it exists */
 157        if (dssdev->dev->of_node)
 158                of_property_read_string(dssdev->dev->of_node, "label",
 159                        &dssdev->name);
 160
 161        if (dssdev->name == NULL)
 162                dssdev->name = dssdev->alias;
 163
 164        if (drv && drv->get_resolution == NULL)
 165                drv->get_resolution = omapdss_default_get_resolution;
 166        if (drv && drv->get_recommended_bpp == NULL)
 167                drv->get_recommended_bpp = omapdss_default_get_recommended_bpp;
 168        if (drv && drv->get_timings == NULL)
 169                drv->get_timings = omapdss_default_get_timings;
 170
 171        mutex_lock(&panel_list_mutex);
 172        list_add_tail(&dssdev->panel_list, &panel_list);
 173        mutex_unlock(&panel_list_mutex);
 174        return 0;
 175}
 176EXPORT_SYMBOL(omapdss_register_display);
 177
 178void omapdss_unregister_display(struct omap_dss_device *dssdev)
 179{
 180        mutex_lock(&panel_list_mutex);
 181        list_del(&dssdev->panel_list);
 182        mutex_unlock(&panel_list_mutex);
 183}
 184EXPORT_SYMBOL(omapdss_unregister_display);
 185
 186struct omap_dss_device *omap_dss_get_device(struct omap_dss_device *dssdev)
 187{
 188        if (!try_module_get(dssdev->owner))
 189                return NULL;
 190
 191        if (get_device(dssdev->dev) == NULL) {
 192                module_put(dssdev->owner);
 193                return NULL;
 194        }
 195
 196        return dssdev;
 197}
 198EXPORT_SYMBOL(omap_dss_get_device);
 199
 200void omap_dss_put_device(struct omap_dss_device *dssdev)
 201{
 202        put_device(dssdev->dev);
 203        module_put(dssdev->owner);
 204}
 205EXPORT_SYMBOL(omap_dss_put_device);
 206
 207/*
 208 * ref count of the found device is incremented.
 209 * ref count of from-device is decremented.
 210 */
 211struct omap_dss_device *omap_dss_get_next_device(struct omap_dss_device *from)
 212{
 213        struct list_head *l;
 214        struct omap_dss_device *dssdev;
 215
 216        mutex_lock(&panel_list_mutex);
 217
 218        if (list_empty(&panel_list)) {
 219                dssdev = NULL;
 220                goto out;
 221        }
 222
 223        if (from == NULL) {
 224                dssdev = list_first_entry(&panel_list, struct omap_dss_device,
 225                                panel_list);
 226                omap_dss_get_device(dssdev);
 227                goto out;
 228        }
 229
 230        omap_dss_put_device(from);
 231
 232        list_for_each(l, &panel_list) {
 233                dssdev = list_entry(l, struct omap_dss_device, panel_list);
 234                if (dssdev == from) {
 235                        if (list_is_last(l, &panel_list)) {
 236                                dssdev = NULL;
 237                                goto out;
 238                        }
 239
 240                        dssdev = list_entry(l->next, struct omap_dss_device,
 241                                        panel_list);
 242                        omap_dss_get_device(dssdev);
 243                        goto out;
 244                }
 245        }
 246
 247        WARN(1, "'from' dssdev not found\n");
 248
 249        dssdev = NULL;
 250out:
 251        mutex_unlock(&panel_list_mutex);
 252        return dssdev;
 253}
 254EXPORT_SYMBOL(omap_dss_get_next_device);
 255
 256struct omap_dss_device *omap_dss_find_device(void *data,
 257                int (*match)(struct omap_dss_device *dssdev, void *data))
 258{
 259        struct omap_dss_device *dssdev = NULL;
 260
 261        while ((dssdev = omap_dss_get_next_device(dssdev)) != NULL) {
 262                if (match(dssdev, data))
 263                        return dssdev;
 264        }
 265
 266        return NULL;
 267}
 268EXPORT_SYMBOL(omap_dss_find_device);
 269
 270void videomode_to_omap_video_timings(const struct videomode *vm,
 271                struct omap_video_timings *ovt)
 272{
 273        memset(ovt, 0, sizeof(*ovt));
 274
 275        ovt->pixelclock = vm->pixelclock;
 276        ovt->x_res = vm->hactive;
 277        ovt->hbp = vm->hback_porch;
 278        ovt->hfp = vm->hfront_porch;
 279        ovt->hsw = vm->hsync_len;
 280        ovt->y_res = vm->vactive;
 281        ovt->vbp = vm->vback_porch;
 282        ovt->vfp = vm->vfront_porch;
 283        ovt->vsw = vm->vsync_len;
 284
 285        ovt->vsync_level = vm->flags & DISPLAY_FLAGS_VSYNC_HIGH ?
 286                OMAPDSS_SIG_ACTIVE_HIGH :
 287                OMAPDSS_SIG_ACTIVE_LOW;
 288        ovt->hsync_level = vm->flags & DISPLAY_FLAGS_HSYNC_HIGH ?
 289                OMAPDSS_SIG_ACTIVE_HIGH :
 290                OMAPDSS_SIG_ACTIVE_LOW;
 291        ovt->de_level = vm->flags & DISPLAY_FLAGS_DE_HIGH ?
 292                OMAPDSS_SIG_ACTIVE_HIGH :
 293                OMAPDSS_SIG_ACTIVE_LOW;
 294        ovt->data_pclk_edge = vm->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE ?
 295                OMAPDSS_DRIVE_SIG_RISING_EDGE :
 296                OMAPDSS_DRIVE_SIG_FALLING_EDGE;
 297
 298        ovt->sync_pclk_edge = ovt->data_pclk_edge;
 299}
 300EXPORT_SYMBOL(videomode_to_omap_video_timings);
 301
 302void omap_video_timings_to_videomode(const struct omap_video_timings *ovt,
 303                struct videomode *vm)
 304{
 305        memset(vm, 0, sizeof(*vm));
 306
 307        vm->pixelclock = ovt->pixelclock;
 308
 309        vm->hactive = ovt->x_res;
 310        vm->hback_porch = ovt->hbp;
 311        vm->hfront_porch = ovt->hfp;
 312        vm->hsync_len = ovt->hsw;
 313        vm->vactive = ovt->y_res;
 314        vm->vback_porch = ovt->vbp;
 315        vm->vfront_porch = ovt->vfp;
 316        vm->vsync_len = ovt->vsw;
 317
 318        if (ovt->hsync_level == OMAPDSS_SIG_ACTIVE_HIGH)
 319                vm->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
 320        else
 321                vm->flags |= DISPLAY_FLAGS_HSYNC_LOW;
 322
 323        if (ovt->vsync_level == OMAPDSS_SIG_ACTIVE_HIGH)
 324                vm->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
 325        else
 326                vm->flags |= DISPLAY_FLAGS_VSYNC_LOW;
 327
 328        if (ovt->de_level == OMAPDSS_SIG_ACTIVE_HIGH)
 329                vm->flags |= DISPLAY_FLAGS_DE_HIGH;
 330        else
 331                vm->flags |= DISPLAY_FLAGS_DE_LOW;
 332
 333        if (ovt->data_pclk_edge == OMAPDSS_DRIVE_SIG_RISING_EDGE)
 334                vm->flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE;
 335        else
 336                vm->flags |= DISPLAY_FLAGS_PIXDATA_NEGEDGE;
 337}
 338EXPORT_SYMBOL(omap_video_timings_to_videomode);
 339