diff options
author | Terje Bergstrom <tbergstrom@nvidia.com> | 2011-08-12 11:25:13 +0300 |
---|---|---|
committer | Rohan Somvanshi <rsomvanshi@nvidia.com> | 2011-08-30 04:20:38 -0700 |
commit | ed2d44a1fc1fef35240b264beaec09d50202bd21 (patch) | |
tree | 15e6c041b9a94e79b0ece12f1e135fcd346010cd /drivers | |
parent | 68fbd17c5ab167d79de27392ffa4ca40b71c21b8 (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.c | 136 | ||||
-rw-r--r-- | drivers/video/tegra/host/3dctx_common.h | 52 | ||||
-rw-r--r-- | drivers/video/tegra/host/Makefile | 1 | ||||
-rw-r--r-- | drivers/video/tegra/host/nvhost_hwctx.h | 3 | ||||
-rw-r--r-- | drivers/video/tegra/host/t20/3dctx_t20.c | 735 | ||||
-rw-r--r-- | drivers/video/tegra/host/t20/3dctx_t20.h | 30 | ||||
-rw-r--r-- | drivers/video/tegra/host/t20/cdma_t20.c | 2 | ||||
-rw-r--r-- | drivers/video/tegra/host/t20/channel_t20.c | 19 | ||||
-rw-r--r-- | drivers/video/tegra/host/t20/channel_t20.h | 30 | ||||
-rw-r--r-- | drivers/video/tegra/host/t20/hardware_t20.h | 8 | ||||
-rw-r--r-- | drivers/video/tegra/host/t20/syncpt_t20.h | 1 | ||||
-rw-r--r-- | drivers/video/tegra/host/t30/3dctx_t30.c | 454 | ||||
-rw-r--r-- | drivers/video/tegra/host/t30/3dctx_t30.h | 30 | ||||
-rw-r--r-- | drivers/video/tegra/host/t30/Makefile | 4 | ||||
-rw-r--r-- | drivers/video/tegra/host/t30/channel_t30.c | 70 | ||||
-rw-r--r-- | drivers/video/tegra/host/t30/t30.c | 6 | ||||
-rw-r--r-- | drivers/video/tegra/host/t30/t30.h | 29 |
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_ */ |