2 * Copyright (C) 2012 Avionic Design GmbH
3 * Copyright (C) 2012-2013 NVIDIA CORPORATION. All rights reserved.
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.
10 #include <linux/host1x.h>
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
22 struct tegra_drm_file {
23 struct list_head contexts;
26 static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
28 struct host1x_device *device = to_host1x_device(drm->dev);
29 struct tegra_drm *tegra;
32 tegra = kzalloc(sizeof(*tegra), GFP_KERNEL);
36 dev_set_drvdata(drm->dev, tegra);
37 mutex_init(&tegra->clients_lock);
38 INIT_LIST_HEAD(&tegra->clients);
39 drm->dev_private = tegra;
42 drm_mode_config_init(drm);
44 err = host1x_device_init(device);
49 * We don't use the drm_irq_install() helpers provided by the DRM
50 * core, so we need to set this manually in order to allow the
51 * DRM_IOCTL_WAIT_VBLANK to operate correctly.
53 drm->irq_enabled = true;
55 err = drm_vblank_init(drm, drm->mode_config.num_crtc);
59 err = tegra_drm_fb_init(drm);
63 drm_kms_helper_poll_init(drm);
68 static int tegra_drm_unload(struct drm_device *drm)
70 struct host1x_device *device = to_host1x_device(drm->dev);
73 drm_kms_helper_poll_fini(drm);
74 tegra_drm_fb_exit(drm);
75 drm_vblank_cleanup(drm);
76 drm_mode_config_cleanup(drm);
78 err = host1x_device_exit(device);
85 static int tegra_drm_open(struct drm_device *drm, struct drm_file *filp)
87 struct tegra_drm_file *fpriv;
89 fpriv = kzalloc(sizeof(*fpriv), GFP_KERNEL);
93 INIT_LIST_HEAD(&fpriv->contexts);
94 filp->driver_priv = fpriv;
99 static void tegra_drm_context_free(struct tegra_drm_context *context)
101 context->client->ops->close_channel(context);
105 static void tegra_drm_lastclose(struct drm_device *drm)
107 struct tegra_drm *tegra = drm->dev_private;
109 tegra_fbdev_restore_mode(tegra->fbdev);
112 static struct host1x_bo *
113 host1x_bo_lookup(struct drm_device *drm, struct drm_file *file, u32 handle)
115 struct drm_gem_object *gem;
118 gem = drm_gem_object_lookup(drm, file, handle);
122 mutex_lock(&drm->struct_mutex);
123 drm_gem_object_unreference(gem);
124 mutex_unlock(&drm->struct_mutex);
126 bo = to_tegra_bo(gem);
130 int tegra_drm_submit(struct tegra_drm_context *context,
131 struct drm_tegra_submit *args, struct drm_device *drm,
132 struct drm_file *file)
134 unsigned int num_cmdbufs = args->num_cmdbufs;
135 unsigned int num_relocs = args->num_relocs;
136 unsigned int num_waitchks = args->num_waitchks;
137 struct drm_tegra_cmdbuf __user *cmdbufs =
138 (void __user *)(uintptr_t)args->cmdbufs;
139 struct drm_tegra_reloc __user *relocs =
140 (void __user *)(uintptr_t)args->relocs;
141 struct drm_tegra_waitchk __user *waitchks =
142 (void __user *)(uintptr_t)args->waitchks;
143 struct drm_tegra_syncpt syncpt;
144 struct host1x_job *job;
147 /* We don't yet support other than one syncpt_incr struct per submit */
148 if (args->num_syncpts != 1)
151 job = host1x_job_alloc(context->channel, args->num_cmdbufs,
152 args->num_relocs, args->num_waitchks);
156 job->num_relocs = args->num_relocs;
157 job->num_waitchk = args->num_waitchks;
158 job->client = (u32)args->context;
159 job->class = context->client->base.class;
160 job->serialize = true;
162 while (num_cmdbufs) {
163 struct drm_tegra_cmdbuf cmdbuf;
164 struct host1x_bo *bo;
166 if (copy_from_user(&cmdbuf, cmdbufs, sizeof(cmdbuf))) {
171 bo = host1x_bo_lookup(drm, file, cmdbuf.handle);
177 host1x_job_add_gather(job, bo, cmdbuf.words, cmdbuf.offset);
182 if (copy_from_user(job->relocarray, relocs,
183 sizeof(*relocs) * num_relocs)) {
188 while (num_relocs--) {
189 struct host1x_reloc *reloc = &job->relocarray[num_relocs];
190 struct host1x_bo *cmdbuf, *target;
192 cmdbuf = host1x_bo_lookup(drm, file, (u32)reloc->cmdbuf);
193 target = host1x_bo_lookup(drm, file, (u32)reloc->target);
195 reloc->cmdbuf = cmdbuf;
196 reloc->target = target;
198 if (!reloc->target || !reloc->cmdbuf) {
204 if (copy_from_user(job->waitchk, waitchks,
205 sizeof(*waitchks) * num_waitchks)) {
210 if (copy_from_user(&syncpt, (void __user *)(uintptr_t)args->syncpts,
216 job->is_addr_reg = context->client->ops->is_addr_reg;
217 job->syncpt_incrs = syncpt.incrs;
218 job->syncpt_id = syncpt.id;
219 job->timeout = 10000;
221 if (args->timeout && args->timeout < 10000)
222 job->timeout = args->timeout;
224 err = host1x_job_pin(job, context->client->base.dev);
228 err = host1x_job_submit(job);
232 args->fence = job->syncpt_end;
238 host1x_job_unpin(job);
245 #ifdef CONFIG_DRM_TEGRA_STAGING
246 static struct tegra_drm_context *tegra_drm_get_context(__u64 context)
248 return (struct tegra_drm_context *)(uintptr_t)context;
251 static bool tegra_drm_file_owns_context(struct tegra_drm_file *file,
252 struct tegra_drm_context *context)
254 struct tegra_drm_context *ctx;
256 list_for_each_entry(ctx, &file->contexts, list)
263 static int tegra_gem_create(struct drm_device *drm, void *data,
264 struct drm_file *file)
266 struct drm_tegra_gem_create *args = data;
269 bo = tegra_bo_create_with_handle(file, drm, args->size, args->flags,
277 static int tegra_gem_mmap(struct drm_device *drm, void *data,
278 struct drm_file *file)
280 struct drm_tegra_gem_mmap *args = data;
281 struct drm_gem_object *gem;
284 gem = drm_gem_object_lookup(drm, file, args->handle);
288 bo = to_tegra_bo(gem);
290 args->offset = drm_vma_node_offset_addr(&bo->gem.vma_node);
292 drm_gem_object_unreference(gem);
297 static int tegra_syncpt_read(struct drm_device *drm, void *data,
298 struct drm_file *file)
300 struct host1x *host = dev_get_drvdata(drm->dev->parent);
301 struct drm_tegra_syncpt_read *args = data;
302 struct host1x_syncpt *sp;
304 sp = host1x_syncpt_get(host, args->id);
308 args->value = host1x_syncpt_read_min(sp);
312 static int tegra_syncpt_incr(struct drm_device *drm, void *data,
313 struct drm_file *file)
315 struct host1x *host1x = dev_get_drvdata(drm->dev->parent);
316 struct drm_tegra_syncpt_incr *args = data;
317 struct host1x_syncpt *sp;
319 sp = host1x_syncpt_get(host1x, args->id);
323 return host1x_syncpt_incr(sp);
326 static int tegra_syncpt_wait(struct drm_device *drm, void *data,
327 struct drm_file *file)
329 struct host1x *host1x = dev_get_drvdata(drm->dev->parent);
330 struct drm_tegra_syncpt_wait *args = data;
331 struct host1x_syncpt *sp;
333 sp = host1x_syncpt_get(host1x, args->id);
337 return host1x_syncpt_wait(sp, args->thresh, args->timeout,
341 static int tegra_open_channel(struct drm_device *drm, void *data,
342 struct drm_file *file)
344 struct tegra_drm_file *fpriv = file->driver_priv;
345 struct tegra_drm *tegra = drm->dev_private;
346 struct drm_tegra_open_channel *args = data;
347 struct tegra_drm_context *context;
348 struct tegra_drm_client *client;
351 context = kzalloc(sizeof(*context), GFP_KERNEL);
355 list_for_each_entry(client, &tegra->clients, list)
356 if (client->base.class == args->client) {
357 err = client->ops->open_channel(client, context);
361 list_add(&context->list, &fpriv->contexts);
362 args->context = (uintptr_t)context;
363 context->client = client;
371 static int tegra_close_channel(struct drm_device *drm, void *data,
372 struct drm_file *file)
374 struct tegra_drm_file *fpriv = file->driver_priv;
375 struct drm_tegra_close_channel *args = data;
376 struct tegra_drm_context *context;
378 context = tegra_drm_get_context(args->context);
380 if (!tegra_drm_file_owns_context(fpriv, context))
383 list_del(&context->list);
384 tegra_drm_context_free(context);
389 static int tegra_get_syncpt(struct drm_device *drm, void *data,
390 struct drm_file *file)
392 struct tegra_drm_file *fpriv = file->driver_priv;
393 struct drm_tegra_get_syncpt *args = data;
394 struct tegra_drm_context *context;
395 struct host1x_syncpt *syncpt;
397 context = tegra_drm_get_context(args->context);
399 if (!tegra_drm_file_owns_context(fpriv, context))
402 if (args->index >= context->client->base.num_syncpts)
405 syncpt = context->client->base.syncpts[args->index];
406 args->id = host1x_syncpt_id(syncpt);
411 static int tegra_submit(struct drm_device *drm, void *data,
412 struct drm_file *file)
414 struct tegra_drm_file *fpriv = file->driver_priv;
415 struct drm_tegra_submit *args = data;
416 struct tegra_drm_context *context;
418 context = tegra_drm_get_context(args->context);
420 if (!tegra_drm_file_owns_context(fpriv, context))
423 return context->client->ops->submit(context, args, drm, file);
426 static int tegra_get_syncpt_base(struct drm_device *drm, void *data,
427 struct drm_file *file)
429 struct tegra_drm_file *fpriv = file->driver_priv;
430 struct drm_tegra_get_syncpt_base *args = data;
431 struct tegra_drm_context *context;
432 struct host1x_syncpt_base *base;
433 struct host1x_syncpt *syncpt;
435 context = tegra_drm_get_context(args->context);
437 if (!tegra_drm_file_owns_context(fpriv, context))
440 if (args->syncpt >= context->client->base.num_syncpts)
443 syncpt = context->client->base.syncpts[args->syncpt];
445 base = host1x_syncpt_get_base(syncpt);
449 args->id = host1x_syncpt_base_id(base);
455 static const struct drm_ioctl_desc tegra_drm_ioctls[] = {
456 #ifdef CONFIG_DRM_TEGRA_STAGING
457 DRM_IOCTL_DEF_DRV(TEGRA_GEM_CREATE, tegra_gem_create, DRM_UNLOCKED | DRM_AUTH),
458 DRM_IOCTL_DEF_DRV(TEGRA_GEM_MMAP, tegra_gem_mmap, DRM_UNLOCKED),
459 DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_READ, tegra_syncpt_read, DRM_UNLOCKED),
460 DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_INCR, tegra_syncpt_incr, DRM_UNLOCKED),
461 DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_WAIT, tegra_syncpt_wait, DRM_UNLOCKED),
462 DRM_IOCTL_DEF_DRV(TEGRA_OPEN_CHANNEL, tegra_open_channel, DRM_UNLOCKED),
463 DRM_IOCTL_DEF_DRV(TEGRA_CLOSE_CHANNEL, tegra_close_channel, DRM_UNLOCKED),
464 DRM_IOCTL_DEF_DRV(TEGRA_GET_SYNCPT, tegra_get_syncpt, DRM_UNLOCKED),
465 DRM_IOCTL_DEF_DRV(TEGRA_SUBMIT, tegra_submit, DRM_UNLOCKED),
466 DRM_IOCTL_DEF_DRV(TEGRA_GET_SYNCPT_BASE, tegra_get_syncpt_base, DRM_UNLOCKED),
470 static const struct file_operations tegra_drm_fops = {
471 .owner = THIS_MODULE,
473 .release = drm_release,
474 .unlocked_ioctl = drm_ioctl,
475 .mmap = tegra_drm_mmap,
479 .compat_ioctl = drm_compat_ioctl,
481 .llseek = noop_llseek,
484 static struct drm_crtc *tegra_crtc_from_pipe(struct drm_device *drm, int pipe)
486 struct drm_crtc *crtc;
488 list_for_each_entry(crtc, &drm->mode_config.crtc_list, head) {
489 struct tegra_dc *dc = to_tegra_dc(crtc);
491 if (dc->pipe == pipe)
498 static u32 tegra_drm_get_vblank_counter(struct drm_device *dev, int crtc)
500 /* TODO: implement real hardware counter using syncpoints */
501 return drm_vblank_count(dev, crtc);
504 static int tegra_drm_enable_vblank(struct drm_device *drm, int pipe)
506 struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe);
507 struct tegra_dc *dc = to_tegra_dc(crtc);
512 tegra_dc_enable_vblank(dc);
517 static void tegra_drm_disable_vblank(struct drm_device *drm, int pipe)
519 struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe);
520 struct tegra_dc *dc = to_tegra_dc(crtc);
523 tegra_dc_disable_vblank(dc);
526 static void tegra_drm_preclose(struct drm_device *drm, struct drm_file *file)
528 struct tegra_drm_file *fpriv = file->driver_priv;
529 struct tegra_drm_context *context, *tmp;
530 struct drm_crtc *crtc;
532 list_for_each_entry(crtc, &drm->mode_config.crtc_list, head)
533 tegra_dc_cancel_page_flip(crtc, file);
535 list_for_each_entry_safe(context, tmp, &fpriv->contexts, list)
536 tegra_drm_context_free(context);
541 #ifdef CONFIG_DEBUG_FS
542 static int tegra_debugfs_framebuffers(struct seq_file *s, void *data)
544 struct drm_info_node *node = (struct drm_info_node *)s->private;
545 struct drm_device *drm = node->minor->dev;
546 struct drm_framebuffer *fb;
548 mutex_lock(&drm->mode_config.fb_lock);
550 list_for_each_entry(fb, &drm->mode_config.fb_list, head) {
551 seq_printf(s, "%3d: user size: %d x %d, depth %d, %d bpp, refcount %d\n",
552 fb->base.id, fb->width, fb->height, fb->depth,
554 atomic_read(&fb->refcount.refcount));
557 mutex_unlock(&drm->mode_config.fb_lock);
562 static struct drm_info_list tegra_debugfs_list[] = {
563 { "framebuffers", tegra_debugfs_framebuffers, 0 },
566 static int tegra_debugfs_init(struct drm_minor *minor)
568 return drm_debugfs_create_files(tegra_debugfs_list,
569 ARRAY_SIZE(tegra_debugfs_list),
570 minor->debugfs_root, minor);
573 static void tegra_debugfs_cleanup(struct drm_minor *minor)
575 drm_debugfs_remove_files(tegra_debugfs_list,
576 ARRAY_SIZE(tegra_debugfs_list), minor);
580 static struct drm_driver tegra_drm_driver = {
581 .driver_features = DRIVER_MODESET | DRIVER_GEM,
582 .load = tegra_drm_load,
583 .unload = tegra_drm_unload,
584 .open = tegra_drm_open,
585 .preclose = tegra_drm_preclose,
586 .lastclose = tegra_drm_lastclose,
588 .get_vblank_counter = tegra_drm_get_vblank_counter,
589 .enable_vblank = tegra_drm_enable_vblank,
590 .disable_vblank = tegra_drm_disable_vblank,
592 #if defined(CONFIG_DEBUG_FS)
593 .debugfs_init = tegra_debugfs_init,
594 .debugfs_cleanup = tegra_debugfs_cleanup,
597 .gem_free_object = tegra_bo_free_object,
598 .gem_vm_ops = &tegra_bo_vm_ops,
599 .dumb_create = tegra_bo_dumb_create,
600 .dumb_map_offset = tegra_bo_dumb_map_offset,
601 .dumb_destroy = drm_gem_dumb_destroy,
603 .ioctls = tegra_drm_ioctls,
604 .num_ioctls = ARRAY_SIZE(tegra_drm_ioctls),
605 .fops = &tegra_drm_fops,
610 .major = DRIVER_MAJOR,
611 .minor = DRIVER_MINOR,
612 .patchlevel = DRIVER_PATCHLEVEL,
615 int tegra_drm_register_client(struct tegra_drm *tegra,
616 struct tegra_drm_client *client)
618 mutex_lock(&tegra->clients_lock);
619 list_add_tail(&client->list, &tegra->clients);
620 mutex_unlock(&tegra->clients_lock);
625 int tegra_drm_unregister_client(struct tegra_drm *tegra,
626 struct tegra_drm_client *client)
628 mutex_lock(&tegra->clients_lock);
629 list_del_init(&client->list);
630 mutex_unlock(&tegra->clients_lock);
635 static int host1x_drm_probe(struct host1x_device *device)
637 return drm_host1x_init(&tegra_drm_driver, device);
640 static int host1x_drm_remove(struct host1x_device *device)
642 drm_host1x_exit(&tegra_drm_driver, device);
647 static const struct of_device_id host1x_drm_subdevs[] = {
648 { .compatible = "nvidia,tegra20-dc", },
649 { .compatible = "nvidia,tegra20-hdmi", },
650 { .compatible = "nvidia,tegra20-gr2d", },
651 { .compatible = "nvidia,tegra20-gr3d", },
652 { .compatible = "nvidia,tegra30-dc", },
653 { .compatible = "nvidia,tegra30-hdmi", },
654 { .compatible = "nvidia,tegra30-gr2d", },
655 { .compatible = "nvidia,tegra30-gr3d", },
656 { .compatible = "nvidia,tegra114-hdmi", },
657 { .compatible = "nvidia,tegra114-gr3d", },
661 static struct host1x_driver host1x_drm_driver = {
663 .probe = host1x_drm_probe,
664 .remove = host1x_drm_remove,
665 .subdevs = host1x_drm_subdevs,
668 static int __init host1x_drm_init(void)
672 err = host1x_driver_register(&host1x_drm_driver);
676 err = platform_driver_register(&tegra_dc_driver);
678 goto unregister_host1x;
680 err = platform_driver_register(&tegra_hdmi_driver);
684 err = platform_driver_register(&tegra_gr2d_driver);
686 goto unregister_hdmi;
688 err = platform_driver_register(&tegra_gr3d_driver);
690 goto unregister_gr2d;
695 platform_driver_unregister(&tegra_gr2d_driver);
697 platform_driver_unregister(&tegra_hdmi_driver);
699 platform_driver_unregister(&tegra_dc_driver);
701 host1x_driver_unregister(&host1x_drm_driver);
704 module_init(host1x_drm_init);
706 static void __exit host1x_drm_exit(void)
708 platform_driver_unregister(&tegra_gr3d_driver);
709 platform_driver_unregister(&tegra_gr2d_driver);
710 platform_driver_unregister(&tegra_hdmi_driver);
711 platform_driver_unregister(&tegra_dc_driver);
712 host1x_driver_unregister(&host1x_drm_driver);
714 module_exit(host1x_drm_exit);
716 MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>");
717 MODULE_DESCRIPTION("NVIDIA Tegra DRM driver");
718 MODULE_LICENSE("GPL v2");