linux/drivers/video/omap2/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
  30#include <video/omapdss.h>
  31#include "dss.h"
  32#include "dss_features.h"
  33
  34static ssize_t display_enabled_show(struct device *dev,
  35                struct device_attribute *attr, char *buf)
  36{
  37        struct omap_dss_device *dssdev = to_dss_device(dev);
  38        bool enabled = dssdev->state != OMAP_DSS_DISPLAY_DISABLED;
  39
  40        return snprintf(buf, PAGE_SIZE, "%d\n", enabled);
  41}
  42
  43static ssize_t display_enabled_store(struct device *dev,
  44                struct device_attribute *attr,
  45                const char *buf, size_t size)
  46{
  47        struct omap_dss_device *dssdev = to_dss_device(dev);
  48        int r;
  49        bool enabled;
  50
  51        r = strtobool(buf, &enabled);
  52        if (r)
  53                return r;
  54
  55        if (enabled != (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)) {
  56                if (enabled) {
  57                        r = dssdev->driver->enable(dssdev);
  58                        if (r)
  59                                return r;
  60                } else {
  61                        dssdev->driver->disable(dssdev);
  62                }
  63        }
  64
  65        return size;
  66}
  67
  68static ssize_t display_tear_show(struct device *dev,
  69                struct device_attribute *attr, char *buf)
  70{
  71        struct omap_dss_device *dssdev = to_dss_device(dev);
  72        return snprintf(buf, PAGE_SIZE, "%d\n",
  73                        dssdev->driver->get_te ?
  74                        dssdev->driver->get_te(dssdev) : 0);
  75}
  76
  77static ssize_t display_tear_store(struct device *dev,
  78                struct device_attribute *attr, const char *buf, size_t size)
  79{
  80        struct omap_dss_device *dssdev = to_dss_device(dev);
  81        int r;
  82        bool te;
  83
  84        if (!dssdev->driver->enable_te || !dssdev->driver->get_te)
  85                return -ENOENT;
  86
  87        r = strtobool(buf, &te);
  88        if (r)
  89                return r;
  90
  91        r = dssdev->driver->enable_te(dssdev, te);
  92        if (r)
  93                return r;
  94
  95        return size;
  96}
  97
  98static ssize_t display_timings_show(struct device *dev,
  99                struct device_attribute *attr, char *buf)
 100{
 101        struct omap_dss_device *dssdev = to_dss_device(dev);
 102        struct omap_video_timings t;
 103
 104        if (!dssdev->driver->get_timings)
 105                return -ENOENT;
 106
 107        dssdev->driver->get_timings(dssdev, &t);
 108
 109        return snprintf(buf, PAGE_SIZE, "%u,%u/%u/%u/%u,%u/%u/%u/%u\n",
 110                        t.pixel_clock,
 111                        t.x_res, t.hfp, t.hbp, t.hsw,
 112                        t.y_res, t.vfp, t.vbp, t.vsw);
 113}
 114
 115static ssize_t display_timings_store(struct device *dev,
 116                struct device_attribute *attr, const char *buf, size_t size)
 117{
 118        struct omap_dss_device *dssdev = to_dss_device(dev);
 119        struct omap_video_timings t;
 120        int r, found;
 121
 122        if (!dssdev->driver->set_timings || !dssdev->driver->check_timings)
 123                return -ENOENT;
 124
 125        found = 0;
 126#ifdef CONFIG_OMAP2_DSS_VENC
 127        if (strncmp("pal", buf, 3) == 0) {
 128                t = omap_dss_pal_timings;
 129                found = 1;
 130        } else if (strncmp("ntsc", buf, 4) == 0) {
 131                t = omap_dss_ntsc_timings;
 132                found = 1;
 133        }
 134#endif
 135        if (!found && sscanf(buf, "%u,%hu/%hu/%hu/%hu,%hu/%hu/%hu/%hu",
 136                                &t.pixel_clock,
 137                                &t.x_res, &t.hfp, &t.hbp, &t.hsw,
 138                                &t.y_res, &t.vfp, &t.vbp, &t.vsw) != 9)
 139                return -EINVAL;
 140
 141        r = dssdev->driver->check_timings(dssdev, &t);
 142        if (r)
 143                return r;
 144
 145        dssdev->driver->set_timings(dssdev, &t);
 146
 147        return size;
 148}
 149
 150static ssize_t display_rotate_show(struct device *dev,
 151                struct device_attribute *attr, char *buf)
 152{
 153        struct omap_dss_device *dssdev = to_dss_device(dev);
 154        int rotate;
 155        if (!dssdev->driver->get_rotate)
 156                return -ENOENT;
 157        rotate = dssdev->driver->get_rotate(dssdev);
 158        return snprintf(buf, PAGE_SIZE, "%u\n", rotate);
 159}
 160
 161static ssize_t display_rotate_store(struct device *dev,
 162                struct device_attribute *attr, const char *buf, size_t size)
 163{
 164        struct omap_dss_device *dssdev = to_dss_device(dev);
 165        int rot, r;
 166
 167        if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate)
 168                return -ENOENT;
 169
 170        r = kstrtoint(buf, 0, &rot);
 171        if (r)
 172                return r;
 173
 174        r = dssdev->driver->set_rotate(dssdev, rot);
 175        if (r)
 176                return r;
 177
 178        return size;
 179}
 180
 181static ssize_t display_mirror_show(struct device *dev,
 182                struct device_attribute *attr, char *buf)
 183{
 184        struct omap_dss_device *dssdev = to_dss_device(dev);
 185        int mirror;
 186        if (!dssdev->driver->get_mirror)
 187                return -ENOENT;
 188        mirror = dssdev->driver->get_mirror(dssdev);
 189        return snprintf(buf, PAGE_SIZE, "%u\n", mirror);
 190}
 191
 192static ssize_t display_mirror_store(struct device *dev,
 193                struct device_attribute *attr, const char *buf, size_t size)
 194{
 195        struct omap_dss_device *dssdev = to_dss_device(dev);
 196        int r;
 197        bool mirror;
 198
 199        if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror)
 200                return -ENOENT;
 201
 202        r = strtobool(buf, &mirror);
 203        if (r)
 204                return r;
 205
 206        r = dssdev->driver->set_mirror(dssdev, mirror);
 207        if (r)
 208                return r;
 209
 210        return size;
 211}
 212
 213static ssize_t display_wss_show(struct device *dev,
 214                struct device_attribute *attr, char *buf)
 215{
 216        struct omap_dss_device *dssdev = to_dss_device(dev);
 217        unsigned int wss;
 218
 219        if (!dssdev->driver->get_wss)
 220                return -ENOENT;
 221
 222        wss = dssdev->driver->get_wss(dssdev);
 223
 224        return snprintf(buf, PAGE_SIZE, "0x%05x\n", wss);
 225}
 226
 227static ssize_t display_wss_store(struct device *dev,
 228                struct device_attribute *attr, const char *buf, size_t size)
 229{
 230        struct omap_dss_device *dssdev = to_dss_device(dev);
 231        u32 wss;
 232        int r;
 233
 234        if (!dssdev->driver->get_wss || !dssdev->driver->set_wss)
 235                return -ENOENT;
 236
 237        r = kstrtou32(buf, 0, &wss);
 238        if (r)
 239                return r;
 240
 241        if (wss > 0xfffff)
 242                return -EINVAL;
 243
 244        r = dssdev->driver->set_wss(dssdev, wss);
 245        if (r)
 246                return r;
 247
 248        return size;
 249}
 250
 251static DEVICE_ATTR(enabled, S_IRUGO|S_IWUSR,
 252                display_enabled_show, display_enabled_store);
 253static DEVICE_ATTR(tear_elim, S_IRUGO|S_IWUSR,
 254                display_tear_show, display_tear_store);
 255static DEVICE_ATTR(timings, S_IRUGO|S_IWUSR,
 256                display_timings_show, display_timings_store);
 257static DEVICE_ATTR(rotate, S_IRUGO|S_IWUSR,
 258                display_rotate_show, display_rotate_store);
 259static DEVICE_ATTR(mirror, S_IRUGO|S_IWUSR,
 260                display_mirror_show, display_mirror_store);
 261static DEVICE_ATTR(wss, S_IRUGO|S_IWUSR,
 262                display_wss_show, display_wss_store);
 263
 264static struct device_attribute *display_sysfs_attrs[] = {
 265        &dev_attr_enabled,
 266        &dev_attr_tear_elim,
 267        &dev_attr_timings,
 268        &dev_attr_rotate,
 269        &dev_attr_mirror,
 270        &dev_attr_wss,
 271        NULL
 272};
 273
 274void omapdss_default_get_resolution(struct omap_dss_device *dssdev,
 275                        u16 *xres, u16 *yres)
 276{
 277        *xres = dssdev->panel.timings.x_res;
 278        *yres = dssdev->panel.timings.y_res;
 279}
 280EXPORT_SYMBOL(omapdss_default_get_resolution);
 281
 282void default_get_overlay_fifo_thresholds(enum omap_plane plane,
 283                u32 fifo_size, u32 burst_size,
 284                u32 *fifo_low, u32 *fifo_high)
 285{
 286        unsigned buf_unit = dss_feat_get_buffer_size_unit();
 287
 288        *fifo_high = fifo_size - buf_unit;
 289        *fifo_low = fifo_size - burst_size;
 290}
 291
 292int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev)
 293{
 294        switch (dssdev->type) {
 295        case OMAP_DISPLAY_TYPE_DPI:
 296                if (dssdev->phy.dpi.data_lines == 24)
 297                        return 24;
 298                else
 299                        return 16;
 300
 301        case OMAP_DISPLAY_TYPE_DBI:
 302                if (dssdev->ctrl.pixel_size == 24)
 303                        return 24;
 304                else
 305                        return 16;
 306        case OMAP_DISPLAY_TYPE_DSI:
 307                if (dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) > 16)
 308                        return 24;
 309                else
 310                        return 16;
 311        case OMAP_DISPLAY_TYPE_VENC:
 312        case OMAP_DISPLAY_TYPE_SDI:
 313        case OMAP_DISPLAY_TYPE_HDMI:
 314                return 24;
 315        default:
 316                BUG();
 317        }
 318}
 319EXPORT_SYMBOL(omapdss_default_get_recommended_bpp);
 320
 321/* Checks if replication logic should be used. Only use for active matrix,
 322 * when overlay is in RGB12U or RGB16 mode, and LCD interface is
 323 * 18bpp or 24bpp */
 324bool dss_use_replication(struct omap_dss_device *dssdev,
 325                enum omap_color_mode mode)
 326{
 327        int bpp;
 328
 329        if (mode != OMAP_DSS_COLOR_RGB12U && mode != OMAP_DSS_COLOR_RGB16)
 330                return false;
 331
 332        if (dssdev->type == OMAP_DISPLAY_TYPE_DPI &&
 333                        (dssdev->panel.config & OMAP_DSS_LCD_TFT) == 0)
 334                return false;
 335
 336        switch (dssdev->type) {
 337        case OMAP_DISPLAY_TYPE_DPI:
 338                bpp = dssdev->phy.dpi.data_lines;
 339                break;
 340        case OMAP_DISPLAY_TYPE_HDMI:
 341        case OMAP_DISPLAY_TYPE_VENC:
 342        case OMAP_DISPLAY_TYPE_SDI:
 343                bpp = 24;
 344                break;
 345        case OMAP_DISPLAY_TYPE_DBI:
 346                bpp = dssdev->ctrl.pixel_size;
 347                break;
 348        case OMAP_DISPLAY_TYPE_DSI:
 349                bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt);
 350                break;
 351        default:
 352                BUG();
 353        }
 354
 355        return bpp > 16;
 356}
 357
 358void dss_init_device(struct platform_device *pdev,
 359                struct omap_dss_device *dssdev)
 360{
 361        struct device_attribute *attr;
 362        int i;
 363        int r;
 364
 365        switch (dssdev->type) {
 366#ifdef CONFIG_OMAP2_DSS_DPI
 367        case OMAP_DISPLAY_TYPE_DPI:
 368                r = dpi_init_display(dssdev);
 369                break;
 370#endif
 371#ifdef CONFIG_OMAP2_DSS_RFBI
 372        case OMAP_DISPLAY_TYPE_DBI:
 373                r = rfbi_init_display(dssdev);
 374                break;
 375#endif
 376#ifdef CONFIG_OMAP2_DSS_VENC
 377        case OMAP_DISPLAY_TYPE_VENC:
 378                r = venc_init_display(dssdev);
 379                break;
 380#endif
 381#ifdef CONFIG_OMAP2_DSS_SDI
 382        case OMAP_DISPLAY_TYPE_SDI:
 383                r = sdi_init_display(dssdev);
 384                break;
 385#endif
 386#ifdef CONFIG_OMAP2_DSS_DSI
 387        case OMAP_DISPLAY_TYPE_DSI:
 388                r = dsi_init_display(dssdev);
 389                break;
 390#endif
 391        case OMAP_DISPLAY_TYPE_HDMI:
 392                r = hdmi_init_display(dssdev);
 393                break;
 394        default:
 395                DSSERR("Support for display '%s' not compiled in.\n",
 396                                dssdev->name);
 397                return;
 398        }
 399
 400        if (r) {
 401                DSSERR("failed to init display %s\n", dssdev->name);
 402                return;
 403        }
 404
 405        /* create device sysfs files */
 406        i = 0;
 407        while ((attr = display_sysfs_attrs[i++]) != NULL) {
 408                r = device_create_file(&dssdev->dev, attr);
 409                if (r)
 410                        DSSERR("failed to create sysfs file\n");
 411        }
 412
 413        /* create display? sysfs links */
 414        r = sysfs_create_link(&pdev->dev.kobj, &dssdev->dev.kobj,
 415                        dev_name(&dssdev->dev));
 416        if (r)
 417                DSSERR("failed to create sysfs display link\n");
 418}
 419
 420void dss_uninit_device(struct platform_device *pdev,
 421                struct omap_dss_device *dssdev)
 422{
 423        struct device_attribute *attr;
 424        int i = 0;
 425
 426        sysfs_remove_link(&pdev->dev.kobj, dev_name(&dssdev->dev));
 427
 428        while ((attr = display_sysfs_attrs[i++]) != NULL)
 429                device_remove_file(&dssdev->dev, attr);
 430
 431        if (dssdev->manager)
 432                dssdev->manager->unset_device(dssdev->manager);
 433}
 434
 435static int dss_suspend_device(struct device *dev, void *data)
 436{
 437        int r;
 438        struct omap_dss_device *dssdev = to_dss_device(dev);
 439
 440        if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
 441                dssdev->activate_after_resume = false;
 442                return 0;
 443        }
 444
 445        if (!dssdev->driver->suspend) {
 446                DSSERR("display '%s' doesn't implement suspend\n",
 447                                dssdev->name);
 448                return -ENOSYS;
 449        }
 450
 451        r = dssdev->driver->suspend(dssdev);
 452        if (r)
 453                return r;
 454
 455        dssdev->activate_after_resume = true;
 456
 457        return 0;
 458}
 459
 460int dss_suspend_all_devices(void)
 461{
 462        int r;
 463        struct bus_type *bus = dss_get_bus();
 464
 465        r = bus_for_each_dev(bus, NULL, NULL, dss_suspend_device);
 466        if (r) {
 467                /* resume all displays that were suspended */
 468                dss_resume_all_devices();
 469                return r;
 470        }
 471
 472        return 0;
 473}
 474
 475static int dss_resume_device(struct device *dev, void *data)
 476{
 477        int r;
 478        struct omap_dss_device *dssdev = to_dss_device(dev);
 479
 480        if (dssdev->activate_after_resume && dssdev->driver->resume) {
 481                r = dssdev->driver->resume(dssdev);
 482                if (r)
 483                        return r;
 484        }
 485
 486        dssdev->activate_after_resume = false;
 487
 488        return 0;
 489}
 490
 491int dss_resume_all_devices(void)
 492{
 493        struct bus_type *bus = dss_get_bus();
 494
 495        return bus_for_each_dev(bus, NULL, NULL, dss_resume_device);
 496}
 497
 498static int dss_disable_device(struct device *dev, void *data)
 499{
 500        struct omap_dss_device *dssdev = to_dss_device(dev);
 501
 502        if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)
 503                dssdev->driver->disable(dssdev);
 504
 505        return 0;
 506}
 507
 508void dss_disable_all_devices(void)
 509{
 510        struct bus_type *bus = dss_get_bus();
 511        bus_for_each_dev(bus, NULL, NULL, dss_disable_device);
 512}
 513
 514
 515void omap_dss_get_device(struct omap_dss_device *dssdev)
 516{
 517        get_device(&dssdev->dev);
 518}
 519EXPORT_SYMBOL(omap_dss_get_device);
 520
 521void omap_dss_put_device(struct omap_dss_device *dssdev)
 522{
 523        put_device(&dssdev->dev);
 524}
 525EXPORT_SYMBOL(omap_dss_put_device);
 526
 527/* ref count of the found device is incremented. ref count
 528 * of from-device is decremented. */
 529struct omap_dss_device *omap_dss_get_next_device(struct omap_dss_device *from)
 530{
 531        struct device *dev;
 532        struct device *dev_start = NULL;
 533        struct omap_dss_device *dssdev = NULL;
 534
 535        int match(struct device *dev, void *data)
 536        {
 537                return 1;
 538        }
 539
 540        if (from)
 541                dev_start = &from->dev;
 542        dev = bus_find_device(dss_get_bus(), dev_start, NULL, match);
 543        if (dev)
 544                dssdev = to_dss_device(dev);
 545        if (from)
 546                put_device(&from->dev);
 547
 548        return dssdev;
 549}
 550EXPORT_SYMBOL(omap_dss_get_next_device);
 551
 552struct omap_dss_device *omap_dss_find_device(void *data,
 553                int (*match)(struct omap_dss_device *dssdev, void *data))
 554{
 555        struct omap_dss_device *dssdev = NULL;
 556
 557        while ((dssdev = omap_dss_get_next_device(dssdev)) != NULL) {
 558                if (match(dssdev, data))
 559                        return dssdev;
 560        }
 561
 562        return NULL;
 563}
 564EXPORT_SYMBOL(omap_dss_find_device);
 565
 566int omap_dss_start_device(struct omap_dss_device *dssdev)
 567{
 568        if (!dssdev->driver) {
 569                DSSDBG("no driver\n");
 570                return -ENODEV;
 571        }
 572
 573        if (!try_module_get(dssdev->dev.driver->owner)) {
 574                return -ENODEV;
 575        }
 576
 577        return 0;
 578}
 579EXPORT_SYMBOL(omap_dss_start_device);
 580
 581void omap_dss_stop_device(struct omap_dss_device *dssdev)
 582{
 583        module_put(dssdev->dev.driver->owner);
 584}
 585EXPORT_SYMBOL(omap_dss_stop_device);
 586
 587