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