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