summaryrefslogtreecommitdiff
path: root/drivers/video
diff options
context:
space:
mode:
authorTerje Bergstrom <tbergstrom@nvidia.com>2012-09-03 14:59:39 +0300
committerSimone Willett <swillett@nvidia.com>2012-09-06 15:56:17 -0700
commit094de5dde5fcd8e65116ca1569a58e1d581d484d (patch)
treeec23a2932dc1913ff25cc9afb77e75ed06395a75 /drivers/video
parente0218bd21e9ab395898229b2bb59326116009028 (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.c2
-rw-r--r--drivers/video/tegra/host/gr3d/gr3d_t114.c231
-rw-r--r--drivers/video/tegra/host/gr3d/gr3d_t114.h8
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