1 /* 2 * Copyright (C) 2012 Avionic Design GmbH 3 * Copyright (C) 2012-2013 NVIDIA CORPORATION. All rights reserved. 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 */ 9 10 #include <linux/host1x.h> 11 12 #include "drm.h" 13 #include "gem.h" 14 15 #define DRIVER_NAME "tegra" 16 #define DRIVER_DESC "NVIDIA Tegra graphics" 17 #define DRIVER_DATE "20120330" 18 #define DRIVER_MAJOR 0 19 #define DRIVER_MINOR 0 20 #define DRIVER_PATCHLEVEL 0 21 22 struct tegra_drm_file { 23 struct list_head contexts; 24 }; 25 26 static int tegra_drm_load(struct drm_device *drm, unsigned long flags) 27 { 28 struct host1x_device *device = to_host1x_device(drm->dev); 29 struct tegra_drm *tegra; 30 int err; 31 32 tegra = kzalloc(sizeof(*tegra), GFP_KERNEL); 33 if (!tegra) 34 return -ENOMEM; 35 36 mutex_init(&tegra->clients_lock); 37 INIT_LIST_HEAD(&tegra->clients); 38 drm->dev_private = tegra; 39 tegra->drm = drm; 40 41 drm_mode_config_init(drm); 42 43 err = host1x_device_init(device); 44 if (err < 0) 45 return err; 46 47 /* 48 * We don't use the drm_irq_install() helpers provided by the DRM 49 * core, so we need to set this manually in order to allow the 50 * DRM_IOCTL_WAIT_VBLANK to operate correctly. 51 */ 52 drm->irq_enabled = true; 53 54 err = drm_vblank_init(drm, drm->mode_config.num_crtc); 55 if (err < 0) 56 return err; 57 58 err = tegra_drm_fb_init(drm); 59 if (err < 0) 60 return err; 61 62 drm_kms_helper_poll_init(drm); 63 64 return 0; 65 } 66 67 static int tegra_drm_unload(struct drm_device *drm) 68 { 69 struct host1x_device *device = to_host1x_device(drm->dev); 70 int err; 71 72 drm_kms_helper_poll_fini(drm); 73 tegra_drm_fb_exit(drm); 74 drm_vblank_cleanup(drm); 75 drm_mode_config_cleanup(drm); 76 77 err = host1x_device_exit(device); 78 if (err < 0) 79 return err; 80 81 return 0; 82 } 83 84 static int tegra_drm_open(struct drm_device *drm, struct drm_file *filp) 85 { 86 struct tegra_drm_file *fpriv; 87 88 fpriv = kzalloc(sizeof(*fpriv), GFP_KERNEL); 89 if (!fpriv) 90 return -ENOMEM; 91 92 INIT_LIST_HEAD(&fpriv->contexts); 93 filp->driver_priv = fpriv; 94 95 return 0; 96 } 97 98 static void tegra_drm_context_free(struct tegra_drm_context *context) 99 { 100 context->client->ops->close_channel(context); 101 kfree(context); 102 } 103 104 static void tegra_drm_lastclose(struct drm_device *drm) 105 { 106 #ifdef CONFIG_DRM_TEGRA_FBDEV 107 struct tegra_drm *tegra = drm->dev_private; 108 109 tegra_fbdev_restore_mode(tegra->fbdev); 110 #endif 111 } 112 113 static struct host1x_bo * 114 host1x_bo_lookup(struct drm_device *drm, struct drm_file *file, u32 handle) 115 { 116 struct drm_gem_object *gem; 117 struct tegra_bo *bo; 118 119 gem = drm_gem_object_lookup(drm, file, handle); 120 if (!gem) 121 return NULL; 122 123 mutex_lock(&drm->struct_mutex); 124 drm_gem_object_unreference(gem); 125 mutex_unlock(&drm->struct_mutex); 126 127 bo = to_tegra_bo(gem); 128 return &bo->base; 129 } 130 131 int tegra_drm_submit(struct tegra_drm_context *context, 132 struct drm_tegra_submit *args, struct drm_device *drm, 133 struct drm_file *file) 134 { 135 unsigned int num_cmdbufs = args->num_cmdbufs; 136 unsigned int num_relocs = args->num_relocs; 137 unsigned int num_waitchks = args->num_waitchks; 138 struct drm_tegra_cmdbuf __user *cmdbufs = 139 (void __user *)(uintptr_t)args->cmdbufs; 140 struct drm_tegra_reloc __user *relocs = 141 (void __user *)(uintptr_t)args->relocs; 142 struct drm_tegra_waitchk __user *waitchks = 143 (void __user *)(uintptr_t)args->waitchks; 144 struct drm_tegra_syncpt syncpt; 145 struct host1x_job *job; 146 int err; 147 148 /* We don't yet support other than one syncpt_incr struct per submit */ 149 if (args->num_syncpts != 1) 150 return -EINVAL; 151 152 job = host1x_job_alloc(context->channel, args->num_cmdbufs, 153 args->num_relocs, args->num_waitchks); 154 if (!job) 155 return -ENOMEM; 156 157 job->num_relocs = args->num_relocs; 158 job->num_waitchk = args->num_waitchks; 159 job->client = (u32)args->context; 160 job->class = context->client->base.class; 161 job->serialize = true; 162 163 while (num_cmdbufs) { 164 struct drm_tegra_cmdbuf cmdbuf; 165 struct host1x_bo *bo; 166 167 if (copy_from_user(&cmdbuf, cmdbufs, sizeof(cmdbuf))) { 168 err = -EFAULT; 169 goto fail; 170 } 171 172 bo = host1x_bo_lookup(drm, file, cmdbuf.handle); 173 if (!bo) { 174 err = -ENOENT; 175 goto fail; 176 } 177 178 host1x_job_add_gather(job, bo, cmdbuf.words, cmdbuf.offset); 179 num_cmdbufs--; 180 cmdbufs++; 181 } 182 183 if (copy_from_user(job->relocarray, relocs, 184 sizeof(*relocs) * num_relocs)) { 185 err = -EFAULT; 186 goto fail; 187 } 188 189 while (num_relocs--) { 190 struct host1x_reloc *reloc = &job->relocarray[num_relocs]; 191 struct host1x_bo *cmdbuf, *target; 192 193 cmdbuf = host1x_bo_lookup(drm, file, (u32)reloc->cmdbuf); 194 target = host1x_bo_lookup(drm, file, (u32)reloc->target); 195 196 reloc->cmdbuf = cmdbuf; 197 reloc->target = target; 198 199 if (!reloc->target || !reloc->cmdbuf) { 200 err = -ENOENT; 201 goto fail; 202 } 203 } 204 205 if (copy_from_user(job->waitchk, waitchks, 206 sizeof(*waitchks) * num_waitchks)) { 207 err = -EFAULT; 208 goto fail; 209 } 210 211 if (copy_from_user(&syncpt, (void __user *)(uintptr_t)args->syncpts, 212 sizeof(syncpt))) { 213 err = -EFAULT; 214 goto fail; 215 } 216 217 job->is_addr_reg = context->client->ops->is_addr_reg; 218 job->syncpt_incrs = syncpt.incrs; 219 job->syncpt_id = syncpt.id; 220 job->timeout = 10000; 221 222 if (args->timeout && args->timeout < 10000) 223 job->timeout = args->timeout; 224 225 err = host1x_job_pin(job, context->client->base.dev); 226 if (err) 227 goto fail; 228 229 err = host1x_job_submit(job); 230 if (err) 231 goto fail_submit; 232 233 args->fence = job->syncpt_end; 234 235 host1x_job_put(job); 236 return 0; 237 238 fail_submit: 239 host1x_job_unpin(job); 240 fail: 241 host1x_job_put(job); 242 return err; 243 } 244 245 246 #ifdef CONFIG_DRM_TEGRA_STAGING 247 static struct tegra_drm_context *tegra_drm_get_context(__u64 context) 248 { 249 return (struct tegra_drm_context *)(uintptr_t)context; 250 } 251 252 static bool tegra_drm_file_owns_context(struct tegra_drm_file *file, 253 struct tegra_drm_context *context) 254 { 255 struct tegra_drm_context *ctx; 256 257 list_for_each_entry(ctx, &file->contexts, list) 258 if (ctx == context) 259 return true; 260 261 return false; 262 } 263 264 static int tegra_gem_create(struct drm_device *drm, void *data, 265 struct drm_file *file) 266 { 267 struct drm_tegra_gem_create *args = data; 268 struct tegra_bo *bo; 269 270 bo = tegra_bo_create_with_handle(file, drm, args->size, args->flags, 271 &args->handle); 272 if (IS_ERR(bo)) 273 return PTR_ERR(bo); 274 275 return 0; 276 } 277 278 static int tegra_gem_mmap(struct drm_device *drm, void *data, 279 struct drm_file *file) 280 { 281 struct drm_tegra_gem_mmap *args = data; 282 struct drm_gem_object *gem; 283 struct tegra_bo *bo; 284 285 gem = drm_gem_object_lookup(drm, file, args->handle); 286 if (!gem) 287 return -EINVAL; 288 289 bo = to_tegra_bo(gem); 290 291 args->offset = drm_vma_node_offset_addr(&bo->gem.vma_node); 292 293 drm_gem_object_unreference(gem); 294 295 return 0; 296 } 297 298 static int tegra_syncpt_read(struct drm_device *drm, void *data, 299 struct drm_file *file) 300 { 301 struct host1x *host = dev_get_drvdata(drm->dev->parent); 302 struct drm_tegra_syncpt_read *args = data; 303 struct host1x_syncpt *sp; 304 305 sp = host1x_syncpt_get(host, args->id); 306 if (!sp) 307 return -EINVAL; 308 309 args->value = host1x_syncpt_read_min(sp); 310 return 0; 311 } 312 313 static int tegra_syncpt_incr(struct drm_device *drm, void *data, 314 struct drm_file *file) 315 { 316 struct host1x *host1x = dev_get_drvdata(drm->dev->parent); 317 struct drm_tegra_syncpt_incr *args = data; 318 struct host1x_syncpt *sp; 319 320 sp = host1x_syncpt_get(host1x, args->id); 321 if (!sp) 322 return -EINVAL; 323 324 return host1x_syncpt_incr(sp); 325 } 326 327 static int tegra_syncpt_wait(struct drm_device *drm, void *data, 328 struct drm_file *file) 329 { 330 struct host1x *host1x = dev_get_drvdata(drm->dev->parent); 331 struct drm_tegra_syncpt_wait *args = data; 332 struct host1x_syncpt *sp; 333 334 sp = host1x_syncpt_get(host1x, args->id); 335 if (!sp) 336 return -EINVAL; 337 338 return host1x_syncpt_wait(sp, args->thresh, args->timeout, 339 &args->value); 340 } 341 342 static int tegra_open_channel(struct drm_device *drm, void *data, 343 struct drm_file *file) 344 { 345 struct tegra_drm_file *fpriv = file->driver_priv; 346 struct tegra_drm *tegra = drm->dev_private; 347 struct drm_tegra_open_channel *args = data; 348 struct tegra_drm_context *context; 349 struct tegra_drm_client *client; 350 int err = -ENODEV; 351 352 context = kzalloc(sizeof(*context), GFP_KERNEL); 353 if (!context) 354 return -ENOMEM; 355 356 list_for_each_entry(client, &tegra->clients, list) 357 if (client->base.class == args->client) { 358 err = client->ops->open_channel(client, context); 359 if (err) 360 break; 361 362 list_add(&context->list, &fpriv->contexts); 363 args->context = (uintptr_t)context; 364 context->client = client; 365 return 0; 366 } 367 368 kfree(context); 369 return err; 370 } 371 372 static int tegra_close_channel(struct drm_device *drm, void *data, 373 struct drm_file *file) 374 { 375 struct tegra_drm_file *fpriv = file->driver_priv; 376 struct drm_tegra_close_channel *args = data; 377 struct tegra_drm_context *context; 378 379 context = tegra_drm_get_context(args->context); 380 381 if (!tegra_drm_file_owns_context(fpriv, context)) 382 return -EINVAL; 383 384 list_del(&context->list); 385 tegra_drm_context_free(context); 386 387 return 0; 388 } 389 390 static int tegra_get_syncpt(struct drm_device *drm, void *data, 391 struct drm_file *file) 392 { 393 struct tegra_drm_file *fpriv = file->driver_priv; 394 struct drm_tegra_get_syncpt *args = data; 395 struct tegra_drm_context *context; 396 struct host1x_syncpt *syncpt; 397 398 context = tegra_drm_get_context(args->context); 399 400 if (!tegra_drm_file_owns_context(fpriv, context)) 401 return -ENODEV; 402 403 if (args->index >= context->client->base.num_syncpts) 404 return -EINVAL; 405 406 syncpt = context->client->base.syncpts[args->index]; 407 args->id = host1x_syncpt_id(syncpt); 408 409 return 0; 410 } 411 412 static int tegra_submit(struct drm_device *drm, void *data, 413 struct drm_file *file) 414 { 415 struct tegra_drm_file *fpriv = file->driver_priv; 416 struct drm_tegra_submit *args = data; 417 struct tegra_drm_context *context; 418 419 context = tegra_drm_get_context(args->context); 420 421 if (!tegra_drm_file_owns_context(fpriv, context)) 422 return -ENODEV; 423 424 return context->client->ops->submit(context, args, drm, file); 425 } 426 427 static int tegra_get_syncpt_base(struct drm_device *drm, void *data, 428 struct drm_file *file) 429 { 430 struct tegra_drm_file *fpriv = file->driver_priv; 431 struct drm_tegra_get_syncpt_base *args = data; 432 struct tegra_drm_context *context; 433 struct host1x_syncpt_base *base; 434 struct host1x_syncpt *syncpt; 435 436 context = tegra_drm_get_context(args->context); 437 438 if (!tegra_drm_file_owns_context(fpriv, context)) 439 return -ENODEV; 440 441 if (args->syncpt >= context->client->base.num_syncpts) 442 return -EINVAL; 443 444 syncpt = context->client->base.syncpts[args->syncpt]; 445 446 base = host1x_syncpt_get_base(syncpt); 447 if (!base) 448 return -ENXIO; 449 450 args->id = host1x_syncpt_base_id(base); 451 452 return 0; 453 } 454 #endif 455 456 static const struct drm_ioctl_desc tegra_drm_ioctls[] = { 457 #ifdef CONFIG_DRM_TEGRA_STAGING 458 DRM_IOCTL_DEF_DRV(TEGRA_GEM_CREATE, tegra_gem_create, DRM_UNLOCKED | DRM_AUTH), 459 DRM_IOCTL_DEF_DRV(TEGRA_GEM_MMAP, tegra_gem_mmap, DRM_UNLOCKED), 460 DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_READ, tegra_syncpt_read, DRM_UNLOCKED), 461 DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_INCR, tegra_syncpt_incr, DRM_UNLOCKED), 462 DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_WAIT, tegra_syncpt_wait, DRM_UNLOCKED), 463 DRM_IOCTL_DEF_DRV(TEGRA_OPEN_CHANNEL, tegra_open_channel, DRM_UNLOCKED), 464 DRM_IOCTL_DEF_DRV(TEGRA_CLOSE_CHANNEL, tegra_close_channel, DRM_UNLOCKED), 465 DRM_IOCTL_DEF_DRV(TEGRA_GET_SYNCPT, tegra_get_syncpt, DRM_UNLOCKED), 466 DRM_IOCTL_DEF_DRV(TEGRA_SUBMIT, tegra_submit, DRM_UNLOCKED), 467 DRM_IOCTL_DEF_DRV(TEGRA_GET_SYNCPT_BASE, tegra_get_syncpt_base, DRM_UNLOCKED), 468 #endif 469 }; 470 471 static const struct file_operations tegra_drm_fops = { 472 .owner = THIS_MODULE, 473 .open = drm_open, 474 .release = drm_release, 475 .unlocked_ioctl = drm_ioctl, 476 .mmap = tegra_drm_mmap, 477 .poll = drm_poll, 478 .read = drm_read, 479 #ifdef CONFIG_COMPAT 480 .compat_ioctl = drm_compat_ioctl, 481 #endif 482 .llseek = noop_llseek, 483 }; 484 485 static struct drm_crtc *tegra_crtc_from_pipe(struct drm_device *drm, int pipe) 486 { 487 struct drm_crtc *crtc; 488 489 list_for_each_entry(crtc, &drm->mode_config.crtc_list, head) { 490 struct tegra_dc *dc = to_tegra_dc(crtc); 491 492 if (dc->pipe == pipe) 493 return crtc; 494 } 495 496 return NULL; 497 } 498 499 static u32 tegra_drm_get_vblank_counter(struct drm_device *dev, int crtc) 500 { 501 /* TODO: implement real hardware counter using syncpoints */ 502 return drm_vblank_count(dev, crtc); 503 } 504 505 static int tegra_drm_enable_vblank(struct drm_device *drm, int pipe) 506 { 507 struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe); 508 struct tegra_dc *dc = to_tegra_dc(crtc); 509 510 if (!crtc) 511 return -ENODEV; 512 513 tegra_dc_enable_vblank(dc); 514 515 return 0; 516 } 517 518 static void tegra_drm_disable_vblank(struct drm_device *drm, int pipe) 519 { 520 struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe); 521 struct tegra_dc *dc = to_tegra_dc(crtc); 522 523 if (crtc) 524 tegra_dc_disable_vblank(dc); 525 } 526 527 static void tegra_drm_preclose(struct drm_device *drm, struct drm_file *file) 528 { 529 struct tegra_drm_file *fpriv = file->driver_priv; 530 struct tegra_drm_context *context, *tmp; 531 struct drm_crtc *crtc; 532 533 list_for_each_entry(crtc, &drm->mode_config.crtc_list, head) 534 tegra_dc_cancel_page_flip(crtc, file); 535 536 list_for_each_entry_safe(context, tmp, &fpriv->contexts, list) 537 tegra_drm_context_free(context); 538 539 kfree(fpriv); 540 } 541 542 #ifdef CONFIG_DEBUG_FS 543 static int tegra_debugfs_framebuffers(struct seq_file *s, void *data) 544 { 545 struct drm_info_node *node = (struct drm_info_node *)s->private; 546 struct drm_device *drm = node->minor->dev; 547 struct drm_framebuffer *fb; 548 549 mutex_lock(&drm->mode_config.fb_lock); 550 551 list_for_each_entry(fb, &drm->mode_config.fb_list, head) { 552 seq_printf(s, "%3d: user size: %d x %d, depth %d, %d bpp, refcount %d\n", 553 fb->base.id, fb->width, fb->height, fb->depth, 554 fb->bits_per_pixel, 555 atomic_read(&fb->refcount.refcount)); 556 } 557 558 mutex_unlock(&drm->mode_config.fb_lock); 559 560 return 0; 561 } 562 563 static struct drm_info_list tegra_debugfs_list[] = { 564 { "framebuffers", tegra_debugfs_framebuffers, 0 }, 565 }; 566 567 static int tegra_debugfs_init(struct drm_minor *minor) 568 { 569 return drm_debugfs_create_files(tegra_debugfs_list, 570 ARRAY_SIZE(tegra_debugfs_list), 571 minor->debugfs_root, minor); 572 } 573 574 static void tegra_debugfs_cleanup(struct drm_minor *minor) 575 { 576 drm_debugfs_remove_files(tegra_debugfs_list, 577 ARRAY_SIZE(tegra_debugfs_list), minor); 578 } 579 #endif 580 581 static struct drm_driver tegra_drm_driver = { 582 .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME, 583 .load = tegra_drm_load, 584 .unload = tegra_drm_unload, 585 .open = tegra_drm_open, 586 .preclose = tegra_drm_preclose, 587 .lastclose = tegra_drm_lastclose, 588 589 .get_vblank_counter = tegra_drm_get_vblank_counter, 590 .enable_vblank = tegra_drm_enable_vblank, 591 .disable_vblank = tegra_drm_disable_vblank, 592 593 #if defined(CONFIG_DEBUG_FS) 594 .debugfs_init = tegra_debugfs_init, 595 .debugfs_cleanup = tegra_debugfs_cleanup, 596 #endif 597 598 .gem_free_object = tegra_bo_free_object, 599 .gem_vm_ops = &tegra_bo_vm_ops, 600 601 .prime_handle_to_fd = drm_gem_prime_handle_to_fd, 602 .prime_fd_to_handle = drm_gem_prime_fd_to_handle, 603 .gem_prime_export = tegra_gem_prime_export, 604 .gem_prime_import = tegra_gem_prime_import, 605 606 .dumb_create = tegra_bo_dumb_create, 607 .dumb_map_offset = tegra_bo_dumb_map_offset, 608 .dumb_destroy = drm_gem_dumb_destroy, 609 610 .ioctls = tegra_drm_ioctls, 611 .num_ioctls = ARRAY_SIZE(tegra_drm_ioctls), 612 .fops = &tegra_drm_fops, 613 614 .name = DRIVER_NAME, 615 .desc = DRIVER_DESC, 616 .date = DRIVER_DATE, 617 .major = DRIVER_MAJOR, 618 .minor = DRIVER_MINOR, 619 .patchlevel = DRIVER_PATCHLEVEL, 620 }; 621 622 int tegra_drm_register_client(struct tegra_drm *tegra, 623 struct tegra_drm_client *client) 624 { 625 mutex_lock(&tegra->clients_lock); 626 list_add_tail(&client->list, &tegra->clients); 627 mutex_unlock(&tegra->clients_lock); 628 629 return 0; 630 } 631 632 int tegra_drm_unregister_client(struct tegra_drm *tegra, 633 struct tegra_drm_client *client) 634 { 635 mutex_lock(&tegra->clients_lock); 636 list_del_init(&client->list); 637 mutex_unlock(&tegra->clients_lock); 638 639 return 0; 640 } 641 642 static int host1x_drm_probe(struct host1x_device *dev) 643 { 644 struct drm_driver *driver = &tegra_drm_driver; 645 struct drm_device *drm; 646 int err; 647 648 drm = drm_dev_alloc(driver, &dev->dev); 649 if (!drm) 650 return -ENOMEM; 651 652 drm_dev_set_unique(drm, dev_name(&dev->dev)); 653 dev_set_drvdata(&dev->dev, drm); 654 655 err = drm_dev_register(drm, 0); 656 if (err < 0) 657 goto unref; 658 659 DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", driver->name, 660 driver->major, driver->minor, driver->patchlevel, 661 driver->date, drm->primary->index); 662 663 return 0; 664 665 unref: 666 drm_dev_unref(drm); 667 return err; 668 } 669 670 static int host1x_drm_remove(struct host1x_device *dev) 671 { 672 struct drm_device *drm = dev_get_drvdata(&dev->dev); 673 674 drm_dev_unregister(drm); 675 drm_dev_unref(drm); 676 677 return 0; 678 } 679 680 static const struct of_device_id host1x_drm_subdevs[] = { 681 { .compatible = "nvidia,tegra20-dc", }, 682 { .compatible = "nvidia,tegra20-hdmi", }, 683 { .compatible = "nvidia,tegra20-gr2d", }, 684 { .compatible = "nvidia,tegra20-gr3d", }, 685 { .compatible = "nvidia,tegra30-dc", }, 686 { .compatible = "nvidia,tegra30-hdmi", }, 687 { .compatible = "nvidia,tegra30-gr2d", }, 688 { .compatible = "nvidia,tegra30-gr3d", }, 689 { .compatible = "nvidia,tegra114-dsi", }, 690 { .compatible = "nvidia,tegra114-hdmi", }, 691 { .compatible = "nvidia,tegra114-gr3d", }, 692 { .compatible = "nvidia,tegra124-dc", }, 693 { .compatible = "nvidia,tegra124-sor", }, 694 { .compatible = "nvidia,tegra124-hdmi", }, 695 { /* sentinel */ } 696 }; 697 698 static struct host1x_driver host1x_drm_driver = { 699 .name = "drm", 700 .probe = host1x_drm_probe, 701 .remove = host1x_drm_remove, 702 .subdevs = host1x_drm_subdevs, 703 }; 704 705 static int __init host1x_drm_init(void) 706 { 707 int err; 708 709 err = host1x_driver_register(&host1x_drm_driver); 710 if (err < 0) 711 return err; 712 713 err = platform_driver_register(&tegra_dc_driver); 714 if (err < 0) 715 goto unregister_host1x; 716 717 err = platform_driver_register(&tegra_dsi_driver); 718 if (err < 0) 719 goto unregister_dc; 720 721 err = platform_driver_register(&tegra_sor_driver); 722 if (err < 0) 723 goto unregister_dsi; 724 725 err = platform_driver_register(&tegra_hdmi_driver); 726 if (err < 0) 727 goto unregister_sor; 728 729 err = platform_driver_register(&tegra_dpaux_driver); 730 if (err < 0) 731 goto unregister_hdmi; 732 733 err = platform_driver_register(&tegra_gr2d_driver); 734 if (err < 0) 735 goto unregister_dpaux; 736 737 err = platform_driver_register(&tegra_gr3d_driver); 738 if (err < 0) 739 goto unregister_gr2d; 740 741 return 0; 742 743 unregister_gr2d: 744 platform_driver_unregister(&tegra_gr2d_driver); 745 unregister_dpaux: 746 platform_driver_unregister(&tegra_dpaux_driver); 747 unregister_hdmi: 748 platform_driver_unregister(&tegra_hdmi_driver); 749 unregister_sor: 750 platform_driver_unregister(&tegra_sor_driver); 751 unregister_dsi: 752 platform_driver_unregister(&tegra_dsi_driver); 753 unregister_dc: 754 platform_driver_unregister(&tegra_dc_driver); 755 unregister_host1x: 756 host1x_driver_unregister(&host1x_drm_driver); 757 return err; 758 } 759 module_init(host1x_drm_init); 760 761 static void __exit host1x_drm_exit(void) 762 { 763 platform_driver_unregister(&tegra_gr3d_driver); 764 platform_driver_unregister(&tegra_gr2d_driver); 765 platform_driver_unregister(&tegra_dpaux_driver); 766 platform_driver_unregister(&tegra_hdmi_driver); 767 platform_driver_unregister(&tegra_sor_driver); 768 platform_driver_unregister(&tegra_dsi_driver); 769 platform_driver_unregister(&tegra_dc_driver); 770 host1x_driver_unregister(&host1x_drm_driver); 771 } 772 module_exit(host1x_drm_exit); 773 774 MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>"); 775 MODULE_DESCRIPTION("NVIDIA Tegra DRM driver"); 776 MODULE_LICENSE("GPL v2"); 777