diff options
author | Terje Bergstrom <tbergstrom@nvidia.com> | 2011-06-08 13:07:23 +0300 |
---|---|---|
committer | Varun Colbert <vcolbert@nvidia.com> | 2011-08-05 11:12:49 -0700 |
commit | 289cd515cde8d0ff1a98acfaecff34ee14c0389b (patch) | |
tree | 6456e123331564206c6b9ad11676b42076da2ecf /drivers/video/tegra/host/t20/channel_t20.c | |
parent | cd75d6a85c89af612f1e9d2e7655c8aad752fc15 (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.c | 172 |
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; } |