Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v3.16-rc7 776 lines 19 kB view raw
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 22struct tegra_drm_file { 23 struct list_head contexts; 24}; 25 26static 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 67static 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 84static 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 98static void tegra_drm_context_free(struct tegra_drm_context *context) 99{ 100 context->client->ops->close_channel(context); 101 kfree(context); 102} 103 104static 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 113static struct host1x_bo * 114host1x_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 131int 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 238fail_submit: 239 host1x_job_unpin(job); 240fail: 241 host1x_job_put(job); 242 return err; 243} 244 245 246#ifdef CONFIG_DRM_TEGRA_STAGING 247static struct tegra_drm_context *tegra_drm_get_context(__u64 context) 248{ 249 return (struct tegra_drm_context *)(uintptr_t)context; 250} 251 252static 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 264static 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 278static 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 298static 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 313static 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 327static 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 342static 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 372static 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 390static 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 412static 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 427static 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 456static 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 471static 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 485static 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 499static 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 505static 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 518static 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 527static 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 543static 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 563static struct drm_info_list tegra_debugfs_list[] = { 564 { "framebuffers", tegra_debugfs_framebuffers, 0 }, 565}; 566 567static 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 574static 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 581static 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 622int 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 632int 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 642static 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 665unref: 666 drm_dev_unref(drm); 667 return err; 668} 669 670static 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 680static 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 698static 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 705static 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 743unregister_gr2d: 744 platform_driver_unregister(&tegra_gr2d_driver); 745unregister_dpaux: 746 platform_driver_unregister(&tegra_dpaux_driver); 747unregister_hdmi: 748 platform_driver_unregister(&tegra_hdmi_driver); 749unregister_sor: 750 platform_driver_unregister(&tegra_sor_driver); 751unregister_dsi: 752 platform_driver_unregister(&tegra_dsi_driver); 753unregister_dc: 754 platform_driver_unregister(&tegra_dc_driver); 755unregister_host1x: 756 host1x_driver_unregister(&host1x_drm_driver); 757 return err; 758} 759module_init(host1x_drm_init); 760 761static 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} 772module_exit(host1x_drm_exit); 773 774MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>"); 775MODULE_DESCRIPTION("NVIDIA Tegra DRM driver"); 776MODULE_LICENSE("GPL v2");