]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blame - drivers/gpu/drm/tegra/drm.c
drm/tegra: gem: Use more consistent data types
[mirror_ubuntu-hirsute-kernel.git] / drivers / gpu / drm / tegra / drm.c
CommitLineData
d8f4a9ed
TR
1/*
2 * Copyright (C) 2012 Avionic Design GmbH
d43f81cb 3 * Copyright (C) 2012-2013 NVIDIA CORPORATION. All rights reserved.
d8f4a9ed
TR
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
776dc384 10#include <linux/host1x.h>
df06b759 11#include <linux/iommu.h>
776dc384 12
d8f4a9ed 13#include "drm.h"
de2ba664 14#include "gem.h"
d8f4a9ed
TR
15
16#define DRIVER_NAME "tegra"
17#define DRIVER_DESC "NVIDIA Tegra graphics"
18#define DRIVER_DATE "20120330"
19#define DRIVER_MAJOR 0
20#define DRIVER_MINOR 0
21#define DRIVER_PATCHLEVEL 0
22
08943e6c
TR
23struct tegra_drm_file {
24 struct list_head contexts;
25};
26
776dc384 27static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
692e6d7b 28{
776dc384 29 struct host1x_device *device = to_host1x_device(drm->dev);
386a2a71 30 struct tegra_drm *tegra;
692e6d7b
TB
31 int err;
32
776dc384 33 tegra = kzalloc(sizeof(*tegra), GFP_KERNEL);
386a2a71 34 if (!tegra)
692e6d7b
TB
35 return -ENOMEM;
36
df06b759
TR
37 if (iommu_present(&platform_bus_type)) {
38 tegra->domain = iommu_domain_alloc(&platform_bus_type);
39 if (IS_ERR(tegra->domain)) {
40 err = PTR_ERR(tegra->domain);
41 goto free;
42 }
43
44 DRM_DEBUG("IOMMU context initialized\n");
45 drm_mm_init(&tegra->mm, 0, SZ_2G);
46 }
47
386a2a71
TR
48 mutex_init(&tegra->clients_lock);
49 INIT_LIST_HEAD(&tegra->clients);
386a2a71
TR
50 drm->dev_private = tegra;
51 tegra->drm = drm;
d8f4a9ed
TR
52
53 drm_mode_config_init(drm);
54
e2215321
TR
55 err = tegra_drm_fb_prepare(drm);
56 if (err < 0)
1d1e6fe9 57 goto config;
e2215321
TR
58
59 drm_kms_helper_poll_init(drm);
60
776dc384 61 err = host1x_device_init(device);
d8f4a9ed 62 if (err < 0)
1d1e6fe9 63 goto fbdev;
d8f4a9ed 64
603f0cc9
TR
65 /*
66 * We don't use the drm_irq_install() helpers provided by the DRM
67 * core, so we need to set this manually in order to allow the
68 * DRM_IOCTL_WAIT_VBLANK to operate correctly.
69 */
4423843c 70 drm->irq_enabled = true;
603f0cc9 71
6e5ff998
TR
72 err = drm_vblank_init(drm, drm->mode_config.num_crtc);
73 if (err < 0)
1d1e6fe9 74 goto device;
6e5ff998 75
d8f4a9ed
TR
76 err = tegra_drm_fb_init(drm);
77 if (err < 0)
1d1e6fe9 78 goto vblank;
d8f4a9ed 79
d8f4a9ed 80 return 0;
1d1e6fe9
TR
81
82vblank:
83 drm_vblank_cleanup(drm);
84device:
85 host1x_device_exit(device);
86fbdev:
87 drm_kms_helper_poll_fini(drm);
88 tegra_drm_fb_free(drm);
89config:
90 drm_mode_config_cleanup(drm);
df06b759
TR
91
92 if (tegra->domain) {
93 iommu_domain_free(tegra->domain);
94 drm_mm_takedown(&tegra->mm);
95 }
96free:
1d1e6fe9
TR
97 kfree(tegra);
98 return err;
d8f4a9ed
TR
99}
100
101static int tegra_drm_unload(struct drm_device *drm)
102{
776dc384 103 struct host1x_device *device = to_host1x_device(drm->dev);
df06b759 104 struct tegra_drm *tegra = drm->dev_private;
776dc384
TR
105 int err;
106
d8f4a9ed
TR
107 drm_kms_helper_poll_fini(drm);
108 tegra_drm_fb_exit(drm);
f002abc1
TR
109 drm_vblank_cleanup(drm);
110 drm_mode_config_cleanup(drm);
d8f4a9ed 111
776dc384
TR
112 err = host1x_device_exit(device);
113 if (err < 0)
114 return err;
115
df06b759
TR
116 if (tegra->domain) {
117 iommu_domain_free(tegra->domain);
118 drm_mm_takedown(&tegra->mm);
119 }
120
d8f4a9ed
TR
121 return 0;
122}
123
124static int tegra_drm_open(struct drm_device *drm, struct drm_file *filp)
125{
08943e6c 126 struct tegra_drm_file *fpriv;
d43f81cb
TB
127
128 fpriv = kzalloc(sizeof(*fpriv), GFP_KERNEL);
129 if (!fpriv)
130 return -ENOMEM;
131
132 INIT_LIST_HEAD(&fpriv->contexts);
133 filp->driver_priv = fpriv;
134
d8f4a9ed
TR
135 return 0;
136}
137
c88c3630 138static void tegra_drm_context_free(struct tegra_drm_context *context)
d43f81cb
TB
139{
140 context->client->ops->close_channel(context);
141 kfree(context);
142}
143
d8f4a9ed
TR
144static void tegra_drm_lastclose(struct drm_device *drm)
145{
6e60163b 146#ifdef CONFIG_DRM_TEGRA_FBDEV
386a2a71 147 struct tegra_drm *tegra = drm->dev_private;
d8f4a9ed 148
386a2a71 149 tegra_fbdev_restore_mode(tegra->fbdev);
60c2f709 150#endif
d8f4a9ed
TR
151}
152
c40f0f1a
TR
153static struct host1x_bo *
154host1x_bo_lookup(struct drm_device *drm, struct drm_file *file, u32 handle)
155{
156 struct drm_gem_object *gem;
157 struct tegra_bo *bo;
158
159 gem = drm_gem_object_lookup(drm, file, handle);
160 if (!gem)
161 return NULL;
162
163 mutex_lock(&drm->struct_mutex);
164 drm_gem_object_unreference(gem);
165 mutex_unlock(&drm->struct_mutex);
166
167 bo = to_tegra_bo(gem);
168 return &bo->base;
169}
170
961e3bea
TR
171static int host1x_reloc_copy_from_user(struct host1x_reloc *dest,
172 struct drm_tegra_reloc __user *src,
173 struct drm_device *drm,
174 struct drm_file *file)
175{
176 u32 cmdbuf, target;
177 int err;
178
179 err = get_user(cmdbuf, &src->cmdbuf.handle);
180 if (err < 0)
181 return err;
182
183 err = get_user(dest->cmdbuf.offset, &src->cmdbuf.offset);
184 if (err < 0)
185 return err;
186
187 err = get_user(target, &src->target.handle);
188 if (err < 0)
189 return err;
190
191 err = get_user(dest->target.offset, &src->cmdbuf.offset);
192 if (err < 0)
193 return err;
194
195 err = get_user(dest->shift, &src->shift);
196 if (err < 0)
197 return err;
198
199 dest->cmdbuf.bo = host1x_bo_lookup(drm, file, cmdbuf);
200 if (!dest->cmdbuf.bo)
201 return -ENOENT;
202
203 dest->target.bo = host1x_bo_lookup(drm, file, target);
204 if (!dest->target.bo)
205 return -ENOENT;
206
207 return 0;
208}
209
c40f0f1a
TR
210int tegra_drm_submit(struct tegra_drm_context *context,
211 struct drm_tegra_submit *args, struct drm_device *drm,
212 struct drm_file *file)
213{
214 unsigned int num_cmdbufs = args->num_cmdbufs;
215 unsigned int num_relocs = args->num_relocs;
216 unsigned int num_waitchks = args->num_waitchks;
217 struct drm_tegra_cmdbuf __user *cmdbufs =
a7ed68fc 218 (void __user *)(uintptr_t)args->cmdbufs;
c40f0f1a 219 struct drm_tegra_reloc __user *relocs =
a7ed68fc 220 (void __user *)(uintptr_t)args->relocs;
c40f0f1a 221 struct drm_tegra_waitchk __user *waitchks =
a7ed68fc 222 (void __user *)(uintptr_t)args->waitchks;
c40f0f1a
TR
223 struct drm_tegra_syncpt syncpt;
224 struct host1x_job *job;
225 int err;
226
227 /* We don't yet support other than one syncpt_incr struct per submit */
228 if (args->num_syncpts != 1)
229 return -EINVAL;
230
231 job = host1x_job_alloc(context->channel, args->num_cmdbufs,
232 args->num_relocs, args->num_waitchks);
233 if (!job)
234 return -ENOMEM;
235
236 job->num_relocs = args->num_relocs;
237 job->num_waitchk = args->num_waitchks;
238 job->client = (u32)args->context;
239 job->class = context->client->base.class;
240 job->serialize = true;
241
242 while (num_cmdbufs) {
243 struct drm_tegra_cmdbuf cmdbuf;
244 struct host1x_bo *bo;
245
9a991600
DC
246 if (copy_from_user(&cmdbuf, cmdbufs, sizeof(cmdbuf))) {
247 err = -EFAULT;
c40f0f1a 248 goto fail;
9a991600 249 }
c40f0f1a
TR
250
251 bo = host1x_bo_lookup(drm, file, cmdbuf.handle);
252 if (!bo) {
253 err = -ENOENT;
254 goto fail;
255 }
256
257 host1x_job_add_gather(job, bo, cmdbuf.words, cmdbuf.offset);
258 num_cmdbufs--;
259 cmdbufs++;
260 }
261
961e3bea 262 /* copy and resolve relocations from submit */
c40f0f1a 263 while (num_relocs--) {
961e3bea
TR
264 err = host1x_reloc_copy_from_user(&job->relocarray[num_relocs],
265 &relocs[num_relocs], drm,
266 file);
267 if (err < 0)
c40f0f1a 268 goto fail;
c40f0f1a
TR
269 }
270
9a991600
DC
271 if (copy_from_user(job->waitchk, waitchks,
272 sizeof(*waitchks) * num_waitchks)) {
273 err = -EFAULT;
c40f0f1a 274 goto fail;
9a991600 275 }
c40f0f1a 276
9a991600
DC
277 if (copy_from_user(&syncpt, (void __user *)(uintptr_t)args->syncpts,
278 sizeof(syncpt))) {
279 err = -EFAULT;
c40f0f1a 280 goto fail;
9a991600 281 }
c40f0f1a
TR
282
283 job->is_addr_reg = context->client->ops->is_addr_reg;
284 job->syncpt_incrs = syncpt.incrs;
285 job->syncpt_id = syncpt.id;
286 job->timeout = 10000;
287
288 if (args->timeout && args->timeout < 10000)
289 job->timeout = args->timeout;
290
291 err = host1x_job_pin(job, context->client->base.dev);
292 if (err)
293 goto fail;
294
295 err = host1x_job_submit(job);
296 if (err)
297 goto fail_submit;
298
299 args->fence = job->syncpt_end;
300
301 host1x_job_put(job);
302 return 0;
303
304fail_submit:
305 host1x_job_unpin(job);
306fail:
307 host1x_job_put(job);
308 return err;
309}
310
311
d43f81cb 312#ifdef CONFIG_DRM_TEGRA_STAGING
c88c3630
TR
313static struct tegra_drm_context *tegra_drm_get_context(__u64 context)
314{
315 return (struct tegra_drm_context *)(uintptr_t)context;
316}
317
08943e6c 318static bool tegra_drm_file_owns_context(struct tegra_drm_file *file,
c88c3630 319 struct tegra_drm_context *context)
d43f81cb 320{
c88c3630 321 struct tegra_drm_context *ctx;
d43f81cb
TB
322
323 list_for_each_entry(ctx, &file->contexts, list)
324 if (ctx == context)
325 return true;
326
327 return false;
328}
329
330static int tegra_gem_create(struct drm_device *drm, void *data,
331 struct drm_file *file)
332{
333 struct drm_tegra_gem_create *args = data;
334 struct tegra_bo *bo;
335
773af77f 336 bo = tegra_bo_create_with_handle(file, drm, args->size, args->flags,
d43f81cb
TB
337 &args->handle);
338 if (IS_ERR(bo))
339 return PTR_ERR(bo);
340
341 return 0;
342}
343
344static int tegra_gem_mmap(struct drm_device *drm, void *data,
345 struct drm_file *file)
346{
347 struct drm_tegra_gem_mmap *args = data;
348 struct drm_gem_object *gem;
349 struct tegra_bo *bo;
350
351 gem = drm_gem_object_lookup(drm, file, args->handle);
352 if (!gem)
353 return -EINVAL;
354
355 bo = to_tegra_bo(gem);
356
2bc7b0ca 357 args->offset = drm_vma_node_offset_addr(&bo->gem.vma_node);
d43f81cb
TB
358
359 drm_gem_object_unreference(gem);
360
361 return 0;
362}
363
364static int tegra_syncpt_read(struct drm_device *drm, void *data,
365 struct drm_file *file)
366{
776dc384 367 struct host1x *host = dev_get_drvdata(drm->dev->parent);
d43f81cb 368 struct drm_tegra_syncpt_read *args = data;
776dc384 369 struct host1x_syncpt *sp;
d43f81cb 370
776dc384 371 sp = host1x_syncpt_get(host, args->id);
d43f81cb
TB
372 if (!sp)
373 return -EINVAL;
374
375 args->value = host1x_syncpt_read_min(sp);
376 return 0;
377}
378
379static int tegra_syncpt_incr(struct drm_device *drm, void *data,
380 struct drm_file *file)
381{
776dc384 382 struct host1x *host1x = dev_get_drvdata(drm->dev->parent);
d43f81cb 383 struct drm_tegra_syncpt_incr *args = data;
776dc384 384 struct host1x_syncpt *sp;
d43f81cb 385
776dc384 386 sp = host1x_syncpt_get(host1x, args->id);
d43f81cb
TB
387 if (!sp)
388 return -EINVAL;
389
ebae30b1 390 return host1x_syncpt_incr(sp);
d43f81cb
TB
391}
392
393static int tegra_syncpt_wait(struct drm_device *drm, void *data,
394 struct drm_file *file)
395{
776dc384 396 struct host1x *host1x = dev_get_drvdata(drm->dev->parent);
d43f81cb 397 struct drm_tegra_syncpt_wait *args = data;
776dc384 398 struct host1x_syncpt *sp;
d43f81cb 399
776dc384 400 sp = host1x_syncpt_get(host1x, args->id);
d43f81cb
TB
401 if (!sp)
402 return -EINVAL;
403
404 return host1x_syncpt_wait(sp, args->thresh, args->timeout,
405 &args->value);
406}
407
408static int tegra_open_channel(struct drm_device *drm, void *data,
409 struct drm_file *file)
410{
08943e6c 411 struct tegra_drm_file *fpriv = file->driver_priv;
386a2a71 412 struct tegra_drm *tegra = drm->dev_private;
d43f81cb 413 struct drm_tegra_open_channel *args = data;
c88c3630 414 struct tegra_drm_context *context;
53fa7f72 415 struct tegra_drm_client *client;
d43f81cb
TB
416 int err = -ENODEV;
417
418 context = kzalloc(sizeof(*context), GFP_KERNEL);
419 if (!context)
420 return -ENOMEM;
421
776dc384 422 list_for_each_entry(client, &tegra->clients, list)
53fa7f72 423 if (client->base.class == args->client) {
d43f81cb
TB
424 err = client->ops->open_channel(client, context);
425 if (err)
426 break;
427
d43f81cb
TB
428 list_add(&context->list, &fpriv->contexts);
429 args->context = (uintptr_t)context;
53fa7f72 430 context->client = client;
d43f81cb
TB
431 return 0;
432 }
433
434 kfree(context);
435 return err;
436}
437
438static int tegra_close_channel(struct drm_device *drm, void *data,
439 struct drm_file *file)
440{
08943e6c 441 struct tegra_drm_file *fpriv = file->driver_priv;
776dc384 442 struct drm_tegra_close_channel *args = data;
c88c3630
TR
443 struct tegra_drm_context *context;
444
445 context = tegra_drm_get_context(args->context);
d43f81cb 446
08943e6c 447 if (!tegra_drm_file_owns_context(fpriv, context))
d43f81cb
TB
448 return -EINVAL;
449
450 list_del(&context->list);
c88c3630 451 tegra_drm_context_free(context);
d43f81cb
TB
452
453 return 0;
454}
455
456static int tegra_get_syncpt(struct drm_device *drm, void *data,
457 struct drm_file *file)
458{
08943e6c 459 struct tegra_drm_file *fpriv = file->driver_priv;
d43f81cb 460 struct drm_tegra_get_syncpt *args = data;
c88c3630 461 struct tegra_drm_context *context;
d43f81cb
TB
462 struct host1x_syncpt *syncpt;
463
c88c3630
TR
464 context = tegra_drm_get_context(args->context);
465
08943e6c 466 if (!tegra_drm_file_owns_context(fpriv, context))
d43f81cb
TB
467 return -ENODEV;
468
53fa7f72 469 if (args->index >= context->client->base.num_syncpts)
d43f81cb
TB
470 return -EINVAL;
471
53fa7f72 472 syncpt = context->client->base.syncpts[args->index];
d43f81cb
TB
473 args->id = host1x_syncpt_id(syncpt);
474
475 return 0;
476}
477
478static int tegra_submit(struct drm_device *drm, void *data,
479 struct drm_file *file)
480{
08943e6c 481 struct tegra_drm_file *fpriv = file->driver_priv;
d43f81cb 482 struct drm_tegra_submit *args = data;
c88c3630
TR
483 struct tegra_drm_context *context;
484
485 context = tegra_drm_get_context(args->context);
d43f81cb 486
08943e6c 487 if (!tegra_drm_file_owns_context(fpriv, context))
d43f81cb
TB
488 return -ENODEV;
489
490 return context->client->ops->submit(context, args, drm, file);
491}
c54a169b
AM
492
493static int tegra_get_syncpt_base(struct drm_device *drm, void *data,
494 struct drm_file *file)
495{
496 struct tegra_drm_file *fpriv = file->driver_priv;
497 struct drm_tegra_get_syncpt_base *args = data;
498 struct tegra_drm_context *context;
499 struct host1x_syncpt_base *base;
500 struct host1x_syncpt *syncpt;
501
502 context = tegra_drm_get_context(args->context);
503
504 if (!tegra_drm_file_owns_context(fpriv, context))
505 return -ENODEV;
506
507 if (args->syncpt >= context->client->base.num_syncpts)
508 return -EINVAL;
509
510 syncpt = context->client->base.syncpts[args->syncpt];
511
512 base = host1x_syncpt_get_base(syncpt);
513 if (!base)
514 return -ENXIO;
515
516 args->id = host1x_syncpt_base_id(base);
517
518 return 0;
519}
7678d71f
TR
520
521static int tegra_gem_set_tiling(struct drm_device *drm, void *data,
522 struct drm_file *file)
523{
524 struct drm_tegra_gem_set_tiling *args = data;
525 enum tegra_bo_tiling_mode mode;
526 struct drm_gem_object *gem;
527 unsigned long value = 0;
528 struct tegra_bo *bo;
529
530 switch (args->mode) {
531 case DRM_TEGRA_GEM_TILING_MODE_PITCH:
532 mode = TEGRA_BO_TILING_MODE_PITCH;
533
534 if (args->value != 0)
535 return -EINVAL;
536
537 break;
538
539 case DRM_TEGRA_GEM_TILING_MODE_TILED:
540 mode = TEGRA_BO_TILING_MODE_TILED;
541
542 if (args->value != 0)
543 return -EINVAL;
544
545 break;
546
547 case DRM_TEGRA_GEM_TILING_MODE_BLOCK:
548 mode = TEGRA_BO_TILING_MODE_BLOCK;
549
550 if (args->value > 5)
551 return -EINVAL;
552
553 value = args->value;
554 break;
555
556 default:
557 return -EINVAL;
558 }
559
560 gem = drm_gem_object_lookup(drm, file, args->handle);
561 if (!gem)
562 return -ENOENT;
563
564 bo = to_tegra_bo(gem);
565
566 bo->tiling.mode = mode;
567 bo->tiling.value = value;
568
569 drm_gem_object_unreference(gem);
570
571 return 0;
572}
573
574static int tegra_gem_get_tiling(struct drm_device *drm, void *data,
575 struct drm_file *file)
576{
577 struct drm_tegra_gem_get_tiling *args = data;
578 struct drm_gem_object *gem;
579 struct tegra_bo *bo;
580 int err = 0;
581
582 gem = drm_gem_object_lookup(drm, file, args->handle);
583 if (!gem)
584 return -ENOENT;
585
586 bo = to_tegra_bo(gem);
587
588 switch (bo->tiling.mode) {
589 case TEGRA_BO_TILING_MODE_PITCH:
590 args->mode = DRM_TEGRA_GEM_TILING_MODE_PITCH;
591 args->value = 0;
592 break;
593
594 case TEGRA_BO_TILING_MODE_TILED:
595 args->mode = DRM_TEGRA_GEM_TILING_MODE_TILED;
596 args->value = 0;
597 break;
598
599 case TEGRA_BO_TILING_MODE_BLOCK:
600 args->mode = DRM_TEGRA_GEM_TILING_MODE_BLOCK;
601 args->value = bo->tiling.value;
602 break;
603
604 default:
605 err = -EINVAL;
606 break;
607 }
608
609 drm_gem_object_unreference(gem);
610
611 return err;
612}
7b129087
TR
613
614static int tegra_gem_set_flags(struct drm_device *drm, void *data,
615 struct drm_file *file)
616{
617 struct drm_tegra_gem_set_flags *args = data;
618 struct drm_gem_object *gem;
619 struct tegra_bo *bo;
620
621 if (args->flags & ~DRM_TEGRA_GEM_FLAGS)
622 return -EINVAL;
623
624 gem = drm_gem_object_lookup(drm, file, args->handle);
625 if (!gem)
626 return -ENOENT;
627
628 bo = to_tegra_bo(gem);
629 bo->flags = 0;
630
631 if (args->flags & DRM_TEGRA_GEM_BOTTOM_UP)
632 bo->flags |= TEGRA_BO_BOTTOM_UP;
633
634 drm_gem_object_unreference(gem);
635
636 return 0;
637}
638
639static int tegra_gem_get_flags(struct drm_device *drm, void *data,
640 struct drm_file *file)
641{
642 struct drm_tegra_gem_get_flags *args = data;
643 struct drm_gem_object *gem;
644 struct tegra_bo *bo;
645
646 gem = drm_gem_object_lookup(drm, file, args->handle);
647 if (!gem)
648 return -ENOENT;
649
650 bo = to_tegra_bo(gem);
651 args->flags = 0;
652
653 if (bo->flags & TEGRA_BO_BOTTOM_UP)
654 args->flags |= DRM_TEGRA_GEM_BOTTOM_UP;
655
656 drm_gem_object_unreference(gem);
657
658 return 0;
659}
d43f81cb
TB
660#endif
661
baa70943 662static const struct drm_ioctl_desc tegra_drm_ioctls[] = {
d43f81cb 663#ifdef CONFIG_DRM_TEGRA_STAGING
bd4f2360 664 DRM_IOCTL_DEF_DRV(TEGRA_GEM_CREATE, tegra_gem_create, DRM_UNLOCKED),
d43f81cb
TB
665 DRM_IOCTL_DEF_DRV(TEGRA_GEM_MMAP, tegra_gem_mmap, DRM_UNLOCKED),
666 DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_READ, tegra_syncpt_read, DRM_UNLOCKED),
667 DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_INCR, tegra_syncpt_incr, DRM_UNLOCKED),
668 DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_WAIT, tegra_syncpt_wait, DRM_UNLOCKED),
669 DRM_IOCTL_DEF_DRV(TEGRA_OPEN_CHANNEL, tegra_open_channel, DRM_UNLOCKED),
670 DRM_IOCTL_DEF_DRV(TEGRA_CLOSE_CHANNEL, tegra_close_channel, DRM_UNLOCKED),
671 DRM_IOCTL_DEF_DRV(TEGRA_GET_SYNCPT, tegra_get_syncpt, DRM_UNLOCKED),
672 DRM_IOCTL_DEF_DRV(TEGRA_SUBMIT, tegra_submit, DRM_UNLOCKED),
c54a169b 673 DRM_IOCTL_DEF_DRV(TEGRA_GET_SYNCPT_BASE, tegra_get_syncpt_base, DRM_UNLOCKED),
7678d71f
TR
674 DRM_IOCTL_DEF_DRV(TEGRA_GEM_SET_TILING, tegra_gem_set_tiling, DRM_UNLOCKED),
675 DRM_IOCTL_DEF_DRV(TEGRA_GEM_GET_TILING, tegra_gem_get_tiling, DRM_UNLOCKED),
7b129087
TR
676 DRM_IOCTL_DEF_DRV(TEGRA_GEM_SET_FLAGS, tegra_gem_set_flags, DRM_UNLOCKED),
677 DRM_IOCTL_DEF_DRV(TEGRA_GEM_GET_FLAGS, tegra_gem_get_flags, DRM_UNLOCKED),
d43f81cb 678#endif
d8f4a9ed
TR
679};
680
681static const struct file_operations tegra_drm_fops = {
682 .owner = THIS_MODULE,
683 .open = drm_open,
684 .release = drm_release,
685 .unlocked_ioctl = drm_ioctl,
de2ba664 686 .mmap = tegra_drm_mmap,
d8f4a9ed 687 .poll = drm_poll,
d8f4a9ed
TR
688 .read = drm_read,
689#ifdef CONFIG_COMPAT
690 .compat_ioctl = drm_compat_ioctl,
691#endif
692 .llseek = noop_llseek,
693};
694
6e5ff998
TR
695static struct drm_crtc *tegra_crtc_from_pipe(struct drm_device *drm, int pipe)
696{
697 struct drm_crtc *crtc;
698
699 list_for_each_entry(crtc, &drm->mode_config.crtc_list, head) {
700 struct tegra_dc *dc = to_tegra_dc(crtc);
701
702 if (dc->pipe == pipe)
703 return crtc;
704 }
705
706 return NULL;
707}
708
709static u32 tegra_drm_get_vblank_counter(struct drm_device *dev, int crtc)
710{
711 /* TODO: implement real hardware counter using syncpoints */
712 return drm_vblank_count(dev, crtc);
713}
714
715static int tegra_drm_enable_vblank(struct drm_device *drm, int pipe)
716{
717 struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe);
718 struct tegra_dc *dc = to_tegra_dc(crtc);
719
720 if (!crtc)
721 return -ENODEV;
722
723 tegra_dc_enable_vblank(dc);
724
725 return 0;
726}
727
728static void tegra_drm_disable_vblank(struct drm_device *drm, int pipe)
729{
730 struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe);
731 struct tegra_dc *dc = to_tegra_dc(crtc);
732
733 if (crtc)
734 tegra_dc_disable_vblank(dc);
735}
736
3c03c46a
TR
737static void tegra_drm_preclose(struct drm_device *drm, struct drm_file *file)
738{
08943e6c 739 struct tegra_drm_file *fpriv = file->driver_priv;
c88c3630 740 struct tegra_drm_context *context, *tmp;
3c03c46a
TR
741 struct drm_crtc *crtc;
742
743 list_for_each_entry(crtc, &drm->mode_config.crtc_list, head)
744 tegra_dc_cancel_page_flip(crtc, file);
d43f81cb
TB
745
746 list_for_each_entry_safe(context, tmp, &fpriv->contexts, list)
c88c3630 747 tegra_drm_context_free(context);
d43f81cb
TB
748
749 kfree(fpriv);
3c03c46a
TR
750}
751
e450fcc6
TR
752#ifdef CONFIG_DEBUG_FS
753static int tegra_debugfs_framebuffers(struct seq_file *s, void *data)
754{
755 struct drm_info_node *node = (struct drm_info_node *)s->private;
756 struct drm_device *drm = node->minor->dev;
757 struct drm_framebuffer *fb;
758
759 mutex_lock(&drm->mode_config.fb_lock);
760
761 list_for_each_entry(fb, &drm->mode_config.fb_list, head) {
762 seq_printf(s, "%3d: user size: %d x %d, depth %d, %d bpp, refcount %d\n",
763 fb->base.id, fb->width, fb->height, fb->depth,
764 fb->bits_per_pixel,
765 atomic_read(&fb->refcount.refcount));
766 }
767
768 mutex_unlock(&drm->mode_config.fb_lock);
769
770 return 0;
771}
772
773static struct drm_info_list tegra_debugfs_list[] = {
774 { "framebuffers", tegra_debugfs_framebuffers, 0 },
775};
776
777static int tegra_debugfs_init(struct drm_minor *minor)
778{
779 return drm_debugfs_create_files(tegra_debugfs_list,
780 ARRAY_SIZE(tegra_debugfs_list),
781 minor->debugfs_root, minor);
782}
783
784static void tegra_debugfs_cleanup(struct drm_minor *minor)
785{
786 drm_debugfs_remove_files(tegra_debugfs_list,
787 ARRAY_SIZE(tegra_debugfs_list), minor);
788}
789#endif
790
9b57f5f2 791static struct drm_driver tegra_drm_driver = {
3800391d 792 .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME,
d8f4a9ed
TR
793 .load = tegra_drm_load,
794 .unload = tegra_drm_unload,
795 .open = tegra_drm_open,
3c03c46a 796 .preclose = tegra_drm_preclose,
d8f4a9ed
TR
797 .lastclose = tegra_drm_lastclose,
798
6e5ff998
TR
799 .get_vblank_counter = tegra_drm_get_vblank_counter,
800 .enable_vblank = tegra_drm_enable_vblank,
801 .disable_vblank = tegra_drm_disable_vblank,
802
e450fcc6
TR
803#if defined(CONFIG_DEBUG_FS)
804 .debugfs_init = tegra_debugfs_init,
805 .debugfs_cleanup = tegra_debugfs_cleanup,
806#endif
807
de2ba664
AM
808 .gem_free_object = tegra_bo_free_object,
809 .gem_vm_ops = &tegra_bo_vm_ops,
3800391d
TR
810
811 .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
812 .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
813 .gem_prime_export = tegra_gem_prime_export,
814 .gem_prime_import = tegra_gem_prime_import,
815
de2ba664
AM
816 .dumb_create = tegra_bo_dumb_create,
817 .dumb_map_offset = tegra_bo_dumb_map_offset,
43387b37 818 .dumb_destroy = drm_gem_dumb_destroy,
d8f4a9ed
TR
819
820 .ioctls = tegra_drm_ioctls,
821 .num_ioctls = ARRAY_SIZE(tegra_drm_ioctls),
822 .fops = &tegra_drm_fops,
823
824 .name = DRIVER_NAME,
825 .desc = DRIVER_DESC,
826 .date = DRIVER_DATE,
827 .major = DRIVER_MAJOR,
828 .minor = DRIVER_MINOR,
829 .patchlevel = DRIVER_PATCHLEVEL,
830};
776dc384
TR
831
832int tegra_drm_register_client(struct tegra_drm *tegra,
833 struct tegra_drm_client *client)
834{
835 mutex_lock(&tegra->clients_lock);
836 list_add_tail(&client->list, &tegra->clients);
837 mutex_unlock(&tegra->clients_lock);
838
839 return 0;
840}
841
842int tegra_drm_unregister_client(struct tegra_drm *tegra,
843 struct tegra_drm_client *client)
844{
845 mutex_lock(&tegra->clients_lock);
846 list_del_init(&client->list);
847 mutex_unlock(&tegra->clients_lock);
848
849 return 0;
850}
851
9910f5c4 852static int host1x_drm_probe(struct host1x_device *dev)
776dc384 853{
9910f5c4
TR
854 struct drm_driver *driver = &tegra_drm_driver;
855 struct drm_device *drm;
856 int err;
857
858 drm = drm_dev_alloc(driver, &dev->dev);
859 if (!drm)
860 return -ENOMEM;
861
862 drm_dev_set_unique(drm, dev_name(&dev->dev));
863 dev_set_drvdata(&dev->dev, drm);
864
865 err = drm_dev_register(drm, 0);
866 if (err < 0)
867 goto unref;
868
869 DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", driver->name,
870 driver->major, driver->minor, driver->patchlevel,
871 driver->date, drm->primary->index);
872
873 return 0;
874
875unref:
876 drm_dev_unref(drm);
877 return err;
776dc384
TR
878}
879
9910f5c4 880static int host1x_drm_remove(struct host1x_device *dev)
776dc384 881{
9910f5c4
TR
882 struct drm_device *drm = dev_get_drvdata(&dev->dev);
883
884 drm_dev_unregister(drm);
885 drm_dev_unref(drm);
776dc384
TR
886
887 return 0;
888}
889
890static const struct of_device_id host1x_drm_subdevs[] = {
891 { .compatible = "nvidia,tegra20-dc", },
892 { .compatible = "nvidia,tegra20-hdmi", },
893 { .compatible = "nvidia,tegra20-gr2d", },
5f60ed0d 894 { .compatible = "nvidia,tegra20-gr3d", },
776dc384
TR
895 { .compatible = "nvidia,tegra30-dc", },
896 { .compatible = "nvidia,tegra30-hdmi", },
897 { .compatible = "nvidia,tegra30-gr2d", },
5f60ed0d 898 { .compatible = "nvidia,tegra30-gr3d", },
dec72739 899 { .compatible = "nvidia,tegra114-dsi", },
7d1d28ac 900 { .compatible = "nvidia,tegra114-hdmi", },
5f60ed0d 901 { .compatible = "nvidia,tegra114-gr3d", },
8620fc62 902 { .compatible = "nvidia,tegra124-dc", },
6b6b6042 903 { .compatible = "nvidia,tegra124-sor", },
fb7be70e 904 { .compatible = "nvidia,tegra124-hdmi", },
776dc384
TR
905 { /* sentinel */ }
906};
907
908static struct host1x_driver host1x_drm_driver = {
909 .name = "drm",
910 .probe = host1x_drm_probe,
911 .remove = host1x_drm_remove,
912 .subdevs = host1x_drm_subdevs,
913};
914
915static int __init host1x_drm_init(void)
916{
917 int err;
918
919 err = host1x_driver_register(&host1x_drm_driver);
920 if (err < 0)
921 return err;
922
923 err = platform_driver_register(&tegra_dc_driver);
924 if (err < 0)
925 goto unregister_host1x;
926
dec72739 927 err = platform_driver_register(&tegra_dsi_driver);
776dc384
TR
928 if (err < 0)
929 goto unregister_dc;
930
6b6b6042 931 err = platform_driver_register(&tegra_sor_driver);
dec72739
TR
932 if (err < 0)
933 goto unregister_dsi;
934
6b6b6042
TR
935 err = platform_driver_register(&tegra_hdmi_driver);
936 if (err < 0)
937 goto unregister_sor;
938
939 err = platform_driver_register(&tegra_dpaux_driver);
776dc384
TR
940 if (err < 0)
941 goto unregister_hdmi;
942
6b6b6042
TR
943 err = platform_driver_register(&tegra_gr2d_driver);
944 if (err < 0)
945 goto unregister_dpaux;
946
5f60ed0d
TR
947 err = platform_driver_register(&tegra_gr3d_driver);
948 if (err < 0)
949 goto unregister_gr2d;
950
776dc384
TR
951 return 0;
952
5f60ed0d
TR
953unregister_gr2d:
954 platform_driver_unregister(&tegra_gr2d_driver);
6b6b6042
TR
955unregister_dpaux:
956 platform_driver_unregister(&tegra_dpaux_driver);
776dc384
TR
957unregister_hdmi:
958 platform_driver_unregister(&tegra_hdmi_driver);
6b6b6042
TR
959unregister_sor:
960 platform_driver_unregister(&tegra_sor_driver);
dec72739
TR
961unregister_dsi:
962 platform_driver_unregister(&tegra_dsi_driver);
776dc384
TR
963unregister_dc:
964 platform_driver_unregister(&tegra_dc_driver);
965unregister_host1x:
966 host1x_driver_unregister(&host1x_drm_driver);
967 return err;
968}
969module_init(host1x_drm_init);
970
971static void __exit host1x_drm_exit(void)
972{
5f60ed0d 973 platform_driver_unregister(&tegra_gr3d_driver);
776dc384 974 platform_driver_unregister(&tegra_gr2d_driver);
6b6b6042 975 platform_driver_unregister(&tegra_dpaux_driver);
776dc384 976 platform_driver_unregister(&tegra_hdmi_driver);
6b6b6042 977 platform_driver_unregister(&tegra_sor_driver);
dec72739 978 platform_driver_unregister(&tegra_dsi_driver);
776dc384
TR
979 platform_driver_unregister(&tegra_dc_driver);
980 host1x_driver_unregister(&host1x_drm_driver);
981}
982module_exit(host1x_drm_exit);
983
984MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>");
985MODULE_DESCRIPTION("NVIDIA Tegra DRM driver");
986MODULE_LICENSE("GPL v2");