diff options
author | Terje Bergstrom <tbergstrom@nvidia.com> | 2012-09-03 14:59:39 +0300 |
---|---|---|
committer | Simone Willett <swillett@nvidia.com> | 2012-09-06 15:56:17 -0700 |
commit | 094de5dde5fcd8e65116ca1569a58e1d581d484d (patch) | |
tree | ec23a2932dc1913ff25cc9afb77e75ed06395a75 /drivers/video | |
parent | e0218bd21e9ab395898229b2bb59326116009028 (diff) |
video: tegra: host: Implement Tegra11 3D reg read
Implement 3D register read using Tegra11 gr3d direct to memory
write.
Bug 1038891
Change-Id: I5dc3a6cc3ce2363af4b90ba2be291da74e4541d5
Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com>
Reviewed-on: http://git-master/r/129953
Reviewed-by: Automatic_Commit_Validation_User
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/tegra/host/gr3d/gr3d.c | 2 | ||||
-rw-r--r-- | drivers/video/tegra/host/gr3d/gr3d_t114.c | 231 | ||||
-rw-r--r-- | drivers/video/tegra/host/gr3d/gr3d_t114.h | 8 |
3 files changed, 240 insertions, 1 deletions
diff --git a/drivers/video/tegra/host/gr3d/gr3d.c b/drivers/video/tegra/host/gr3d/gr3d.c index 735810e08e56..69b40a3d3e83 100644 --- a/drivers/video/tegra/host/gr3d/gr3d.c +++ b/drivers/video/tegra/host/gr3d/gr3d.c @@ -205,7 +205,7 @@ static const struct gr3d_desc gr3d[] = { .prepare_poweroff = nvhost_gr3d_t114_prepare_power_off, .finalize_poweron = nvhost_gr3d_t114_finalize_power_on, .alloc_hwctx_handler = nvhost_gr3d_t114_ctxhandler_init, - .read_reg = nvhost_gr3d_t20_read_reg, + .read_reg = nvhost_gr3d_t114_read_reg, }, }; diff --git a/drivers/video/tegra/host/gr3d/gr3d_t114.c b/drivers/video/tegra/host/gr3d/gr3d_t114.c index ef4cb39e0ab9..b10f69c996d3 100644 --- a/drivers/video/tegra/host/gr3d/gr3d_t114.c +++ b/drivers/video/tegra/host/gr3d/gr3d_t114.c @@ -28,6 +28,8 @@ #include "chip_support.h" #include "nvhost_memmgr.h" #include "scale3d.h" +#include "nvhost_job.h" +#include "nvhost_acm.h" #include <linux/slab.h> @@ -398,3 +400,232 @@ void nvhost_gr3d_t114_finalize_power_on(struct nvhost_device *dev) * power gated state */ actmon_op().init(nvhost_get_host(dev)); } + +int nvhost_gr3d_t114_read_reg( + struct nvhost_device *dev, + struct nvhost_channel *channel, + struct nvhost_hwctx *hwctx, + u32 offset, + u32 *value) +{ + struct host1x_hwctx *hwctx_to_save = NULL; + struct nvhost_hwctx_handler *h = hwctx->h; + struct host1x_hwctx_handler *p = to_host1x_hwctx_handler(h); + bool need_restore = false; + u32 syncpt_incrs = 3; + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); + void *ref; + void *ctx_waiter = NULL, *read_waiter = NULL, *completed_waiter = NULL; + struct nvhost_job *job; + u32 syncval; + int err; + struct mem_mgr *memmgr = NULL; + struct mem_handle *mem = NULL; + u32 *mem_ptr = NULL; + dma_addr_t mem_dma = 0; + + if (hwctx && hwctx->has_timedout) + return -ETIMEDOUT; + + memmgr = nvhost_get_host(dev)->memmgr; + + mem = mem_op().alloc(memmgr, 4, 32, mem_mgr_flag_uncacheable); + if (IS_ERR_OR_NULL(mem)) + return -ENOMEM; + + mem_ptr = mem_op().mmap(mem); + if (IS_ERR_OR_NULL(mem_ptr)) { + err = -ENOMEM; + goto done; + } + + mem_dma = mem_op().pin(memmgr, mem); + if (IS_ERR_VALUE(mem_dma)) { + err = mem_dma; + goto done; + } + + ctx_waiter = nvhost_intr_alloc_waiter(); + read_waiter = nvhost_intr_alloc_waiter(); + completed_waiter = nvhost_intr_alloc_waiter(); + if (!ctx_waiter || !read_waiter || !completed_waiter) { + err = -ENOMEM; + goto done; + } + + job = nvhost_job_alloc(channel, hwctx, + NULL, + nvhost_get_host(dev)->memmgr, 0, 0); + if (!job) { + err = -ENOMEM; + goto done; + } + + /* keep module powered */ + nvhost_module_busy(dev); + + /* get submit lock */ + err = mutex_lock_interruptible(&channel->submitlock); + if (err) { + nvhost_module_idle(dev); + return err; + } + + /* context switch */ + if (channel->cur_ctx != hwctx) { + hwctx_to_save = channel->cur_ctx ? + to_host1x_hwctx(channel->cur_ctx) : NULL; + if (hwctx_to_save) { + syncpt_incrs += hwctx_to_save->save_incrs; + hwctx_to_save->hwctx.valid = true; + nvhost_job_get_hwctx(job, &hwctx_to_save->hwctx); + } + channel->cur_ctx = hwctx; + if (channel->cur_ctx && channel->cur_ctx->valid) { + need_restore = true; + syncpt_incrs += to_host1x_hwctx(channel->cur_ctx) + ->restore_incrs; + } + } + + syncval = nvhost_syncpt_incr_max(&nvhost_get_host(dev)->syncpt, + p->syncpt, syncpt_incrs); + + job->syncpt_id = p->syncpt; + job->syncpt_incrs = syncpt_incrs; + job->syncpt_end = syncval; + + /* begin a CDMA submit */ + nvhost_cdma_begin(&channel->cdma, job); + + /* push save buffer (pre-gather setup depends on unit) */ + if (hwctx_to_save) + h->save_push(&hwctx_to_save->hwctx, &channel->cdma); + + /* gather restore buffer */ + if (need_restore) + nvhost_cdma_push(&channel->cdma, + nvhost_opcode_gather(to_host1x_hwctx(channel->cur_ctx) + ->restore_size), + to_host1x_hwctx(channel->cur_ctx)->restore_phys); + + /* Switch to 3D - wait for it to complete what it was doing */ + nvhost_cdma_push(&channel->cdma, + nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0), + nvhost_opcode_imm_incr_syncpt( + host1x_uclass_incr_syncpt_cond_op_done_v(), + p->syncpt)); + nvhost_cdma_push(&channel->cdma, + nvhost_opcode_setclass(NV_HOST1X_CLASS_ID, + host1x_uclass_wait_syncpt_base_r(), 1), + nvhost_class_host_wait_syncpt_base(p->syncpt, + p->waitbase, 1)); + /* Invalidate FDC */ + nvhost_cdma_push(&channel->cdma, + nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0), + nvhost_opcode_imm(AR3D_FDC_CONTROL_0, + AR3D_FDC_CONTROL_0_RESET_VAL + | AR3D_FDC_CONTROL_0_INVALIDATE)); + /* Send reads to memory */ + nvhost_cdma_push(&channel->cdma, + nvhost_opcode_imm(AR3D_GLOBAL_MEMORY_OUTPUT_READS, 1), + nvhost_opcode_nonincr(AR3D_DW_MEMORY_OUTPUT_ADDRESS, 1)); + /* Set up indirect writes */ + nvhost_cdma_push(&channel->cdma, + mem_dma, + nvhost_opcode_setclass(NV_HOST1X_CLASS_ID, + host1x_uclass_indoff_r(), + nvhost_mask2( + host1x_uclass_indoff_r(), + host1x_uclass_inddata_r()))); + nvhost_cdma_push(&channel->cdma, + nvhost_class_host_indoff_reg_read(NV_HOST_MODULE_GR3D, + offset, true), + 0); + /* back to 3D - increment syncpt */ + nvhost_cdma_push(&channel->cdma, + nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0), + nvhost_opcode_imm_incr_syncpt( + host1x_uclass_incr_syncpt_cond_op_done_v(), + p->syncpt)); + /* host wait for that syncpt incr, and advance the wait base */ + nvhost_cdma_push(&channel->cdma, + nvhost_opcode_setclass(NV_HOST1X_CLASS_ID, + host1x_uclass_wait_syncpt_base_r(), + nvhost_mask2( + host1x_uclass_wait_syncpt_base_r(), + host1x_uclass_incr_syncpt_base_r())), + nvhost_class_host_wait_syncpt_base(p->syncpt, + p->waitbase, p->save_incrs - 1)); + nvhost_cdma_push(&channel->cdma, + nvhost_class_host_incr_syncpt_base(p->waitbase, + p->save_incrs), + nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0)); + /* send reg reads back to host */ + nvhost_cdma_push(&channel->cdma, + nvhost_opcode_imm(AR3D_GLOBAL_MEMORY_OUTPUT_READS, 0), + nvhost_opcode_imm_incr_syncpt( + host1x_uclass_incr_syncpt_cond_op_done_v(), + p->syncpt)); + + /* end CDMA submit */ + nvhost_cdma_end(&channel->cdma, job); + nvhost_job_put(job); + job = NULL; + + /* + * schedule a context save interrupt (to drain the host FIFO + * if necessary, and to release the restore buffer) + */ + if (hwctx_to_save) { + err = nvhost_intr_add_action( + &nvhost_get_host(dev)->intr, + p->syncpt, + syncval - syncpt_incrs + + hwctx_to_save->save_incrs + - 1, + NVHOST_INTR_ACTION_CTXSAVE, hwctx_to_save, + ctx_waiter, + NULL); + ctx_waiter = NULL; + WARN(err, "Failed to set context save interrupt"); + } + + /* Schedule a submit complete interrupt */ + err = nvhost_intr_add_action(&nvhost_get_host(dev)->intr, + p->syncpt, syncval, + NVHOST_INTR_ACTION_SUBMIT_COMPLETE, channel, + completed_waiter, NULL); + completed_waiter = NULL; + WARN(err, "Failed to set submit complete interrupt"); + + /* Wait for read to be ready */ + err = nvhost_intr_add_action(&nvhost_get_host(dev)->intr, + p->syncpt, syncval, + NVHOST_INTR_ACTION_WAKEUP, &wq, + read_waiter, + &ref); + read_waiter = NULL; + WARN(err, "Failed to set wakeup interrupt"); + wait_event(wq, + nvhost_syncpt_is_expired(&nvhost_get_host(dev)->syncpt, + p->syncpt, syncval - 2)); + nvhost_intr_put_ref(&nvhost_get_host(dev)->intr, p->syncpt, + ref); + + mutex_unlock(&channel->submitlock); + + *value = *mem_ptr; + +done: + kfree(ctx_waiter); + kfree(read_waiter); + kfree(completed_waiter); + if (mem_ptr) + mem_op().munmap(mem, mem_ptr); + if (mem_dma) + mem_op().unpin(memmgr, mem); + if (mem) + mem_op().put(memmgr, mem); + return err; +} diff --git a/drivers/video/tegra/host/gr3d/gr3d_t114.h b/drivers/video/tegra/host/gr3d/gr3d_t114.h index ed66cb19f27e..b325c4736d1f 100644 --- a/drivers/video/tegra/host/gr3d/gr3d_t114.h +++ b/drivers/video/tegra/host/gr3d/gr3d_t114.h @@ -26,6 +26,7 @@ struct nvhost_hwctx_handler; struct nvhost_device; struct nvhost_channel; +struct nvhost_hwctx; struct nvhost_hwctx_handler *nvhost_gr3d_t114_ctxhandler_init( u32 syncpt, u32 base, @@ -36,4 +37,11 @@ void nvhost_gr3d_t114_deinit(struct nvhost_device *dev); int nvhost_gr3d_t114_prepare_power_off(struct nvhost_device *dev); void nvhost_gr3d_t114_finalize_power_on(struct nvhost_device *dev); +int nvhost_gr3d_t114_read_reg( + struct nvhost_device *dev, + struct nvhost_channel *channel, + struct nvhost_hwctx *hwctx, + u32 offset, + u32 *value); + #endif |