summaryrefslogtreecommitdiff
path: root/drivers/video/tegra/host/t20/channel_t20.c
diff options
context:
space:
mode:
authorTerje Bergstrom <tbergstrom@nvidia.com>2011-06-08 13:07:23 +0300
committerVarun Colbert <vcolbert@nvidia.com>2011-08-05 11:12:49 -0700
commit289cd515cde8d0ff1a98acfaecff34ee14c0389b (patch)
tree6456e123331564206c6b9ad11676b42076da2ecf /drivers/video/tegra/host/t20/channel_t20.c
parentcd75d6a85c89af612f1e9d2e7655c8aad752fc15 (diff)
nvhost: Add IOCTL to read 3D registers
Add IOCTL to read values from registers of 3D unit. Bug 716734 Change-Id: I5e85429d67433d6dadb4a853ce32901a9e66ab74 Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com> Reviewed-on: http://git-master/r/38035 Reviewed-by: Scott Williams <scwilliams@nvidia.com> Reviewed-by: Juha Tukkinen <jtukkinen@nvidia.com> Reviewed-by: Daniel Willemsen <dwillemsen@nvidia.com>
Diffstat (limited to 'drivers/video/tegra/host/t20/channel_t20.c')
-rw-r--r--drivers/video/tegra/host/t20/channel_t20.c172
1 files changed, 172 insertions, 0 deletions
diff --git a/drivers/video/tegra/host/t20/channel_t20.c b/drivers/video/tegra/host/t20/channel_t20.c
index 68cffd71f7fd..b6a72e177005 100644
--- a/drivers/video/tegra/host/t20/channel_t20.c
+++ b/drivers/video/tegra/host/t20/channel_t20.c
@@ -40,6 +40,7 @@
#define NVMODMUTEX_DISPLAYB (7)
#define NVMODMUTEX_VI (8)
#define NVMODMUTEX_DSI (9)
+#define NV_FIFO_READ_TIMEOUT 200000
static void power_2d(struct nvhost_module *mod, enum nvhost_power_action action);
static void power_3d(struct nvhost_module *mod, enum nvhost_power_action action);
@@ -352,6 +353,134 @@ static void power_mpe(struct nvhost_module *mod, enum nvhost_power_action action
{
}
+static int t20_channel_read_3d_reg(
+ struct nvhost_channel *channel,
+ struct nvhost_hwctx *hwctx,
+ u32 offset,
+ u32 *value)
+{
+ struct nvhost_hwctx *hwctx_to_save = NULL;
+ bool need_restore = false;
+ u32 syncpt_incrs = 4;
+ unsigned int pending = 0;
+ DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
+ void *ref;
+ u32 syncval;
+ int err;
+
+ /* keep module powered */
+ nvhost_module_busy(&channel->mod);
+
+ /* get submit lock */
+ err = mutex_lock_interruptible(&channel->submitlock);
+ if (err) {
+ nvhost_module_idle(&channel->mod);
+ return err;
+ }
+
+ /* context switch */
+ if (channel->cur_ctx != hwctx) {
+ hwctx_to_save = channel->cur_ctx;
+ if (hwctx_to_save) {
+ syncpt_incrs += hwctx_to_save->save_incrs;
+ hwctx_to_save->valid = true;
+ channel->ctxhandler.get(hwctx_to_save);
+ }
+ channel->cur_ctx = hwctx;
+ if (channel->cur_ctx && channel->cur_ctx->valid) {
+ need_restore = true;
+ syncpt_incrs += channel->cur_ctx->restore_incrs;
+ }
+ }
+
+ syncval = nvhost_syncpt_incr_max(&channel->dev->syncpt,
+ NVSYNCPT_3D, syncpt_incrs);
+
+ /* begin a CDMA submit */
+ nvhost_cdma_begin(&channel->cdma);
+
+ /* push save buffer (pre-gather setup depends on unit) */
+ if (hwctx_to_save)
+ channel->ctxhandler.save_push(&channel->cdma, hwctx_to_save);
+
+ /* gather restore buffer */
+ if (need_restore)
+ nvhost_cdma_push(&channel->cdma,
+ nvhost_opcode_gather(channel->cur_ctx->restore_size),
+ 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(NV_CLASS_HOST_INCR_SYNCPT,
+ NV_CLASS_HOST_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),
+ nvhost_class_host_wait_syncpt_base(NVSYNCPT_3D,
+ NVWAITBASE_3D, 1));
+ /* Tell 3D to send register value to FIFO */
+ nvhost_cdma_push(&channel->cdma,
+ nvhost_opcode_nonincr(NV_CLASS_HOST_INDOFF, 1),
+ nvhost_class_host_indoff_reg_read(NV_HOST_MODULE_GR3D,
+ offset, false));
+ nvhost_cdma_push(&channel->cdma,
+ nvhost_opcode_imm(NV_CLASS_HOST_INDDATA, 0),
+ NVHOST_OPCODE_NOOP);
+ /* Increment syncpt to indicate that FIFO can be read */
+ nvhost_cdma_push(&channel->cdma,
+ nvhost_opcode_imm(NV_CLASS_HOST_INCR_SYNCPT, NVSYNCPT_3D),
+ NVHOST_OPCODE_NOOP);
+ /* Wait for value to be read from FIFO */
+ nvhost_cdma_push(&channel->cdma,
+ nvhost_opcode_nonincr(NV_CLASS_HOST_WAIT_SYNCPT_BASE, 1),
+ nvhost_class_host_wait_syncpt_base(NVSYNCPT_3D,
+ NVWAITBASE_3D, 3));
+ /* Indicate submit complete */
+ nvhost_cdma_push(&channel->cdma,
+ nvhost_opcode_nonincr(NV_CLASS_HOST_INCR_SYNCPT_BASE, 1),
+ nvhost_class_host_incr_syncpt_base(NVWAITBASE_3D, 4));
+ nvhost_cdma_push(&channel->cdma,
+ NVHOST_OPCODE_NOOP,
+ nvhost_opcode_imm(NV_CLASS_HOST_INCR_SYNCPT, NVSYNCPT_3D));
+
+ /* end CDMA submit */
+ nvhost_cdma_end(&channel->cdma, channel->dev->nvmap,
+ NVSYNCPT_3D, syncval, NULL, 0);
+
+ /*
+ * schedule a context save interrupt (to drain the host FIFO
+ * if necessary, and to release the restore buffer)
+ */
+ if (hwctx_to_save)
+ nvhost_intr_add_action(&channel->dev->intr, NVSYNCPT_3D,
+ syncval - syncpt_incrs + hwctx_to_save->save_incrs - 1,
+ NVHOST_INTR_ACTION_CTXSAVE, hwctx_to_save, NULL);
+
+ /* Wait for FIFO to be ready */
+ nvhost_intr_add_action(&channel->dev->intr, NVSYNCPT_3D, syncval - 2,
+ NVHOST_INTR_ACTION_WAKEUP, &wq, &ref);
+ wait_event(wq,
+ nvhost_syncpt_min_cmp(&channel->dev->syncpt,
+ NVSYNCPT_3D, syncval - 2));
+ nvhost_intr_put_ref(&channel->dev->intr, ref);
+
+ /* Read the register value from FIFO */
+ err = nvhost_drain_read_fifo(channel->aperture,
+ value, 1, &pending);
+
+ /* Indicate we've read the value */
+ nvhost_syncpt_cpu_incr(&channel->dev->syncpt, NVSYNCPT_3D);
+
+ /* Schedule a submit complete interrupt */
+ nvhost_intr_add_action(&channel->dev->intr, NVSYNCPT_3D, syncval,
+ NVHOST_INTR_ACTION_SUBMIT_COMPLETE, channel, NULL);
+
+ mutex_unlock(&channel->submitlock);
+
+ return err;
+}
+
int nvhost_init_t20_channel_support(struct nvhost_master *host)
{
@@ -362,6 +491,49 @@ int nvhost_init_t20_channel_support(struct nvhost_master *host)
host->op.channel.init = t20_channel_init;
host->op.channel.submit = t20_channel_submit;
+ host->op.channel.read3dreg = t20_channel_read_3d_reg;
+
+ return 0;
+}
+
+int nvhost_drain_read_fifo(void __iomem *chan_regs,
+ u32 *ptr, unsigned int count, unsigned int *pending)
+{
+ unsigned int entries = *pending;
+ unsigned long timeout = jiffies + NV_FIFO_READ_TIMEOUT;
+ while (count) {
+ unsigned int num;
+
+ while (!entries && time_before(jiffies, timeout)) {
+ /* query host for number of entries in fifo */
+ entries = nvhost_channel_fifostat_outfentries(
+ readl(chan_regs + HOST1X_CHANNEL_FIFOSTAT));
+ if (!entries)
+ cpu_relax();
+ }
+
+ /* timeout -> return error */
+ if (!entries)
+ return -EIO;
+
+ num = min(entries, count);
+ entries -= num;
+ count -= num;
+
+ while (num & ~0x3) {
+ u32 arr[4];
+ arr[0] = readl(chan_regs + HOST1X_CHANNEL_INDDATA);
+ arr[1] = readl(chan_regs + HOST1X_CHANNEL_INDDATA);
+ arr[2] = readl(chan_regs + HOST1X_CHANNEL_INDDATA);
+ arr[3] = readl(chan_regs + HOST1X_CHANNEL_INDDATA);
+ memcpy(ptr, arr, 4*sizeof(u32));
+ ptr += 4;
+ num -= 4;
+ }
+ while (num--)
+ *ptr++ = readl(chan_regs + HOST1X_CHANNEL_INDDATA);
+ }
+ *pending = entries;
return 0;
}