video: tegra: host: Implement Tegra3 3D reg read
Terje Bergstrom [Mon, 3 Sep 2012 11:51:04 +0000 (14:51 +0300)]
Implement 3D register read using Tegra3 gr3d direct to memory
write.

Bug 1038891

Change-Id: I70481608f7e06280c7c1378ae5e2454fca5342ed
Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com>
Reviewed-on: http://git-master/r/129952
Reviewed-by: Automatic_Commit_Validation_User

drivers/video/tegra/host/gr3d/gr3d.c
drivers/video/tegra/host/gr3d/gr3d_t30.c
drivers/video/tegra/host/gr3d/gr3d_t30.h

index ffedb4d..735810e 100644 (file)
@@ -194,7 +194,7 @@ static const struct gr3d_desc gr3d[] = {
                .deinit = nvhost_scale3d_deinit,
                .prepare_poweroff = nvhost_gr3d_prepare_power_off,
                .alloc_hwctx_handler = nvhost_gr3d_t30_ctxhandler_init,
-               .read_reg = nvhost_gr3d_t20_read_reg,
+               .read_reg = nvhost_gr3d_t30_read_reg,
        },
        [gr3d_03] = {
                .busy = nvhost_scale3d_notify_busy,
index 664708c..3a1ad5a 100644 (file)
@@ -26,6 +26,8 @@
 #include "gr3d.h"
 #include "chip_support.h"
 #include "nvhost_memmgr.h"
+#include "nvhost_job.h"
+#include "nvhost_acm.h"
 
 #include <mach/gpufuse.h>
 #include <mach/hardware.h>
@@ -437,3 +439,240 @@ struct nvhost_hwctx_handler *nvhost_gr3d_t30_ctxhandler_init(
 
        return &p->h;
 }
+
+int nvhost_gr3d_t30_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));
+       /* Select GPU 0 */
+       nvhost_cdma_push(&channel->cdma,
+               nvhost_opcode_imm(AR3D_GSHIM_READ_SELECT, 0),
+               nvhost_opcode_imm(AR3D_GSHIM_WRITE_MASK, 1));
+       /* 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(AR3D_GSHIM_WRITE_MASK,
+                       (1 << 2) - 1));
+       nvhost_cdma_push(&channel->cdma,
+               nvhost_opcode_imm_incr_syncpt(
+                       host1x_uclass_incr_syncpt_cond_op_done_v(),
+                       p->syncpt),
+               NVHOST_OPCODE_NOOP);
+       /* 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;
+}
index 94d5dc0..68870c7 100644 (file)
 
 struct nvhost_hwctx_handler;
 struct nvhost_channel;
+struct nvhost_device;
+struct nvhost_hwctx;
 
 struct nvhost_hwctx_handler *nvhost_gr3d_t30_ctxhandler_init(
                u32 syncpt, u32 waitbase,
                struct nvhost_channel *ch);
 
+int nvhost_gr3d_t30_read_reg(
+       struct nvhost_device *dev,
+       struct nvhost_channel *channel,
+       struct nvhost_hwctx *hwctx,
+       u32 offset,
+       u32 *value);
 #endif