1 /* 2 * Copyright (C) 2012 Texas Instruments 3 * Author: Rob Clark <robdclark@gmail.com> 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 as published by 7 * the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 * more details. 13 * 14 * You should have received a copy of the GNU General Public License along with 15 * this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 /* LCDC DRM driver, based on da8xx-fb */ 19 20 #include <linux/component.h> 21 #include <linux/pinctrl/consumer.h> 22 #include <linux/suspend.h> 23 #include <drm/drm_atomic.h> 24 #include <drm/drm_atomic_helper.h> 25 #include <drm/drm_fb_helper.h> 26 27 #include "tilcdc_drv.h" 28 #include "tilcdc_regs.h" 29 #include "tilcdc_tfp410.h" 30 #include "tilcdc_panel.h" 31 #include "tilcdc_external.h" 32 33 static LIST_HEAD(module_list); 34 35 static const u32 tilcdc_rev1_formats[] = { DRM_FORMAT_RGB565 }; 36 37 static const u32 tilcdc_straight_formats[] = { DRM_FORMAT_RGB565, 38 DRM_FORMAT_BGR888, 39 DRM_FORMAT_XBGR8888 }; 40 41 static const u32 tilcdc_crossed_formats[] = { DRM_FORMAT_BGR565, 42 DRM_FORMAT_RGB888, 43 DRM_FORMAT_XRGB8888 }; 44 45 static const u32 tilcdc_legacy_formats[] = { DRM_FORMAT_RGB565, 46 DRM_FORMAT_RGB888, 47 DRM_FORMAT_XRGB8888 }; 48 49 void tilcdc_module_init(struct tilcdc_module *mod, const char *name, 50 const struct tilcdc_module_ops *funcs) 51 { 52 mod->name = name; 53 mod->funcs = funcs; 54 INIT_LIST_HEAD(&mod->list); 55 list_add(&mod->list, &module_list); 56 } 57 58 void tilcdc_module_cleanup(struct tilcdc_module *mod) 59 { 60 list_del(&mod->list); 61 } 62 63 static struct of_device_id tilcdc_of_match[]; 64 65 static struct drm_framebuffer *tilcdc_fb_create(struct drm_device *dev, 66 struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd) 67 { 68 return drm_fb_cma_create(dev, file_priv, mode_cmd); 69 } 70 71 static void tilcdc_fb_output_poll_changed(struct drm_device *dev) 72 { 73 struct tilcdc_drm_private *priv = dev->dev_private; 74 drm_fbdev_cma_hotplug_event(priv->fbdev); 75 } 76 77 static int tilcdc_atomic_check(struct drm_device *dev, 78 struct drm_atomic_state *state) 79 { 80 int ret; 81 82 ret = drm_atomic_helper_check_modeset(dev, state); 83 if (ret) 84 return ret; 85 86 ret = drm_atomic_helper_check_planes(dev, state); 87 if (ret) 88 return ret; 89 90 /* 91 * tilcdc ->atomic_check can update ->mode_changed if pixel format 92 * changes, hence will we check modeset changes again. 93 */ 94 ret = drm_atomic_helper_check_modeset(dev, state); 95 if (ret) 96 return ret; 97 98 return ret; 99 } 100 101 static int tilcdc_commit(struct drm_device *dev, 102 struct drm_atomic_state *state, 103 bool async) 104 { 105 int ret; 106 107 ret = drm_atomic_helper_prepare_planes(dev, state); 108 if (ret) 109 return ret; 110 111 drm_atomic_helper_swap_state(state, true); 112 113 /* 114 * Everything below can be run asynchronously without the need to grab 115 * any modeset locks at all under one condition: It must be guaranteed 116 * that the asynchronous work has either been cancelled (if the driver 117 * supports it, which at least requires that the framebuffers get 118 * cleaned up with drm_atomic_helper_cleanup_planes()) or completed 119 * before the new state gets committed on the software side with 120 * drm_atomic_helper_swap_state(). 121 * 122 * This scheme allows new atomic state updates to be prepared and 123 * checked in parallel to the asynchronous completion of the previous 124 * update. Which is important since compositors need to figure out the 125 * composition of the next frame right after having submitted the 126 * current layout. 127 */ 128 129 drm_atomic_helper_commit_modeset_disables(dev, state); 130 131 drm_atomic_helper_commit_planes(dev, state, 0); 132 133 drm_atomic_helper_commit_modeset_enables(dev, state); 134 135 drm_atomic_helper_wait_for_vblanks(dev, state); 136 137 drm_atomic_helper_cleanup_planes(dev, state); 138 139 return 0; 140 } 141 142 static const struct drm_mode_config_funcs mode_config_funcs = { 143 .fb_create = tilcdc_fb_create, 144 .output_poll_changed = tilcdc_fb_output_poll_changed, 145 .atomic_check = tilcdc_atomic_check, 146 .atomic_commit = tilcdc_commit, 147 }; 148 149 static void modeset_init(struct drm_device *dev) 150 { 151 struct tilcdc_drm_private *priv = dev->dev_private; 152 struct tilcdc_module *mod; 153 154 list_for_each_entry(mod, &module_list, list) { 155 DBG("loading module: %s", mod->name); 156 mod->funcs->modeset_init(mod, dev); 157 } 158 159 dev->mode_config.min_width = 0; 160 dev->mode_config.min_height = 0; 161 dev->mode_config.max_width = tilcdc_crtc_max_width(priv->crtc); 162 dev->mode_config.max_height = 2048; 163 dev->mode_config.funcs = &mode_config_funcs; 164 } 165 166 #ifdef CONFIG_CPU_FREQ 167 static int cpufreq_transition(struct notifier_block *nb, 168 unsigned long val, void *data) 169 { 170 struct tilcdc_drm_private *priv = container_of(nb, 171 struct tilcdc_drm_private, freq_transition); 172 173 if (val == CPUFREQ_POSTCHANGE) 174 tilcdc_crtc_update_clk(priv->crtc); 175 176 return 0; 177 } 178 #endif 179 180 /* 181 * DRM operations: 182 */ 183 184 static void tilcdc_fini(struct drm_device *dev) 185 { 186 struct tilcdc_drm_private *priv = dev->dev_private; 187 188 if (priv->crtc) 189 tilcdc_crtc_shutdown(priv->crtc); 190 191 if (priv->is_registered) 192 drm_dev_unregister(dev); 193 194 drm_kms_helper_poll_fini(dev); 195 196 if (priv->fbdev) 197 drm_fbdev_cma_fini(priv->fbdev); 198 199 drm_irq_uninstall(dev); 200 drm_mode_config_cleanup(dev); 201 tilcdc_remove_external_device(dev); 202 203 #ifdef CONFIG_CPU_FREQ 204 if (priv->freq_transition.notifier_call) 205 cpufreq_unregister_notifier(&priv->freq_transition, 206 CPUFREQ_TRANSITION_NOTIFIER); 207 #endif 208 209 if (priv->clk) 210 clk_put(priv->clk); 211 212 if (priv->mmio) 213 iounmap(priv->mmio); 214 215 if (priv->wq) { 216 flush_workqueue(priv->wq); 217 destroy_workqueue(priv->wq); 218 } 219 220 dev->dev_private = NULL; 221 222 pm_runtime_disable(dev->dev); 223 224 drm_dev_unref(dev); 225 } 226 227 static int tilcdc_init(struct drm_driver *ddrv, struct device *dev) 228 { 229 struct drm_device *ddev; 230 struct platform_device *pdev = to_platform_device(dev); 231 struct device_node *node = dev->of_node; 232 struct tilcdc_drm_private *priv; 233 struct resource *res; 234 u32 bpp = 0; 235 int ret; 236 237 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 238 if (!priv) { 239 dev_err(dev, "failed to allocate private data\n"); 240 return -ENOMEM; 241 } 242 243 ddev = drm_dev_alloc(ddrv, dev); 244 if (IS_ERR(ddev)) 245 return PTR_ERR(ddev); 246 247 ddev->dev_private = priv; 248 platform_set_drvdata(pdev, ddev); 249 drm_mode_config_init(ddev); 250 251 priv->is_componentized = 252 tilcdc_get_external_components(dev, NULL) > 0; 253 254 priv->wq = alloc_ordered_workqueue("tilcdc", 0); 255 if (!priv->wq) { 256 ret = -ENOMEM; 257 goto init_failed; 258 } 259 260 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 261 if (!res) { 262 dev_err(dev, "failed to get memory resource\n"); 263 ret = -EINVAL; 264 goto init_failed; 265 } 266 267 priv->mmio = ioremap_nocache(res->start, resource_size(res)); 268 if (!priv->mmio) { 269 dev_err(dev, "failed to ioremap\n"); 270 ret = -ENOMEM; 271 goto init_failed; 272 } 273 274 priv->clk = clk_get(dev, "fck"); 275 if (IS_ERR(priv->clk)) { 276 dev_err(dev, "failed to get functional clock\n"); 277 ret = -ENODEV; 278 goto init_failed; 279 } 280 281 #ifdef CONFIG_CPU_FREQ 282 priv->freq_transition.notifier_call = cpufreq_transition; 283 ret = cpufreq_register_notifier(&priv->freq_transition, 284 CPUFREQ_TRANSITION_NOTIFIER); 285 if (ret) { 286 dev_err(dev, "failed to register cpufreq notifier\n"); 287 priv->freq_transition.notifier_call = NULL; 288 goto init_failed; 289 } 290 #endif 291 292 if (of_property_read_u32(node, "max-bandwidth", &priv->max_bandwidth)) 293 priv->max_bandwidth = TILCDC_DEFAULT_MAX_BANDWIDTH; 294 295 DBG("Maximum Bandwidth Value %d", priv->max_bandwidth); 296 297 if (of_property_read_u32(node, "max-width", &priv->max_width)) 298 priv->max_width = TILCDC_DEFAULT_MAX_WIDTH; 299 300 DBG("Maximum Horizontal Pixel Width Value %dpixels", priv->max_width); 301 302 if (of_property_read_u32(node, "max-pixelclock", 303 &priv->max_pixelclock)) 304 priv->max_pixelclock = TILCDC_DEFAULT_MAX_PIXELCLOCK; 305 306 DBG("Maximum Pixel Clock Value %dKHz", priv->max_pixelclock); 307 308 pm_runtime_enable(dev); 309 310 /* Determine LCD IP Version */ 311 pm_runtime_get_sync(dev); 312 switch (tilcdc_read(ddev, LCDC_PID_REG)) { 313 case 0x4c100102: 314 priv->rev = 1; 315 break; 316 case 0x4f200800: 317 case 0x4f201000: 318 priv->rev = 2; 319 break; 320 default: 321 dev_warn(dev, "Unknown PID Reg value 0x%08x, " 322 "defaulting to LCD revision 1\n", 323 tilcdc_read(ddev, LCDC_PID_REG)); 324 priv->rev = 1; 325 break; 326 } 327 328 pm_runtime_put_sync(dev); 329 330 if (priv->rev == 1) { 331 DBG("Revision 1 LCDC supports only RGB565 format"); 332 priv->pixelformats = tilcdc_rev1_formats; 333 priv->num_pixelformats = ARRAY_SIZE(tilcdc_rev1_formats); 334 bpp = 16; 335 } else { 336 const char *str = "\0"; 337 338 of_property_read_string(node, "blue-and-red-wiring", &str); 339 if (0 == strcmp(str, "crossed")) { 340 DBG("Configured for crossed blue and red wires"); 341 priv->pixelformats = tilcdc_crossed_formats; 342 priv->num_pixelformats = 343 ARRAY_SIZE(tilcdc_crossed_formats); 344 bpp = 32; /* Choose bpp with RGB support for fbdef */ 345 } else if (0 == strcmp(str, "straight")) { 346 DBG("Configured for straight blue and red wires"); 347 priv->pixelformats = tilcdc_straight_formats; 348 priv->num_pixelformats = 349 ARRAY_SIZE(tilcdc_straight_formats); 350 bpp = 16; /* Choose bpp with RGB support for fbdef */ 351 } else { 352 DBG("Blue and red wiring '%s' unknown, use legacy mode", 353 str); 354 priv->pixelformats = tilcdc_legacy_formats; 355 priv->num_pixelformats = 356 ARRAY_SIZE(tilcdc_legacy_formats); 357 bpp = 16; /* This is just a guess */ 358 } 359 } 360 361 ret = tilcdc_crtc_create(ddev); 362 if (ret < 0) { 363 dev_err(dev, "failed to create crtc\n"); 364 goto init_failed; 365 } 366 modeset_init(ddev); 367 368 if (priv->is_componentized) { 369 ret = component_bind_all(dev, ddev); 370 if (ret < 0) 371 goto init_failed; 372 373 ret = tilcdc_add_component_encoder(ddev); 374 if (ret < 0) 375 goto init_failed; 376 } else { 377 ret = tilcdc_attach_external_device(ddev); 378 if (ret) 379 goto init_failed; 380 } 381 382 if (!priv->external_connector && 383 ((priv->num_encoders == 0) || (priv->num_connectors == 0))) { 384 dev_err(dev, "no encoders/connectors found\n"); 385 ret = -ENXIO; 386 goto init_failed; 387 } 388 389 ret = drm_vblank_init(ddev, 1); 390 if (ret < 0) { 391 dev_err(dev, "failed to initialize vblank\n"); 392 goto init_failed; 393 } 394 395 ret = drm_irq_install(ddev, platform_get_irq(pdev, 0)); 396 if (ret < 0) { 397 dev_err(dev, "failed to install IRQ handler\n"); 398 goto init_failed; 399 } 400 401 drm_mode_config_reset(ddev); 402 403 priv->fbdev = drm_fbdev_cma_init(ddev, bpp, 404 ddev->mode_config.num_connector); 405 if (IS_ERR(priv->fbdev)) { 406 ret = PTR_ERR(priv->fbdev); 407 goto init_failed; 408 } 409 410 drm_kms_helper_poll_init(ddev); 411 412 ret = drm_dev_register(ddev, 0); 413 if (ret) 414 goto init_failed; 415 416 priv->is_registered = true; 417 return 0; 418 419 init_failed: 420 tilcdc_fini(ddev); 421 422 return ret; 423 } 424 425 static void tilcdc_lastclose(struct drm_device *dev) 426 { 427 struct tilcdc_drm_private *priv = dev->dev_private; 428 drm_fbdev_cma_restore_mode(priv->fbdev); 429 } 430 431 static irqreturn_t tilcdc_irq(int irq, void *arg) 432 { 433 struct drm_device *dev = arg; 434 struct tilcdc_drm_private *priv = dev->dev_private; 435 return tilcdc_crtc_irq(priv->crtc); 436 } 437 438 #if defined(CONFIG_DEBUG_FS) 439 static const struct { 440 const char *name; 441 uint8_t rev; 442 uint8_t save; 443 uint32_t reg; 444 } registers[] = { 445 #define REG(rev, save, reg) { #reg, rev, save, reg } 446 /* exists in revision 1: */ 447 REG(1, false, LCDC_PID_REG), 448 REG(1, true, LCDC_CTRL_REG), 449 REG(1, false, LCDC_STAT_REG), 450 REG(1, true, LCDC_RASTER_CTRL_REG), 451 REG(1, true, LCDC_RASTER_TIMING_0_REG), 452 REG(1, true, LCDC_RASTER_TIMING_1_REG), 453 REG(1, true, LCDC_RASTER_TIMING_2_REG), 454 REG(1, true, LCDC_DMA_CTRL_REG), 455 REG(1, true, LCDC_DMA_FB_BASE_ADDR_0_REG), 456 REG(1, true, LCDC_DMA_FB_CEILING_ADDR_0_REG), 457 REG(1, true, LCDC_DMA_FB_BASE_ADDR_1_REG), 458 REG(1, true, LCDC_DMA_FB_CEILING_ADDR_1_REG), 459 /* new in revision 2: */ 460 REG(2, false, LCDC_RAW_STAT_REG), 461 REG(2, false, LCDC_MASKED_STAT_REG), 462 REG(2, true, LCDC_INT_ENABLE_SET_REG), 463 REG(2, false, LCDC_INT_ENABLE_CLR_REG), 464 REG(2, false, LCDC_END_OF_INT_IND_REG), 465 REG(2, true, LCDC_CLK_ENABLE_REG), 466 #undef REG 467 }; 468 469 #endif 470 471 #ifdef CONFIG_DEBUG_FS 472 static int tilcdc_regs_show(struct seq_file *m, void *arg) 473 { 474 struct drm_info_node *node = (struct drm_info_node *) m->private; 475 struct drm_device *dev = node->minor->dev; 476 struct tilcdc_drm_private *priv = dev->dev_private; 477 unsigned i; 478 479 pm_runtime_get_sync(dev->dev); 480 481 seq_printf(m, "revision: %d\n", priv->rev); 482 483 for (i = 0; i < ARRAY_SIZE(registers); i++) 484 if (priv->rev >= registers[i].rev) 485 seq_printf(m, "%s:\t %08x\n", registers[i].name, 486 tilcdc_read(dev, registers[i].reg)); 487 488 pm_runtime_put_sync(dev->dev); 489 490 return 0; 491 } 492 493 static int tilcdc_mm_show(struct seq_file *m, void *arg) 494 { 495 struct drm_info_node *node = (struct drm_info_node *) m->private; 496 struct drm_device *dev = node->minor->dev; 497 struct drm_printer p = drm_seq_file_printer(m); 498 drm_mm_print(&dev->vma_offset_manager->vm_addr_space_mm, &p); 499 return 0; 500 } 501 502 static struct drm_info_list tilcdc_debugfs_list[] = { 503 { "regs", tilcdc_regs_show, 0 }, 504 { "mm", tilcdc_mm_show, 0 }, 505 { "fb", drm_fb_cma_debugfs_show, 0 }, 506 }; 507 508 static int tilcdc_debugfs_init(struct drm_minor *minor) 509 { 510 struct drm_device *dev = minor->dev; 511 struct tilcdc_module *mod; 512 int ret; 513 514 ret = drm_debugfs_create_files(tilcdc_debugfs_list, 515 ARRAY_SIZE(tilcdc_debugfs_list), 516 minor->debugfs_root, minor); 517 518 list_for_each_entry(mod, &module_list, list) 519 if (mod->funcs->debugfs_init) 520 mod->funcs->debugfs_init(mod, minor); 521 522 if (ret) { 523 dev_err(dev->dev, "could not install tilcdc_debugfs_list\n"); 524 return ret; 525 } 526 527 return ret; 528 } 529 #endif 530 531 DEFINE_DRM_GEM_CMA_FOPS(fops); 532 533 static struct drm_driver tilcdc_driver = { 534 .driver_features = (DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET | 535 DRIVER_PRIME | DRIVER_ATOMIC), 536 .lastclose = tilcdc_lastclose, 537 .irq_handler = tilcdc_irq, 538 .gem_free_object_unlocked = drm_gem_cma_free_object, 539 .gem_vm_ops = &drm_gem_cma_vm_ops, 540 .dumb_create = drm_gem_cma_dumb_create, 541 .dumb_map_offset = drm_gem_cma_dumb_map_offset, 542 .dumb_destroy = drm_gem_dumb_destroy, 543 544 .prime_handle_to_fd = drm_gem_prime_handle_to_fd, 545 .prime_fd_to_handle = drm_gem_prime_fd_to_handle, 546 .gem_prime_import = drm_gem_prime_import, 547 .gem_prime_export = drm_gem_prime_export, 548 .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, 549 .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, 550 .gem_prime_vmap = drm_gem_cma_prime_vmap, 551 .gem_prime_vunmap = drm_gem_cma_prime_vunmap, 552 .gem_prime_mmap = drm_gem_cma_prime_mmap, 553 #ifdef CONFIG_DEBUG_FS 554 .debugfs_init = tilcdc_debugfs_init, 555 #endif 556 .fops = &fops, 557 .name = "tilcdc", 558 .desc = "TI LCD Controller DRM", 559 .date = "20121205", 560 .major = 1, 561 .minor = 0, 562 }; 563 564 /* 565 * Power management: 566 */ 567 568 #ifdef CONFIG_PM_SLEEP 569 static int tilcdc_pm_suspend(struct device *dev) 570 { 571 struct drm_device *ddev = dev_get_drvdata(dev); 572 struct tilcdc_drm_private *priv = ddev->dev_private; 573 574 priv->saved_state = drm_atomic_helper_suspend(ddev); 575 576 /* Select sleep pin state */ 577 pinctrl_pm_select_sleep_state(dev); 578 579 return 0; 580 } 581 582 static int tilcdc_pm_resume(struct device *dev) 583 { 584 struct drm_device *ddev = dev_get_drvdata(dev); 585 struct tilcdc_drm_private *priv = ddev->dev_private; 586 int ret = 0; 587 588 /* Select default pin state */ 589 pinctrl_pm_select_default_state(dev); 590 591 if (priv->saved_state) 592 ret = drm_atomic_helper_resume(ddev, priv->saved_state); 593 594 return ret; 595 } 596 #endif 597 598 static const struct dev_pm_ops tilcdc_pm_ops = { 599 SET_SYSTEM_SLEEP_PM_OPS(tilcdc_pm_suspend, tilcdc_pm_resume) 600 }; 601 602 /* 603 * Platform driver: 604 */ 605 static int tilcdc_bind(struct device *dev) 606 { 607 return tilcdc_init(&tilcdc_driver, dev); 608 } 609 610 static void tilcdc_unbind(struct device *dev) 611 { 612 struct drm_device *ddev = dev_get_drvdata(dev); 613 614 /* Check if a subcomponent has already triggered the unloading. */ 615 if (!ddev->dev_private) 616 return; 617 618 tilcdc_fini(dev_get_drvdata(dev)); 619 } 620 621 static const struct component_master_ops tilcdc_comp_ops = { 622 .bind = tilcdc_bind, 623 .unbind = tilcdc_unbind, 624 }; 625 626 static int tilcdc_pdev_probe(struct platform_device *pdev) 627 { 628 struct component_match *match = NULL; 629 int ret; 630 631 /* bail out early if no DT data: */ 632 if (!pdev->dev.of_node) { 633 dev_err(&pdev->dev, "device-tree data is missing\n"); 634 return -ENXIO; 635 } 636 637 ret = tilcdc_get_external_components(&pdev->dev, &match); 638 if (ret < 0) 639 return ret; 640 else if (ret == 0) 641 return tilcdc_init(&tilcdc_driver, &pdev->dev); 642 else 643 return component_master_add_with_match(&pdev->dev, 644 &tilcdc_comp_ops, 645 match); 646 } 647 648 static int tilcdc_pdev_remove(struct platform_device *pdev) 649 { 650 int ret; 651 652 ret = tilcdc_get_external_components(&pdev->dev, NULL); 653 if (ret < 0) 654 return ret; 655 else if (ret == 0) 656 tilcdc_fini(platform_get_drvdata(pdev)); 657 else 658 component_master_del(&pdev->dev, &tilcdc_comp_ops); 659 660 return 0; 661 } 662 663 static struct of_device_id tilcdc_of_match[] = { 664 { .compatible = "ti,am33xx-tilcdc", }, 665 { .compatible = "ti,da850-tilcdc", }, 666 { }, 667 }; 668 MODULE_DEVICE_TABLE(of, tilcdc_of_match); 669 670 static struct platform_driver tilcdc_platform_driver = { 671 .probe = tilcdc_pdev_probe, 672 .remove = tilcdc_pdev_remove, 673 .driver = { 674 .name = "tilcdc", 675 .pm = &tilcdc_pm_ops, 676 .of_match_table = tilcdc_of_match, 677 }, 678 }; 679 680 static int __init tilcdc_drm_init(void) 681 { 682 DBG("init"); 683 tilcdc_tfp410_init(); 684 tilcdc_panel_init(); 685 return platform_driver_register(&tilcdc_platform_driver); 686 } 687 688 static void __exit tilcdc_drm_fini(void) 689 { 690 DBG("fini"); 691 platform_driver_unregister(&tilcdc_platform_driver); 692 tilcdc_panel_fini(); 693 tilcdc_tfp410_fini(); 694 } 695 696 module_init(tilcdc_drm_init); 697 module_exit(tilcdc_drm_fini); 698 699 MODULE_AUTHOR("Rob Clark <robdclark@gmail.com"); 700 MODULE_DESCRIPTION("TI LCD Controller DRM Driver"); 701 MODULE_LICENSE("GPL"); 702