Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.7-rc7 671 lines 14 kB view raw
1/* 2 * linux/drivers/video/omap2/dss/core.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 "CORE" 24 25#include <linux/kernel.h> 26#include <linux/module.h> 27#include <linux/clk.h> 28#include <linux/err.h> 29#include <linux/platform_device.h> 30#include <linux/seq_file.h> 31#include <linux/debugfs.h> 32#include <linux/io.h> 33#include <linux/device.h> 34#include <linux/regulator/consumer.h> 35#include <linux/suspend.h> 36#include <linux/slab.h> 37 38#include <video/omapdss.h> 39 40#include "dss.h" 41#include "dss_features.h" 42 43static struct { 44 struct platform_device *pdev; 45 46 struct regulator *vdds_dsi_reg; 47 struct regulator *vdds_sdi_reg; 48 49 const char *default_display_name; 50} core; 51 52static char *def_disp_name; 53module_param_named(def_disp, def_disp_name, charp, 0); 54MODULE_PARM_DESC(def_disp, "default display name"); 55 56#ifdef DEBUG 57bool dss_debug; 58module_param_named(debug, dss_debug, bool, 0644); 59#endif 60 61const char *dss_get_default_display_name(void) 62{ 63 return core.default_display_name; 64} 65 66/* REGULATORS */ 67 68struct regulator *dss_get_vdds_dsi(void) 69{ 70 struct regulator *reg; 71 72 if (core.vdds_dsi_reg != NULL) 73 return core.vdds_dsi_reg; 74 75 reg = regulator_get(&core.pdev->dev, "vdds_dsi"); 76 if (!IS_ERR(reg)) 77 core.vdds_dsi_reg = reg; 78 79 return reg; 80} 81 82struct regulator *dss_get_vdds_sdi(void) 83{ 84 struct regulator *reg; 85 86 if (core.vdds_sdi_reg != NULL) 87 return core.vdds_sdi_reg; 88 89 reg = regulator_get(&core.pdev->dev, "vdds_sdi"); 90 if (!IS_ERR(reg)) 91 core.vdds_sdi_reg = reg; 92 93 return reg; 94} 95 96int dss_get_ctx_loss_count(struct device *dev) 97{ 98 struct omap_dss_board_info *board_data = core.pdev->dev.platform_data; 99 int cnt; 100 101 if (!board_data->get_context_loss_count) 102 return -ENOENT; 103 104 cnt = board_data->get_context_loss_count(dev); 105 106 WARN_ONCE(cnt < 0, "get_context_loss_count failed: %d\n", cnt); 107 108 return cnt; 109} 110 111int dss_dsi_enable_pads(int dsi_id, unsigned lane_mask) 112{ 113 struct omap_dss_board_info *board_data = core.pdev->dev.platform_data; 114 115 if (!board_data->dsi_enable_pads) 116 return -ENOENT; 117 118 return board_data->dsi_enable_pads(dsi_id, lane_mask); 119} 120 121void dss_dsi_disable_pads(int dsi_id, unsigned lane_mask) 122{ 123 struct omap_dss_board_info *board_data = core.pdev->dev.platform_data; 124 125 if (!board_data->dsi_enable_pads) 126 return; 127 128 return board_data->dsi_disable_pads(dsi_id, lane_mask); 129} 130 131int dss_set_min_bus_tput(struct device *dev, unsigned long tput) 132{ 133 struct omap_dss_board_info *pdata = core.pdev->dev.platform_data; 134 135 if (pdata->set_min_bus_tput) 136 return pdata->set_min_bus_tput(dev, tput); 137 else 138 return 0; 139} 140 141#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) 142static int dss_debug_show(struct seq_file *s, void *unused) 143{ 144 void (*func)(struct seq_file *) = s->private; 145 func(s); 146 return 0; 147} 148 149static int dss_debug_open(struct inode *inode, struct file *file) 150{ 151 return single_open(file, dss_debug_show, inode->i_private); 152} 153 154static const struct file_operations dss_debug_fops = { 155 .open = dss_debug_open, 156 .read = seq_read, 157 .llseek = seq_lseek, 158 .release = single_release, 159}; 160 161static struct dentry *dss_debugfs_dir; 162 163static int dss_initialize_debugfs(void) 164{ 165 dss_debugfs_dir = debugfs_create_dir("omapdss", NULL); 166 if (IS_ERR(dss_debugfs_dir)) { 167 int err = PTR_ERR(dss_debugfs_dir); 168 dss_debugfs_dir = NULL; 169 return err; 170 } 171 172 debugfs_create_file("clk", S_IRUGO, dss_debugfs_dir, 173 &dss_debug_dump_clocks, &dss_debug_fops); 174 175 return 0; 176} 177 178static void dss_uninitialize_debugfs(void) 179{ 180 if (dss_debugfs_dir) 181 debugfs_remove_recursive(dss_debugfs_dir); 182} 183 184int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *)) 185{ 186 struct dentry *d; 187 188 d = debugfs_create_file(name, S_IRUGO, dss_debugfs_dir, 189 write, &dss_debug_fops); 190 191 if (IS_ERR(d)) 192 return PTR_ERR(d); 193 194 return 0; 195} 196#else /* CONFIG_DEBUG_FS && CONFIG_OMAP2_DSS_DEBUG_SUPPORT */ 197static inline int dss_initialize_debugfs(void) 198{ 199 return 0; 200} 201static inline void dss_uninitialize_debugfs(void) 202{ 203} 204int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *)) 205{ 206 return 0; 207} 208#endif /* CONFIG_DEBUG_FS && CONFIG_OMAP2_DSS_DEBUG_SUPPORT */ 209 210/* PLATFORM DEVICE */ 211static int omap_dss_pm_notif(struct notifier_block *b, unsigned long v, void *d) 212{ 213 DSSDBG("pm notif %lu\n", v); 214 215 switch (v) { 216 case PM_SUSPEND_PREPARE: 217 DSSDBG("suspending displays\n"); 218 return dss_suspend_all_devices(); 219 220 case PM_POST_SUSPEND: 221 DSSDBG("resuming displays\n"); 222 return dss_resume_all_devices(); 223 224 default: 225 return 0; 226 } 227} 228 229static struct notifier_block omap_dss_pm_notif_block = { 230 .notifier_call = omap_dss_pm_notif, 231}; 232 233static int __init omap_dss_probe(struct platform_device *pdev) 234{ 235 struct omap_dss_board_info *pdata = pdev->dev.platform_data; 236 int r; 237 238 core.pdev = pdev; 239 240 dss_features_init(); 241 242 dss_apply_init(); 243 244 dss_init_overlay_managers(pdev); 245 dss_init_overlays(pdev); 246 247 r = dss_initialize_debugfs(); 248 if (r) 249 goto err_debugfs; 250 251 if (def_disp_name) 252 core.default_display_name = def_disp_name; 253 else if (pdata->default_device) 254 core.default_display_name = pdata->default_device->name; 255 256 register_pm_notifier(&omap_dss_pm_notif_block); 257 258 return 0; 259 260err_debugfs: 261 262 return r; 263} 264 265static int omap_dss_remove(struct platform_device *pdev) 266{ 267 unregister_pm_notifier(&omap_dss_pm_notif_block); 268 269 dss_uninitialize_debugfs(); 270 271 dss_uninit_overlays(pdev); 272 dss_uninit_overlay_managers(pdev); 273 274 return 0; 275} 276 277static void omap_dss_shutdown(struct platform_device *pdev) 278{ 279 DSSDBG("shutdown\n"); 280 dss_disable_all_devices(); 281} 282 283static struct platform_driver omap_dss_driver = { 284 .remove = omap_dss_remove, 285 .shutdown = omap_dss_shutdown, 286 .driver = { 287 .name = "omapdss", 288 .owner = THIS_MODULE, 289 }, 290}; 291 292/* BUS */ 293static int dss_bus_match(struct device *dev, struct device_driver *driver) 294{ 295 struct omap_dss_device *dssdev = to_dss_device(dev); 296 297 DSSDBG("bus_match. dev %s/%s, drv %s\n", 298 dev_name(dev), dssdev->driver_name, driver->name); 299 300 return strcmp(dssdev->driver_name, driver->name) == 0; 301} 302 303static ssize_t device_name_show(struct device *dev, 304 struct device_attribute *attr, char *buf) 305{ 306 struct omap_dss_device *dssdev = to_dss_device(dev); 307 return snprintf(buf, PAGE_SIZE, "%s\n", 308 dssdev->name ? 309 dssdev->name : ""); 310} 311 312static struct device_attribute default_dev_attrs[] = { 313 __ATTR(name, S_IRUGO, device_name_show, NULL), 314 __ATTR_NULL, 315}; 316 317static ssize_t driver_name_show(struct device_driver *drv, char *buf) 318{ 319 struct omap_dss_driver *dssdrv = to_dss_driver(drv); 320 return snprintf(buf, PAGE_SIZE, "%s\n", 321 dssdrv->driver.name ? 322 dssdrv->driver.name : ""); 323} 324static struct driver_attribute default_drv_attrs[] = { 325 __ATTR(name, S_IRUGO, driver_name_show, NULL), 326 __ATTR_NULL, 327}; 328 329static struct bus_type dss_bus_type = { 330 .name = "omapdss", 331 .match = dss_bus_match, 332 .dev_attrs = default_dev_attrs, 333 .drv_attrs = default_drv_attrs, 334}; 335 336static void dss_bus_release(struct device *dev) 337{ 338 DSSDBG("bus_release\n"); 339} 340 341static struct device dss_bus = { 342 .release = dss_bus_release, 343}; 344 345struct bus_type *dss_get_bus(void) 346{ 347 return &dss_bus_type; 348} 349 350/* DRIVER */ 351static int dss_driver_probe(struct device *dev) 352{ 353 int r; 354 struct omap_dss_driver *dssdrv = to_dss_driver(dev->driver); 355 struct omap_dss_device *dssdev = to_dss_device(dev); 356 357 DSSDBG("driver_probe: dev %s/%s, drv %s\n", 358 dev_name(dev), dssdev->driver_name, 359 dssdrv->driver.name); 360 361 r = dss_init_device(core.pdev, dssdev); 362 if (r) 363 return r; 364 365 r = dssdrv->probe(dssdev); 366 367 if (r) { 368 DSSERR("driver probe failed: %d\n", r); 369 dss_uninit_device(core.pdev, dssdev); 370 return r; 371 } 372 373 DSSDBG("probe done for device %s\n", dev_name(dev)); 374 375 dssdev->driver = dssdrv; 376 377 return 0; 378} 379 380static int dss_driver_remove(struct device *dev) 381{ 382 struct omap_dss_driver *dssdrv = to_dss_driver(dev->driver); 383 struct omap_dss_device *dssdev = to_dss_device(dev); 384 385 DSSDBG("driver_remove: dev %s/%s\n", dev_name(dev), 386 dssdev->driver_name); 387 388 dssdrv->remove(dssdev); 389 390 dss_uninit_device(core.pdev, dssdev); 391 392 dssdev->driver = NULL; 393 394 return 0; 395} 396 397int omap_dss_register_driver(struct omap_dss_driver *dssdriver) 398{ 399 dssdriver->driver.bus = &dss_bus_type; 400 dssdriver->driver.probe = dss_driver_probe; 401 dssdriver->driver.remove = dss_driver_remove; 402 403 if (dssdriver->get_resolution == NULL) 404 dssdriver->get_resolution = omapdss_default_get_resolution; 405 if (dssdriver->get_recommended_bpp == NULL) 406 dssdriver->get_recommended_bpp = 407 omapdss_default_get_recommended_bpp; 408 if (dssdriver->get_timings == NULL) 409 dssdriver->get_timings = omapdss_default_get_timings; 410 411 return driver_register(&dssdriver->driver); 412} 413EXPORT_SYMBOL(omap_dss_register_driver); 414 415void omap_dss_unregister_driver(struct omap_dss_driver *dssdriver) 416{ 417 driver_unregister(&dssdriver->driver); 418} 419EXPORT_SYMBOL(omap_dss_unregister_driver); 420 421/* DEVICE */ 422 423static void omap_dss_dev_release(struct device *dev) 424{ 425 struct omap_dss_device *dssdev = to_dss_device(dev); 426 kfree(dssdev); 427} 428 429static int disp_num_counter; 430 431struct omap_dss_device *dss_alloc_and_init_device(struct device *parent) 432{ 433 struct omap_dss_device *dssdev; 434 435 dssdev = kzalloc(sizeof(*dssdev), GFP_KERNEL); 436 if (!dssdev) 437 return NULL; 438 439 dssdev->dev.bus = &dss_bus_type; 440 dssdev->dev.parent = parent; 441 dssdev->dev.release = omap_dss_dev_release; 442 dev_set_name(&dssdev->dev, "display%d", disp_num_counter++); 443 444 device_initialize(&dssdev->dev); 445 446 return dssdev; 447} 448 449int dss_add_device(struct omap_dss_device *dssdev) 450{ 451 return device_add(&dssdev->dev); 452} 453 454void dss_put_device(struct omap_dss_device *dssdev) 455{ 456 put_device(&dssdev->dev); 457} 458 459void dss_unregister_device(struct omap_dss_device *dssdev) 460{ 461 device_unregister(&dssdev->dev); 462} 463 464static int dss_unregister_dss_dev(struct device *dev, void *data) 465{ 466 struct omap_dss_device *dssdev = to_dss_device(dev); 467 dss_unregister_device(dssdev); 468 return 0; 469} 470 471void dss_unregister_child_devices(struct device *parent) 472{ 473 device_for_each_child(parent, NULL, dss_unregister_dss_dev); 474} 475 476void dss_copy_device_pdata(struct omap_dss_device *dst, 477 const struct omap_dss_device *src) 478{ 479 u8 *d = (u8 *)dst; 480 u8 *s = (u8 *)src; 481 size_t dsize = sizeof(struct device); 482 483 memcpy(d + dsize, s + dsize, sizeof(struct omap_dss_device) - dsize); 484} 485 486/* BUS */ 487static int __init omap_dss_bus_register(void) 488{ 489 int r; 490 491 r = bus_register(&dss_bus_type); 492 if (r) { 493 DSSERR("bus register failed\n"); 494 return r; 495 } 496 497 dev_set_name(&dss_bus, "omapdss"); 498 r = device_register(&dss_bus); 499 if (r) { 500 DSSERR("bus driver register failed\n"); 501 bus_unregister(&dss_bus_type); 502 return r; 503 } 504 505 return 0; 506} 507 508/* INIT */ 509static int (*dss_output_drv_reg_funcs[])(void) __initdata = { 510#ifdef CONFIG_OMAP2_DSS_DPI 511 dpi_init_platform_driver, 512#endif 513#ifdef CONFIG_OMAP2_DSS_SDI 514 sdi_init_platform_driver, 515#endif 516#ifdef CONFIG_OMAP2_DSS_RFBI 517 rfbi_init_platform_driver, 518#endif 519#ifdef CONFIG_OMAP2_DSS_VENC 520 venc_init_platform_driver, 521#endif 522#ifdef CONFIG_OMAP2_DSS_DSI 523 dsi_init_platform_driver, 524#endif 525#ifdef CONFIG_OMAP4_DSS_HDMI 526 hdmi_init_platform_driver, 527#endif 528}; 529 530static void (*dss_output_drv_unreg_funcs[])(void) __exitdata = { 531#ifdef CONFIG_OMAP2_DSS_DPI 532 dpi_uninit_platform_driver, 533#endif 534#ifdef CONFIG_OMAP2_DSS_SDI 535 sdi_uninit_platform_driver, 536#endif 537#ifdef CONFIG_OMAP2_DSS_RFBI 538 rfbi_uninit_platform_driver, 539#endif 540#ifdef CONFIG_OMAP2_DSS_VENC 541 venc_uninit_platform_driver, 542#endif 543#ifdef CONFIG_OMAP2_DSS_DSI 544 dsi_uninit_platform_driver, 545#endif 546#ifdef CONFIG_OMAP4_DSS_HDMI 547 hdmi_uninit_platform_driver, 548#endif 549}; 550 551static bool dss_output_drv_loaded[ARRAY_SIZE(dss_output_drv_reg_funcs)]; 552 553static int __init omap_dss_register_drivers(void) 554{ 555 int r; 556 int i; 557 558 r = platform_driver_probe(&omap_dss_driver, omap_dss_probe); 559 if (r) 560 return r; 561 562 r = dss_init_platform_driver(); 563 if (r) { 564 DSSERR("Failed to initialize DSS platform driver\n"); 565 goto err_dss; 566 } 567 568 r = dispc_init_platform_driver(); 569 if (r) { 570 DSSERR("Failed to initialize dispc platform driver\n"); 571 goto err_dispc; 572 } 573 574 /* 575 * It's ok if the output-driver register fails. It happens, for example, 576 * when there is no output-device (e.g. SDI for OMAP4). 577 */ 578 for (i = 0; i < ARRAY_SIZE(dss_output_drv_reg_funcs); ++i) { 579 r = dss_output_drv_reg_funcs[i](); 580 if (r == 0) 581 dss_output_drv_loaded[i] = true; 582 } 583 584 return 0; 585 586err_dispc: 587 dss_uninit_platform_driver(); 588err_dss: 589 platform_driver_unregister(&omap_dss_driver); 590 591 return r; 592} 593 594static void __exit omap_dss_unregister_drivers(void) 595{ 596 int i; 597 598 for (i = 0; i < ARRAY_SIZE(dss_output_drv_unreg_funcs); ++i) { 599 if (dss_output_drv_loaded[i]) 600 dss_output_drv_unreg_funcs[i](); 601 } 602 603 dispc_uninit_platform_driver(); 604 dss_uninit_platform_driver(); 605 606 platform_driver_unregister(&omap_dss_driver); 607} 608 609#ifdef CONFIG_OMAP2_DSS_MODULE 610static void omap_dss_bus_unregister(void) 611{ 612 device_unregister(&dss_bus); 613 614 bus_unregister(&dss_bus_type); 615} 616 617static int __init omap_dss_init(void) 618{ 619 int r; 620 621 r = omap_dss_bus_register(); 622 if (r) 623 return r; 624 625 r = omap_dss_register_drivers(); 626 if (r) { 627 omap_dss_bus_unregister(); 628 return r; 629 } 630 631 return 0; 632} 633 634static void __exit omap_dss_exit(void) 635{ 636 if (core.vdds_dsi_reg != NULL) { 637 regulator_put(core.vdds_dsi_reg); 638 core.vdds_dsi_reg = NULL; 639 } 640 641 if (core.vdds_sdi_reg != NULL) { 642 regulator_put(core.vdds_sdi_reg); 643 core.vdds_sdi_reg = NULL; 644 } 645 646 omap_dss_unregister_drivers(); 647 648 omap_dss_bus_unregister(); 649} 650 651module_init(omap_dss_init); 652module_exit(omap_dss_exit); 653#else 654static int __init omap_dss_init(void) 655{ 656 return omap_dss_bus_register(); 657} 658 659static int __init omap_dss_init2(void) 660{ 661 return omap_dss_register_drivers(); 662} 663 664core_initcall(omap_dss_init); 665device_initcall(omap_dss_init2); 666#endif 667 668MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>"); 669MODULE_DESCRIPTION("OMAP2/3 Display Subsystem"); 670MODULE_LICENSE("GPL v2"); 671