summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThierry Reding <treding@nvidia.com>2017-09-06 09:36:04 +0200
committerThierry Reding <treding@nvidia.com>2017-09-06 09:36:04 +0200
commit73a2e697d37d8e9f81b94b878729acf3c16c79d6 (patch)
tree125061d4bb8500c45c42ebb8b30395472d7bb485
parentf19a3b1c7d799f0f1937443e395bb5d605d5ad49 (diff)
parentf8f1d215115b7691ba0bd56f788309c5f44491c2 (diff)
Merge branch 'staging/tegra' into staging/masterstaging/master
-rw-r--r--tegra/Android.mk42
-rw-r--r--tegra/Makefile.am8
-rw-r--r--tegra/Makefile.sources10
-rw-r--r--tegra/channel.c131
-rw-r--r--tegra/fence.c65
-rw-r--r--tegra/job.c175
-rw-r--r--tegra/private.h91
-rw-r--r--tegra/pushbuf.c204
-rw-r--r--tegra/tegra.c344
-rw-r--r--tegra/tegra.h69
-rw-r--r--tests/tegra/.gitignore1
-rw-r--r--tests/tegra/Makefile.am28
-rw-r--r--tests/tegra/drm-test-tegra.c154
-rw-r--r--tests/tegra/drm-test-tegra.h60
-rw-r--r--tests/tegra/drm-test.c247
-rw-r--r--tests/tegra/drm-test.h72
-rw-r--r--tests/tegra/gr2d-fill.c155
-rw-r--r--tests/tegra/openclose.c52
-rw-r--r--tests/tegra/vic-syncpt.c109
19 files changed, 1798 insertions, 219 deletions
diff --git a/tegra/Android.mk b/tegra/Android.mk
new file mode 100644
index 00000000..2d6881a3
--- /dev/null
+++ b/tegra/Android.mk
@@ -0,0 +1,42 @@
+#
+# Copyright © 2015 NVIDIA Corporation
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+# Import variables LIBDRM_TEGRA_FILES, LIBDRM_TEGRA_H_FILES
+include $(LOCAL_PATH)/Makefile.sources
+
+LOCAL_MODULE := libdrm_tegra
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(LIBDRM_TEGRA_FILES)
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+
+LOCAL_CFLAGS := \
+ -DHAVE_LIBDRM_ATOMIC_PRIMITIVES=1
+
+LOCAL_SHARED_LIBRARIES := \
+ libdrm
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/tegra/Makefile.am b/tegra/Makefile.am
index fb40be55..a51e2259 100644
--- a/tegra/Makefile.am
+++ b/tegra/Makefile.am
@@ -1,3 +1,5 @@
+include Makefile.sources
+
AM_CPPFLAGS = \
-I$(top_srcdir) \
-I$(top_srcdir)/include/drm
@@ -11,12 +13,10 @@ libdrm_tegra_la_LTLIBRARIES = libdrm_tegra.la
libdrm_tegra_la_LDFLAGS = -version-number 0:0:0 -no-undefined
libdrm_tegra_la_LIBADD = ../libdrm.la @PTHREADSTUBS_LIBS@
-libdrm_tegra_la_SOURCES = \
- private.h \
- tegra.c
+libdrm_tegra_la_SOURCES = $(LIBDRM_TEGRA_FILES)
libdrm_tegraincludedir = ${includedir}/libdrm
-libdrm_tegrainclude_HEADERS = tegra.h
+libdrm_tegrainclude_HEADERS = $(LIBDRM_TEGRA_H_FILES)
pkgconfigdir = @pkgconfigdir@
pkgconfig_DATA = libdrm_tegra.pc
diff --git a/tegra/Makefile.sources b/tegra/Makefile.sources
new file mode 100644
index 00000000..52a21c8b
--- /dev/null
+++ b/tegra/Makefile.sources
@@ -0,0 +1,10 @@
+LIBDRM_TEGRA_FILES := \
+ channel.c \
+ fence.c \
+ job.c \
+ private.h \
+ pushbuf.c \
+ tegra.c
+
+LIBDRM_TEGRA_H_FILES := \
+ tegra.h
diff --git a/tegra/channel.c b/tegra/channel.c
new file mode 100644
index 00000000..982d008c
--- /dev/null
+++ b/tegra/channel.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright © 2012, 2013 Thierry Reding
+ * Copyright © 2013 Erik Faye-Lund
+ * Copyright © 2014 NVIDIA Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <errno.h>
+#include <string.h>
+
+#include <sys/ioctl.h>
+
+#include "private.h"
+
+static int drm_tegra_channel_setup(struct drm_tegra_channel *channel)
+{
+ struct drm_tegra *drm = channel->drm;
+ struct drm_tegra_get_syncpt args;
+ int err;
+
+ memset(&args, 0, sizeof(args));
+ args.context = channel->context;
+ args.index = 0;
+
+ err = ioctl(drm->fd, DRM_IOCTL_TEGRA_GET_SYNCPT, &args);
+ if (err < 0)
+ return -errno;
+
+ channel->syncpt = args.id;
+
+ return 0;
+}
+
+int drm_tegra_channel_open(struct drm_tegra_channel **channelp,
+ struct drm_tegra *drm,
+ enum drm_tegra_class client)
+{
+ struct drm_tegra_open_channel args;
+ struct drm_tegra_channel *channel;
+ enum host1x_class class;
+ int err;
+
+ switch (client) {
+ case DRM_TEGRA_GR2D:
+ class = HOST1X_CLASS_GR2D;
+ break;
+
+ case DRM_TEGRA_GR3D:
+ class = HOST1X_CLASS_GR3D;
+ break;
+
+ case DRM_TEGRA_VIC:
+ class = HOST1X_CLASS_VIC;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ channel = calloc(1, sizeof(*channel));
+ if (!channel)
+ return -ENOMEM;
+
+ channel->drm = drm;
+
+ memset(&args, 0, sizeof(args));
+ args.client = class;
+
+ err = ioctl(drm->fd, DRM_IOCTL_TEGRA_OPEN_CHANNEL, &args);
+ if (err < 0) {
+ free(channel);
+ return -errno;
+ }
+
+ channel->context = args.context;
+ channel->class = class;
+
+ err = drm_tegra_channel_setup(channel);
+ if (err < 0) {
+ free(channel);
+ return err;
+ }
+
+ *channelp = channel;
+
+ return 0;
+}
+
+int drm_tegra_channel_close(struct drm_tegra_channel *channel)
+{
+ struct drm_tegra_close_channel args;
+ struct drm_tegra *drm;
+ int err;
+
+ if (!channel)
+ return -EINVAL;
+
+ drm = channel->drm;
+
+ memset(&args, 0, sizeof(args));
+ args.context = channel->context;
+
+ err = ioctl(drm->fd, DRM_IOCTL_TEGRA_CLOSE_CHANNEL, &args);
+ if (err < 0)
+ return -errno;
+
+ free(channel);
+
+ return 0;
+}
diff --git a/tegra/fence.c b/tegra/fence.c
new file mode 100644
index 00000000..210415f7
--- /dev/null
+++ b/tegra/fence.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright © 2012, 2013 Thierry Reding
+ * Copyright © 2013 Erik Faye-Lund
+ * Copyright © 2014 NVIDIA Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <errno.h>
+#include <string.h>
+
+#include <sys/ioctl.h>
+
+#include "private.h"
+
+int drm_tegra_fence_wait_timeout(struct drm_tegra_fence *fence,
+ unsigned long timeout)
+{
+ struct drm_tegra_syncpt_wait args;
+ int err;
+
+ memset(&args, 0, sizeof(args));
+ args.id = fence->syncpt;
+ args.thresh = fence->value;
+ args.timeout = timeout;
+
+ while (true) {
+ err = ioctl(fence->drm->fd, DRM_IOCTL_TEGRA_SYNCPT_WAIT, &args);
+ if (err < 0) {
+ if (errno == EINTR)
+ continue;
+
+ return -errno;
+ }
+
+ break;
+ }
+
+ return 0;
+}
+
+void drm_tegra_fence_free(struct drm_tegra_fence *fence)
+{
+ free(fence);
+}
diff --git a/tegra/job.c b/tegra/job.c
new file mode 100644
index 00000000..671e9a85
--- /dev/null
+++ b/tegra/job.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright © 2012, 2013 Thierry Reding
+ * Copyright © 2013 Erik Faye-Lund
+ * Copyright © 2014 NVIDIA Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/ioctl.h>
+
+#include "private.h"
+
+drm_private
+int drm_tegra_job_add_reloc(struct drm_tegra_job *job,
+ const struct drm_tegra_reloc *reloc)
+{
+ struct drm_tegra_reloc *relocs;
+ size_t size;
+
+ size = (job->num_relocs + 1) * sizeof(*reloc);
+
+ relocs = realloc(job->relocs, size);
+ if (!reloc)
+ return -ENOMEM;
+
+ job->relocs = relocs;
+
+ job->relocs[job->num_relocs++] = *reloc;
+
+ return 0;
+}
+
+drm_private
+int drm_tegra_job_add_cmdbuf(struct drm_tegra_job *job,
+ const struct drm_tegra_cmdbuf *cmdbuf)
+{
+ struct drm_tegra_cmdbuf *cmdbufs;
+ size_t size;
+
+ size = (job->num_cmdbufs + 1) * sizeof(*cmdbuf);
+
+ cmdbufs = realloc(job->cmdbufs, size);
+ if (!cmdbufs)
+ return -ENOMEM;
+
+ cmdbufs[job->num_cmdbufs++] = *cmdbuf;
+ job->cmdbufs = cmdbufs;
+
+ return 0;
+}
+
+int drm_tegra_job_new(struct drm_tegra_job **jobp,
+ struct drm_tegra_channel *channel)
+{
+ struct drm_tegra_job *job;
+
+ job = calloc(1, sizeof(*job));
+ if (!job)
+ return -ENOMEM;
+
+ DRMINITLISTHEAD(&job->pushbufs);
+ job->channel = channel;
+
+ *jobp = job;
+
+ return 0;
+}
+
+int drm_tegra_job_free(struct drm_tegra_job *job)
+{
+ struct drm_tegra_pushbuf_private *pushbuf;
+
+ if (!job)
+ return -EINVAL;
+
+ DRMLISTFOREACHENTRY(pushbuf, &job->pushbufs, list)
+ drm_tegra_pushbuf_free(&pushbuf->base);
+
+ free(job->cmdbufs);
+ free(job->relocs);
+ free(job);
+
+ return 0;
+}
+
+int drm_tegra_job_submit(struct drm_tegra_job *job,
+ struct drm_tegra_fence **fencep)
+{
+ struct drm_tegra *drm = job->channel->drm;
+ struct drm_tegra_fence *fence = NULL;
+ struct drm_tegra_syncpt *syncpts;
+ struct drm_tegra_submit args;
+ int err;
+
+ /*
+ * Make sure the current command stream buffer is queued for
+ * submission.
+ */
+ err = drm_tegra_pushbuf_queue(job->pushbuf);
+ if (err < 0)
+ return err;
+
+ job->pushbuf = NULL;
+
+ if (fencep) {
+ fence = calloc(1, sizeof(*fence));
+ if (!fence)
+ return -ENOMEM;
+ }
+
+ syncpts = calloc(1, sizeof(*syncpts));
+ if (!syncpts) {
+ free(fence);
+ return -ENOMEM;
+ }
+
+ syncpts[0].id = job->syncpt;
+ syncpts[0].incrs = job->increments;
+
+ memset(&args, 0, sizeof(args));
+ args.context = job->channel->context;
+ args.num_syncpts = 1;
+ args.num_cmdbufs = job->num_cmdbufs;
+ args.num_relocs = job->num_relocs;
+ args.num_waitchks = 0;
+ args.waitchk_mask = 0;
+ args.timeout = 1000;
+
+ args.syncpts = (uintptr_t)syncpts;
+ args.cmdbufs = (uintptr_t)job->cmdbufs;
+ args.relocs = (uintptr_t)job->relocs;
+ args.waitchks = 0;
+
+ err = ioctl(drm->fd, DRM_IOCTL_TEGRA_SUBMIT, &args);
+ if (err < 0) {
+ free(syncpts);
+ free(fence);
+ return -errno;
+ }
+
+ if (fence) {
+ fence->syncpt = job->syncpt;
+ fence->value = args.fence;
+ fence->drm = drm;
+ *fencep = fence;
+ }
+
+ free(syncpts);
+
+ return 0;
+}
diff --git a/tegra/private.h b/tegra/private.h
index bb6c1a51..02e1b7bf 100644
--- a/tegra/private.h
+++ b/tegra/private.h
@@ -26,26 +26,99 @@
#define __DRM_TEGRA_PRIVATE_H__ 1
#include <stdbool.h>
+#include <stddef.h>
#include <stdint.h>
+#include <libdrm_lists.h>
#include <libdrm_macros.h>
#include <xf86atomic.h>
+#include "tegra_drm.h"
#include "tegra.h"
+#define container_of(ptr, type, member) ({ \
+ const typeof(((type *)0)->member) *__mptr = (ptr); \
+ (type *)((char *)__mptr - offsetof(type, member)); \
+ })
+
+#define align(offset, align) \
+ (((offset) + (align) - 1) & ~((align) - 1))
+
+enum host1x_class {
+ HOST1X_CLASS_HOST1X = 0x01,
+ HOST1X_CLASS_GR2D = 0x51,
+ HOST1X_CLASS_GR2D_SB = 0x52,
+ HOST1X_CLASS_VIC = 0x5d,
+ HOST1X_CLASS_GR3D = 0x60,
+};
+
struct drm_tegra {
- bool close;
- int fd;
+ bool close;
+ int fd;
};
struct drm_tegra_bo {
- struct drm_tegra *drm;
- uint32_t handle;
- uint32_t offset;
- uint32_t flags;
- uint32_t size;
- atomic_t ref;
- void *map;
+ struct drm_tegra *drm;
+ drmMMListHead list;
+ uint32_t handle;
+ uint32_t offset;
+ uint32_t flags;
+ uint32_t size;
+ atomic_t ref;
+ void *map;
+};
+
+struct drm_tegra_channel {
+ struct drm_tegra *drm;
+ enum host1x_class class;
+ uint64_t context;
+ uint32_t syncpt;
+};
+
+struct drm_tegra_fence {
+ struct drm_tegra *drm;
+ uint32_t syncpt;
+ uint32_t value;
+};
+
+struct drm_tegra_pushbuf_private {
+ struct drm_tegra_pushbuf base;
+ struct drm_tegra_job *job;
+ drmMMListHead list;
+ drmMMListHead bos;
+
+ struct drm_tegra_bo *bo;
+ uint32_t *start;
+ uint32_t *end;
+};
+
+static inline struct drm_tegra_pushbuf_private *
+drm_tegra_pushbuf(struct drm_tegra_pushbuf *pb)
+{
+ return container_of(pb, struct drm_tegra_pushbuf_private, base);
+}
+
+int drm_tegra_pushbuf_queue(struct drm_tegra_pushbuf_private *pushbuf);
+
+struct drm_tegra_job {
+ struct drm_tegra_channel *channel;
+
+ unsigned int increments;
+ uint32_t syncpt;
+
+ struct drm_tegra_reloc *relocs;
+ unsigned int num_relocs;
+
+ struct drm_tegra_cmdbuf *cmdbufs;
+ unsigned int num_cmdbufs;
+
+ struct drm_tegra_pushbuf_private *pushbuf;
+ drmMMListHead pushbufs;
};
+int drm_tegra_job_add_reloc(struct drm_tegra_job *job,
+ const struct drm_tegra_reloc *reloc);
+int drm_tegra_job_add_cmdbuf(struct drm_tegra_job *job,
+ const struct drm_tegra_cmdbuf *cmdbuf);
+
#endif /* __DRM_TEGRA_PRIVATE_H__ */
diff --git a/tegra/pushbuf.c b/tegra/pushbuf.c
new file mode 100644
index 00000000..e578a1f1
--- /dev/null
+++ b/tegra/pushbuf.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright © 2012, 2013 Thierry Reding
+ * Copyright © 2013 Erik Faye-Lund
+ * Copyright © 2014 NVIDIA Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "private.h"
+
+#define HOST1X_OPCODE_NONINCR(offset, count) \
+ ((0x2 << 28) | (((offset) & 0xfff) << 16) | ((count) & 0xffff))
+
+static inline unsigned long
+drm_tegra_pushbuf_get_offset(struct drm_tegra_pushbuf *pushbuf)
+{
+ struct drm_tegra_pushbuf_private *priv = drm_tegra_pushbuf(pushbuf);
+
+ return (unsigned long)pushbuf->ptr - (unsigned long)priv->start;
+}
+
+drm_private
+int drm_tegra_pushbuf_queue(struct drm_tegra_pushbuf_private *pushbuf)
+{
+ struct drm_tegra_cmdbuf cmdbuf;
+ int err;
+
+ if (!pushbuf || !pushbuf->bo)
+ return 0;
+
+ /* unmap buffer object since it won't be accessed anymore */
+ drm_tegra_bo_unmap(pushbuf->bo);
+
+ /* add buffer object as command buffers for this job */
+ memset(&cmdbuf, 0, sizeof(cmdbuf));
+ cmdbuf.words = pushbuf->base.ptr - pushbuf->start;
+ cmdbuf.handle = pushbuf->bo->handle;
+ cmdbuf.offset = 0;
+
+ err = drm_tegra_job_add_cmdbuf(pushbuf->job, &cmdbuf);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+int drm_tegra_pushbuf_new(struct drm_tegra_pushbuf **pushbufp,
+ struct drm_tegra_job *job)
+{
+ struct drm_tegra_pushbuf_private *pushbuf;
+
+ pushbuf = calloc(1, sizeof(*pushbuf));
+ if (!pushbuf)
+ return -ENOMEM;
+
+ DRMINITLISTHEAD(&pushbuf->list);
+ DRMINITLISTHEAD(&pushbuf->bos);
+ pushbuf->job = job;
+
+ *pushbufp = &pushbuf->base;
+
+ DRMLISTADD(&pushbuf->list, &job->pushbufs);
+ job->pushbuf = pushbuf;
+
+ return 0;
+}
+
+int drm_tegra_pushbuf_free(struct drm_tegra_pushbuf *pushbuf)
+{
+ struct drm_tegra_pushbuf_private *priv = drm_tegra_pushbuf(pushbuf);
+ struct drm_tegra_bo *bo, *tmp;
+
+ if (!pushbuf)
+ return -EINVAL;
+
+ drm_tegra_bo_unmap(priv->bo);
+
+ DRMLISTFOREACHENTRYSAFE(bo, tmp, &priv->bos, list)
+ drm_tegra_bo_unref(priv->bo);
+
+ DRMLISTDEL(&priv->list);
+ free(priv);
+
+ return 0;
+}
+
+/**
+ * drm_tegra_pushbuf_prepare() - prepare push buffer for a series of pushes
+ * @pushbuf: push buffer
+ * @words: maximum number of words in series of pushes to follow
+ */
+int drm_tegra_pushbuf_prepare(struct drm_tegra_pushbuf *pushbuf,
+ unsigned int words)
+{
+ struct drm_tegra_pushbuf_private *priv = drm_tegra_pushbuf(pushbuf);
+ struct drm_tegra_channel *channel = priv->job->channel;
+ struct drm_tegra_bo *bo;
+ void *ptr;
+ int err;
+
+ if (priv->bo && (pushbuf->ptr + words < priv->end))
+ return 0;
+
+ /*
+ * Align to full pages, since buffer object allocations are page
+ * granular anyway.
+ */
+ words = align(words, 1024);
+
+ err = drm_tegra_bo_new(&bo, channel->drm, 0, words * sizeof(uint32_t));
+ if (err < 0)
+ return err;
+
+ err = drm_tegra_bo_map(bo, &ptr);
+ if (err < 0) {
+ drm_tegra_bo_unref(bo);
+ return err;
+ }
+
+ /* queue current command stream buffer for submission */
+ err = drm_tegra_pushbuf_queue(priv);
+ if (err < 0) {
+ drm_tegra_bo_unmap(bo);
+ drm_tegra_bo_unref(bo);
+ return err;
+ }
+
+ DRMLISTADD(&bo->list, &priv->bos);
+
+ priv->start = priv->base.ptr = ptr;
+ priv->end = priv->start + bo->size;
+ priv->bo = bo;
+
+ return 0;
+}
+
+int drm_tegra_pushbuf_relocate(struct drm_tegra_pushbuf *pushbuf,
+ struct drm_tegra_bo *target,
+ unsigned long offset,
+ unsigned long shift)
+{
+ struct drm_tegra_pushbuf_private *priv = drm_tegra_pushbuf(pushbuf);
+ struct drm_tegra_reloc reloc;
+ int err;
+
+ memset(&reloc, 0, sizeof(reloc));
+ reloc.cmdbuf.handle = priv->bo->handle;
+ reloc.cmdbuf.offset = drm_tegra_pushbuf_get_offset(pushbuf);
+ reloc.target.handle = target->handle;
+ reloc.target.offset = offset;
+ reloc.shift = shift;
+
+ err = drm_tegra_job_add_reloc(priv->job, &reloc);
+ if (err < 0)
+ return err;
+
+ *pushbuf->ptr++ = 0xdeadbeef;
+
+ return 0;
+}
+
+int drm_tegra_pushbuf_sync(struct drm_tegra_pushbuf *pushbuf,
+ enum drm_tegra_syncpt_cond cond)
+{
+ struct drm_tegra_pushbuf_private *priv = drm_tegra_pushbuf(pushbuf);
+ int err;
+
+ if (cond >= DRM_TEGRA_SYNCPT_COND_MAX)
+ return -EINVAL;
+
+ err = drm_tegra_pushbuf_prepare(pushbuf, 2);
+ if (err < 0)
+ return err;
+
+ *pushbuf->ptr++ = HOST1X_OPCODE_NONINCR(0x0, 0x1);
+ *pushbuf->ptr++ = cond << 8 | priv->job->syncpt;
+ priv->job->increments++;
+
+ return 0;
+}
diff --git a/tegra/tegra.c b/tegra/tegra.c
index f7dc89ad..c3fbc9af 100644
--- a/tegra/tegra.c
+++ b/tegra/tegra.c
@@ -41,292 +41,294 @@
static void drm_tegra_bo_free(struct drm_tegra_bo *bo)
{
- struct drm_tegra *drm = bo->drm;
- struct drm_gem_close args;
+ struct drm_tegra *drm = bo->drm;
+ struct drm_gem_close args;
- if (bo->map)
- munmap(bo->map, bo->size);
+ if (bo->map)
+ munmap(bo->map, bo->size);
- memset(&args, 0, sizeof(args));
- args.handle = bo->handle;
+ memset(&args, 0, sizeof(args));
+ args.handle = bo->handle;
- drmIoctl(drm->fd, DRM_IOCTL_GEM_CLOSE, &args);
+ drmIoctl(drm->fd, DRM_IOCTL_GEM_CLOSE, &args);
- free(bo);
+ DRMLISTDEL(&bo->list);
+ free(bo);
}
static int drm_tegra_wrap(struct drm_tegra **drmp, int fd, bool close)
{
- struct drm_tegra *drm;
+ struct drm_tegra *drm;
- if (fd < 0 || !drmp)
- return -EINVAL;
+ if (fd < 0 || !drmp)
+ return -EINVAL;
- drm = calloc(1, sizeof(*drm));
- if (!drm)
- return -ENOMEM;
+ drm = calloc(1, sizeof(*drm));
+ if (!drm)
+ return -ENOMEM;
- drm->close = close;
- drm->fd = fd;
+ drm->close = close;
+ drm->fd = fd;
- *drmp = drm;
+ *drmp = drm;
- return 0;
+ return 0;
}
int drm_tegra_new(struct drm_tegra **drmp, int fd)
{
- bool supported = false;
- drmVersionPtr version;
+ bool supported = false;
+ drmVersionPtr version;
- version = drmGetVersion(fd);
- if (!version)
- return -ENOMEM;
+ version = drmGetVersion(fd);
+ if (!version)
+ return -ENOMEM;
- if (!strncmp(version->name, "tegra", version->name_len))
- supported = true;
+ if (!strncmp(version->name, "tegra", version->name_len))
+ supported = true;
- drmFreeVersion(version);
+ drmFreeVersion(version);
- if (!supported)
- return -ENOTSUP;
+ if (!supported)
+ return -ENOTSUP;
- return drm_tegra_wrap(drmp, fd, false);
+ return drm_tegra_wrap(drmp, fd, false);
}
void drm_tegra_close(struct drm_tegra *drm)
{
- if (!drm)
- return;
+ if (!drm)
+ return;
- if (drm->close)
- close(drm->fd);
+ if (drm->close)
+ close(drm->fd);
- free(drm);
+ free(drm);
}
int drm_tegra_bo_new(struct drm_tegra_bo **bop, struct drm_tegra *drm,
- uint32_t flags, uint32_t size)
+ uint32_t flags, uint32_t size)
{
- struct drm_tegra_gem_create args;
- struct drm_tegra_bo *bo;
- int err;
+ struct drm_tegra_gem_create args;
+ struct drm_tegra_bo *bo;
+ int err;
- if (!drm || size == 0 || !bop)
- return -EINVAL;
+ if (!drm || size == 0 || !bop)
+ return -EINVAL;
- bo = calloc(1, sizeof(*bo));
- if (!bo)
- return -ENOMEM;
+ bo = calloc(1, sizeof(*bo));
+ if (!bo)
+ return -ENOMEM;
- atomic_set(&bo->ref, 1);
- bo->flags = flags;
- bo->size = size;
- bo->drm = drm;
+ DRMINITLISTHEAD(&bo->list);
+ atomic_set(&bo->ref, 1);
+ bo->flags = flags;
+ bo->size = size;
+ bo->drm = drm;
- memset(&args, 0, sizeof(args));
- args.flags = flags;
- args.size = size;
+ memset(&args, 0, sizeof(args));
+ args.flags = flags;
+ args.size = size;
- err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_CREATE, &args,
- sizeof(args));
- if (err < 0) {
- err = -errno;
- free(bo);
- return err;
- }
+ err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_CREATE, &args,
+ sizeof(args));
+ if (err < 0) {
+ err = -errno;
+ free(bo);
+ return err;
+ }
- bo->handle = args.handle;
+ bo->handle = args.handle;
- *bop = bo;
+ *bop = bo;
- return 0;
+ return 0;
}
int drm_tegra_bo_wrap(struct drm_tegra_bo **bop, struct drm_tegra *drm,
- uint32_t handle, uint32_t flags, uint32_t size)
+ uint32_t handle, uint32_t flags, uint32_t size)
{
- struct drm_tegra_bo *bo;
+ struct drm_tegra_bo *bo;
- if (!drm || !bop)
- return -EINVAL;
+ if (!drm || !bop)
+ return -EINVAL;
- bo = calloc(1, sizeof(*bo));
- if (!bo)
- return -ENOMEM;
+ bo = calloc(1, sizeof(*bo));
+ if (!bo)
+ return -ENOMEM;
- atomic_set(&bo->ref, 1);
- bo->handle = handle;
- bo->flags = flags;
- bo->size = size;
- bo->drm = drm;
+ atomic_set(&bo->ref, 1);
+ bo->handle = handle;
+ bo->flags = flags;
+ bo->size = size;
+ bo->drm = drm;
- *bop = bo;
+ *bop = bo;
- return 0;
+ return 0;
}
struct drm_tegra_bo *drm_tegra_bo_ref(struct drm_tegra_bo *bo)
{
- if (bo)
- atomic_inc(&bo->ref);
+ if (bo)
+ atomic_inc(&bo->ref);
- return bo;
+ return bo;
}
void drm_tegra_bo_unref(struct drm_tegra_bo *bo)
{
- if (bo && atomic_dec_and_test(&bo->ref))
- drm_tegra_bo_free(bo);
+ if (bo && atomic_dec_and_test(&bo->ref))
+ drm_tegra_bo_free(bo);
}
int drm_tegra_bo_get_handle(struct drm_tegra_bo *bo, uint32_t *handle)
{
- if (!bo || !handle)
- return -EINVAL;
+ if (!bo || !handle)
+ return -EINVAL;
- *handle = bo->handle;
+ *handle = bo->handle;
- return 0;
+ return 0;
}
int drm_tegra_bo_map(struct drm_tegra_bo *bo, void **ptr)
{
- struct drm_tegra *drm = bo->drm;
+ struct drm_tegra *drm = bo->drm;
- if (!bo->map) {
- struct drm_tegra_gem_mmap args;
- int err;
+ if (!bo->map) {
+ struct drm_tegra_gem_mmap args;
+ int err;
- memset(&args, 0, sizeof(args));
- args.handle = bo->handle;
+ memset(&args, 0, sizeof(args));
+ args.handle = bo->handle;
- err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_MMAP, &args,
- sizeof(args));
- if (err < 0)
- return -errno;
+ err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_MMAP, &args,
+ sizeof(args));
+ if (err < 0)
+ return -errno;
- bo->offset = args.offset;
+ bo->offset = args.offset;
- bo->map = mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED,
- drm->fd, bo->offset);
- if (bo->map == MAP_FAILED) {
- bo->map = NULL;
- return -errno;
- }
- }
+ bo->map = mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED,
+ drm->fd, bo->offset);
+ if (bo->map == MAP_FAILED) {
+ bo->map = NULL;
+ return -errno;
+ }
+ }
- if (ptr)
- *ptr = bo->map;
+ if (ptr)
+ *ptr = bo->map;
- return 0;
+ return 0;
}
int drm_tegra_bo_unmap(struct drm_tegra_bo *bo)
{
- if (!bo)
- return -EINVAL;
+ if (!bo)
+ return -EINVAL;
- if (!bo->map)
- return 0;
+ if (!bo->map)
+ return 0;
- if (munmap(bo->map, bo->size))
- return -errno;
+ if (munmap(bo->map, bo->size))
+ return -errno;
- bo->map = NULL;
+ bo->map = NULL;
- return 0;
+ return 0;
}
int drm_tegra_bo_get_flags(struct drm_tegra_bo *bo, uint32_t *flags)
{
- struct drm_tegra_gem_get_flags args;
- struct drm_tegra *drm = bo->drm;
- int err;
+ struct drm_tegra_gem_get_flags args;
+ struct drm_tegra *drm = bo->drm;
+ int err;
- if (!bo)
- return -EINVAL;
+ if (!bo)
+ return -EINVAL;
- memset(&args, 0, sizeof(args));
- args.handle = bo->handle;
+ memset(&args, 0, sizeof(args));
+ args.handle = bo->handle;
- err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_GET_FLAGS, &args,
- sizeof(args));
- if (err < 0)
- return -errno;
+ err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_GET_FLAGS, &args,
+ sizeof(args));
+ if (err < 0)
+ return -errno;
- if (flags)
- *flags = args.flags;
+ if (flags)
+ *flags = args.flags;
- return 0;
+ return 0;
}
int drm_tegra_bo_set_flags(struct drm_tegra_bo *bo, uint32_t flags)
{
- struct drm_tegra_gem_get_flags args;
- struct drm_tegra *drm = bo->drm;
- int err;
+ struct drm_tegra_gem_get_flags args;
+ struct drm_tegra *drm = bo->drm;
+ int err;
- if (!bo)
- return -EINVAL;
+ if (!bo)
+ return -EINVAL;
- memset(&args, 0, sizeof(args));
- args.handle = bo->handle;
- args.flags = flags;
+ memset(&args, 0, sizeof(args));
+ args.handle = bo->handle;
+ args.flags = flags;
- err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_SET_FLAGS, &args,
- sizeof(args));
- if (err < 0)
- return -errno;
+ err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_SET_FLAGS, &args,
+ sizeof(args));
+ if (err < 0)
+ return -errno;
- return 0;
+ return 0;
}
int drm_tegra_bo_get_tiling(struct drm_tegra_bo *bo,
- struct drm_tegra_bo_tiling *tiling)
+ struct drm_tegra_bo_tiling *tiling)
{
- struct drm_tegra_gem_get_tiling args;
- struct drm_tegra *drm = bo->drm;
- int err;
+ struct drm_tegra_gem_get_tiling args;
+ struct drm_tegra *drm = bo->drm;
+ int err;
- if (!bo)
- return -EINVAL;
+ if (!bo)
+ return -EINVAL;
- memset(&args, 0, sizeof(args));
- args.handle = bo->handle;
+ memset(&args, 0, sizeof(args));
+ args.handle = bo->handle;
- err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_GET_TILING, &args,
- sizeof(args));
- if (err < 0)
- return -errno;
+ err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_GET_TILING, &args,
+ sizeof(args));
+ if (err < 0)
+ return -errno;
- if (tiling) {
- tiling->mode = args.mode;
- tiling->value = args.value;
- }
+ if (tiling) {
+ tiling->mode = args.mode;
+ tiling->value = args.value;
+ }
- return 0;
+ return 0;
}
int drm_tegra_bo_set_tiling(struct drm_tegra_bo *bo,
- const struct drm_tegra_bo_tiling *tiling)
+ const struct drm_tegra_bo_tiling *tiling)
{
- struct drm_tegra_gem_set_tiling args;
- struct drm_tegra *drm = bo->drm;
- int err;
+ struct drm_tegra_gem_set_tiling args;
+ struct drm_tegra *drm = bo->drm;
+ int err;
- if (!bo)
- return -EINVAL;
+ if (!bo)
+ return -EINVAL;
- memset(&args, 0, sizeof(args));
- args.handle = bo->handle;
- args.mode = tiling->mode;
- args.value = tiling->value;
+ memset(&args, 0, sizeof(args));
+ args.handle = bo->handle;
+ args.mode = tiling->mode;
+ args.value = tiling->value;
- err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_SET_TILING, &args,
- sizeof(args));
- if (err < 0)
- return -errno;
+ err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_SET_TILING, &args,
+ sizeof(args));
+ if (err < 0)
+ return -errno;
- return 0;
+ return 0;
}
diff --git a/tegra/tegra.h b/tegra/tegra.h
index 31b0995a..20dd1bc9 100644
--- a/tegra/tegra.h
+++ b/tegra/tegra.h
@@ -28,6 +28,14 @@
#include <stdint.h>
#include <stdlib.h>
+#include <tegra_drm.h>
+
+enum drm_tegra_class {
+ DRM_TEGRA_GR2D,
+ DRM_TEGRA_GR3D,
+ DRM_TEGRA_VIC,
+};
+
struct drm_tegra_bo;
struct drm_tegra;
@@ -35,9 +43,9 @@ int drm_tegra_new(struct drm_tegra **drmp, int fd);
void drm_tegra_close(struct drm_tegra *drm);
int drm_tegra_bo_new(struct drm_tegra_bo **bop, struct drm_tegra *drm,
- uint32_t flags, uint32_t size);
+ uint32_t flags, uint32_t size);
int drm_tegra_bo_wrap(struct drm_tegra_bo **bop, struct drm_tegra *drm,
- uint32_t handle, uint32_t flags, uint32_t size);
+ uint32_t handle, uint32_t flags, uint32_t size);
struct drm_tegra_bo *drm_tegra_bo_ref(struct drm_tegra_bo *bo);
void drm_tegra_bo_unref(struct drm_tegra_bo *bo);
int drm_tegra_bo_get_handle(struct drm_tegra_bo *bo, uint32_t *handle);
@@ -48,13 +56,62 @@ int drm_tegra_bo_get_flags(struct drm_tegra_bo *bo, uint32_t *flags);
int drm_tegra_bo_set_flags(struct drm_tegra_bo *bo, uint32_t flags);
struct drm_tegra_bo_tiling {
- uint32_t mode;
- uint32_t value;
+ uint32_t mode;
+ uint32_t value;
};
int drm_tegra_bo_get_tiling(struct drm_tegra_bo *bo,
- struct drm_tegra_bo_tiling *tiling);
+ struct drm_tegra_bo_tiling *tiling);
int drm_tegra_bo_set_tiling(struct drm_tegra_bo *bo,
- const struct drm_tegra_bo_tiling *tiling);
+ const struct drm_tegra_bo_tiling *tiling);
+
+struct drm_tegra_channel;
+struct drm_tegra_job;
+
+struct drm_tegra_pushbuf {
+ uint32_t *ptr;
+};
+
+struct drm_tegra_fence;
+
+enum drm_tegra_syncpt_cond {
+ DRM_TEGRA_SYNCPT_COND_IMMEDIATE,
+ DRM_TEGRA_SYNCPT_COND_OP_DONE,
+ DRM_TEGRA_SYNCPT_COND_RD_DONE,
+ DRM_TEGRA_SYNCPT_COND_WR_SAFE,
+ DRM_TEGRA_SYNCPT_COND_MAX,
+};
+
+int drm_tegra_channel_open(struct drm_tegra_channel **channelp,
+ struct drm_tegra *drm,
+ enum drm_tegra_class client);
+int drm_tegra_channel_close(struct drm_tegra_channel *channel);
+
+int drm_tegra_job_new(struct drm_tegra_job **jobp,
+ struct drm_tegra_channel *channel);
+int drm_tegra_job_free(struct drm_tegra_job *job);
+int drm_tegra_job_submit(struct drm_tegra_job *job,
+ struct drm_tegra_fence **fencep);
+
+int drm_tegra_pushbuf_new(struct drm_tegra_pushbuf **pushbufp,
+ struct drm_tegra_job *job);
+int drm_tegra_pushbuf_free(struct drm_tegra_pushbuf *pushbuf);
+int drm_tegra_pushbuf_prepare(struct drm_tegra_pushbuf *pushbuf,
+ unsigned int words);
+int drm_tegra_pushbuf_relocate(struct drm_tegra_pushbuf *pushbuf,
+ struct drm_tegra_bo *target,
+ unsigned long offset,
+ unsigned long shift);
+int drm_tegra_pushbuf_sync(struct drm_tegra_pushbuf *pushbuf,
+ enum drm_tegra_syncpt_cond cond);
+
+int drm_tegra_fence_wait_timeout(struct drm_tegra_fence *fence,
+ unsigned long timeout);
+void drm_tegra_fence_free(struct drm_tegra_fence *fence);
+
+static inline int drm_tegra_fence_wait(struct drm_tegra_fence *fence)
+{
+ return drm_tegra_fence_wait_timeout(fence, -1);
+}
#endif /* __DRM_TEGRA_H__ */
diff --git a/tests/tegra/.gitignore b/tests/tegra/.gitignore
index 5c5216c5..5e0b5c60 100644
--- a/tests/tegra/.gitignore
+++ b/tests/tegra/.gitignore
@@ -1 +1,2 @@
+gr2d-fill
openclose
diff --git a/tests/tegra/Makefile.am b/tests/tegra/Makefile.am
index 8e625c8f..3fc92b79 100644
--- a/tests/tegra/Makefile.am
+++ b/tests/tegra/Makefile.am
@@ -5,9 +5,31 @@ AM_CPPFLAGS = \
AM_CFLAGS = $(WARN_CFLAGS)
+noinst_LTLIBRARIES = libdrm-test.la
+libdrm_test_la_SOURCES = \
+ drm-test.c \
+ drm-test.h \
+ drm-test-tegra.c \
+ drm-test-tegra.h
+
+libdrm_test_la_LIBADD = \
+ ../../libdrm.la
+
LDADD = \
../../tegra/libdrm_tegra.la \
- ../../libdrm.la
+ ../../libdrm.la \
+ libdrm-test.la
+
+TESTS = \
+ openclose \
+ gr2d-fill \
+ vic-syncpt
-noinst_PROGRAMS = \
- openclose
+if HAVE_INSTALL_TESTS
+testdir = $(libexecdir)/libdrm/tests/tegra
+test_PROGRAMS = \
+ $(TESTS)
+else
+noinst_PROGRAMS = $(TESTS)
+check_PROGRAMS = $(TESTS)
+endif
diff --git a/tests/tegra/drm-test-tegra.c b/tests/tegra/drm-test-tegra.c
new file mode 100644
index 00000000..21d8b47f
--- /dev/null
+++ b/tests/tegra/drm-test-tegra.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright © 2014 NVIDIA Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+
+#include "drm-test-tegra.h"
+#include "tegra.h"
+
+int drm_tegra_gr2d_open(struct drm_tegra_gr2d **gr2dp, struct drm_tegra *drm)
+{
+ struct drm_tegra_gr2d *gr2d;
+ int err;
+
+ gr2d = calloc(1, sizeof(*gr2d));
+ if (!gr2d)
+ return -ENOMEM;
+
+ gr2d->drm = drm;
+
+ err = drm_tegra_channel_open(&gr2d->channel, drm, DRM_TEGRA_GR2D);
+ if (err < 0) {
+ free(gr2d);
+ return err;
+ }
+
+ *gr2dp = gr2d;
+
+ return 0;
+}
+
+int drm_tegra_gr2d_close(struct drm_tegra_gr2d *gr2d)
+{
+ if (!gr2d)
+ return -EINVAL;
+
+ drm_tegra_channel_close(gr2d->channel);
+ free(gr2d);
+
+ return 0;
+}
+
+int drm_tegra_gr2d_fill(struct drm_tegra_pushbuf *pushbuf,
+ struct drm_framebuffer *fb, unsigned int x,
+ unsigned int y, unsigned int width,
+ unsigned int height, uint32_t color)
+{
+ struct drm_tegra_bo *bo = fb->data;
+ int err;
+
+ err = drm_tegra_pushbuf_prepare(pushbuf, 32);
+ if (err < 0)
+ return err;
+
+ *pushbuf->ptr++ = HOST1X_OPCODE_SETCL(0, HOST1X_CLASS_GR2D, 0);
+
+ *pushbuf->ptr++ = HOST1X_OPCODE_MASK(0x9, 0x9);
+ *pushbuf->ptr++ = 0x0000003a;
+ *pushbuf->ptr++ = 0x00000000;
+
+ *pushbuf->ptr++ = HOST1X_OPCODE_MASK(0x1e, 0x7);
+ *pushbuf->ptr++ = 0x00000000;
+ *pushbuf->ptr++ = (2 << 16) | (1 << 6) | (1 << 2);
+ *pushbuf->ptr++ = 0x000000cc;
+
+ *pushbuf->ptr++ = HOST1X_OPCODE_MASK(0x2b, 0x9);
+
+ /* relocate destination buffer */
+ err = drm_tegra_pushbuf_relocate(pushbuf, bo, 0, 0);
+ if (err < 0) {
+ fprintf(stderr, "failed to relocate buffer object: %d\n", err);
+ return err;
+ }
+
+ *pushbuf->ptr++ = fb->pitch;
+
+ *pushbuf->ptr++ = HOST1X_OPCODE_NONINCR(0x35, 1);
+ *pushbuf->ptr++ = color;
+
+ *pushbuf->ptr++ = HOST1X_OPCODE_NONINCR(0x46, 1);
+ *pushbuf->ptr++ = 0x00000000;
+
+ *pushbuf->ptr++ = HOST1X_OPCODE_MASK(0x38, 0x5);
+ *pushbuf->ptr++ = height << 16 | width;
+ *pushbuf->ptr++ = y << 16 | x;
+
+ return 0;
+}
+
+int drm_tegra_gr2d_fill_simple(struct drm_tegra_gr2d *gr2d,
+ struct drm_framebuffer *fb, unsigned int x,
+ unsigned int y, unsigned int width,
+ unsigned int height, uint32_t color)
+{
+ struct drm_tegra_pushbuf *pushbuf;
+ struct drm_tegra_fence *fence;
+ struct drm_tegra_job *job;
+ int err;
+
+ err = drm_tegra_job_new(&job, gr2d->channel);
+ if (err < 0)
+ return err;
+
+ err = drm_tegra_pushbuf_new(&pushbuf, job);
+ if (err < 0)
+ return err;
+
+ err = drm_tegra_gr2d_fill(pushbuf, fb, x, y, width, height, color);
+ if (err < 0) {
+ fprintf(stderr, "failed to compose 2D fill: %d\n", err);
+ return err;
+ }
+
+ err = drm_tegra_job_submit(job, &fence);
+ if (err < 0) {
+ fprintf(stderr, "failed to submit job: %d\n", err);
+ return err;
+ }
+
+ err = drm_tegra_fence_wait(fence);
+ if (err < 0) {
+ fprintf(stderr, "failed to wait for fence: %d\n", err);
+ return err;
+ }
+
+ drm_tegra_fence_free(fence);
+ drm_tegra_pushbuf_free(pushbuf);
+ drm_tegra_job_free(job);
+
+ return 0;
+}
diff --git a/tests/tegra/drm-test-tegra.h b/tests/tegra/drm-test-tegra.h
new file mode 100644
index 00000000..501e3b6b
--- /dev/null
+++ b/tests/tegra/drm-test-tegra.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright © 2014 NVIDIA Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef TEGRA_DRM_TEST_TEGRA_H
+#define TEGRA_DRM_TEST_TEGRA_H
+
+#include "drm-test.h"
+#include "tegra.h"
+
+#define HOST1X_OPCODE_SETCL(offset, classid, mask) \
+ ((0x0 << 28) | (((offset) & 0xfff) << 16) | (((classid) & 0x3ff) << 6) | ((mask) & 0x3f))
+#define HOST1X_OPCODE_INCR(offset, count) \
+ ((0x1 << 28) | (((offset) & 0xfff) << 16) | ((count) & 0xffff))
+#define HOST1X_OPCODE_NONINCR(offset, count) \
+ ((0x2 << 28) | (((offset) & 0xfff) << 16) | ((count) & 0xffff))
+#define HOST1X_OPCODE_MASK(offset, mask) \
+ ((0x3 << 28) | (((offset) & 0xfff) << 16) | ((mask) & 0xffff))
+#define HOST1X_OPCODE_IMM(offset, data) \
+ ((0x4 << 28) | (((offset) & 0xfff) << 16) | ((data) & 0xffff))
+#define HOST1X_OPCODE_EXTEND(subop, value) \
+ ((0xe << 28) | (((subop) & 0xf) << 24) | ((value) & 0xffffff))
+
+#define HOST1X_CLASS_GR2D 0x51
+
+struct drm_tegra_gr2d {
+ struct drm_tegra *drm;
+ struct drm_tegra_channel *channel;
+};
+
+int drm_tegra_gr2d_open(struct drm_tegra_gr2d **gr2dp, struct drm_tegra *drm);
+int drm_tegra_gr2d_close(struct drm_tegra_gr2d *gr2d);
+int drm_tegra_gr2d_fill_simple(struct drm_tegra_gr2d *gr2d,
+ struct drm_framebuffer *fb, unsigned int x,
+ unsigned int y, unsigned int width,
+ unsigned int height, uint32_t color);
+int drm_tegra_gr2d_fill(struct drm_tegra_pushbuf *pushbuf,
+ struct drm_framebuffer *fb, unsigned int x,
+ unsigned int y, unsigned int width,
+ unsigned int height, uint32_t color);
+
+#endif
diff --git a/tests/tegra/drm-test.c b/tests/tegra/drm-test.c
new file mode 100644
index 00000000..4ebc8ee4
--- /dev/null
+++ b/tests/tegra/drm-test.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright © 2014 NVIDIA Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/ioctl.h>
+
+#include "xf86drm.h"
+#include "xf86drmMode.h"
+#include "drm_fourcc.h"
+
+#include "drm-test.h"
+
+static int drm_screen_probe_connector(struct drm_screen *screen,
+ drmModeConnectorPtr connector)
+{
+ drmModeEncoderPtr encoder;
+ drmModeCrtcPtr crtc;
+ drmModeFBPtr fb;
+
+ encoder = drmModeGetEncoder(screen->fd, connector->encoder_id);
+ if (!encoder)
+ return -ENODEV;
+
+ crtc = drmModeGetCrtc(screen->fd, encoder->crtc_id);
+ if (!crtc) {
+ drmModeFreeEncoder(encoder);
+ return -ENODEV;
+ }
+
+ screen->old_fb = crtc->buffer_id;
+
+ fb = drmModeGetFB(screen->fd, crtc->buffer_id);
+ if (!fb) {
+ /* TODO: create new framebuffer */
+ drmModeFreeEncoder(encoder);
+ drmModeFreeCrtc(crtc);
+ return -ENOSYS;
+ }
+
+ screen->connector = connector->connector_id;
+ screen->old_fb = crtc->buffer_id;
+ screen->crtc = encoder->crtc_id;
+ /* TODO: check crtc->mode_valid */
+ screen->mode = crtc->mode;
+
+ screen->width = fb->width;
+ screen->height = fb->height;
+ screen->pitch = fb->pitch;
+ screen->depth = fb->depth;
+ screen->bpp = fb->bpp;
+
+ drmModeFreeEncoder(encoder);
+ drmModeFreeCrtc(crtc);
+ drmModeFreeFB(fb);
+
+ return 0;
+}
+
+int drm_screen_open(struct drm_screen **screenp, int fd)
+{
+ drmModeConnectorPtr connector;
+ struct drm_screen *screen;
+ bool found = false;
+ drmModeResPtr res;
+ int err, i;
+
+ if (!screenp || fd < 0)
+ return -EINVAL;
+
+ screen = calloc(1, sizeof(*screen));
+ if (!screen)
+ return -ENOMEM;
+
+ screen->format = DRM_FORMAT_XRGB8888;
+ screen->fd = fd;
+
+ res = drmModeGetResources(fd);
+ if (!res) {
+ free(screen);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < res->count_connectors; i++) {
+ connector = drmModeGetConnector(fd, res->connectors[i]);
+ if (!connector)
+ continue;
+
+ if (connector->connection != DRM_MODE_CONNECTED) {
+ drmModeFreeConnector(connector);
+ continue;
+ }
+
+ err = drm_screen_probe_connector(screen, connector);
+ if (err < 0) {
+ drmModeFreeConnector(connector);
+ continue;
+ }
+
+ drmModeFreeConnector(connector);
+ found = true;
+ break;
+ }
+
+ drmModeFreeResources(res);
+
+ if (!found) {
+ free(screen);
+ return -ENODEV;
+ }
+
+ *screenp = screen;
+
+ return 0;
+}
+
+int drm_screen_close(struct drm_screen *screen)
+{
+ int err;
+
+ err = drmModeSetCrtc(screen->fd, screen->crtc, screen->old_fb, 0, 0,
+ &screen->connector, 1, &screen->mode);
+ if (err < 0) {
+ fprintf(stderr, "drmModeSetCrtc() failed: %m\n");
+ return -errno;
+ }
+
+ free(screen);
+
+ return 0;
+}
+
+int drm_framebuffer_new(struct drm_framebuffer **fbp,
+ struct drm_screen *screen, uint32_t handle,
+ unsigned int width, unsigned int height,
+ unsigned int pitch, uint32_t format,
+ void *data)
+{
+ struct drm_framebuffer *fb;
+ uint32_t handles[4];
+ uint32_t pitches[4];
+ uint32_t offsets[4];
+ int err;
+
+ fb = calloc(1, sizeof(*fb));
+ if (!fb)
+ return -ENOMEM;
+
+ fb->fd = screen->fd;
+ fb->width = width;
+ fb->height = height;
+ fb->pitch = pitch;
+ fb->format = format;
+ fb->data = data;
+
+ handles[0] = handle;
+ pitches[0] = pitch;
+ offsets[0] = 0;
+
+ err = drmModeAddFB2(screen->fd, width, height, format, handles,
+ pitches, offsets, &fb->handle, 0);
+ if (err < 0)
+ return -errno;
+
+ *fbp = fb;
+
+ return 0;
+}
+
+int drm_framebuffer_free(struct drm_framebuffer *fb)
+{
+ int err;
+
+ err = drmModeRmFB(fb->fd, fb->handle);
+ if (err < 0)
+ return -errno;
+
+ free(fb);
+
+ return 0;
+}
+
+int drm_screen_set_framebuffer(struct drm_screen *screen,
+ struct drm_framebuffer *fb)
+{
+ int err;
+
+ err = drmModeSetCrtc(screen->fd, screen->crtc, fb->handle, 0, 0,
+ &screen->connector, 1, &screen->mode);
+ if (err < 0)
+ return -errno;
+
+ return 0;
+}
+
+int drm_open(const char *path)
+{
+ int fd, err;
+
+ fd = open(path, O_RDWR);
+ if (fd < 0)
+ return -errno;
+
+ err = drmSetMaster(fd);
+ if (err < 0) {
+ close(fd);
+ return -errno;
+ }
+
+ return fd;
+}
+
+void drm_close(int fd)
+{
+ drmDropMaster(fd);
+ close(fd);
+}
diff --git a/tests/tegra/drm-test.h b/tests/tegra/drm-test.h
new file mode 100644
index 00000000..f11aed42
--- /dev/null
+++ b/tests/tegra/drm-test.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright © 2014 NVIDIA Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef TEGRA_DRM_TEST_H
+#define TEGRA_DRM_TEST_H
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "xf86drmMode.h"
+
+struct drm_screen {
+ int fd;
+
+ unsigned int width;
+ unsigned int height;
+ unsigned int pitch;
+ unsigned int depth;
+ unsigned int bpp;
+
+ drmModeModeInfo mode;
+ uint32_t connector;
+ uint32_t old_fb;
+ uint32_t format;
+ uint32_t crtc;
+};
+
+struct drm_framebuffer {
+ unsigned int width;
+ unsigned int height;
+ unsigned int pitch;
+ uint32_t format;
+ uint32_t handle;
+ void *data;
+ int fd;
+};
+
+int drm_screen_open(struct drm_screen **screenp, int fd);
+int drm_screen_close(struct drm_screen *screen);
+int drm_screen_set_framebuffer(struct drm_screen *screen,
+ struct drm_framebuffer *fb);
+
+int drm_framebuffer_new(struct drm_framebuffer **fbp,
+ struct drm_screen *screen, uint32_t handle,
+ unsigned int width, unsigned int height,
+ unsigned int pitch, uint32_t format,
+ void *data);
+int drm_framebuffer_free(struct drm_framebuffer *fb);
+
+int drm_open(const char *path);
+void drm_close(int fd);
+
+#endif
diff --git a/tests/tegra/gr2d-fill.c b/tests/tegra/gr2d-fill.c
new file mode 100644
index 00000000..990cd470
--- /dev/null
+++ b/tests/tegra/gr2d-fill.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright © 2014 NVIDIA Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/ioctl.h>
+
+#include "xf86drm.h"
+#include "xf86drmMode.h"
+#include "drm_fourcc.h"
+
+#include "drm-test-tegra.h"
+#include "tegra.h"
+
+static const char default_device[] = "/dev/dri/card0";
+
+int main(int argc, char *argv[])
+{
+ uint32_t format = DRM_FORMAT_XRGB8888;
+ struct drm_tegra_gr2d *gr2d;
+ struct drm_framebuffer *fb;
+ struct drm_screen *screen;
+ unsigned int pitch, size;
+ struct drm_tegra_bo *bo;
+ struct drm_tegra *drm;
+ const char *device;
+ uint32_t handle;
+ int fd, err;
+ void *ptr;
+
+ if (argc < 2)
+ device = default_device;
+ else
+ device = argv[1];
+
+ fd = drm_open(device);
+ if (fd < 0) {
+ fprintf(stderr, "failed to open DRM device %s: %s\n", device,
+ strerror(errno));
+ return 1;
+ }
+
+ err = drm_screen_open(&screen, fd);
+ if (err < 0) {
+ fprintf(stderr, "failed to open screen: %s\n", strerror(-err));
+ return 1;
+ }
+
+ err = drm_tegra_new(&drm, fd);
+ if (err < 0) {
+ fprintf(stderr, "failed to create Tegra DRM context: %s\n",
+ strerror(-err));
+ return 1;
+ }
+
+ err = drm_tegra_gr2d_open(&gr2d, drm);
+ if (err < 0) {
+ fprintf(stderr, "failed to open gr2d channel: %s\n",
+ strerror(-err));
+ return 1;
+ }
+
+ pitch = screen->width * screen->bpp / 8;
+ size = pitch * screen->height;
+
+ err = drm_tegra_bo_new(&bo, drm, 0, size);
+ if (err < 0) {
+ fprintf(stderr, "failed to create buffer object: %s\n",
+ strerror(-err));
+ return 1;
+ }
+
+ err = drm_tegra_bo_get_handle(bo, &handle);
+ if (err < 0) {
+ fprintf(stderr, "failed to get handle to buffer object: %s\n",
+ strerror(-err));
+ return 1;
+ }
+
+ err = drm_tegra_bo_map(bo, &ptr);
+ if (err < 0) {
+ fprintf(stderr, "failed to map buffer object: %s\n",
+ strerror(-err));
+ return 1;
+ }
+
+ memset(ptr, 0xff, size);
+
+ err = drm_framebuffer_new(&fb, screen, handle, screen->width,
+ screen->height, pitch, format, bo);
+ if (err < 0) {
+ fprintf(stderr, "failed to create framebuffer: %s\n",
+ strerror(-err));
+ return 1;
+ }
+
+ err = drm_screen_set_framebuffer(screen, fb);
+ if (err < 0) {
+ fprintf(stderr, "failed to display framebuffer: %s\n",
+ strerror(-err));
+ return 1;
+ }
+
+ sleep(1);
+
+ err = drm_tegra_gr2d_fill_simple(gr2d, fb, fb->width / 4,
+ fb->height / 4, fb->width / 2,
+ fb->height / 2, 0x00000000);
+ if (err < 0) {
+ fprintf(stderr, "failed to fill rectangle: %s\n",
+ strerror(-err));
+ return 1;
+ }
+
+ sleep(1);
+
+ drm_framebuffer_free(fb);
+ drm_tegra_bo_unref(bo);
+ drm_tegra_gr2d_close(gr2d);
+ drm_tegra_close(drm);
+ drm_screen_close(screen);
+ drm_close(fd);
+
+ return 0;
+}
diff --git a/tests/tegra/openclose.c b/tests/tegra/openclose.c
index 881d8aa4..08da41a6 100644
--- a/tests/tegra/openclose.c
+++ b/tests/tegra/openclose.c
@@ -35,37 +35,37 @@ static const char default_device[] = "/dev/dri/card0";
int main(int argc, char *argv[])
{
- struct drm_tegra *tegra;
- drmVersionPtr version;
- const char *device;
- int err, fd;
+ struct drm_tegra *tegra;
+ drmVersionPtr version;
+ const char *device;
+ int err, fd;
- if (argc < 2)
- device = default_device;
- else
- device = argv[1];
+ if (argc < 2)
+ device = default_device;
+ else
+ device = argv[1];
- fd = open(device, O_RDWR);
- if (fd < 0)
- return 1;
+ fd = open(device, O_RDWR);
+ if (fd < 0)
+ return 1;
- version = drmGetVersion(fd);
- if (version) {
- printf("Version: %d.%d.%d\n", version->version_major,
- version->version_minor, version->version_patchlevel);
- printf(" Name: %s\n", version->name);
- printf(" Date: %s\n", version->date);
- printf(" Description: %s\n", version->desc);
+ version = drmGetVersion(fd);
+ if (version) {
+ printf("Version: %d.%d.%d\n", version->version_major,
+ version->version_minor, version->version_patchlevel);
+ printf(" Name: %s\n", version->name);
+ printf(" Date: %s\n", version->date);
+ printf(" Description: %s\n", version->desc);
- drmFreeVersion(version);
- }
+ drmFreeVersion(version);
+ }
- err = drm_tegra_new(&tegra, fd);
- if (err < 0)
- return 1;
+ err = drm_tegra_new(&tegra, fd);
+ if (err < 0)
+ return 1;
- drm_tegra_close(tegra);
- close(fd);
+ drm_tegra_close(tegra);
+ close(fd);
- return 0;
+ return 0;
}
diff --git a/tests/tegra/vic-syncpt.c b/tests/tegra/vic-syncpt.c
new file mode 100644
index 00000000..91a6baef
--- /dev/null
+++ b/tests/tegra/vic-syncpt.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright © 2014 NVIDIA Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "drm-test-tegra.h"
+#include "tegra.h"
+
+static const char default_device[] = "/dev/dri/card0";
+
+int main(int argc, char *argv[])
+{
+ struct drm_tegra_channel *channel;
+ struct drm_tegra_pushbuf *pushbuf;
+ struct drm_tegra_fence *fence;
+ struct drm_tegra_job *job;
+ struct drm_tegra *drm;
+ const char *device;
+ int fd, err;
+
+ if (argc < 2)
+ device = default_device;
+ else
+ device = argv[1];
+
+ fd = drm_open(device);
+ if (fd < 0) {
+ fprintf(stderr, "failed to open DRM device %s: %s\n", device,
+ strerror(errno));
+ return 1;
+ }
+
+ err = drm_tegra_new(&drm, fd);
+ if (err < 0) {
+ fprintf(stderr, "failed to create Tegra DRM context: %s\n",
+ strerror(-err));
+ return 1;
+ }
+
+ err = drm_tegra_channel_open(&channel, drm, DRM_TEGRA_VIC);
+ if (err < 0) {
+ fprintf(stderr, "failed to open channel to VIC: %s\n",
+ strerror(-err));
+ return 1;
+ }
+
+ err = drm_tegra_job_new(&job, channel);
+ if (err < 0)
+ return 1;
+
+ err = drm_tegra_pushbuf_new(&pushbuf, job);
+ if (err < 0)
+ return 1;
+
+ err = drm_tegra_pushbuf_prepare(pushbuf, 4);
+ if (err < 0)
+ return 1;
+
+ *pushbuf->ptr++ = HOST1X_OPCODE_SETCL(0, HOST1X_CLASS_GR2D, 0);
+
+ err = drm_tegra_pushbuf_sync(pushbuf, DRM_TEGRA_SYNCPT_COND_OP_DONE);
+ if (err < 0)
+ return 1;
+
+ err = drm_tegra_job_submit(job, &fence);
+ if (err < 0) {
+ return 1;
+ }
+
+ err = drm_tegra_fence_wait(fence);
+ if (err < 0) {
+ return 1;
+ }
+
+ drm_tegra_fence_free(fence);
+ drm_tegra_pushbuf_free(pushbuf);
+ drm_tegra_job_free(job);
+
+ drm_tegra_channel_close(channel);
+ drm_tegra_close(drm);
+ drm_close(fd);
+
+ return 0;
+}