summaryrefslogtreecommitdiff
path: root/drivers/video
diff options
context:
space:
mode:
authorScott Williams <scwilliams@nvidia.com>2012-01-27 13:53:25 -0800
committerVarun Wadekar <vwadekar@nvidia.com>2012-06-25 15:32:17 +0530
commit489484b20f3803305d318cbe9c85b299bf6916d1 (patch)
treebe1577ac702e53f1272322790db0921302ab8ff3 /drivers/video
parent035d38b0618d10a83fc3a65029051d8c5fabd3d1 (diff)
video: tegra: host: Tegra11x 3D support
Add support for context switch for Tegra11x 3D unit. Bug 839973 Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com> Reviewed-on: http://git-master/r/57220 Reviewed-by: Scott Williams <scwilliams@nvidia.com> Tested-by: Scott Williams <scwilliams@nvidia.com> (cherry picked from commit aafea7c82885d16b350336036813b3863509de58) Change-Id: I2f65840077a250f0348e9d3bfa8d37c237e9d0a5 Signed-off-by: Scott Williams <scwilliams@nvidia.com> Reviewed-on: http://git-master/r/77873 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com> Reviewed-by: Mark Stadler <mastadler@nvidia.com>
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/tegra/host/gr3d/Makefile1
-rw-r--r--drivers/video/tegra/host/gr3d/gr3d_t114.c349
-rw-r--r--drivers/video/tegra/host/gr3d/gr3d_t114.h30
3 files changed, 380 insertions, 0 deletions
diff --git a/drivers/video/tegra/host/gr3d/Makefile b/drivers/video/tegra/host/gr3d/Makefile
index dfbd078ab423..13f27443c264 100644
--- a/drivers/video/tegra/host/gr3d/Makefile
+++ b/drivers/video/tegra/host/gr3d/Makefile
@@ -5,6 +5,7 @@ nvhost-gr3d-objs = \
gr3d.o \
gr3d_t20.o \
gr3d_t30.o \
+ gr3d_t114.o \
scale3d.o
obj-$(CONFIG_TEGRA_GRHOST) += nvhost-gr3d.o
diff --git a/drivers/video/tegra/host/gr3d/gr3d_t114.c b/drivers/video/tegra/host/gr3d/gr3d_t114.c
new file mode 100644
index 000000000000..a92244199ba5
--- /dev/null
+++ b/drivers/video/tegra/host/gr3d/gr3d_t114.c
@@ -0,0 +1,349 @@
+/*
+ * drivers/video/tegra/host/t20/3dctx_t114.c
+ *
+ * Tegra Graphics Host 3d hardware context
+ *
+ * Copyright (c) 2011-2012 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "nvhost_hwctx.h"
+#include "dev.h"
+#include "host1x/host1x_hardware.h"
+#include "host1x/host1x_syncpt.h"
+#include "gr3d/gr3d.h"
+
+#include <linux/slab.h>
+
+static const struct hwctx_reginfo ctxsave_regs_3d_global[] = {
+ HWCTX_REGINFO(0xe00, 4, DIRECT),
+ HWCTX_REGINFO(0xe05, 30, DIRECT),
+ HWCTX_REGINFO(0xe25, 2, DIRECT),
+ HWCTX_REGINFO(0xe28, 2, DIRECT),
+ HWCTX_REGINFO(0xe30, 16, DIRECT),
+ HWCTX_REGINFO(0x001, 2, DIRECT),
+ HWCTX_REGINFO(0x00c, 10, DIRECT),
+ HWCTX_REGINFO(0x100, 34, DIRECT),
+ HWCTX_REGINFO(0x124, 2, DIRECT),
+ HWCTX_REGINFO(0x127, 1, DIRECT),
+ HWCTX_REGINFO(0x200, 5, DIRECT),
+ HWCTX_REGINFO(0x205, 1024, INDIRECT),
+ HWCTX_REGINFO(0x207, 1024, INDIRECT),
+ HWCTX_REGINFO(0x209, 1, DIRECT),
+ HWCTX_REGINFO(0x300, 64, DIRECT),
+ HWCTX_REGINFO(0x343, 25, DIRECT),
+ HWCTX_REGINFO(0x363, 2, DIRECT),
+ HWCTX_REGINFO(0x400, 16, DIRECT),
+ HWCTX_REGINFO(0x411, 1, DIRECT),
+ HWCTX_REGINFO(0x412, 1, DIRECT),
+ HWCTX_REGINFO(0x413, 1, DIRECT),
+ HWCTX_REGINFO(0x500, 4, DIRECT),
+ HWCTX_REGINFO(0x520, 32, DIRECT),
+ HWCTX_REGINFO(0x540, 64, INDIRECT),
+ HWCTX_REGINFO(0x548, 64, INDIRECT),
+ HWCTX_REGINFO(0x600, 16, INDIRECT_4X),
+ HWCTX_REGINFO(0x603, 128, INDIRECT),
+ HWCTX_REGINFO(0x608, 4, DIRECT),
+ HWCTX_REGINFO(0x60e, 1, DIRECT),
+ HWCTX_REGINFO(0x700, 64, INDIRECT),
+ HWCTX_REGINFO(0x710, 50, DIRECT),
+ HWCTX_REGINFO(0x750, 16, DIRECT),
+ HWCTX_REGINFO(0x760, 16, DIRECT),
+ HWCTX_REGINFO(0x780, 32, DIRECT),
+ HWCTX_REGINFO(0x7e0, 1, DIRECT),
+ HWCTX_REGINFO(0x7e1, 1, DIRECT),
+ HWCTX_REGINFO(0x7f9, 1, DIRECT),
+ HWCTX_REGINFO(0x800, 16, INDIRECT_4X),
+ HWCTX_REGINFO(0x803, 1024, INDIRECT),
+ HWCTX_REGINFO(0x805, 64, INDIRECT),
+ HWCTX_REGINFO(0x807, 1, DIRECT),
+ HWCTX_REGINFO(0x820, 32, DIRECT),
+ HWCTX_REGINFO(0x900, 64, INDIRECT),
+ HWCTX_REGINFO(0x902, 2, DIRECT),
+ HWCTX_REGINFO(0x90a, 1, DIRECT),
+ HWCTX_REGINFO(0x90b, 1, DIRECT),
+ HWCTX_REGINFO(0xa02, 10, DIRECT),
+ HWCTX_REGINFO(0xb04, 1, DIRECT),
+ HWCTX_REGINFO(0xb06, 13, DIRECT),
+ HWCTX_REGINFO(0xe04, 1, DIRECT),
+ HWCTX_REGINFO(0xe2a, 1, DIRECT),
+ HWCTX_REGINFO(0xe41, 1, DIRECT),
+ HWCTX_REGINFO(0xe44, 1, DIRECT),
+ HWCTX_REGINFO(0xe45, 1, DIRECT),
+};
+
+/* the same context save command sequence is used for all contexts. */
+static phys_addr_t save_phys;
+static unsigned int save_size;
+
+#define SAVE_BEGIN_V1_SIZE (1 + RESTORE_BEGIN_SIZE)
+#define SAVE_DIRECT_V1_SIZE (4 + RESTORE_DIRECT_SIZE)
+#define SAVE_INDIRECT_V1_SIZE (6 + RESTORE_INDIRECT_SIZE)
+#define SAVE_END_V1_SIZE (8 + RESTORE_END_SIZE)
+#define SAVE_INCRS 3
+#define RESTORE_BEGIN_SIZE 4
+#define RESTORE_DIRECT_SIZE 1
+#define RESTORE_INDIRECT_SIZE 2
+#define RESTORE_END_SIZE 1
+
+struct save_info {
+ u32 *ptr;
+ unsigned int save_count;
+ unsigned int restore_count;
+ unsigned int save_incrs;
+ unsigned int restore_incrs;
+};
+
+/*** save ***/
+
+static void save_push_v1(struct nvhost_cdma *cdma,
+ struct nvhost_hwctx *ctx)
+{
+ /* wait for 3d idle */
+ nvhost_cdma_push(cdma,
+ nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0),
+ nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_OP_DONE,
+ NVSYNCPT_3D));
+ nvhost_cdma_push(cdma,
+ nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
+ NV_CLASS_HOST_WAIT_SYNCPT_BASE, 1),
+ nvhost_class_host_wait_syncpt_base(NVSYNCPT_3D,
+ NVWAITBASE_3D, 1));
+ /* back to 3d */
+ nvhost_cdma_push(cdma,
+ nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0),
+ NVHOST_OPCODE_NOOP);
+ nvhost_cdma_push(cdma,
+ nvhost_opcode_imm(0xb00, 1),
+ nvhost_opcode_imm(0xe40, 1));
+ nvhost_cdma_push(cdma,
+ nvhost_opcode_nonincr(0x904, 1),
+ ctx->restore_phys);
+ /* gather the save buffer */
+ nvhost_cdma_push_gather(cdma,
+ (void *)NVHOST_CDMA_PUSH_GATHER_CTXSAVE,
+ (void *)NVHOST_CDMA_PUSH_GATHER_CTXSAVE,
+ nvhost_opcode_gather(save_size),
+ save_phys);
+}
+
+static void __init save_begin_v1(u32 *ptr)
+{
+ ptr[0] = nvhost_opcode_nonincr(0x905, RESTORE_BEGIN_SIZE);
+ nvhost_3dctx_restore_begin(ptr + 1);
+ ptr += RESTORE_BEGIN_SIZE;
+}
+
+static void __init save_direct_v1(u32 *ptr, u32 start_reg, u32 count)
+{
+#if RESTORE_DIRECT_SIZE != 1
+#error whoops! code is optimized for RESTORE_DIRECT_SIZE == 1
+#endif
+ ptr[0] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0x905, 1);
+ nvhost_3dctx_restore_direct(ptr + 1, start_reg, count);
+ ptr += RESTORE_DIRECT_SIZE;
+ ptr[1] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
+ NV_CLASS_HOST_INDOFF, 1);
+ ptr[2] = nvhost_class_host_indoff_reg_read(NV_HOST_MODULE_GR3D,
+ start_reg, true);
+ /* TODO could do this in the setclass if count < 6 */
+ ptr[3] = nvhost_opcode_nonincr(NV_CLASS_HOST_INDDATA, count);
+}
+
+static void __init save_indirect_v1(u32 *ptr, u32 offset_reg, u32 offset,
+ u32 data_reg, u32 count)
+{
+ ptr[0] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0);
+ ptr[1] = nvhost_opcode_nonincr(0x905, RESTORE_INDIRECT_SIZE);
+ nvhost_3dctx_restore_indirect(ptr + 2, offset_reg, offset, data_reg,
+ count);
+ ptr += RESTORE_INDIRECT_SIZE;
+ ptr[2] = nvhost_opcode_imm(offset_reg, offset);
+ ptr[3] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
+ NV_CLASS_HOST_INDOFF, 1);
+ ptr[4] = nvhost_class_host_indoff_reg_read(NV_HOST_MODULE_GR3D,
+ data_reg, false);
+ ptr[5] = nvhost_opcode_nonincr(NV_CLASS_HOST_INDDATA, count);
+}
+
+static void __init save_end_v1(u32 *ptr)
+{
+#if RESTORE_END_SIZE != 1
+#error whoops! code is optimized for RESTORE_END_SIZE == 1
+#endif
+ /* write end of restore buffer */
+ ptr[0] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0x905, 1);
+ nvhost_3dctx_restore_end(ptr + 1);
+ ptr += RESTORE_END_SIZE;
+ /* op_done syncpt incr to flush FDC */
+ ptr[1] = nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_OP_DONE, NVSYNCPT_3D);
+ /* host wait for that syncpt incr, and advance the wait base */
+ ptr[2] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
+ NV_CLASS_HOST_WAIT_SYNCPT_BASE,
+ nvhost_mask2(
+ NV_CLASS_HOST_WAIT_SYNCPT_BASE,
+ NV_CLASS_HOST_INCR_SYNCPT_BASE));
+ ptr[3] = nvhost_class_host_wait_syncpt_base(NVSYNCPT_3D,
+ NVWAITBASE_3D, nvhost_3dctx_save_incrs - 1);
+ ptr[4] = nvhost_class_host_incr_syncpt_base(NVWAITBASE_3D,
+ nvhost_3dctx_save_incrs);
+ /* set class back to 3d */
+ ptr[5] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0);
+ /* send reg reads back to host */
+ ptr[6] = nvhost_opcode_imm(0xe40, 0);
+ /* final syncpt increment to release waiters */
+ ptr[7] = nvhost_opcode_imm(0, NVSYNCPT_3D);
+}
+
+static void __init setup_save_regs(struct save_info *info,
+ const struct hwctx_reginfo *regs,
+ unsigned int nr_regs)
+{
+ const struct hwctx_reginfo *rend = regs + nr_regs;
+ u32 *ptr = info->ptr;
+ unsigned int save_count = info->save_count;
+ unsigned int restore_count = info->restore_count;
+
+ for ( ; regs != rend; ++regs) {
+ u32 offset = regs->offset;
+ u32 count = regs->count;
+ u32 indoff = offset + 1;
+ switch (regs->type) {
+ case HWCTX_REGINFO_DIRECT:
+ if (ptr) {
+ save_direct_v1(ptr, offset, count);
+ ptr += SAVE_DIRECT_V1_SIZE;
+ }
+ save_count += SAVE_DIRECT_V1_SIZE;
+ restore_count += RESTORE_DIRECT_SIZE;
+ break;
+ case HWCTX_REGINFO_INDIRECT_4X:
+ ++indoff;
+ /* fall through */
+ case HWCTX_REGINFO_INDIRECT:
+ if (ptr) {
+ save_indirect_v1(ptr, offset, 0,
+ indoff, count);
+ ptr += SAVE_INDIRECT_V1_SIZE;
+ }
+ save_count += SAVE_INDIRECT_V1_SIZE;
+ restore_count += RESTORE_INDIRECT_SIZE;
+ break;
+ }
+ if (ptr) {
+ /* SAVE cases only: reserve room for incoming data */
+ u32 k = 0;
+ /*
+ * Create a signature pattern for indirect data (which
+ * will be overwritten by true incoming data) for
+ * better deducing where we are in a long command
+ * sequence, when given only a FIFO snapshot for debug
+ * purposes.
+ */
+ for (k = 0; k < count; k++)
+ *(ptr + k) = 0xd000d000 | (offset << 16) | k;
+ ptr += count;
+ }
+ save_count += count;
+ restore_count += count;
+ }
+
+ info->ptr = ptr;
+ info->save_count = save_count;
+ info->restore_count = restore_count;
+}
+
+static void __init setup_save(u32 *ptr)
+{
+ struct save_info info = {
+ ptr,
+ SAVE_BEGIN_V1_SIZE,
+ RESTORE_BEGIN_SIZE,
+ SAVE_INCRS,
+ 1
+ };
+
+ if (info.ptr) {
+ save_begin_v1(info.ptr);
+ info.ptr += SAVE_BEGIN_V1_SIZE;
+ }
+
+ /* save regs */
+ setup_save_regs(&info,
+ ctxsave_regs_3d_global,
+ ARRAY_SIZE(ctxsave_regs_3d_global));
+
+ if (info.ptr) {
+ save_end_v1(info.ptr);
+ info.ptr += SAVE_END_V1_SIZE;
+ }
+
+ wmb();
+
+ save_size = info.save_count + SAVE_END_V1_SIZE;
+ nvhost_3dctx_restore_size = info.restore_count + RESTORE_END_SIZE;
+ nvhost_3dctx_save_incrs = info.save_incrs;
+ nvhost_3dctx_save_thresh = nvhost_3dctx_save_incrs;
+ nvhost_3dctx_restore_incrs = info.restore_incrs;
+}
+
+/*** ctx3d ***/
+
+static struct nvhost_hwctx *ctx3d_alloc_v1(struct nvhost_channel *ch)
+{
+ return nvhost_3dctx_alloc_common(ch, false);
+}
+
+int __init t114_nvhost_3dctx_handler_init(struct nvhost_hwctx_handler *h)
+{
+ struct nvhost_channel *ch;
+ struct nvmap_client *nvmap;
+ u32 *save_ptr;
+
+ ch = container_of(h, struct nvhost_channel, ctxhandler);
+ nvmap = ch->dev->host->nvmap;
+
+ setup_save(NULL);
+
+ nvhost_3dctx_save_buf = nvmap_alloc(nvmap, save_size * 4, 32,
+ NVMAP_HANDLE_WRITE_COMBINE);
+ if (IS_ERR(nvhost_3dctx_save_buf)) {
+ int err = PTR_ERR(nvhost_3dctx_save_buf);
+ nvhost_3dctx_save_buf = NULL;
+ return err;
+ }
+
+ nvhost_3dctx_save_slots = 6;
+
+ save_ptr = nvmap_mmap(nvhost_3dctx_save_buf);
+ if (!save_ptr) {
+ nvmap_free(nvmap, nvhost_3dctx_save_buf);
+ nvhost_3dctx_save_buf = NULL;
+ return -ENOMEM;
+ }
+
+ save_phys = nvmap_pin(nvmap, nvhost_3dctx_save_buf);
+
+ setup_save(save_ptr);
+
+ h->alloc = ctx3d_alloc_v1;
+ h->save_push = save_push_v1;
+ h->save_service = NULL;
+ h->get = nvhost_3dctx_get;
+ h->put = nvhost_3dctx_put;
+
+ return 0;
+}
diff --git a/drivers/video/tegra/host/gr3d/gr3d_t114.h b/drivers/video/tegra/host/gr3d/gr3d_t114.h
new file mode 100644
index 000000000000..4fa69c014274
--- /dev/null
+++ b/drivers/video/tegra/host/gr3d/gr3d_t114.h
@@ -0,0 +1,30 @@
+/*
+ * drivers/video/tegra/host/t30/3dctx_t114.h
+ *
+ * Tegra Graphics Host Context Switching for Tegra11x SOCs
+ *
+ * Copyright (c) 2011-2012, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __NVHOST_3DCTX_T114_H
+#define __NVHOST_3DCTX_T114_H
+
+struct nvhost_hwctx_handler;
+
+int t114_nvhost_3dctx_handler_init(struct nvhost_hwctx_handler *h);
+
+#endif