aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTerje Bergstrom <tbergstrom@nvidia.com>2013-03-22 10:34:09 -0400
committerThierry Reding <thierry.reding@avionic-design.de>2013-04-22 06:40:04 -0400
commitd43f81cbaf43531a977e8b4c4427f19acf8a5061 (patch)
tree76fbf323c5df37de5a29f52817ddc4953328d213
parentde2ba664c30fcdb0f678ab6cbb57e01a0b206085 (diff)
drm/tegra: Add gr2d device
Add client driver for 2D device, and IOCTLs to pass work to host1x channel for 2D. Also adds functions that can be called to access sync points from DRM. Signed-off-by: Arto Merilainen <amerilainen@nvidia.com> Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com> Reviewed-by: Thierry Reding <thierry.reding@avionic-design.de> Tested-by: Thierry Reding <thierry.reding@avionic-design.de> Tested-by: Erik Faye-Lund <kusmabite@gmail.com> Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
-rw-r--r--drivers/gpu/host1x/Makefile1
-rw-r--r--drivers/gpu/host1x/dev.c7
-rw-r--r--drivers/gpu/host1x/drm/Kconfig8
-rw-r--r--drivers/gpu/host1x/drm/drm.c212
-rw-r--r--drivers/gpu/host1x/drm/drm.h27
-rw-r--r--drivers/gpu/host1x/drm/gr2d.c339
-rw-r--r--drivers/gpu/host1x/host1x.h4
-rw-r--r--include/uapi/drm/Kbuild1
-rw-r--r--include/uapi/drm/tegra_drm.h136
9 files changed, 732 insertions, 3 deletions
diff --git a/drivers/gpu/host1x/Makefile b/drivers/gpu/host1x/Makefile
index 3768dbc27184..3b037b6e0298 100644
--- a/drivers/gpu/host1x/Makefile
+++ b/drivers/gpu/host1x/Makefile
@@ -16,4 +16,5 @@ ccflags-$(CONFIG_DRM_TEGRA_DEBUG) += -DDEBUG
16host1x-$(CONFIG_DRM_TEGRA) += drm/drm.o drm/fb.o drm/dc.o 16host1x-$(CONFIG_DRM_TEGRA) += drm/drm.o drm/fb.o drm/dc.o
17host1x-$(CONFIG_DRM_TEGRA) += drm/output.o drm/rgb.o drm/hdmi.o 17host1x-$(CONFIG_DRM_TEGRA) += drm/output.o drm/rgb.o drm/hdmi.o
18host1x-$(CONFIG_DRM_TEGRA) += drm/gem.o 18host1x-$(CONFIG_DRM_TEGRA) += drm/gem.o
19host1x-$(CONFIG_DRM_TEGRA) += drm/gr2d.o
19obj-$(CONFIG_TEGRA_HOST1X) += host1x.o 20obj-$(CONFIG_TEGRA_HOST1X) += host1x.o
diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c
index 8ce9889cefd5..28e28a23d444 100644
--- a/drivers/gpu/host1x/dev.c
+++ b/drivers/gpu/host1x/dev.c
@@ -209,11 +209,17 @@ static int __init tegra_host1x_init(void)
209 err = platform_driver_register(&tegra_hdmi_driver); 209 err = platform_driver_register(&tegra_hdmi_driver);
210 if (err < 0) 210 if (err < 0)
211 goto unregister_dc; 211 goto unregister_dc;
212
213 err = platform_driver_register(&tegra_gr2d_driver);
214 if (err < 0)
215 goto unregister_hdmi;
212#endif 216#endif
213 217
214 return 0; 218 return 0;
215 219
216#ifdef CONFIG_DRM_TEGRA 220#ifdef CONFIG_DRM_TEGRA
221unregister_hdmi:
222 platform_driver_unregister(&tegra_hdmi_driver);
217unregister_dc: 223unregister_dc:
218 platform_driver_unregister(&tegra_dc_driver); 224 platform_driver_unregister(&tegra_dc_driver);
219unregister_host1x: 225unregister_host1x:
@@ -226,6 +232,7 @@ module_init(tegra_host1x_init);
226static void __exit tegra_host1x_exit(void) 232static void __exit tegra_host1x_exit(void)
227{ 233{
228#ifdef CONFIG_DRM_TEGRA 234#ifdef CONFIG_DRM_TEGRA
235 platform_driver_unregister(&tegra_gr2d_driver);
229 platform_driver_unregister(&tegra_hdmi_driver); 236 platform_driver_unregister(&tegra_hdmi_driver);
230 platform_driver_unregister(&tegra_dc_driver); 237 platform_driver_unregister(&tegra_dc_driver);
231#endif 238#endif
diff --git a/drivers/gpu/host1x/drm/Kconfig b/drivers/gpu/host1x/drm/Kconfig
index 9a28901d07ce..aa9d0768d6eb 100644
--- a/drivers/gpu/host1x/drm/Kconfig
+++ b/drivers/gpu/host1x/drm/Kconfig
@@ -13,6 +13,14 @@ config DRM_TEGRA
13 13
14if DRM_TEGRA 14if DRM_TEGRA
15 15
16config DRM_TEGRA_STAGING
17 bool "Enable HOST1X interface"
18 depends on STAGING
19 help
20 Say yes if HOST1X should be available for userspace DRM users.
21
22 If unsure, choose N.
23
16config DRM_TEGRA_DEBUG 24config DRM_TEGRA_DEBUG
17 bool "NVIDIA Tegra DRM debug support" 25 bool "NVIDIA Tegra DRM debug support"
18 help 26 help
diff --git a/drivers/gpu/host1x/drm/drm.c b/drivers/gpu/host1x/drm/drm.c
index c4e45c16f991..2b561c9118c6 100644
--- a/drivers/gpu/host1x/drm/drm.c
+++ b/drivers/gpu/host1x/drm/drm.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * Copyright (C) 2012 Avionic Design GmbH 2 * Copyright (C) 2012 Avionic Design GmbH
3 * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. 3 * Copyright (C) 2012-2013 NVIDIA CORPORATION. All rights reserved.
4 * 4 *
5 * This program is free software; you can redistribute it and/or modify 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 6 * it under the terms of the GNU General Public License version 2 as
@@ -14,6 +14,9 @@
14#include <linux/dma-mapping.h> 14#include <linux/dma-mapping.h>
15#include <asm/dma-iommu.h> 15#include <asm/dma-iommu.h>
16 16
17#include <drm/drm.h>
18#include <drm/drmP.h>
19
17#include "host1x_client.h" 20#include "host1x_client.h"
18#include "dev.h" 21#include "dev.h"
19#include "drm.h" 22#include "drm.h"
@@ -81,8 +84,10 @@ static int host1x_parse_dt(struct host1x_drm *host1x)
81 static const char * const compat[] = { 84 static const char * const compat[] = {
82 "nvidia,tegra20-dc", 85 "nvidia,tegra20-dc",
83 "nvidia,tegra20-hdmi", 86 "nvidia,tegra20-hdmi",
87 "nvidia,tegra20-gr2d",
84 "nvidia,tegra30-dc", 88 "nvidia,tegra30-dc",
85 "nvidia,tegra30-hdmi", 89 "nvidia,tegra30-hdmi",
90 "nvidia,tegra30-gr2d",
86 }; 91 };
87 unsigned int i; 92 unsigned int i;
88 int err; 93 int err;
@@ -277,9 +282,24 @@ static int tegra_drm_unload(struct drm_device *drm)
277 282
278static int tegra_drm_open(struct drm_device *drm, struct drm_file *filp) 283static int tegra_drm_open(struct drm_device *drm, struct drm_file *filp)
279{ 284{
285 struct host1x_drm_file *fpriv;
286
287 fpriv = kzalloc(sizeof(*fpriv), GFP_KERNEL);
288 if (!fpriv)
289 return -ENOMEM;
290
291 INIT_LIST_HEAD(&fpriv->contexts);
292 filp->driver_priv = fpriv;
293
280 return 0; 294 return 0;
281} 295}
282 296
297static void host1x_drm_context_free(struct host1x_drm_context *context)
298{
299 context->client->ops->close_channel(context);
300 kfree(context);
301}
302
283static void tegra_drm_lastclose(struct drm_device *drm) 303static void tegra_drm_lastclose(struct drm_device *drm)
284{ 304{
285 struct host1x_drm *host1x = drm->dev_private; 305 struct host1x_drm *host1x = drm->dev_private;
@@ -287,7 +307,190 @@ static void tegra_drm_lastclose(struct drm_device *drm)
287 tegra_fbdev_restore_mode(host1x->fbdev); 307 tegra_fbdev_restore_mode(host1x->fbdev);
288} 308}
289 309
310#ifdef CONFIG_DRM_TEGRA_STAGING
311static bool host1x_drm_file_owns_context(struct host1x_drm_file *file,
312 struct host1x_drm_context *context)
313{
314 struct host1x_drm_context *ctx;
315
316 list_for_each_entry(ctx, &file->contexts, list)
317 if (ctx == context)
318 return true;
319
320 return false;
321}
322
323static int tegra_gem_create(struct drm_device *drm, void *data,
324 struct drm_file *file)
325{
326 struct drm_tegra_gem_create *args = data;
327 struct tegra_bo *bo;
328
329 bo = tegra_bo_create_with_handle(file, drm, args->size,
330 &args->handle);
331 if (IS_ERR(bo))
332 return PTR_ERR(bo);
333
334 return 0;
335}
336
337static int tegra_gem_mmap(struct drm_device *drm, void *data,
338 struct drm_file *file)
339{
340 struct drm_tegra_gem_mmap *args = data;
341 struct drm_gem_object *gem;
342 struct tegra_bo *bo;
343
344 gem = drm_gem_object_lookup(drm, file, args->handle);
345 if (!gem)
346 return -EINVAL;
347
348 bo = to_tegra_bo(gem);
349
350 args->offset = tegra_bo_get_mmap_offset(bo);
351
352 drm_gem_object_unreference(gem);
353
354 return 0;
355}
356
357static int tegra_syncpt_read(struct drm_device *drm, void *data,
358 struct drm_file *file)
359{
360 struct drm_tegra_syncpt_read *args = data;
361 struct host1x *host = dev_get_drvdata(drm->dev);
362 struct host1x_syncpt *sp = host1x_syncpt_get(host, args->id);
363
364 if (!sp)
365 return -EINVAL;
366
367 args->value = host1x_syncpt_read_min(sp);
368 return 0;
369}
370
371static int tegra_syncpt_incr(struct drm_device *drm, void *data,
372 struct drm_file *file)
373{
374 struct drm_tegra_syncpt_incr *args = data;
375 struct host1x *host = dev_get_drvdata(drm->dev);
376 struct host1x_syncpt *sp = host1x_syncpt_get(host, args->id);
377
378 if (!sp)
379 return -EINVAL;
380
381 host1x_syncpt_incr(sp);
382 return 0;
383}
384
385static int tegra_syncpt_wait(struct drm_device *drm, void *data,
386 struct drm_file *file)
387{
388 struct drm_tegra_syncpt_wait *args = data;
389 struct host1x *host = dev_get_drvdata(drm->dev);
390 struct host1x_syncpt *sp = host1x_syncpt_get(host, args->id);
391
392 if (!sp)
393 return -EINVAL;
394
395 return host1x_syncpt_wait(sp, args->thresh, args->timeout,
396 &args->value);
397}
398
399static int tegra_open_channel(struct drm_device *drm, void *data,
400 struct drm_file *file)
401{
402 struct drm_tegra_open_channel *args = data;
403 struct host1x_client *client;
404 struct host1x_drm_context *context;
405 struct host1x_drm_file *fpriv = file->driver_priv;
406 struct host1x_drm *host1x = drm->dev_private;
407 int err = -ENODEV;
408
409 context = kzalloc(sizeof(*context), GFP_KERNEL);
410 if (!context)
411 return -ENOMEM;
412
413 list_for_each_entry(client, &host1x->clients, list)
414 if (client->class == args->client) {
415 err = client->ops->open_channel(client, context);
416 if (err)
417 break;
418
419 context->client = client;
420 list_add(&context->list, &fpriv->contexts);
421 args->context = (uintptr_t)context;
422 return 0;
423 }
424
425 kfree(context);
426 return err;
427}
428
429static int tegra_close_channel(struct drm_device *drm, void *data,
430 struct drm_file *file)
431{
432 struct drm_tegra_close_channel *args = data;
433 struct host1x_drm_file *fpriv = file->driver_priv;
434 struct host1x_drm_context *context =
435 (struct host1x_drm_context *)(uintptr_t)args->context;
436
437 if (!host1x_drm_file_owns_context(fpriv, context))
438 return -EINVAL;
439
440 list_del(&context->list);
441 host1x_drm_context_free(context);
442
443 return 0;
444}
445
446static int tegra_get_syncpt(struct drm_device *drm, void *data,
447 struct drm_file *file)
448{
449 struct drm_tegra_get_syncpt *args = data;
450 struct host1x_drm_file *fpriv = file->driver_priv;
451 struct host1x_drm_context *context =
452 (struct host1x_drm_context *)(uintptr_t)args->context;
453 struct host1x_syncpt *syncpt;
454
455 if (!host1x_drm_file_owns_context(fpriv, context))
456 return -ENODEV;
457
458 if (args->index >= context->client->num_syncpts)
459 return -EINVAL;
460
461 syncpt = context->client->syncpts[args->index];
462 args->id = host1x_syncpt_id(syncpt);
463
464 return 0;
465}
466
467static int tegra_submit(struct drm_device *drm, void *data,
468 struct drm_file *file)
469{
470 struct drm_tegra_submit *args = data;
471 struct host1x_drm_file *fpriv = file->driver_priv;
472 struct host1x_drm_context *context =
473 (struct host1x_drm_context *)(uintptr_t)args->context;
474
475 if (!host1x_drm_file_owns_context(fpriv, context))
476 return -ENODEV;
477
478 return context->client->ops->submit(context, args, drm, file);
479}
480#endif
481
290static struct drm_ioctl_desc tegra_drm_ioctls[] = { 482static struct drm_ioctl_desc tegra_drm_ioctls[] = {
483#ifdef CONFIG_DRM_TEGRA_STAGING
484 DRM_IOCTL_DEF_DRV(TEGRA_GEM_CREATE, tegra_gem_create, DRM_UNLOCKED | DRM_AUTH),
485 DRM_IOCTL_DEF_DRV(TEGRA_GEM_MMAP, tegra_gem_mmap, DRM_UNLOCKED),
486 DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_READ, tegra_syncpt_read, DRM_UNLOCKED),
487 DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_INCR, tegra_syncpt_incr, DRM_UNLOCKED),
488 DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_WAIT, tegra_syncpt_wait, DRM_UNLOCKED),
489 DRM_IOCTL_DEF_DRV(TEGRA_OPEN_CHANNEL, tegra_open_channel, DRM_UNLOCKED),
490 DRM_IOCTL_DEF_DRV(TEGRA_CLOSE_CHANNEL, tegra_close_channel, DRM_UNLOCKED),
491 DRM_IOCTL_DEF_DRV(TEGRA_GET_SYNCPT, tegra_get_syncpt, DRM_UNLOCKED),
492 DRM_IOCTL_DEF_DRV(TEGRA_SUBMIT, tegra_submit, DRM_UNLOCKED),
493#endif
291}; 494};
292 495
293static const struct file_operations tegra_drm_fops = { 496static const struct file_operations tegra_drm_fops = {
@@ -349,10 +552,17 @@ static void tegra_drm_disable_vblank(struct drm_device *drm, int pipe)
349 552
350static void tegra_drm_preclose(struct drm_device *drm, struct drm_file *file) 553static void tegra_drm_preclose(struct drm_device *drm, struct drm_file *file)
351{ 554{
555 struct host1x_drm_file *fpriv = file->driver_priv;
556 struct host1x_drm_context *context, *tmp;
352 struct drm_crtc *crtc; 557 struct drm_crtc *crtc;
353 558
354 list_for_each_entry(crtc, &drm->mode_config.crtc_list, head) 559 list_for_each_entry(crtc, &drm->mode_config.crtc_list, head)
355 tegra_dc_cancel_page_flip(crtc, file); 560 tegra_dc_cancel_page_flip(crtc, file);
561
562 list_for_each_entry_safe(context, tmp, &fpriv->contexts, list)
563 host1x_drm_context_free(context);
564
565 kfree(fpriv);
356} 566}
357 567
358#ifdef CONFIG_DEBUG_FS 568#ifdef CONFIG_DEBUG_FS
diff --git a/drivers/gpu/host1x/drm/drm.h b/drivers/gpu/host1x/drm/drm.h
index 3864a39f8ad3..02ce020f2575 100644
--- a/drivers/gpu/host1x/drm/drm.h
+++ b/drivers/gpu/host1x/drm/drm.h
@@ -1,6 +1,6 @@
1/* 1/*
2 * Copyright (C) 2012 Avionic Design GmbH 2 * Copyright (C) 2012 Avionic Design GmbH
3 * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. 3 * Copyright (C) 2012-2013 NVIDIA CORPORATION. All rights reserved.
4 * 4 *
5 * This program is free software; you can redistribute it and/or modify 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 6 * it under the terms of the GNU General Public License version 2 as
@@ -15,6 +15,9 @@
15#include <drm/drm_edid.h> 15#include <drm/drm_edid.h>
16#include <drm/drm_fb_helper.h> 16#include <drm/drm_fb_helper.h>
17#include <drm/drm_fixed.h> 17#include <drm/drm_fixed.h>
18#include <uapi/drm/tegra_drm.h>
19
20#include "host1x.h"
18 21
19struct tegra_fb { 22struct tegra_fb {
20 struct drm_framebuffer base; 23 struct drm_framebuffer base;
@@ -47,9 +50,25 @@ struct host1x_drm {
47 50
48struct host1x_client; 51struct host1x_client;
49 52
53struct host1x_drm_context {
54 struct host1x_client *client;
55 struct host1x_channel *channel;
56 struct list_head list;
57};
58
50struct host1x_client_ops { 59struct host1x_client_ops {
51 int (*drm_init)(struct host1x_client *client, struct drm_device *drm); 60 int (*drm_init)(struct host1x_client *client, struct drm_device *drm);
52 int (*drm_exit)(struct host1x_client *client); 61 int (*drm_exit)(struct host1x_client *client);
62 int (*open_channel)(struct host1x_client *client,
63 struct host1x_drm_context *context);
64 void (*close_channel)(struct host1x_drm_context *context);
65 int (*submit)(struct host1x_drm_context *context,
66 struct drm_tegra_submit *args, struct drm_device *drm,
67 struct drm_file *file);
68};
69
70struct host1x_drm_file {
71 struct list_head contexts;
53}; 72};
54 73
55struct host1x_client { 74struct host1x_client {
@@ -58,6 +77,12 @@ struct host1x_client {
58 77
59 const struct host1x_client_ops *ops; 78 const struct host1x_client_ops *ops;
60 79
80 enum host1x_class class;
81 struct host1x_channel *channel;
82
83 struct host1x_syncpt **syncpts;
84 unsigned int num_syncpts;
85
61 struct list_head list; 86 struct list_head list;
62}; 87};
63 88
diff --git a/drivers/gpu/host1x/drm/gr2d.c b/drivers/gpu/host1x/drm/gr2d.c
new file mode 100644
index 000000000000..6a45ae090ee7
--- /dev/null
+++ b/drivers/gpu/host1x/drm/gr2d.c
@@ -0,0 +1,339 @@
1/*
2 * drivers/video/tegra/host/gr2d/gr2d.c
3 *
4 * Tegra Graphics 2D
5 *
6 * Copyright (c) 2012-2013, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include <linux/export.h>
22#include <linux/of.h>
23#include <linux/of_device.h>
24#include <linux/clk.h>
25
26#include "channel.h"
27#include "drm.h"
28#include "gem.h"
29#include "job.h"
30#include "host1x.h"
31#include "host1x_bo.h"
32#include "host1x_client.h"
33#include "syncpt.h"
34
35struct gr2d {
36 struct host1x_client client;
37 struct clk *clk;
38 struct host1x_channel *channel;
39 unsigned long *addr_regs;
40};
41
42static inline struct gr2d *to_gr2d(struct host1x_client *client)
43{
44 return container_of(client, struct gr2d, client);
45}
46
47static int gr2d_is_addr_reg(struct device *dev, u32 class, u32 reg);
48
49static int gr2d_client_init(struct host1x_client *client,
50 struct drm_device *drm)
51{
52 return 0;
53}
54
55static int gr2d_client_exit(struct host1x_client *client)
56{
57 return 0;
58}
59
60static int gr2d_open_channel(struct host1x_client *client,
61 struct host1x_drm_context *context)
62{
63 struct gr2d *gr2d = to_gr2d(client);
64
65 context->channel = host1x_channel_get(gr2d->channel);
66
67 if (!context->channel)
68 return -ENOMEM;
69
70 return 0;
71}
72
73static void gr2d_close_channel(struct host1x_drm_context *context)
74{
75 host1x_channel_put(context->channel);
76}
77
78static struct host1x_bo *host1x_bo_lookup(struct drm_device *drm,
79 struct drm_file *file,
80 u32 handle)
81{
82 struct drm_gem_object *gem;
83 struct tegra_bo *bo;
84
85 gem = drm_gem_object_lookup(drm, file, handle);
86 if (!gem)
87 return 0;
88
89 mutex_lock(&drm->struct_mutex);
90 drm_gem_object_unreference(gem);
91 mutex_unlock(&drm->struct_mutex);
92
93 bo = to_tegra_bo(gem);
94 return &bo->base;
95}
96
97static int gr2d_submit(struct host1x_drm_context *context,
98 struct drm_tegra_submit *args, struct drm_device *drm,
99 struct drm_file *file)
100{
101 struct host1x_job *job;
102 unsigned int num_cmdbufs = args->num_cmdbufs;
103 unsigned int num_relocs = args->num_relocs;
104 unsigned int num_waitchks = args->num_waitchks;
105 struct drm_tegra_cmdbuf __user *cmdbufs =
106 (void * __user)(uintptr_t)args->cmdbufs;
107 struct drm_tegra_reloc __user *relocs =
108 (void * __user)(uintptr_t)args->relocs;
109 struct drm_tegra_waitchk __user *waitchks =
110 (void * __user)(uintptr_t)args->waitchks;
111 struct drm_tegra_syncpt syncpt;
112 int err;
113
114 /* We don't yet support other than one syncpt_incr struct per submit */
115 if (args->num_syncpts != 1)
116 return -EINVAL;
117
118 job = host1x_job_alloc(context->channel, args->num_cmdbufs,
119 args->num_relocs, args->num_waitchks);
120 if (!job)
121 return -ENOMEM;
122
123 job->num_relocs = args->num_relocs;
124 job->num_waitchk = args->num_waitchks;
125 job->client = (u32)args->context;
126 job->class = context->client->class;
127 job->serialize = true;
128
129 while (num_cmdbufs) {
130 struct drm_tegra_cmdbuf cmdbuf;
131 struct host1x_bo *bo;
132
133 err = copy_from_user(&cmdbuf, cmdbufs, sizeof(cmdbuf));
134 if (err)
135 goto fail;
136
137 bo = host1x_bo_lookup(drm, file, cmdbuf.handle);
138 if (!bo)
139 goto fail;
140
141 host1x_job_add_gather(job, bo, cmdbuf.words, cmdbuf.offset);
142 num_cmdbufs--;
143 cmdbufs++;
144 }
145
146 err = copy_from_user(job->relocarray, relocs,
147 sizeof(*relocs) * num_relocs);
148 if (err)
149 goto fail;
150
151 while (num_relocs--) {
152 struct host1x_reloc *reloc = &job->relocarray[num_relocs];
153 struct host1x_bo *cmdbuf, *target;
154
155 cmdbuf = host1x_bo_lookup(drm, file, (u32)reloc->cmdbuf);
156 target = host1x_bo_lookup(drm, file, (u32)reloc->target);
157
158 reloc->cmdbuf = cmdbuf;
159 reloc->target = target;
160
161 if (!reloc->target || !reloc->cmdbuf)
162 goto fail;
163 }
164
165 err = copy_from_user(job->waitchk, waitchks,
166 sizeof(*waitchks) * num_waitchks);
167 if (err)
168 goto fail;
169
170 err = copy_from_user(&syncpt, (void * __user)(uintptr_t)args->syncpts,
171 sizeof(syncpt));
172 if (err)
173 goto fail;
174
175 job->syncpt_id = syncpt.id;
176 job->syncpt_incrs = syncpt.incrs;
177 job->timeout = 10000;
178 job->is_addr_reg = gr2d_is_addr_reg;
179
180 if (args->timeout && args->timeout < 10000)
181 job->timeout = args->timeout;
182
183 err = host1x_job_pin(job, context->client->dev);
184 if (err)
185 goto fail;
186
187 err = host1x_job_submit(job);
188 if (err)
189 goto fail_submit;
190
191 args->fence = job->syncpt_end;
192
193 host1x_job_put(job);
194 return 0;
195
196fail_submit:
197 host1x_job_unpin(job);
198fail:
199 host1x_job_put(job);
200 return err;
201}
202
203static struct host1x_client_ops gr2d_client_ops = {
204 .drm_init = gr2d_client_init,
205 .drm_exit = gr2d_client_exit,
206 .open_channel = gr2d_open_channel,
207 .close_channel = gr2d_close_channel,
208 .submit = gr2d_submit,
209};
210
211static void gr2d_init_addr_reg_map(struct device *dev, struct gr2d *gr2d)
212{
213 const u32 gr2d_addr_regs[] = {0x1a, 0x1b, 0x26, 0x2b, 0x2c, 0x2d, 0x31,
214 0x32, 0x48, 0x49, 0x4a, 0x4b, 0x4c};
215 unsigned long *bitmap;
216 int i;
217
218 bitmap = devm_kzalloc(dev, DIV_ROUND_UP(256, BITS_PER_BYTE),
219 GFP_KERNEL);
220
221 for (i = 0; i < ARRAY_SIZE(gr2d_addr_regs); ++i) {
222 u32 reg = gr2d_addr_regs[i];
223 bitmap[BIT_WORD(reg)] |= BIT_MASK(reg);
224 }
225
226 gr2d->addr_regs = bitmap;
227}
228
229static int gr2d_is_addr_reg(struct device *dev, u32 class, u32 reg)
230{
231 struct gr2d *gr2d = dev_get_drvdata(dev);
232
233 switch (class) {
234 case HOST1X_CLASS_HOST1X:
235 return reg == 0x2b;
236 case HOST1X_CLASS_GR2D:
237 case HOST1X_CLASS_GR2D_SB:
238 reg &= 0xff;
239 if (gr2d->addr_regs[BIT_WORD(reg)] & BIT_MASK(reg))
240 return 1;
241 default:
242 return 0;
243 }
244}
245
246static const struct of_device_id gr2d_match[] = {
247 { .compatible = "nvidia,tegra30-gr2d" },
248 { .compatible = "nvidia,tegra20-gr2d" },
249 { },
250};
251
252static int gr2d_probe(struct platform_device *pdev)
253{
254 struct device *dev = &pdev->dev;
255 struct host1x_drm *host1x = host1x_get_drm_data(dev->parent);
256 int err;
257 struct gr2d *gr2d = NULL;
258 struct host1x_syncpt **syncpts;
259
260 gr2d = devm_kzalloc(dev, sizeof(*gr2d), GFP_KERNEL);
261 if (!gr2d)
262 return -ENOMEM;
263
264 syncpts = devm_kzalloc(dev, sizeof(*syncpts), GFP_KERNEL);
265 if (!syncpts)
266 return -ENOMEM;
267
268 gr2d->clk = devm_clk_get(dev, NULL);
269 if (IS_ERR(gr2d->clk)) {
270 dev_err(dev, "cannot get clock\n");
271 return PTR_ERR(gr2d->clk);
272 }
273
274 err = clk_prepare_enable(gr2d->clk);
275 if (err) {
276 dev_err(dev, "cannot turn on clock\n");
277 return err;
278 }
279
280 gr2d->channel = host1x_channel_request(dev);
281 if (!gr2d->channel)
282 return -ENOMEM;
283
284 *syncpts = host1x_syncpt_request(dev, 0);
285 if (!(*syncpts)) {
286 host1x_channel_free(gr2d->channel);
287 return -ENOMEM;
288 }
289
290 gr2d->client.ops = &gr2d_client_ops;
291 gr2d->client.dev = dev;
292 gr2d->client.class = HOST1X_CLASS_GR2D;
293 gr2d->client.syncpts = syncpts;
294 gr2d->client.num_syncpts = 1;
295
296 err = host1x_register_client(host1x, &gr2d->client);
297 if (err < 0) {
298 dev_err(dev, "failed to register host1x client: %d\n", err);
299 return err;
300 }
301
302 gr2d_init_addr_reg_map(dev, gr2d);
303
304 platform_set_drvdata(pdev, gr2d);
305
306 return 0;
307}
308
309static int __exit gr2d_remove(struct platform_device *pdev)
310{
311 struct host1x_drm *host1x = host1x_get_drm_data(pdev->dev.parent);
312 struct gr2d *gr2d = platform_get_drvdata(pdev);
313 unsigned int i;
314 int err;
315
316 err = host1x_unregister_client(host1x, &gr2d->client);
317 if (err < 0) {
318 dev_err(&pdev->dev, "failed to unregister client: %d\n", err);
319 return err;
320 }
321
322 for (i = 0; i < gr2d->client.num_syncpts; i++)
323 host1x_syncpt_free(gr2d->client.syncpts[i]);
324
325 host1x_channel_free(gr2d->channel);
326 clk_disable_unprepare(gr2d->clk);
327
328 return 0;
329}
330
331struct platform_driver tegra_gr2d_driver = {
332 .probe = gr2d_probe,
333 .remove = __exit_p(gr2d_remove),
334 .driver = {
335 .owner = THIS_MODULE,
336 .name = "gr2d",
337 .of_match_table = gr2d_match,
338 }
339};
diff --git a/drivers/gpu/host1x/host1x.h b/drivers/gpu/host1x/host1x.h
index bca6563f6766..a2bc1e65e972 100644
--- a/drivers/gpu/host1x/host1x.h
+++ b/drivers/gpu/host1x/host1x.h
@@ -22,7 +22,9 @@
22#define __LINUX_HOST1X_H 22#define __LINUX_HOST1X_H
23 23
24enum host1x_class { 24enum host1x_class {
25 HOST1X_CLASS_HOST1X = 0x1 25 HOST1X_CLASS_HOST1X = 0x1,
26 HOST1X_CLASS_GR2D = 0x51,
27 HOST1X_CLASS_GR2D_SB = 0x52
26}; 28};
27 29
28#endif 30#endif
diff --git a/include/uapi/drm/Kbuild b/include/uapi/drm/Kbuild
index a042a957296d..119487e05e65 100644
--- a/include/uapi/drm/Kbuild
+++ b/include/uapi/drm/Kbuild
@@ -13,5 +13,6 @@ header-y += r128_drm.h
13header-y += radeon_drm.h 13header-y += radeon_drm.h
14header-y += savage_drm.h 14header-y += savage_drm.h
15header-y += sis_drm.h 15header-y += sis_drm.h
16header-y += tegra_drm.h
16header-y += via_drm.h 17header-y += via_drm.h
17header-y += vmwgfx_drm.h 18header-y += vmwgfx_drm.h
diff --git a/include/uapi/drm/tegra_drm.h b/include/uapi/drm/tegra_drm.h
new file mode 100644
index 000000000000..6e132a2f7420
--- /dev/null
+++ b/include/uapi/drm/tegra_drm.h
@@ -0,0 +1,136 @@
1/*
2 * Copyright (c) 2012-2013, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef _UAPI_TEGRA_DRM_H_
18#define _UAPI_TEGRA_DRM_H_
19
20struct drm_tegra_gem_create {
21 __u64 size;
22 __u32 flags;
23 __u32 handle;
24};
25
26struct drm_tegra_gem_mmap {
27 __u32 handle;
28 __u32 offset;
29};
30
31struct drm_tegra_syncpt_read {
32 __u32 id;
33 __u32 value;
34};
35
36struct drm_tegra_syncpt_incr {
37 __u32 id;
38 __u32 pad;
39};
40
41struct drm_tegra_syncpt_wait {
42 __u32 id;
43 __u32 thresh;
44 __u32 timeout;
45 __u32 value;
46};
47
48#define DRM_TEGRA_NO_TIMEOUT (0xffffffff)
49
50struct drm_tegra_open_channel {
51 __u32 client;
52 __u32 pad;
53 __u64 context;
54};
55
56struct drm_tegra_close_channel {
57 __u64 context;
58};
59
60struct drm_tegra_get_syncpt {
61 __u64 context;
62 __u32 index;
63 __u32 id;
64};
65
66struct drm_tegra_syncpt {
67 __u32 id;
68 __u32 incrs;
69};
70
71struct drm_tegra_cmdbuf {
72 __u32 handle;
73 __u32 offset;
74 __u32 words;
75 __u32 pad;
76};
77
78struct drm_tegra_reloc {
79 struct {
80 __u32 handle;
81 __u32 offset;
82 } cmdbuf;
83 struct {
84 __u32 handle;
85 __u32 offset;
86 } target;
87 __u32 shift;
88 __u32 pad;
89};
90
91struct drm_tegra_waitchk {
92 __u32 handle;
93 __u32 offset;
94 __u32 syncpt;
95 __u32 thresh;
96};
97
98struct drm_tegra_submit {
99 __u64 context;
100 __u32 num_syncpts;
101 __u32 num_cmdbufs;
102 __u32 num_relocs;
103 __u32 num_waitchks;
104 __u32 waitchk_mask;
105 __u32 timeout;
106 __u32 pad;
107 __u64 syncpts;
108 __u64 cmdbufs;
109 __u64 relocs;
110 __u64 waitchks;
111 __u32 fence; /* Return value */
112
113 __u32 reserved[5]; /* future expansion */
114};
115
116#define DRM_TEGRA_GEM_CREATE 0x00
117#define DRM_TEGRA_GEM_MMAP 0x01
118#define DRM_TEGRA_SYNCPT_READ 0x02
119#define DRM_TEGRA_SYNCPT_INCR 0x03
120#define DRM_TEGRA_SYNCPT_WAIT 0x04
121#define DRM_TEGRA_OPEN_CHANNEL 0x05
122#define DRM_TEGRA_CLOSE_CHANNEL 0x06
123#define DRM_TEGRA_GET_SYNCPT 0x07
124#define DRM_TEGRA_SUBMIT 0x08
125
126#define DRM_IOCTL_TEGRA_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GEM_CREATE, struct drm_tegra_gem_create)
127#define DRM_IOCTL_TEGRA_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GEM_MMAP, struct drm_tegra_gem_mmap)
128#define DRM_IOCTL_TEGRA_SYNCPT_READ DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_SYNCPT_READ, struct drm_tegra_syncpt_read)
129#define DRM_IOCTL_TEGRA_SYNCPT_INCR DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_SYNCPT_INCR, struct drm_tegra_syncpt_incr)
130#define DRM_IOCTL_TEGRA_SYNCPT_WAIT DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_SYNCPT_WAIT, struct drm_tegra_syncpt_wait)
131#define DRM_IOCTL_TEGRA_OPEN_CHANNEL DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_OPEN_CHANNEL, struct drm_tegra_open_channel)
132#define DRM_IOCTL_TEGRA_CLOSE_CHANNEL DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_CLOSE_CHANNEL, struct drm_tegra_open_channel)
133#define DRM_IOCTL_TEGRA_GET_SYNCPT DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GET_SYNCPT, struct drm_tegra_get_syncpt)
134#define DRM_IOCTL_TEGRA_SUBMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_SUBMIT, struct drm_tegra_submit)
135
136#endif