summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorTerje Bergstrom <tbergstrom@nvidia.com>2011-08-12 11:25:13 +0300
committerRohan Somvanshi <rsomvanshi@nvidia.com>2011-08-30 04:20:38 -0700
commited2d44a1fc1fef35240b264beaec09d50202bd21 (patch)
tree15e6c041b9a94e79b0ece12f1e135fcd346010cd /drivers
parent68fbd17c5ab167d79de27392ffa4ca40b71c21b8 (diff)
tegra: host: Separate Tegra2/3 code paths for 3D
Separate Tegra2 and Tegra3 code paths for 3D context switching. Bug 839973 Change-Id: I5cfece1c9835a3de329f390aed55c47ad00f87e8 Reviewed-on: http://git-master/r/46887 Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com> Tested-by: Terje Bergstrom <tbergstrom@nvidia.com> Reviewed-by: Scott Williams <scwilliams@nvidia.com> Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/video/tegra/host/3dctx_common.c136
-rw-r--r--drivers/video/tegra/host/3dctx_common.h52
-rw-r--r--drivers/video/tegra/host/Makefile1
-rw-r--r--drivers/video/tegra/host/nvhost_hwctx.h3
-rw-r--r--drivers/video/tegra/host/t20/3dctx_t20.c735
-rw-r--r--drivers/video/tegra/host/t20/3dctx_t20.h30
-rw-r--r--drivers/video/tegra/host/t20/cdma_t20.c2
-rw-r--r--drivers/video/tegra/host/t20/channel_t20.c19
-rw-r--r--drivers/video/tegra/host/t20/channel_t20.h30
-rw-r--r--drivers/video/tegra/host/t20/hardware_t20.h8
-rw-r--r--drivers/video/tegra/host/t20/syncpt_t20.h1
-rw-r--r--drivers/video/tegra/host/t30/3dctx_t30.c454
-rw-r--r--drivers/video/tegra/host/t30/3dctx_t30.h30
-rw-r--r--drivers/video/tegra/host/t30/Makefile4
-rw-r--r--drivers/video/tegra/host/t30/channel_t30.c70
-rw-r--r--drivers/video/tegra/host/t30/t30.c6
-rw-r--r--drivers/video/tegra/host/t30/t30.h29
17 files changed, 1002 insertions, 608 deletions
diff --git a/drivers/video/tegra/host/3dctx_common.c b/drivers/video/tegra/host/3dctx_common.c
new file mode 100644
index 000000000000..59f51ac24f44
--- /dev/null
+++ b/drivers/video/tegra/host/3dctx_common.c
@@ -0,0 +1,136 @@
+/*
+ * drivers/video/tegra/host/3dctx_common.c
+ *
+ * Tegra Graphics Host 3d hardware context
+ *
+ * Copyright (c) 2011 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.
+ */
+
+/*** restore ***/
+
+#include <mach/nvmap.h>
+#include <linux/slab.h>
+#include "3dctx_common.h"
+#include "t20/hardware_t20.h"
+#include "t20/syncpt_t20.h"
+#include "nvhost_hwctx.h"
+#include "dev.h"
+
+unsigned int nvhost_3dctx_restore_size;
+unsigned int nvhost_3dctx_restore_incrs;
+struct nvmap_handle_ref *nvhost_3dctx_save_buf;
+unsigned int nvhost_3dctx_save_incrs;
+unsigned int nvhost_3dctx_save_thresh;
+unsigned int nvhost_3dctx_save_slots;
+
+void nvhost_3dctx_restore_begin(u32 *ptr)
+{
+ /* set class to host */
+ ptr[0] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
+ NV_CLASS_HOST_INCR_SYNCPT_BASE, 1);
+ /* increment sync point base */
+ ptr[1] = nvhost_class_host_incr_syncpt_base(NVWAITBASE_3D,
+ nvhost_3dctx_restore_incrs);
+ /* set class to 3D */
+ ptr[2] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0);
+ /* program PSEQ_QUAD_ID */
+ ptr[3] = nvhost_opcode_imm(0x545, 0);
+}
+
+void nvhost_3dctx_restore_direct(u32 *ptr, u32 start_reg, u32 count)
+{
+ ptr[0] = nvhost_opcode_incr(start_reg, count);
+}
+
+void nvhost_3dctx_restore_indirect(u32 *ptr, u32 offset_reg, u32 offset,
+ u32 data_reg, u32 count)
+{
+ ptr[0] = nvhost_opcode_imm(offset_reg, offset);
+ ptr[1] = nvhost_opcode_nonincr(data_reg, count);
+}
+
+void nvhost_3dctx_restore_end(u32 *ptr)
+{
+ /* syncpt increment to track restore gather. */
+ ptr[0] = nvhost_opcode_imm_incr_syncpt(
+ NV_SYNCPT_OP_DONE, NVSYNCPT_3D);
+}
+
+/*** ctx3d ***/
+
+struct nvhost_hwctx *nvhost_3dctx_alloc_common(struct nvhost_channel *ch,
+ bool map_restore)
+{
+ struct nvmap_client *nvmap = ch->dev->nvmap;
+ struct nvhost_hwctx *ctx;
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return NULL;
+ ctx->restore = nvmap_alloc(nvmap, nvhost_3dctx_restore_size * 4, 32,
+ map_restore ? NVMAP_HANDLE_WRITE_COMBINE
+ : NVMAP_HANDLE_UNCACHEABLE);
+ if (IS_ERR_OR_NULL(ctx->restore)) {
+ kfree(ctx);
+ return NULL;
+ }
+
+ if (map_restore) {
+ ctx->restore_virt = nvmap_mmap(ctx->restore);
+ if (!ctx->restore_virt) {
+ nvmap_free(nvmap, ctx->restore);
+ kfree(ctx);
+ return NULL;
+ }
+ } else {
+ ctx->restore_virt = NULL;
+ }
+
+ kref_init(&ctx->ref);
+ ctx->channel = ch;
+ ctx->valid = false;
+ ctx->save = nvhost_3dctx_save_buf;
+ ctx->save_incrs = nvhost_3dctx_save_incrs;
+ ctx->save_thresh = nvhost_3dctx_save_thresh;
+ ctx->save_slots = nvhost_3dctx_save_slots;
+ ctx->restore_phys = nvmap_pin(nvmap, ctx->restore);
+ ctx->restore_size = nvhost_3dctx_restore_size;
+ ctx->restore_incrs = nvhost_3dctx_restore_incrs;
+ return ctx;
+}
+
+void nvhost_3dctx_get(struct nvhost_hwctx *ctx)
+{
+ kref_get(&ctx->ref);
+}
+
+void nvhost_3dctx_free(struct kref *ref)
+{
+ struct nvhost_hwctx *ctx = container_of(ref, struct nvhost_hwctx, ref);
+ struct nvmap_client *nvmap = ctx->channel->dev->nvmap;
+
+ if (ctx->restore_virt)
+ nvmap_munmap(ctx->restore, ctx->restore_virt);
+ nvmap_unpin(nvmap, ctx->restore);
+ nvmap_free(nvmap, ctx->restore);
+ kfree(ctx);
+}
+
+void nvhost_3dctx_put(struct nvhost_hwctx *ctx)
+{
+ kref_put(&ctx->ref, nvhost_3dctx_free);
+}
diff --git a/drivers/video/tegra/host/3dctx_common.h b/drivers/video/tegra/host/3dctx_common.h
new file mode 100644
index 000000000000..3816b1a7eafd
--- /dev/null
+++ b/drivers/video/tegra/host/3dctx_common.h
@@ -0,0 +1,52 @@
+/*
+ * drivers/video/tegra/host/3dctx_common.h
+ *
+ * Tegra Graphics Host Syncpoints for T20
+ *
+ * Copyright (c) 2011, 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_COMMON_H
+#define __NVHOST_3DCTX_COMMON_H
+
+#include <linux/types.h>
+
+/* Internal variables used by common 3D context switch functions */
+extern unsigned int nvhost_3dctx_restore_size;
+extern unsigned int nvhost_3dctx_restore_incrs;
+extern struct nvmap_handle_ref *nvhost_3dctx_save_buf;
+extern unsigned int nvhost_3dctx_save_incrs;
+extern unsigned int nvhost_3dctx_save_thresh;
+extern unsigned int nvhost_3dctx_save_slots;
+
+struct nvhost_hwctx;
+struct nvhost_channel;
+struct kref;
+
+/* Functions used commonly by all 3D context switch modules */
+extern void nvhost_3dctx_restore_begin(u32 *ptr);
+extern void nvhost_3dctx_restore_direct(u32 *ptr, u32 start_reg, u32 count);
+extern void nvhost_3dctx_restore_indirect(u32 *ptr, u32 offset_reg,
+ u32 offset, u32 data_reg, u32 count);
+extern void nvhost_3dctx_restore_end(u32 *ptr);
+extern struct nvhost_hwctx *nvhost_3dctx_alloc_common(
+ struct nvhost_channel *ch, bool map_restore);
+extern void nvhost_3dctx_get(struct nvhost_hwctx *ctx);
+extern void nvhost_3dctx_free(struct kref *ref);
+extern void nvhost_3dctx_put(struct nvhost_hwctx *ctx);
+
+#endif
diff --git a/drivers/video/tegra/host/Makefile b/drivers/video/tegra/host/Makefile
index e6b7edfa917f..79dcb06ff8fc 100644
--- a/drivers/video/tegra/host/Makefile
+++ b/drivers/video/tegra/host/Makefile
@@ -7,6 +7,7 @@ nvhost-objs = \
nvhost_channel.o \
dev.o \
bus.o \
+ 3dctx_common.o \
debug.o
obj-$(CONFIG_TEGRA_GRHOST) += t20/
diff --git a/drivers/video/tegra/host/nvhost_hwctx.h b/drivers/video/tegra/host/nvhost_hwctx.h
index f128584e96f4..6d6f458d7d75 100644
--- a/drivers/video/tegra/host/nvhost_hwctx.h
+++ b/drivers/video/tegra/host/nvhost_hwctx.h
@@ -65,7 +65,6 @@ struct hwctx_reginfo {
unsigned int offset:12;
unsigned int count:16;
unsigned int type:2;
- unsigned int version:2;
};
enum {
@@ -74,6 +73,6 @@ enum {
HWCTX_REGINFO_INDIRECT_4X
};
-#define HWCTX_REGINFO(version, offset, count, type) {offset, count, HWCTX_REGINFO_##type, version}
+#define HWCTX_REGINFO(offset, count, type) {offset, count, HWCTX_REGINFO_##type}
#endif
diff --git a/drivers/video/tegra/host/t20/3dctx_t20.c b/drivers/video/tegra/host/t20/3dctx_t20.c
index 7ad7166b2d3a..ebf6c73d2693 100644
--- a/drivers/video/tegra/host/t20/3dctx_t20.c
+++ b/drivers/video/tegra/host/t20/3dctx_t20.c
@@ -24,74 +24,62 @@
#include "../dev.h"
#include "hardware_t20.h"
#include "syncpt_t20.h"
+#include "../3dctx_common.h"
-#include <mach/gpufuse.h>
-#include <mach/hardware.h>
#include <linux/slab.h>
-
-#define NV_WAR_789194 1
-
-/* 99 > 2, which makes kernel panic if register set is incorrect */
-static int register_sets = 99;
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
-static bool s_is_v1 = false;
-#else
-static bool s_is_v1 = true;
-#endif
-static bool s_war_insert_syncpoints;
-
-
-
-const struct hwctx_reginfo ctxsave_regs_3d_global[] = {
- HWCTX_REGINFO(0, 0xe00, 4, DIRECT),
- HWCTX_REGINFO(0, 0xe05, 30, DIRECT),
- HWCTX_REGINFO(0, 0xe25, 2, DIRECT),
- HWCTX_REGINFO(0, 0xe28, 2, DIRECT),
- HWCTX_REGINFO(1, 0xe30, 16, DIRECT),
- HWCTX_REGINFO(0, 0x001, 2, DIRECT),
- HWCTX_REGINFO(0, 0x00c, 10, DIRECT),
- HWCTX_REGINFO(0, 0x100, 34, DIRECT),
- HWCTX_REGINFO(0, 0x124, 2, DIRECT),
- HWCTX_REGINFO(0, 0x200, 5, DIRECT),
- HWCTX_REGINFO(0, 0x205, 1024, INDIRECT),
- HWCTX_REGINFO(0, 0x207, 1024, INDIRECT),
- HWCTX_REGINFO(0, 0x209, 1, DIRECT),
- HWCTX_REGINFO(0, 0x300, 64, DIRECT),
- HWCTX_REGINFO(0, 0x343, 25, DIRECT),
- HWCTX_REGINFO(0, 0x363, 2, DIRECT),
- HWCTX_REGINFO(0, 0x400, 16, DIRECT),
- HWCTX_REGINFO(0, 0x411, 1, DIRECT),
- HWCTX_REGINFO(1, 0x412, 1, DIRECT),
- HWCTX_REGINFO(0, 0x500, 4, DIRECT),
- HWCTX_REGINFO(0, 0x520, 32, DIRECT),
- HWCTX_REGINFO(0, 0x540, 64, INDIRECT),
- HWCTX_REGINFO(0, 0x600, 16, INDIRECT_4X),
- HWCTX_REGINFO(0, 0x603, 128, INDIRECT),
- HWCTX_REGINFO(0, 0x608, 4, DIRECT),
- HWCTX_REGINFO(0, 0x60e, 1, DIRECT),
- HWCTX_REGINFO(0, 0x700, 64, INDIRECT),
- HWCTX_REGINFO(0, 0x710, 50, DIRECT),
- HWCTX_REGINFO(1, 0x750, 16, DIRECT),
- HWCTX_REGINFO(0, 0x800, 16, INDIRECT_4X),
- HWCTX_REGINFO(0, 0x803, 512, INDIRECT),
- HWCTX_REGINFO(0, 0x805, 64, INDIRECT),
- HWCTX_REGINFO(0, 0x820, 32, DIRECT),
- HWCTX_REGINFO(0, 0x900, 64, INDIRECT),
- HWCTX_REGINFO(0, 0x902, 2, DIRECT),
- HWCTX_REGINFO(1, 0x90a, 1, DIRECT),
- HWCTX_REGINFO(0, 0xa02, 10, DIRECT),
- HWCTX_REGINFO(1, 0xb04, 1, DIRECT),
- HWCTX_REGINFO(1, 0xb06, 13, DIRECT),
+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(0x001, 2, DIRECT),
+ HWCTX_REGINFO(0x00c, 10, DIRECT),
+ HWCTX_REGINFO(0x100, 34, DIRECT),
+ HWCTX_REGINFO(0x124, 2, 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(0x500, 4, DIRECT),
+ HWCTX_REGINFO(0x520, 32, DIRECT),
+ HWCTX_REGINFO(0x540, 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(0x800, 16, INDIRECT_4X),
+ HWCTX_REGINFO(0x803, 512, INDIRECT),
+ HWCTX_REGINFO(0x805, 64, INDIRECT),
+ HWCTX_REGINFO(0x820, 32, DIRECT),
+ HWCTX_REGINFO(0x900, 64, INDIRECT),
+ HWCTX_REGINFO(0x902, 2, DIRECT),
+ HWCTX_REGINFO(0xa02, 10, DIRECT),
+ HWCTX_REGINFO(0xe04, 1, DIRECT),
+ HWCTX_REGINFO(0xe2a, 1, DIRECT),
};
-const struct hwctx_reginfo ctxsave_regs_3d_perset[] = {
- HWCTX_REGINFO(0, 0xe04, 1, DIRECT),
- HWCTX_REGINFO(0, 0xe2a, 1, DIRECT),
- HWCTX_REGINFO(1, 0x413, 1, DIRECT),
- HWCTX_REGINFO(1, 0x90b, 1, DIRECT),
- HWCTX_REGINFO(1, 0xe41, 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_V0_SIZE 5
+#define SAVE_DIRECT_V0_SIZE 3
+#define SAVE_INDIRECT_V0_SIZE 5
+#define SAVE_END_V0_SIZE 5
+#define SAVE_INCRS 3
+#define SAVE_THRESH_OFFSET 1
+#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;
@@ -101,69 +89,6 @@ struct save_info {
unsigned int restore_incrs;
};
-struct ctx_saver {
- unsigned int version;
- void (*save_begin)(u32 *ptr);
- unsigned int save_begin_size;
- void (*save_direct)(u32 *ptr, u32 start_reg, u32 count);
- unsigned int save_direct_size;
- void (*save_indirect)(u32 *ptr, u32 offset_reg, u32 offset,
- u32 data_reg, u32 count);
- unsigned int save_indirect_size;
- void (*save_end)(u32 *ptr);
- unsigned int save_end_size;
- unsigned short save_incrs;
- unsigned short save_thresh_offset;
- struct nvhost_hwctx *(*ctx3d_alloc)(struct nvhost_channel *ch);
- void (*ctx3d_save_push)(struct nvhost_cdma *cdma,
- struct nvhost_hwctx *ctx);
- void (*ctx3d_save_service)(struct nvhost_hwctx *ctx);
-};
-
-
-/*** restore ***/
-
-static unsigned int restore_size;
-static unsigned int restore_set1_offset;
-static unsigned int restore_incrs;
-
-static void restore_begin(u32 *ptr)
-{
- /* set class to host */
- ptr[0] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
- NV_CLASS_HOST_INCR_SYNCPT_BASE, 1);
- /* increment sync point base */
- ptr[1] = nvhost_class_host_incr_syncpt_base(NVWAITBASE_3D,
- restore_incrs);
- /* set class to 3D */
- ptr[2] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0);
- /* program PSEQ_QUAD_ID */
- ptr[3] = nvhost_opcode_imm(0x545, 0);
-}
-#define RESTORE_BEGIN_SIZE 4
-
-static void restore_direct(u32 *ptr, u32 start_reg, u32 count)
-{
- ptr[0] = nvhost_opcode_incr(start_reg, count);
-}
-#define RESTORE_DIRECT_SIZE 1
-
-static void restore_indirect(u32 *ptr, u32 offset_reg, u32 offset,
- u32 data_reg, u32 count)
-{
- ptr[0] = nvhost_opcode_imm(offset_reg, offset);
- ptr[1] = nvhost_opcode_nonincr(data_reg, count);
-}
-#define RESTORE_INDIRECT_SIZE 2
-
-static void restore_end(u32 *ptr)
-{
- /* syncpt increment to track restore gather. */
- ptr[0] = nvhost_opcode_imm_incr_syncpt(NV_CLASS_HOST_SYNCPT_OP_DONE,
- NVSYNCPT_3D);
-}
-#define RESTORE_END_SIZE 1
-
static u32 *setup_restore_regs_v0(u32 *ptr,
const struct hwctx_reginfo *regs,
unsigned int nr_regs)
@@ -174,18 +99,17 @@ static u32 *setup_restore_regs_v0(u32 *ptr,
u32 offset = regs->offset;
u32 count = regs->count;
u32 indoff = offset + 1;
- if (regs->version > 0)
- continue;
switch (regs->type) {
case HWCTX_REGINFO_DIRECT:
- restore_direct(ptr, offset, count);
+ nvhost_3dctx_restore_direct(ptr, offset, count);
ptr += RESTORE_DIRECT_SIZE;
break;
case HWCTX_REGINFO_INDIRECT_4X:
++indoff;
/* fall through */
case HWCTX_REGINFO_INDIRECT:
- restore_indirect(ptr, offset, 0, indoff, count);
+ nvhost_3dctx_restore_indirect(ptr,
+ offset, 0, indoff, count);
ptr += RESTORE_INDIRECT_SIZE;
break;
}
@@ -196,205 +120,25 @@ static u32 *setup_restore_regs_v0(u32 *ptr,
static void setup_restore_v0(u32 *ptr)
{
- restore_begin(ptr);
+ nvhost_3dctx_restore_begin(ptr);
ptr += RESTORE_BEGIN_SIZE;
ptr = setup_restore_regs_v0(ptr,
ctxsave_regs_3d_global,
ARRAY_SIZE(ctxsave_regs_3d_global));
- ptr = setup_restore_regs_v0(ptr,
- ctxsave_regs_3d_perset,
- ARRAY_SIZE(ctxsave_regs_3d_perset));
-
- restore_end(ptr);
-
- wmb();
-}
-
-
-/*** save ***/
-
-/* the same context save command sequence is used for all contexts. */
-static struct nvmap_handle_ref *save_buf;
-static phys_addr_t save_phys;
-static unsigned int save_size;
-static unsigned int save_incrs;
-static unsigned int save_thresh;
-static unsigned int save_slots;
-
-static void __init setup_save_regs(const struct ctx_saver *saver,
- 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;
- if (regs->version > saver->version)
- continue;
- switch (regs->type) {
- case HWCTX_REGINFO_DIRECT:
- if (ptr) {
- saver->save_direct(ptr, offset, count);
- ptr += saver->save_direct_size;
- }
- save_count += saver->save_direct_size;
- restore_count += RESTORE_DIRECT_SIZE;
- break;
- case HWCTX_REGINFO_INDIRECT_4X:
- ++indoff;
- /* fall through */
- case HWCTX_REGINFO_INDIRECT:
- if (ptr) {
- saver->save_indirect(ptr, offset, 0,
- indoff, count);
- ptr += saver->save_indirect_size;
- }
- save_count += saver->save_indirect_size;
- restore_count += RESTORE_INDIRECT_SIZE;
- break;
- }
- if (ptr) {
- memset(ptr, 0, count * 4);
- ptr += count;
- }
- save_count += count;
- restore_count += count;
- }
-
- info->ptr = ptr;
- info->save_count = save_count;
- info->restore_count = restore_count;
-}
-
-static void __init switch_gpu(struct save_info *info,
- unsigned int save_src_set,
- u32 save_dest_sets,
- u32 restore_dest_sets)
-{
- if (s_war_insert_syncpoints) {
- if (info->ptr) {
- info->ptr[0] = nvhost_opcode_setclass(
- NV_GRAPHICS_3D_CLASS_ID,
- 0, 0);
- info->ptr[1] = nvhost_opcode_nonincr(0x905, 2);
- info->ptr[2] = nvhost_opcode_imm_incr_syncpt(
- NV_CLASS_HOST_SYNCPT_RD_DONE,
- NVSYNCPT_3D);
- info->ptr[3] = nvhost_opcode_imm(0xb00,
- restore_dest_sets);
- info->ptr[4] = nvhost_opcode_imm_incr_syncpt(
- NV_CLASS_HOST_SYNCPT_RD_DONE,
- NVSYNCPT_3D);
- info->ptr[5] = nvhost_opcode_imm(0xb00, save_dest_sets);
- info->ptr[6] = nvhost_opcode_imm(0xb01, save_src_set);
- info->ptr += 7;
- }
- info->save_count += 7;
- info->restore_count += 2;
- info->save_incrs += 1;
- info->restore_incrs += 1;
- } else {
- if (info->ptr) {
- info->ptr[0] = nvhost_opcode_setclass(
- NV_GRAPHICS_3D_CLASS_ID,
- 0x905, 1);
- info->ptr[1] = nvhost_opcode_imm(0xb00,
- restore_dest_sets);
- info->ptr[2] = nvhost_opcode_imm(0xb00, save_dest_sets);
- info->ptr[3] = nvhost_opcode_imm(0xb01, save_src_set);
- info->ptr += 4;
- }
- info->save_count += 4;
- info->restore_count += 1;
- }
-}
-
-static void __init setup_save(const struct ctx_saver *saver, u32 *ptr)
-{
- struct save_info info = {
- ptr,
- saver->save_begin_size,
- RESTORE_BEGIN_SIZE,
- saver->save_incrs,
- 1
- };
- int save_end_size = saver->save_end_size;
- BUG_ON(register_sets > 2);
-
- if (info.ptr) {
- saver->save_begin(info.ptr);
- info.ptr += saver->save_begin_size;
- }
-
- /* read from set 0, write cmds through set 0, restore to sets 0 and 1 */
- if (register_sets == 2)
- switch_gpu(&info, 0, 1, 3);
-
- /* save regs that are common to both sets */
- setup_save_regs(saver, &info,
- ctxsave_regs_3d_global,
- ARRAY_SIZE(ctxsave_regs_3d_global));
-
- /* read from set 0, write cmds through set 0, restore to set 0 */
- if (register_sets == 2)
- switch_gpu(&info, 0, 1, 1);
-
- /* save set 0 specific regs */
- setup_save_regs(saver, &info,
- ctxsave_regs_3d_perset,
- ARRAY_SIZE(ctxsave_regs_3d_perset));
-
- if (register_sets == 2) {
- /* read from set1, write cmds through set1, restore to set1 */
- switch_gpu(&info, 1, 2, 2);
- /* note offset at which set 1 restore starts */
- restore_set1_offset = info.restore_count;
- /* save set 1 specific regs */
- setup_save_regs(saver, &info,
- ctxsave_regs_3d_perset,
- ARRAY_SIZE(ctxsave_regs_3d_perset));
- }
-
- /* read from set 0, write cmds through set 1, restore to sets 0 and 1 */
- if (register_sets == 2)
- switch_gpu(&info, 0, 2, 3);
-
- if (s_war_insert_syncpoints) {
- if (s_is_v1)
- info.save_incrs += register_sets;
- save_end_size++;
- }
-
- if (info.ptr) {
- saver->save_end(info.ptr);
- info.ptr += save_end_size;
- }
+ nvhost_3dctx_restore_end(ptr);
wmb();
-
- save_size = info.save_count + save_end_size;
- restore_size = info.restore_count + RESTORE_END_SIZE;
- save_incrs = info.save_incrs;
- save_thresh = save_incrs - saver->save_thresh_offset;
- restore_incrs = info.restore_incrs;
}
-
/*** v0 saver ***/
static void save_push_v0(struct nvhost_cdma *cdma,
struct nvhost_hwctx *ctx)
{
nvhost_cdma_push_gather(cdma,
- nvmap_ref_to_handle(save_buf),
+ nvmap_ref_to_handle(nvhost_3dctx_save_buf),
nvhost_opcode_gather(save_size),
save_phys);
}
@@ -403,7 +147,7 @@ static void __init save_begin_v0(u32 *ptr)
{
/* 3d: when done, increment syncpt to base+1 */
ptr[0] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0);
- ptr[1] = nvhost_opcode_imm_incr_syncpt(NV_CLASS_HOST_SYNCPT_OP_DONE,
+ ptr[1] = nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_OP_DONE,
NVSYNCPT_3D); /* incr 1 */
/* host: wait for syncpt base+1 */
ptr[2] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
@@ -411,10 +155,9 @@ static void __init save_begin_v0(u32 *ptr)
ptr[3] = nvhost_class_host_wait_syncpt_base(NVSYNCPT_3D,
NVWAITBASE_3D, 1);
/* host: signal context read thread to start reading */
- ptr[4] = nvhost_opcode_imm_incr_syncpt(NV_CLASS_HOST_SYNCPT_IMMEDIATE,
+ ptr[4] = nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_IMMEDIATE,
NVSYNCPT_3D); /* incr 2 */
}
-#define SAVE_BEGIN_V0_SIZE 5
static void __init save_direct_v0(u32 *ptr, u32 start_reg, u32 count)
{
@@ -423,7 +166,6 @@ static void __init save_direct_v0(u32 *ptr, u32 start_reg, u32 count)
start_reg, true);
ptr[2] = nvhost_opcode_nonincr(NV_CLASS_HOST_INDDATA, count);
}
-#define SAVE_DIRECT_V0_SIZE 3
static void __init save_indirect_v0(u32 *ptr, u32 offset_reg, u32 offset,
u32 data_reg, u32 count)
@@ -437,21 +179,20 @@ static void __init save_indirect_v0(u32 *ptr, u32 offset_reg, u32 offset,
data_reg, false);
ptr[4] = nvhost_opcode_nonincr(NV_CLASS_HOST_INDDATA, count);
}
-#define SAVE_INDIRECT_V0_SIZE 5
static void __init save_end_v0(u32 *ptr)
{
/* Wait for context read service to finish (cpu incr 3) */
ptr[0] = nvhost_opcode_nonincr(NV_CLASS_HOST_WAIT_SYNCPT_BASE, 1);
ptr[1] = nvhost_class_host_wait_syncpt_base(NVSYNCPT_3D,
- NVWAITBASE_3D, save_incrs);
+ NVWAITBASE_3D, nvhost_3dctx_save_incrs);
/* Advance syncpoint base */
ptr[2] = nvhost_opcode_nonincr(NV_CLASS_HOST_INCR_SYNCPT_BASE, 1);
- ptr[3] = nvhost_class_host_incr_syncpt_base(NVWAITBASE_3D, save_incrs);
+ ptr[3] = nvhost_class_host_incr_syncpt_base(NVWAITBASE_3D,
+ nvhost_3dctx_save_incrs);
/* set class back to the unit */
ptr[4] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0);
}
-#define SAVE_END_V0_SIZE 5
static u32 *save_regs_v0(u32 *ptr, unsigned int *pending,
void __iomem *chan_regs,
@@ -463,8 +204,6 @@ static u32 *save_regs_v0(u32 *ptr, unsigned int *pending,
for ( ; regs != rend; ++regs) {
u32 count = regs->count;
- if (regs->version > 0)
- continue;
switch (regs->type) {
case HWCTX_REGINFO_DIRECT:
ptr += RESTORE_DIRECT_SIZE;
@@ -482,215 +221,103 @@ static u32 *save_regs_v0(u32 *ptr, unsigned int *pending,
return ptr;
}
+/*** save ***/
-/*** v1 saver ***/
-
-static void save_push_v1(struct nvhost_cdma *cdma,
- struct nvhost_hwctx *ctx)
+static void __init setup_save_regs(struct save_info *info,
+ const struct hwctx_reginfo *regs,
+ unsigned int nr_regs)
{
- /* wait for 3d idle */
- nvhost_cdma_push(cdma,
- nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0),
- nvhost_opcode_imm_incr_syncpt(
- NV_CLASS_HOST_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);
- /* set register set 0 and 1 register read memory output addresses,
- and send their reads to memory */
- if (register_sets == 2) {
- nvhost_cdma_push(cdma,
- nvhost_opcode_imm(0xb00, 2),
- nvhost_opcode_imm(0xe40, 1));
- nvhost_cdma_push(cdma,
- nvhost_opcode_nonincr(0x904, 1),
- ctx->restore_phys + restore_set1_offset * 4);
- if (s_war_insert_syncpoints)
- nvhost_cdma_push(cdma,
- NVHOST_OPCODE_NOOP,
- nvhost_opcode_imm_incr_syncpt(
- NV_CLASS_HOST_SYNCPT_RD_DONE,
- NVSYNCPT_3D));
- }
- 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,
- nvmap_ref_to_handle(save_buf),
- nvhost_opcode_gather(save_size),
- save_phys);
-}
+ 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;
-static void __init save_begin_v1(u32 *ptr)
-{
- ptr[0] = nvhost_opcode_nonincr(0x905, RESTORE_BEGIN_SIZE);
- restore_begin(ptr + 1);
- ptr += RESTORE_BEGIN_SIZE;
-}
-#define SAVE_BEGIN_V1_SIZE (1 + RESTORE_BEGIN_SIZE)
+ 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_v0(ptr, offset, count);
+ ptr += SAVE_DIRECT_V0_SIZE;
+ }
+ save_count += SAVE_DIRECT_V0_SIZE;
+ restore_count += RESTORE_DIRECT_SIZE;
+ break;
+ case HWCTX_REGINFO_INDIRECT_4X:
+ ++indoff;
+ /* fall through */
+ case HWCTX_REGINFO_INDIRECT:
+ if (ptr) {
+ save_indirect_v0(ptr, offset, 0,
+ indoff, count);
+ ptr += SAVE_INDIRECT_V0_SIZE;
+ }
+ save_count += SAVE_INDIRECT_V0_SIZE;
+ restore_count += RESTORE_INDIRECT_SIZE;
+ break;
+ }
+ if (ptr) {
+ memset(ptr, 0, count * 4);
+ ptr += count;
+ }
+ save_count += count;
+ restore_count += count;
+ }
-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);
- 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);
+ info->ptr = ptr;
+ info->save_count = save_count;
+ info->restore_count = restore_count;
}
-#define SAVE_DIRECT_V1_SIZE (4 + RESTORE_DIRECT_SIZE)
-static void __init save_indirect_v1(u32 *ptr, u32 offset_reg, u32 offset,
- u32 data_reg, u32 count)
+static void __init setup_save(u32 *ptr)
{
- ptr[0] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0);
- ptr[1] = nvhost_opcode_nonincr(0x905, RESTORE_INDIRECT_SIZE);
- 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);
-}
-#define SAVE_INDIRECT_V1_SIZE (6 + RESTORE_INDIRECT_SIZE)
+ struct save_info info = {
+ ptr,
+ SAVE_BEGIN_V0_SIZE,
+ RESTORE_BEGIN_SIZE,
+ SAVE_INCRS,
+ 1
+ };
-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);
- restore_end(ptr + 1);
- ptr += RESTORE_END_SIZE;
- /* reset to two register sets if necessary */
- if (s_war_insert_syncpoints) {
- ptr[1] = nvhost_opcode_imm_incr_syncpt(
- NV_CLASS_HOST_SYNCPT_RD_DONE,
- NVSYNCPT_3D);
- ptr += 1;
+ if (info.ptr) {
+ save_begin_v0(info.ptr);
+ info.ptr += SAVE_BEGIN_V0_SIZE;
}
- ptr[1] = nvhost_opcode_imm(0xb00, (1 << register_sets) - 1);
- /* op_done syncpt incr to flush FDC */
- ptr[2] = nvhost_opcode_imm_incr_syncpt(NV_CLASS_HOST_SYNCPT_OP_DONE,
- NVSYNCPT_3D);
- /* host wait for that syncpt incr, and advance the wait base */
- ptr[3] = 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[4] = nvhost_class_host_wait_syncpt_base(NVSYNCPT_3D,
- NVWAITBASE_3D, save_incrs - 1);
- ptr[5] = nvhost_class_host_incr_syncpt_base(NVWAITBASE_3D,
- save_incrs);
- /* set class back to 3d */
- ptr[6] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0);
- /* send reg reads back to host */
- ptr[7] = nvhost_opcode_imm(0xe40, 0);
- /* final syncpt increment to release waiters */
- ptr[8] = nvhost_opcode_imm_incr_syncpt(NV_CLASS_HOST_SYNCPT_IMMEDIATE,
- NVSYNCPT_3D);
-}
-#define SAVE_END_V1_SIZE (9 + RESTORE_END_SIZE)
-/*** ctx3d ***/
+ /* save regs */
+ setup_save_regs(&info,
+ ctxsave_regs_3d_global,
+ ARRAY_SIZE(ctxsave_regs_3d_global));
-static struct nvhost_hwctx *ctx3d_alloc_common(struct nvhost_channel *ch,
- bool map_restore)
-{
- struct nvmap_client *nvmap = ch->dev->nvmap;
- struct nvhost_hwctx *ctx;
-
- ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
- if (!ctx)
- return NULL;
- ctx->restore = nvmap_alloc(nvmap, restore_size * 4, 32,
- map_restore ? NVMAP_HANDLE_WRITE_COMBINE
- : NVMAP_HANDLE_UNCACHEABLE);
- if (IS_ERR_OR_NULL(ctx->restore)) {
- kfree(ctx);
- return NULL;
+ if (info.ptr) {
+ save_end_v0(info.ptr);
+ info.ptr += SAVE_END_V0_SIZE;
}
- if (map_restore) {
- ctx->restore_virt = nvmap_mmap(ctx->restore);
- if (!ctx->restore_virt) {
- nvmap_free(nvmap, ctx->restore);
- kfree(ctx);
- return NULL;
- }
- } else {
- ctx->restore_virt = NULL;
- }
+ wmb();
- kref_init(&ctx->ref);
- ctx->channel = ch;
- ctx->valid = false;
- ctx->save = save_buf;
- ctx->save_incrs = save_incrs;
- ctx->save_thresh = save_thresh;
- ctx->save_slots = save_slots;
- ctx->restore_phys = nvmap_pin(nvmap, ctx->restore);
- ctx->restore_size = restore_size;
- ctx->restore_incrs = restore_incrs;
- return ctx;
+ save_size = info.save_count + SAVE_END_V0_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 - SAVE_THRESH_OFFSET;
+ nvhost_3dctx_restore_incrs = info.restore_incrs;
}
+
+
+/*** ctx3d ***/
+
static struct nvhost_hwctx *ctx3d_alloc_v0(struct nvhost_channel *ch)
{
- struct nvhost_hwctx *ctx = ctx3d_alloc_common(ch, true);
+ struct nvhost_hwctx *ctx = nvhost_3dctx_alloc_common(ch, true);
if (ctx)
setup_restore_v0(ctx->restore_virt);
return ctx;
}
-static struct nvhost_hwctx *ctx3d_alloc_v1(struct nvhost_channel *ch)
-{
- return ctx3d_alloc_common(ch, false);
-}
-
-static void ctx3d_get(struct nvhost_hwctx *ctx)
-{
- kref_get(&ctx->ref);
-}
-
-static void ctx3d_free(struct kref *ref)
-{
- struct nvhost_hwctx *ctx = container_of(ref, struct nvhost_hwctx, ref);
- struct nvmap_client *nvmap = ctx->channel->dev->nvmap;
-
- if (ctx->restore_virt)
- nvmap_munmap(ctx->restore, ctx->restore_virt);
- nvmap_unpin(nvmap, ctx->restore);
- nvmap_free(nvmap, ctx->restore);
- kfree(ctx);
-}
-
-static void ctx3d_put(struct nvhost_hwctx *ctx)
-{
- kref_put(&ctx->ref, ctx3d_free);
-}
-
static void ctx3d_save_service(struct nvhost_hwctx *ctx)
{
u32 *ptr = (u32 *)ctx->restore_virt + RESTORE_BEGIN_SIZE;
@@ -700,10 +327,6 @@ static void ctx3d_save_service(struct nvhost_hwctx *ctx)
ctxsave_regs_3d_global,
ARRAY_SIZE(ctxsave_regs_3d_global));
- ptr = save_regs_v0(ptr, &pending, ctx->channel->aperture,
- ctxsave_regs_3d_perset,
- ARRAY_SIZE(ctxsave_regs_3d_perset));
-
wmb();
nvhost_syncpt_cpu_incr(&ctx->channel->dev->syncpt, NVSYNCPT_3D);
}
@@ -711,43 +334,8 @@ static void ctx3d_save_service(struct nvhost_hwctx *ctx)
/*** savers ***/
-static const struct ctx_saver v0_saver __initconst = {
- .version = 0,
- .save_begin = save_begin_v0,
- .save_begin_size = SAVE_BEGIN_V0_SIZE,
- .save_direct = save_direct_v0,
- .save_direct_size = SAVE_DIRECT_V0_SIZE,
- .save_indirect = save_indirect_v0,
- .save_indirect_size = SAVE_INDIRECT_V0_SIZE,
- .save_end = save_end_v0,
- .save_end_size = SAVE_END_V0_SIZE,
- .save_incrs = 3,
- .save_thresh_offset = 1,
- .ctx3d_alloc = ctx3d_alloc_v0,
- .ctx3d_save_push = save_push_v0,
- .ctx3d_save_service = ctx3d_save_service
-};
-
-static const struct ctx_saver v1_saver __initconst = {
- .version = 1,
- .save_begin = save_begin_v1,
- .save_begin_size = SAVE_BEGIN_V1_SIZE,
- .save_direct = save_direct_v1,
- .save_direct_size = SAVE_DIRECT_V1_SIZE,
- .save_indirect = save_indirect_v1,
- .save_indirect_size = SAVE_INDIRECT_V1_SIZE,
- .save_end = save_end_v1,
- .save_end_size = SAVE_END_V1_SIZE,
- .save_incrs = 3,
- .save_thresh_offset = 0,
- .ctx3d_alloc = ctx3d_alloc_v1,
- .ctx3d_save_push = save_push_v1,
- .ctx3d_save_service = NULL
-};
-
int __init t20_nvhost_3dctx_handler_init(struct nvhost_hwctx_handler *h)
{
- const struct ctx_saver *saver = s_is_v1 ? &v1_saver : &v0_saver;
struct nvhost_channel *ch;
struct nvmap_client *nvmap;
u32 *save_ptr;
@@ -755,53 +343,34 @@ int __init t20_nvhost_3dctx_handler_init(struct nvhost_hwctx_handler *h)
ch = container_of(h, struct nvhost_channel, ctxhandler);
nvmap = ch->dev->nvmap;
- register_sets = tegra_gpu_register_sets();
- BUG_ON(register_sets == 0 || register_sets > 2);
+ setup_save(NULL);
- s_war_insert_syncpoints = tegra_get_chipid() == TEGRA_CHIPID_TEGRA3
- && tegra_get_revision() == TEGRA_REVISION_A01;
-
- setup_save(saver, NULL);
-
- save_buf = nvmap_alloc(nvmap, save_size * 4, 32,
+ nvhost_3dctx_save_buf = nvmap_alloc(nvmap, save_size * 4, 32,
NVMAP_HANDLE_WRITE_COMBINE);
- if (IS_ERR(save_buf)) {
- int err = PTR_ERR(save_buf);
- save_buf = NULL;
+ if (IS_ERR(nvhost_3dctx_save_buf)) {
+ int err = PTR_ERR(nvhost_3dctx_save_buf);
+ nvhost_3dctx_save_buf = NULL;
return err;
}
- save_slots = 1; /* save_push_v0() */
- if (s_is_v1) {
- save_slots = 6; /* save_push_v1() */
- if (register_sets == 2)
- save_slots += 2;
- if (s_war_insert_syncpoints)
- save_slots += 1;
- }
+ nvhost_3dctx_save_slots = 1;
- save_ptr = nvmap_mmap(save_buf);
+ save_ptr = nvmap_mmap(nvhost_3dctx_save_buf);
if (!save_ptr) {
- nvmap_free(nvmap, save_buf);
- save_buf = NULL;
+ nvmap_free(nvmap, nvhost_3dctx_save_buf);
+ nvhost_3dctx_save_buf = NULL;
return -ENOMEM;
}
- save_phys = nvmap_pin(nvmap, save_buf);
+ save_phys = nvmap_pin(nvmap, nvhost_3dctx_save_buf);
- setup_save(saver, save_ptr);
+ setup_save(save_ptr);
- h->alloc = saver->ctx3d_alloc;
- h->save_push = saver->ctx3d_save_push;
- h->save_service = saver->ctx3d_save_service;
- h->get = ctx3d_get;
- h->put = ctx3d_put;
+ h->alloc = ctx3d_alloc_v0;
+ h->save_push = save_push_v0;
+ h->save_service = ctx3d_save_service;
+ h->get = nvhost_3dctx_get;
+ h->put = nvhost_3dctx_put;
return 0;
}
-
-/* TODO: [ahatala 2010-05-27] */
-int __init t20_nvhost_mpectx_handler_init(struct nvhost_hwctx_handler *h)
-{
- return 0;
-}
diff --git a/drivers/video/tegra/host/t20/3dctx_t20.h b/drivers/video/tegra/host/t20/3dctx_t20.h
new file mode 100644
index 000000000000..7961910c99ba
--- /dev/null
+++ b/drivers/video/tegra/host/t20/3dctx_t20.h
@@ -0,0 +1,30 @@
+/*
+ * drivers/video/tegra/host/t20/3dctx_t20.h
+ *
+ * Tegra Graphics Host Syncpoints for T20
+ *
+ * Copyright (c) 2011, 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_T20_H
+#define __NVHOST_3DCTX_T20_H
+
+struct nvhost_hwctx_handler;
+
+int t20_nvhost_3dctx_handler_init(struct nvhost_hwctx_handler *h);
+
+#endif
diff --git a/drivers/video/tegra/host/t20/cdma_t20.c b/drivers/video/tegra/host/t20/cdma_t20.c
index 69c3039357a8..772a7d043e51 100644
--- a/drivers/video/tegra/host/t20/cdma_t20.c
+++ b/drivers/video/tegra/host/t20/cdma_t20.c
@@ -211,7 +211,7 @@ static int t20_cdma_timeout_init(struct nvhost_cdma *cdma,
sb->mapped[i++] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
0, 0);
sb->mapped[i++] = nvhost_opcode_imm_incr_syncpt(
- NV_CLASS_HOST_SYNCPT_IMMEDIATE,
+ NV_SYNCPT_IMMEDIATE,
syncpt_id);
if (syncpt_id == NVSYNCPT_3D) {
/* also contains base increments */
diff --git a/drivers/video/tegra/host/t20/channel_t20.c b/drivers/video/tegra/host/t20/channel_t20.c
index ab01ee1c3745..7a3e4895e3b1 100644
--- a/drivers/video/tegra/host/t20/channel_t20.c
+++ b/drivers/video/tegra/host/t20/channel_t20.c
@@ -28,6 +28,8 @@
#include "hardware_t20.h"
#include "syncpt_t20.h"
#include "../dev.h"
+#include "3dctx_t20.h"
+#include "../t30/3dctx_t30.h"
#define NVHOST_NUMCHANNELS (NV_HOST1X_CHANNELS - 1)
#define NVHOST_CHANNEL_BASE 0
@@ -46,7 +48,7 @@
static void power_3d(struct nvhost_module *mod, enum nvhost_power_action action);
-static const struct nvhost_channeldesc channelmap[] = {
+const struct nvhost_channeldesc nvhost_t20_channelmap[] = {
{
/* channel 0 */
.name = "display",
@@ -113,29 +115,22 @@ static inline void __iomem *t20_channel_aperture(void __iomem *p, int ndx)
return p;
}
-
-int t20_nvhost_3dctx_handler_init(struct nvhost_hwctx_handler *h);
-int t20_nvhost_mpectx_handler_init(struct nvhost_hwctx_handler *h);
-
static inline int t20_nvhost_hwctx_handler_init(
struct nvhost_hwctx_handler *h,
const char *module)
{
if (strcmp(module, "gr3d") == 0)
return t20_nvhost_3dctx_handler_init(h);
- else if (strcmp(module, "mpe") == 0)
- return t20_nvhost_mpectx_handler_init(h);
return 0;
}
-
static int t20_channel_init(struct nvhost_channel *ch,
struct nvhost_master *dev, int index)
{
ch->dev = dev;
ch->chid = index;
- ch->desc = channelmap + index;
+ ch->desc = nvhost_t20_channelmap + index;
mutex_init(&ch->reflock);
mutex_init(&ch->submitlock);
@@ -144,8 +139,6 @@ static int t20_channel_init(struct nvhost_channel *ch,
return t20_nvhost_hwctx_handler_init(&ch->ctxhandler, ch->desc->name);
}
-
-
static int t20_channel_submit(struct nvhost_channel *channel,
struct nvhost_hwctx *hwctx,
struct nvmap_client *user_nvmap,
@@ -440,7 +433,7 @@ static int t20_channel_read_3d_reg(
nvhost_cdma_push(&channel->cdma,
nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0),
nvhost_opcode_imm(NV_CLASS_HOST_INCR_SYNCPT,
- NV_CLASS_HOST_SYNCPT_OP_DONE << 8 | NVSYNCPT_3D));
+ NV_SYNCPT_OP_DONE << 8 | NVSYNCPT_3D));
nvhost_cdma_push(&channel->cdma,
nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
NV_CLASS_HOST_WAIT_SYNCPT_BASE, 1),
@@ -512,7 +505,7 @@ static int t20_channel_read_3d_reg(
int nvhost_init_t20_channel_support(struct nvhost_master *host)
{
- BUILD_BUG_ON(NVHOST_NUMCHANNELS != ARRAY_SIZE(channelmap));
+ BUILD_BUG_ON(NVHOST_NUMCHANNELS != ARRAY_SIZE(nvhost_t20_channelmap));
host->nb_mlocks = NV_HOST1X_SYNC_MLOCK_NUM;
host->nb_channels = NVHOST_NUMCHANNELS;
diff --git a/drivers/video/tegra/host/t20/channel_t20.h b/drivers/video/tegra/host/t20/channel_t20.h
new file mode 100644
index 000000000000..dfd5be29a3e7
--- /dev/null
+++ b/drivers/video/tegra/host/t20/channel_t20.h
@@ -0,0 +1,30 @@
+/*
+ * drivers/video/tegra/host/t20/channel_t20.h
+ *
+ * Tegra Graphics Host Channel
+ *
+ * Copyright (c) 2011, 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_CHANNEL_T20_H
+#define __NVHOST_CHANNEL_T20_H
+
+#include "../nvhost_channel.h"
+
+extern const struct nvhost_channeldesc nvhost_t20_channelmap[];
+
+#endif
diff --git a/drivers/video/tegra/host/t20/hardware_t20.h b/drivers/video/tegra/host/t20/hardware_t20.h
index 4245a44c6bc2..b2245bf76af6 100644
--- a/drivers/video/tegra/host/t20/hardware_t20.h
+++ b/drivers/video/tegra/host/t20/hardware_t20.h
@@ -157,10 +157,10 @@ enum {
};
/* sync point conditionals */
enum {
- NV_CLASS_HOST_SYNCPT_IMMEDIATE = 0x0,
- NV_CLASS_HOST_SYNCPT_OP_DONE = 0x1,
- NV_CLASS_HOST_SYNCPT_RD_DONE = 0x2,
- NV_CLASS_HOST_SYNCPT_REG_WR_SAFE = 0x3,
+ NV_SYNCPT_IMMEDIATE = 0x0,
+ NV_SYNCPT_OP_DONE = 0x1,
+ NV_SYNCPT_RD_DONE = 0x2,
+ NV_SYNCPT_REG_WR_SAFE = 0x3,
};
static inline u32 nvhost_class_host_wait_syncpt(
diff --git a/drivers/video/tegra/host/t20/syncpt_t20.h b/drivers/video/tegra/host/t20/syncpt_t20.h
index 849537acbd69..4dfd75f937fc 100644
--- a/drivers/video/tegra/host/t20/syncpt_t20.h
+++ b/drivers/video/tegra/host/t20/syncpt_t20.h
@@ -72,6 +72,7 @@
#define NVWAITBASE_3D (3)
#define NVWAITBASE_MPE (4)
+struct nvhost_master;
int nvhost_t20_init_syncpt(struct nvhost_master *host);
#endif /* __NVHOST_SYNCPT_T20_H */
diff --git a/drivers/video/tegra/host/t30/3dctx_t30.c b/drivers/video/tegra/host/t30/3dctx_t30.c
new file mode 100644
index 000000000000..264e7c144285
--- /dev/null
+++ b/drivers/video/tegra/host/t30/3dctx_t30.c
@@ -0,0 +1,454 @@
+/*
+ * drivers/video/tegra/host/t30/3dctx_t30.c
+ *
+ * Tegra Graphics Host 3d hardware context
+ *
+ * Copyright (c) 2011 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 "../t20/hardware_t20.h"
+#include "../t20/syncpt_t20.h"
+#include "../3dctx_common.h"
+
+#include <mach/gpufuse.h>
+#include <mach/hardware.h>
+#include <linux/slab.h>
+
+/* 99 > 2, which makes kernel panic if register set is incorrect */
+static int register_sets = 99;
+static bool s_war_insert_syncpoints;
+
+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(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(0x500, 4, DIRECT),
+ HWCTX_REGINFO(0x520, 32, DIRECT),
+ HWCTX_REGINFO(0x540, 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(0x800, 16, INDIRECT_4X),
+ HWCTX_REGINFO(0x803, 512, INDIRECT),
+ HWCTX_REGINFO(0x805, 64, INDIRECT),
+ HWCTX_REGINFO(0x820, 32, DIRECT),
+ HWCTX_REGINFO(0x900, 64, INDIRECT),
+ HWCTX_REGINFO(0x902, 2, DIRECT),
+ HWCTX_REGINFO(0x90a, 1, DIRECT),
+ HWCTX_REGINFO(0xa02, 10, DIRECT),
+ HWCTX_REGINFO(0xb04, 1, DIRECT),
+ HWCTX_REGINFO(0xb06, 13, DIRECT),
+};
+
+static const struct hwctx_reginfo ctxsave_regs_3d_perset[] = {
+ HWCTX_REGINFO(0xe04, 1, DIRECT),
+ HWCTX_REGINFO(0xe2a, 1, DIRECT),
+ HWCTX_REGINFO(0x413, 1, DIRECT),
+ HWCTX_REGINFO(0x90b, 1, DIRECT),
+ HWCTX_REGINFO(0xe41, 1, DIRECT),
+};
+
+static unsigned int restore_set1_offset;
+/* 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 (9 + RESTORE_END_SIZE)
+#define SAVE_INCRS 3
+#define SAVE_THRESH_OFFSET 0
+#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;
+};
+
+/*** v1 saver ***/
+
+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);
+ /* set register set 0 and 1 register read memory output addresses,
+ and send their reads to memory */
+ if (register_sets == 2) {
+ nvhost_cdma_push(cdma,
+ nvhost_opcode_imm(0xb00, 2),
+ nvhost_opcode_imm(0xe40, 1));
+ nvhost_cdma_push(cdma,
+ nvhost_opcode_nonincr(0x904, 1),
+ ctx->restore_phys + restore_set1_offset * 4);
+ if (s_war_insert_syncpoints)
+ nvhost_cdma_push(cdma,
+ NVHOST_OPCODE_NOOP,
+ nvhost_opcode_imm_incr_syncpt(
+ NV_SYNCPT_RD_DONE,
+ NVSYNCPT_3D));
+ }
+ 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(cdma,
+ 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;
+ /* reset to dual reg if necessary */
+ if (s_war_insert_syncpoints) {
+ ptr[1] = nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_RD_DONE,
+ NVSYNCPT_3D);
+ ptr += 1;
+ }
+ ptr[1] = nvhost_opcode_imm(0xb00, (1 << register_sets) - 1);
+ /* op_done syncpt incr to flush FDC */
+ ptr[2] = nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_OP_DONE, NVSYNCPT_3D);
+ /* host wait for that syncpt incr, and advance the wait base */
+ ptr[3] = 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[4] = nvhost_class_host_wait_syncpt_base(NVSYNCPT_3D,
+ NVWAITBASE_3D, nvhost_3dctx_save_incrs - 1);
+ ptr[5] = nvhost_class_host_incr_syncpt_base(NVWAITBASE_3D,
+ nvhost_3dctx_save_incrs);
+ /* set class back to 3d */
+ ptr[6] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0);
+ /* send reg reads back to host */
+ ptr[7] = nvhost_opcode_imm(0xe40, 0);
+ /* final syncpt increment to release waiters */
+ ptr[8] = nvhost_opcode_imm(0, NVSYNCPT_3D);
+}
+
+/*** save ***/
+
+
+
+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) {
+ memset(ptr, 0, count * 4);
+ ptr += count;
+ }
+ save_count += count;
+ restore_count += count;
+ }
+
+ info->ptr = ptr;
+ info->save_count = save_count;
+ info->restore_count = restore_count;
+}
+
+static void __init switch_gpu(struct save_info *info,
+ unsigned int save_src_set,
+ u32 save_dest_sets,
+ u32 restore_dest_sets)
+{
+ if (s_war_insert_syncpoints) {
+ if (info->ptr) {
+ info->ptr[0] = nvhost_opcode_setclass(
+ NV_GRAPHICS_3D_CLASS_ID, 0, 0);
+ info->ptr[1] = nvhost_opcode_nonincr(0x905, 2);
+ info->ptr[2] = nvhost_opcode_imm_incr_syncpt(
+ NV_SYNCPT_RD_DONE, NVSYNCPT_3D);
+ info->ptr[3] = nvhost_opcode_imm(0xb00,
+ restore_dest_sets);
+ info->ptr[4] = nvhost_opcode_imm_incr_syncpt(
+ NV_SYNCPT_RD_DONE, NVSYNCPT_3D);
+ info->ptr[5] = nvhost_opcode_imm(0xb00, save_dest_sets);
+ info->ptr[6] = nvhost_opcode_imm(0xb01, save_src_set);
+ info->ptr += 7;
+ }
+ info->save_count += 7;
+ info->restore_count += 2;
+ info->save_incrs += 1;
+ info->restore_incrs += 1;
+ } else {
+ if (info->ptr) {
+ info->ptr[0] = nvhost_opcode_setclass(
+ NV_GRAPHICS_3D_CLASS_ID, 0x905, 1);
+ info->ptr[1] = nvhost_opcode_imm(0xb00,
+ restore_dest_sets);
+ info->ptr[2] = nvhost_opcode_imm(0xb00,
+ save_dest_sets);
+ info->ptr[3] = nvhost_opcode_imm(0xb01, save_src_set);
+ info->ptr += 4;
+ }
+ info->save_count += 4;
+ info->restore_count += 1;
+ }
+}
+
+static void __init setup_save(u32 *ptr)
+{
+ struct save_info info = {
+ ptr,
+ SAVE_BEGIN_V1_SIZE,
+ RESTORE_BEGIN_SIZE,
+ SAVE_INCRS,
+ 1
+ };
+ int save_end_size = SAVE_END_V1_SIZE;
+
+ BUG_ON(register_sets > 2);
+
+ if (info.ptr) {
+ save_begin_v1(info.ptr);
+ info.ptr += SAVE_BEGIN_V1_SIZE;
+ }
+
+ /* read from set0, write cmds through set0, restore to sets 0 and 1 */
+ if (register_sets == 2)
+ switch_gpu(&info, 0, 1, 3);
+
+ /* save regs that are common to both sets */
+ setup_save_regs(&info,
+ ctxsave_regs_3d_global,
+ ARRAY_SIZE(ctxsave_regs_3d_global));
+
+ /* read from set 0, write cmds through set 0, restore to set 0 */
+ if (register_sets == 2)
+ switch_gpu(&info, 0, 1, 1);
+
+ /* save set 0 specific regs */
+ setup_save_regs(&info,
+ ctxsave_regs_3d_perset,
+ ARRAY_SIZE(ctxsave_regs_3d_perset));
+
+ if (register_sets == 2) {
+ /* read from set1, write cmds through set1, restore to set1 */
+ switch_gpu(&info, 1, 2, 2);
+ /* note offset at which set 1 restore starts */
+ restore_set1_offset = info.restore_count;
+ /* save set 1 specific regs */
+ setup_save_regs(&info,
+ ctxsave_regs_3d_perset,
+ ARRAY_SIZE(ctxsave_regs_3d_perset));
+ }
+
+ /* read from set 0, write cmds through set 1, restore to sets 0 and 1 */
+ if (register_sets == 2)
+ switch_gpu(&info, 0, 2, 3);
+
+ if (s_war_insert_syncpoints) {
+ info.save_incrs += register_sets;
+ save_end_size++;
+ }
+
+ if (info.ptr) {
+ save_end_v1(info.ptr);
+ info.ptr += SAVE_END_V1_SIZE;
+ }
+
+ wmb();
+
+ save_size = info.save_count + save_end_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 - SAVE_THRESH_OFFSET;
+ 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);
+}
+
+/*** savers ***/
+
+int __init t30_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->nvmap;
+
+ register_sets = tegra_gpu_register_sets();
+ BUG_ON(register_sets == 0 || register_sets > 2);
+
+ /* Tegra3 A01 workaround */
+ s_war_insert_syncpoints = tegra_get_revision() == TEGRA_REVISION_A01;
+
+ 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;
+ if (register_sets == 2)
+ nvhost_3dctx_save_slots += 2;
+ if (s_war_insert_syncpoints)
+ nvhost_3dctx_save_slots += 1;
+
+ 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/t30/3dctx_t30.h b/drivers/video/tegra/host/t30/3dctx_t30.h
new file mode 100644
index 000000000000..b42cee154d89
--- /dev/null
+++ b/drivers/video/tegra/host/t30/3dctx_t30.h
@@ -0,0 +1,30 @@
+/*
+ * drivers/video/tegra/host/t30/3dctx_t30.h
+ *
+ * Tegra Graphics Host Context Switching for Tegra3
+ *
+ * Copyright (c) 2011, 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_T30_H
+#define __NVHOST_3DCTX_T30_H
+
+struct nvhost_hwctx_handler;
+
+int t30_nvhost_3dctx_handler_init(struct nvhost_hwctx_handler *h);
+
+#endif
diff --git a/drivers/video/tegra/host/t30/Makefile b/drivers/video/tegra/host/t30/Makefile
index f394706ac134..8f4eb4191da6 100644
--- a/drivers/video/tegra/host/t30/Makefile
+++ b/drivers/video/tegra/host/t30/Makefile
@@ -1,4 +1,6 @@
nvhost-t30-objs = \
- t30.o
+ t30.o \
+ channel_t30.o \
+ 3dctx_t30.o
obj-$(CONFIG_TEGRA_GRHOST) += nvhost-t30.o
diff --git a/drivers/video/tegra/host/t30/channel_t30.c b/drivers/video/tegra/host/t30/channel_t30.c
new file mode 100644
index 000000000000..6ec2f39c5711
--- /dev/null
+++ b/drivers/video/tegra/host/t30/channel_t30.c
@@ -0,0 +1,70 @@
+/*
+ * drivers/video/tegra/host/t30/channel_t30.c
+ *
+ * Tegra Graphics Host Channel
+ *
+ * Copyright (c) 2010-2011, 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 "3dctx_t30.h"
+#include "../dev.h"
+#include "../t20/channel_t20.h"
+#include "../t20/hardware_t20.h"
+#include "../t20/t20.h"
+
+#define NVHOST_CHANNEL_BASE 0
+
+static inline int t30_nvhost_hwctx_handler_init(
+ struct nvhost_hwctx_handler *h,
+ const char *module)
+{
+ if (strcmp(module, "gr3d") == 0)
+ return t30_nvhost_3dctx_handler_init(h);
+
+ return 0;
+}
+
+static inline void __iomem *t30_channel_aperture(void __iomem *p, int ndx)
+{
+ ndx += NVHOST_CHANNEL_BASE;
+ p += NV_HOST1X_CHANNEL0_BASE;
+ p += ndx * NV_HOST1X_CHANNEL_MAP_SIZE_BYTES;
+ return p;
+}
+
+
+static int t30_channel_init(struct nvhost_channel *ch,
+ struct nvhost_master *dev, int index)
+{
+ ch->dev = dev;
+ ch->chid = index;
+ ch->desc = nvhost_t20_channelmap + index;
+ mutex_init(&ch->reflock);
+ mutex_init(&ch->submitlock);
+
+ ch->aperture = t30_channel_aperture(dev->aperture, index);
+
+ return t30_nvhost_hwctx_handler_init(&ch->ctxhandler, ch->desc->name);
+}
+
+int nvhost_init_t30_channel_support(struct nvhost_master *host)
+{
+ int result = nvhost_init_t20_channel_support(host);
+ host->op.channel.init = t30_channel_init;
+
+ return result;
+}
diff --git a/drivers/video/tegra/host/t30/t30.c b/drivers/video/tegra/host/t30/t30.c
index 2b9c3d8fb186..c7a5011cb953 100644
--- a/drivers/video/tegra/host/t30/t30.c
+++ b/drivers/video/tegra/host/t30/t30.c
@@ -21,16 +21,14 @@
*/
#include "../dev.h"
-
-/* t30 uses t20 entry points */
-#include "../t20/t20.h"
+#include "t30.h"
int nvhost_init_t30_support(struct nvhost_master *host)
{
int err;
/* don't worry about cleaning up on failure... "remove" does it. */
- err = nvhost_init_t20_channel_support(host);
+ err = nvhost_init_t30_channel_support(host);
if (err)
return err;
err = nvhost_init_t20_cdma_support(host);
diff --git a/drivers/video/tegra/host/t30/t30.h b/drivers/video/tegra/host/t30/t30.h
new file mode 100644
index 000000000000..3ea69631bf2e
--- /dev/null
+++ b/drivers/video/tegra/host/t30/t30.h
@@ -0,0 +1,29 @@
+/*
+ * drivers/video/tegra/host/t30/t30.h
+ *
+ * Tegra Graphics Chip support for Tegra3
+ *
+ * Copyright (c) 2011, 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_T30_H_
+#define _NVHOST_T30_H_
+
+#include "../t20/t20.h"
+
+int nvhost_init_t30_channel_support(struct nvhost_master *);
+
+#endif /* _NVHOST_T30_H_ */