media: tegra: avp: Add channel based AVP driver
Gajanan Bhat [Fri, 24 Jun 2011 02:09:21 +0000 (19:09 -0700)]
New AVP driver based on channel model. The AVP
acts as s/w host1x channel and has a syncpoint
allocated to synchronize audio/video operation
submitted by the host. The driver is responsible
for loading the AVP kernel and initializing s/w
channel.

Original-Change-Id: I20b68fc3cbb88b7c95542bae0a1acf5edc52c715
Reviewed-on: http://git-master/r/37420
Reviewed-by: Varun Colbert <vcolbert@nvidia.com>
Tested-by: Varun Colbert <vcolbert@nvidia.com>

Rebase-Id: Rfa4a49bb322192861df6c9cc16ada6ae1040f8be

arch/arm/mach-tegra/tegra3_clocks.c
drivers/media/video/tegra/Kconfig
drivers/media/video/tegra/Makefile
drivers/media/video/tegra/nvavp/Kconfig [new file with mode: 0644]
drivers/media/video/tegra/nvavp/Makefile [new file with mode: 0644]
drivers/media/video/tegra/nvavp/nvavp_dev.c [new file with mode: 0644]
drivers/media/video/tegra/nvavp/nvavp_os.h [new file with mode: 0644]
include/linux/tegra_nvavp.h [new file with mode: 0644]

index 7f63000..b7596b3 100644 (file)
@@ -4023,6 +4023,7 @@ struct clk_duplicate tegra_clk_duplicates[] = {
        CLK_DUPLICATE("pwm", "tegra_pwm.2", NULL),
        CLK_DUPLICATE("pwm", "tegra_pwm.3", NULL),
        CLK_DUPLICATE("cop", "tegra-avp", "cop"),
+       CLK_DUPLICATE("bsev", "tegra-avp", "bsev"),
        CLK_DUPLICATE("vde", "tegra-aes", "vde"),
        CLK_DUPLICATE("cml1", "tegra_sata_cml", NULL),
        CLK_DUPLICATE("cml0", "tegra_pcie", "cml"),
index 33117ec..63a3639 100644 (file)
@@ -1,5 +1,6 @@
 source "drivers/media/video/tegra/avp/Kconfig"
 source "drivers/media/video/tegra/mediaserver/Kconfig"
+source "drivers/media/video/tegra/nvavp/Kconfig"
 
 config TEGRA_CAMERA
         bool "Enable support for tegra camera/isp hardware"
index d97cf30..7268b8f 100644 (file)
@@ -3,6 +3,7 @@
 #
 obj-y                          += avp/
 obj-$(CONFIG_TEGRA_MEDIASERVER)        += mediaserver/
+obj-$(CONFIG_TEGRA_NVAVP)      += nvavp/
 obj-$(CONFIG_TEGRA_CAMERA)     += tegra_camera.o
 obj-$(CONFIG_VIDEO_AR0832)     += ar0832_main.o
 obj-$(CONFIG_VIDEO_OV5650)     += ov5650.o
diff --git a/drivers/media/video/tegra/nvavp/Kconfig b/drivers/media/video/tegra/nvavp/Kconfig
new file mode 100644 (file)
index 0000000..66d7c86
--- /dev/null
@@ -0,0 +1,10 @@
+config TEGRA_NVAVP
+       bool "Enable support for Tegra NVAVP driver"
+       depends on ARCH_TEGRA
+       default n
+       help
+         Enables support for the push-buffer mechanism based driver for the Tegra
+         multimedia framework. Exports the Tegra nvavp interface on device node
+         /dev/tegra_avpchannel.
+
+         If unsure, say N
diff --git a/drivers/media/video/tegra/nvavp/Makefile b/drivers/media/video/tegra/nvavp/Makefile
new file mode 100644 (file)
index 0000000..8b16cb4
--- /dev/null
@@ -0,0 +1,2 @@
+obj-$(CONFIG_TEGRA_NVAVP)              += nvavp_dev.o
+obj-$(CONFIG_TEGRA_AVP_KERNEL_ON_MMU)  += ../avp/headavp.o
diff --git a/drivers/media/video/tegra/nvavp/nvavp_dev.c b/drivers/media/video/tegra/nvavp/nvavp_dev.c
new file mode 100644 (file)
index 0000000..05f413c
--- /dev/null
@@ -0,0 +1,994 @@
+/*
+ * drivers/media/video/tegra/nvavp/nvavp_dev.c
+ *
+ * Copyright (C) 2011 NVIDIA Corp.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/uaccess.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/firmware.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioctl.h>
+#include <linux/irq.h>
+#include <linux/kref.h>
+#include <linux/list.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/rbtree.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/tegra_nvavp.h>
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+
+#include <mach/clk.h>
+#include <mach/io.h>
+#include <mach/iomap.h>
+#include <mach/legacy_irq.h>
+#include <mach/nvmap.h>
+#include <mach/nvhost.h>
+
+#include "../../../../video/tegra/nvmap/nvmap.h"
+#include "../../../../video/tegra/host/t20/syncpt_t20.h"
+#include "../../../../video/tegra/host/dev.h"
+#if defined(CONFIG_TEGRA_AVP_KERNEL_ON_MMU)
+#include "../avp/headavp.h"
+#endif
+#include "nvavp_os.h"
+
+#define TEGRA_NVAVP_NAME                       "tegra-avp"
+
+#define NVAVP_PUSHBUFFER_SIZE                  4096
+
+#define NVAVP_PUSHBUFFER_MIN_UPDATE_SPACE      (sizeof(u32) * 3)
+
+#define TEGRA_NVAVP_RESET_VECTOR_ADDR  \
+               (IO_ADDRESS(TEGRA_EXCEPTION_VECTORS_BASE) + 0x200)
+
+#define FLOW_CTRL_HALT_COP_EVENTS      IO_ADDRESS(TEGRA_FLOW_CTRL_BASE + 0x4)
+#define FLOW_MODE_STOP                 (0x2 << 29)
+#define FLOW_MODE_NONE                 0x0
+
+#define NVAVP_OS_INBOX                 IO_ADDRESS(TEGRA_RES_SEMA_BASE + 0x10)
+#define NVAVP_OS_OUTBOX                        IO_ADDRESS(TEGRA_RES_SEMA_BASE + 0x20)
+
+#define NVAVP_INBOX_VALID              (1 << 29)
+
+struct nvavp_info {
+       struct clk                      *bsev_clk;
+       struct clk                      *vde_clk;
+       struct clk                      *cop_clk;
+
+       int                             mbox_from_avp_pend_irq;
+
+       struct mutex                    open_lock;
+       int                             refcount;
+
+       /* os information */
+       struct nvavp_os_info            os_info;
+
+       /* client for driver allocations, persistent */
+       struct nvmap_client             *nvmap;
+
+       struct mutex                    pushbuffer_lock;
+       struct nvmap_handle_ref         *pushbuf_handle;
+       unsigned long                   pushbuf_phys;
+       u8                              *pushbuf_data;
+       u32                             pushbuf_index;
+       u32                             pushbuf_fence;
+
+       struct nv_e276_control          *os_control;
+
+       struct nvhost_syncpt            *nvhost_syncpt;
+       u32                             syncpt_id;
+       u32                             syncpt_value;
+
+       struct nvhost_device            *nvhost_dev;
+       struct miscdevice               misc_dev;
+};
+
+struct nvavp_clientctx {
+       struct nvmap_client *nvmap;
+       struct nvavp_pushbuffer_submit_hdr submit_hdr;
+       struct nvavp_reloc relocs[NVAVP_MAX_RELOCATION_COUNT];
+       struct nvmap_handle_ref *gather_mem;
+       int num_relocs;
+       struct nvavp_info *nvavp;
+};
+
+static int nvavp_service(struct nvavp_info *nvavp)
+{
+       struct nvavp_os_info *os = &nvavp->os_info;
+       u8 *debug_print;
+       u32 inbox;
+
+       inbox = readl(NVAVP_OS_INBOX);
+       if (!(inbox & NVAVP_INBOX_VALID))
+               inbox = 0x00000000;
+
+       writel(0x00000000, NVAVP_OS_INBOX);
+
+       if (inbox & NVE276_OS_INTERRUPT_DEBUG_STRING) {
+               /* Should only occur with debug AVP OS builds */
+               debug_print = os->data;
+               debug_print += os->debug_offset;
+               dev_info(&nvavp->nvhost_dev->dev, "%s\n", debug_print);
+       }
+       if (inbox & NVE276_OS_INTERRUPT_VDE_SHUTDOWN) {
+               /* TODO: We may want to put some sort of
+                * synchronization in place (resource semaphores ?)
+                * so that AVP can set VDE clocks without
+                * involving RM (as this is likely to occur often)
+                */
+               dev_info(&nvavp->nvhost_dev->dev, "shutting down VDE...\n");
+       }
+       if (inbox & (NVE276_OS_INTERRUPT_SEMAPHORE_AWAKEN |
+                    NVE276_OS_INTERRUPT_EXECUTE_AWAKEN)) {
+               dev_info(&nvavp->nvhost_dev->dev,
+                       "AVP awaken event (0x%x)\n", inbox);
+       }
+       if (inbox & NVE276_OS_INTERRUPT_AVP_FATAL_ERROR) {
+               dev_err(&nvavp->nvhost_dev->dev,
+                       "fatal AVP error (0x%08X)\n", inbox);
+       }
+       if (inbox & NVE276_OS_INTERRUPT_AVP_BREAKPOINT)
+               dev_err(&nvavp->nvhost_dev->dev, "AVP breakpoint hit\n");
+
+       return 0;
+}
+
+static irqreturn_t nvavp_mbox_pending_isr(int irq, void *data)
+{
+       struct nvavp_info *nvavp = data;
+
+       nvavp_service(nvavp);
+
+       return IRQ_HANDLED;
+}
+
+static void nvavp_halt_avp(struct nvavp_info *nvavp)
+{
+       /* ensure the AVP is halted */
+       writel(FLOW_MODE_STOP, FLOW_CTRL_HALT_COP_EVENTS);
+       tegra_periph_reset_assert(nvavp->cop_clk);
+
+       writel(0, NVAVP_OS_OUTBOX);
+       writel(0, NVAVP_OS_INBOX);
+}
+
+static int nvavp_reset_avp(struct nvavp_info *nvavp, unsigned long reset_addr)
+{
+#if defined(CONFIG_TEGRA_AVP_KERNEL_ON_MMU)
+       unsigned long stub_code_phys = virt_to_phys(_tegra_avp_boot_stub);
+       dma_addr_t stub_data_phys;
+
+       _tegra_avp_boot_stub_data.map_phys_addr = avp->kernel_phys;
+       _tegra_avp_boot_stub_data.jump_addr = reset_addr;
+       wmb();
+       stub_data_phys = dma_map_single(NULL, &_tegra_avp_boot_stub_data,
+                                       sizeof(_tegra_avp_boot_stub_data),
+                                       DMA_TO_DEVICE);
+       rmb();
+       reset_addr = (unsigned long)stub_data_phys;
+#endif
+       writel(FLOW_MODE_STOP, FLOW_CTRL_HALT_COP_EVENTS);
+
+       writel(reset_addr, TEGRA_NVAVP_RESET_VECTOR_ADDR);
+
+       tegra_periph_reset_assert(nvavp->cop_clk);
+       udelay(2);
+       tegra_periph_reset_deassert(nvavp->cop_clk);
+
+       writel(FLOW_MODE_NONE, FLOW_CTRL_HALT_COP_EVENTS);
+
+#if defined(CONFIG_TEGRA_AVP_KERNEL_ON_MMU)
+       dma_unmap_single(NULL, stub_data_phys,
+                        sizeof(_tegra_avp_boot_stub_data),
+                        DMA_TO_DEVICE);
+#endif
+       return 0;
+}
+
+static void nvavp_halt_vde(struct nvavp_info *nvavp)
+{
+       tegra_periph_reset_assert(nvavp->bsev_clk);
+       clk_disable(nvavp->bsev_clk);
+       tegra_periph_reset_assert(nvavp->vde_clk);
+       clk_disable(nvavp->vde_clk);
+}
+
+static int nvavp_reset_vde(struct nvavp_info *nvavp)
+{
+       clk_enable(nvavp->bsev_clk);
+       tegra_periph_reset_assert(nvavp->bsev_clk);
+       udelay(2);
+       tegra_periph_reset_deassert(nvavp->bsev_clk);
+
+       clk_enable(nvavp->vde_clk);
+       tegra_periph_reset_assert(nvavp->vde_clk);
+       udelay(2);
+       tegra_periph_reset_deassert(nvavp->vde_clk);
+       return 0;
+}
+
+static int nvavp_pushbuffer_alloc(struct nvavp_info *nvavp)
+{
+       int ret = 0;
+
+       nvavp->pushbuf_handle = nvmap_alloc(nvavp->nvmap, NVAVP_PUSHBUFFER_SIZE,
+                               SZ_1M, NVMAP_HANDLE_UNCACHEABLE);
+       if (IS_ERR(nvavp->pushbuf_handle)) {
+               dev_err(&nvavp->nvhost_dev->dev,
+                       "cannot create pushbuffer handle\n");
+               ret = PTR_ERR(nvavp->pushbuf_handle);
+               goto err_pushbuf_alloc;
+       }
+       nvavp->pushbuf_data = (u8 *)nvmap_mmap(nvavp->pushbuf_handle);
+       if (!nvavp->pushbuf_data) {
+               dev_err(&nvavp->nvhost_dev->dev,
+                       "cannot map pushbuffer handle\n");
+               ret = -ENOMEM;
+               goto err_pushbuf_mmap;
+       }
+       nvavp->pushbuf_phys = nvmap_pin(nvavp->nvmap, nvavp->pushbuf_handle);
+       if (IS_ERR((void *)nvavp->pushbuf_phys)) {
+               dev_err(&nvavp->nvhost_dev->dev,
+                       "cannot pin pushbuffer handle\n");
+               ret = PTR_ERR((void *)nvavp->pushbuf_phys);
+               goto err_pushbuf_pin;
+       }
+
+       memset(nvavp->pushbuf_data, 0, NVAVP_PUSHBUFFER_SIZE);
+
+       return 0;
+
+err_pushbuf_pin:
+       nvmap_munmap(nvavp->pushbuf_handle, nvavp->pushbuf_data);
+err_pushbuf_mmap:
+       nvmap_free(nvavp->nvmap, nvavp->pushbuf_handle);
+err_pushbuf_alloc:
+       return ret;
+}
+
+static void nvavp_pushbuffer_free(struct nvavp_info *nvavp)
+{
+       nvmap_unpin(nvavp->nvmap, nvavp->pushbuf_handle);
+       nvmap_munmap(nvavp->pushbuf_handle, nvavp->pushbuf_data);
+       nvmap_free(nvavp->nvmap, nvavp->pushbuf_handle);
+}
+
+static int nvavp_pushbuffer_init(struct nvavp_info *nvavp)
+{
+       void *ptr;
+       struct nvavp_os_info *os = &nvavp->os_info;
+       struct nv_e276_control *control;
+       u32 temp;
+       int ret;
+
+       ret = nvavp_pushbuffer_alloc(nvavp);
+       if (ret) {
+               dev_err(&nvavp->nvhost_dev->dev,
+                       "unable to alloc pushbuffer\n");
+               return ret;
+       }
+
+       ptr = os->data;
+       ptr += os->control_offset;
+       nvavp->os_control = (struct nv_e276_control *)ptr;
+
+       control = nvavp->os_control;
+
+       /* init get and put pointers */
+       writel(0x0, &control->put);
+       writel(0x0, &control->get);
+       /* enable host clock control and disable iram clock gating */
+       writel(0x1, &control->idle_clk_enable);
+       writel(0x0, &control->iram_clk_gating);
+
+       /* init dma start and end pointers */
+       writel(nvavp->pushbuf_phys, &control->dma_start);
+       writel((nvavp->pushbuf_phys + NVAVP_PUSHBUFFER_SIZE),
+                                       &control->dma_end);
+
+       writel(0x00, &nvavp->pushbuf_index);
+       temp = NVAVP_PUSHBUFFER_SIZE - NVAVP_PUSHBUFFER_MIN_UPDATE_SPACE;
+       writel(temp, &nvavp->pushbuf_fence);
+
+       nvavp->syncpt_id = NVSYNCPT_AVP_0;
+       nvavp->syncpt_value = nvhost_syncpt_read(nvavp->nvhost_syncpt,
+                                                nvavp->syncpt_id);
+
+       return 0;
+}
+
+static void nvavp_pushbuffer_deinit(struct nvavp_info *nvavp)
+{
+       nvavp_pushbuffer_free(nvavp);
+}
+
+static int nvavp_pushbuffer_update(struct nvavp_info *nvavp, u32 phys_addr,
+                       u32 gather_count, struct nvavp_syncpt *syncpt)
+{
+       struct nv_e276_control *control = nvavp->os_control;
+       u32 gather_cmd, sync = 0;
+       u32 wordcount = 0;
+       u32 index, value = -1;
+
+       mutex_lock(&nvavp->pushbuffer_lock);
+
+       /* check for pushbuffer wrapping */
+       if (nvavp->pushbuf_index >= nvavp->pushbuf_fence)
+               nvavp->pushbuf_index = 0;
+
+       gather_cmd = NVE26E_CH_OPCODE_GATHER(0, 0, 0, gather_count);
+
+       if (syncpt) {
+               value = ++nvavp->syncpt_value;
+               /* XXX: NvSchedValueWrappingComparison */
+               sync = NVE26E_CH_OPCODE_IMM(NVE26E_HOST1X_INCR_SYNCPT,
+                       (NVE26E_HOST1X_INCR_SYNCPT_COND_OP_DONE << 8) |
+                       (nvavp->syncpt_id & 0xFF));
+       }
+
+       /* write commands out */
+       index = wordcount + nvavp->pushbuf_index;
+       writel(gather_cmd, (nvavp->pushbuf_data + index));
+       wordcount += sizeof(u32);
+
+       index = wordcount + nvavp->pushbuf_index;
+       writel(phys_addr, (nvavp->pushbuf_data + index));
+       wordcount += sizeof(u32);
+
+       if (syncpt) {
+               index = wordcount + nvavp->pushbuf_index;
+               writel(sync, (nvavp->pushbuf_data + index));
+               wordcount += sizeof(u32);
+       }
+       /* update put pointer */
+       nvavp->pushbuf_index = (nvavp->pushbuf_index + wordcount) &
+                                       (NVAVP_PUSHBUFFER_SIZE - 1);
+       writel(nvavp->pushbuf_index, &control->put);
+       wmb();
+
+       /* wake up avp */
+       writel(0xA0000001, NVAVP_OS_OUTBOX);
+
+       /* Fill out fence struct */
+       if (syncpt) {
+               syncpt->id = nvavp->syncpt_id;
+               syncpt->value = value;
+       }
+
+       mutex_unlock(&nvavp->pushbuffer_lock);
+
+       return 0;
+}
+
+static int nvavp_load_os(struct nvavp_os_info *os, struct device *dev,
+               struct nvmap_client *nvmap, void *fw_data)
+{
+       void *ptr = (void *)fw_data;
+       u32 size;
+
+       if (strncmp((const char *)ptr, "NVAVP-OS", 8)) {
+               dev_info(dev, "os hdr string mismatch\n");
+               return -EINVAL;
+       }
+
+       ptr += 8;
+       os->entry_offset = *((u32 *)ptr);
+       ptr += sizeof(u32);
+       os->control_offset = *((u32 *)ptr);
+       ptr += sizeof(u32);
+       os->debug_offset = *((u32 *)ptr);
+       ptr += sizeof(u32);
+
+       size = *((u32 *)ptr);    ptr += sizeof(u32);
+
+       memcpy(os->data, ptr, size);
+       memset(os->data + size, 0, SZ_1M - size);
+
+       dev_info(dev, "entry=%08x control=%08x debug=%08x size=%d\n",
+               os->entry_offset, os->control_offset, os->debug_offset, size);
+
+       os->reset_addr = os->phys + os->entry_offset;
+
+       dev_info(dev, "AVP os at vaddr=%p paddr=%lx reset_addr=%p\n",
+               os->data, (unsigned long)(os->phys), (void *)os->reset_addr);
+
+       return 0;
+}
+
+static int nvavp_init(struct nvavp_info *nvavp)
+{
+       const struct firmware *nvavp_os_fw;
+       char fw_os_file[32];
+       int ret = 0;
+
+#if defined(CONFIG_TEGRA_AVP_KERNEL_ON_MMU) /* Tegra2 with AVP MMU */
+       /* paddr is any address returned from nvmap_pin */
+       /* vaddr is AVP_KERNEL_VIRT_BASE */
+       dev_info(&nvavp->nvhost_dev->dev,
+               "using AVP MMU to relocate AVP os\n");
+       sprintf(fw_os_file, "nvavp_os.bin");
+       nvavp->os_info.reset_addr = AVP_KERNEL_VIRT_BASE;
+#elif defined(CONFIG_TEGRA_AVP_KERNEL_ON_SMMU) /* Tegra3 with SMMU */
+       /* paddr is any address behind SMMU */
+       /* vaddr is TEGRA_SMMU_BASE */
+       dev_info(&nvavp->nvhost_dev->dev,
+               "using SMMU at %lx to load AVP kernel\n",
+               (unsigned long)nvavp->os_info.phys);
+       BUG_ON(nvavp->os_info.phys != 0xe0000000
+               && nvavp->os_info.phys != 0x00001000);
+       sprintf(fw_os_file, "nvavp_os_%08lx.bin",
+               (unsigned long)nvavp->os_info.phys);
+       nvavp->os_info.reset_addr = nvavp->os_info.phys;
+#else /* nvmem= carveout */
+       /* paddr is found in nvmem= carveout */
+       /* vaddr is same as paddr */
+       /* Find nvmem carveout */
+       if (!pfn_valid(__phys_to_pfn(0x8e000000))) {
+               nvavp->os_info->phys = 0x8e000000;
+       } else if (!pfn_valid(__phys_to_pfn(0x9e000000))) {
+               nvavp->os_info.phys = 0x9e000000;
+       } else if (!pfn_valid(__phys_to_pfn(0xbe000000))) {
+               nvavp->os_info.phys = 0xbe000000;
+       } else {
+               dev_err(&nvavp->nvhost_dev->dev,
+                       "cannot find nvmem= carveout to load AVP os\n");
+               dev_err(&nvavp->nvhost_dev->dev,
+                       "check kernel command line "
+                       "to see if nvmem= is defined\n");
+               BUG();
+       }
+       dev_info(&nvavp->nvhost_dev->dev,
+               "using nvmem= carveout at %lx to load AVP os\n",
+               nvavp->os_info.phys);
+       sprintf(fw_os_file, "nvavp_os_%08lx.bin", nvavp->os_info.phys);
+       nvavp->os_info.reset_addr = nvavp->os_info.phys;
+       nvavp->os_info.data = ioremap(nvavp->os_info.phys, SZ_1M);
+#endif
+
+       ret = request_firmware(&nvavp_os_fw, fw_os_file,
+                               nvavp->misc_dev.this_device);
+       if (ret) {
+               dev_err(&nvavp->nvhost_dev->dev,
+                       "cannot read os firmware '%s'\n", fw_os_file);
+               goto err_req_fw;
+       }
+       dev_info(&nvavp->nvhost_dev->dev,
+               "read firmware from '%s' (%d bytes)\n",
+               fw_os_file, nvavp_os_fw->size);
+
+       ret = nvavp_load_os(&nvavp->os_info, &nvavp->nvhost_dev->dev,
+                               nvavp->nvmap, (void *)nvavp_os_fw->data);
+       if (ret) {
+               dev_err(&nvavp->nvhost_dev->dev,
+                       "unable to load os firmware '%s'\n", fw_os_file);
+               goto err_req_fw;
+       }
+
+       ret = nvavp_pushbuffer_init(nvavp);
+       if (ret) {
+               dev_err(&nvavp->nvhost_dev->dev,
+                       "unable to init pushbuffer\n");
+               goto err_req_fw;
+       }
+
+       tegra_init_legacy_irq_cop();
+
+       nvavp_reset_vde(nvavp);
+       nvavp_reset_avp(nvavp, nvavp->os_info.reset_addr);
+       enable_irq(nvavp->mbox_from_avp_pend_irq);
+
+err_req_fw:
+       release_firmware(nvavp_os_fw);
+       return ret;
+}
+
+static void nvavp_uninit(struct nvavp_info *nvavp)
+{
+       disable_irq(nvavp->mbox_from_avp_pend_irq);
+       nvavp_pushbuffer_deinit(nvavp);
+
+       nvavp_halt_vde(nvavp);
+       nvavp_halt_avp(nvavp);
+}
+
+static int nvavp_set_nvmapfd_ioctl(struct file *filp, unsigned int cmd,
+                                                       unsigned long arg)
+{
+       struct nvavp_clientctx *clientctx = filp->private_data;
+       struct nvavp_set_nvmap_fd_args buf;
+       struct nvmap_client *new_client;
+       int fd;
+
+       if (_IOC_DIR(cmd) & _IOC_WRITE) {
+               if (copy_from_user(&buf, (void __user *)arg, _IOC_SIZE(cmd)))
+                       return -EFAULT;
+       }
+
+       fd = buf.fd;
+       new_client = nvmap_client_get_file(fd);
+       if (IS_ERR(new_client))
+               return PTR_ERR(new_client);
+
+       clientctx->nvmap = new_client;
+       return 0;
+}
+
+static int nvavp_pushbuffer_submit_ioctl(struct file *filp, unsigned int cmd,
+                                                       unsigned long arg)
+{
+       struct nvavp_clientctx *clientctx = filp->private_data;
+       struct nvavp_info *nvavp = clientctx->nvavp;
+       struct nvavp_pushbuffer_submit_hdr hdr;
+       u32 *cmdbuf_data;
+       struct nvmap_handle *cmdbuf_handle = NULL;
+       struct nvmap_handle_ref *cmdbuf_dupe;
+       int ret = 0, i;
+       unsigned long phys_addr;
+       unsigned long virt_addr;
+       struct nvavp_pushbuffer_submit_hdr *user_hdr =
+                       (struct nvavp_pushbuffer_submit_hdr *) arg;
+       struct nvavp_syncpt syncpt;
+
+       syncpt.id = NVSYNCPT_INVALID;
+       syncpt.value = 0;
+
+       if (_IOC_DIR(cmd) & _IOC_WRITE) {
+               if (copy_from_user(&hdr, (void __user *)arg,
+                       sizeof(struct nvavp_pushbuffer_submit_hdr)))
+                       return -EFAULT;
+       }
+
+       if (!hdr.cmdbuf.mem)
+               return 0;
+
+       if (copy_from_user(clientctx->relocs, (void __user *)hdr.relocs,
+                       sizeof(struct nvavp_reloc) * hdr.num_relocs)) {
+               return -EFAULT;
+       }
+
+       cmdbuf_handle = nvmap_get_handle_id(clientctx->nvmap, hdr.cmdbuf.mem);
+       if (cmdbuf_handle == NULL) {
+               dev_err(&nvavp->nvhost_dev->dev,
+                       "invalid cmd buffer handle %08x\n", hdr.cmdbuf.mem);
+               return -EPERM;
+       }
+
+       /* duplicate the new pushbuffer's handle into the nvavp driver's
+        * nvmap context, to ensure that the handle won't be freed as
+        * long as it is in-use by the fb driver */
+       cmdbuf_dupe = nvmap_duplicate_handle_id(nvavp->nvmap, hdr.cmdbuf.mem);
+       nvmap_handle_put(cmdbuf_handle);
+
+       if (IS_ERR(cmdbuf_dupe)) {
+               dev_err(&nvavp->nvhost_dev->dev,
+                       "could not duplicate handle\n");
+               return PTR_ERR(cmdbuf_dupe);
+       }
+
+       phys_addr = nvmap_pin(nvavp->nvmap, cmdbuf_dupe);
+       if (IS_ERR((void *)phys_addr)) {
+               dev_err(&nvavp->nvhost_dev->dev, "could not pin handle\n");
+               nvmap_free(nvavp->nvmap, cmdbuf_dupe);
+               return PTR_ERR((void *)phys_addr);
+       }
+
+       virt_addr = (unsigned long)nvmap_mmap(cmdbuf_dupe);
+       if (!virt_addr) {
+               dev_err(&nvavp->nvhost_dev->dev, "cannot map cmdbuf handle\n");
+               ret = -ENOMEM;
+               goto err_cmdbuf_mmap;
+       }
+
+       cmdbuf_data = (u32 *)(virt_addr + hdr.cmdbuf.offset);
+
+       for (i = 0; i < hdr.num_relocs; i++) {
+               u32 *reloc_addr, target_phys_addr;
+
+               if (clientctx->relocs[i].cmdbuf_mem != hdr.cmdbuf.mem) {
+                       dev_err(&nvavp->nvhost_dev->dev,
+                               "reloc info does not match target bufferID\n");
+                       ret = -EPERM;
+                       goto err_reloc_info;
+               }
+
+       reloc_addr = cmdbuf_data + (clientctx->relocs[i].cmdbuf_offset >> 2);
+               target_phys_addr = nvmap_handle_address(clientctx->nvmap,
+                                           clientctx->relocs[i].target);
+               target_phys_addr += (clientctx->relocs[i].target_offset >> 2);
+               writel(target_phys_addr, reloc_addr);
+       }
+
+       if (hdr.syncpt) {
+               ret = nvavp_pushbuffer_update(nvavp,
+                                            (phys_addr + hdr.cmdbuf.offset),
+                                             hdr.cmdbuf.words, &syncpt);
+
+               if (copy_to_user((void __user *)user_hdr->syncpt, &syncpt,
+                               sizeof(struct nvavp_syncpt))) {
+                       ret = -EFAULT;
+                       goto err_reloc_info;
+               }
+       } else {
+               ret = nvavp_pushbuffer_update(nvavp,
+                                            (phys_addr + hdr.cmdbuf.offset),
+                                             hdr.cmdbuf.words, NULL);
+       }
+
+err_reloc_info:
+       nvmap_munmap(cmdbuf_dupe, (void *)virt_addr);
+err_cmdbuf_mmap:
+       nvmap_unpin(nvavp->nvmap, cmdbuf_dupe);
+       nvmap_free(nvavp->nvmap, cmdbuf_dupe);
+
+       return ret;
+}
+
+static int tegra_nvavp_open(struct inode *inode, struct file *filp)
+{
+       struct miscdevice *miscdev = filp->private_data;
+       struct nvavp_info *nvavp = dev_get_drvdata(miscdev->parent);
+       int ret = 0;
+       struct nvavp_clientctx *clientctx;
+
+       nonseekable_open(inode, filp);
+
+       clientctx = kzalloc(sizeof(*clientctx), GFP_KERNEL);
+       if (!clientctx)
+               return -ENOMEM;
+
+       mutex_lock(&nvavp->open_lock);
+
+       if (!nvavp->refcount)
+               ret = nvavp_init(nvavp);
+
+       if (!ret)
+               nvavp->refcount++;
+
+       clientctx->nvmap = nvavp->nvmap;
+       clientctx->nvavp = nvavp;
+
+       filp->private_data = clientctx;
+
+       mutex_unlock(&nvavp->open_lock);
+
+       return ret;
+}
+
+static int tegra_nvavp_release(struct inode *inode, struct file *filp)
+{
+       struct nvavp_clientctx *clientctx = filp->private_data;
+       struct nvavp_info *nvavp = clientctx->nvavp;
+       int ret = 0;
+
+       filp->private_data = NULL;
+
+       mutex_lock(&nvavp->open_lock);
+
+       if (!nvavp->refcount) {
+               dev_err(&nvavp->nvhost_dev->dev,
+                       "releasing while in invalid state\n");
+               ret = -EINVAL;
+               goto out;
+       }
+       if (nvavp->refcount > 0)
+               nvavp->refcount--;
+       if (!nvavp->refcount)
+               nvavp_uninit(nvavp);
+
+out:
+       mutex_unlock(&nvavp->open_lock);
+       kfree(clientctx);
+       return ret;
+}
+
+static long tegra_nvavp_ioctl(struct file *filp, unsigned int cmd,
+                           unsigned long arg)
+{
+       int ret = 0;
+
+       if (_IOC_TYPE(cmd) != NVAVP_IOCTL_MAGIC ||
+           _IOC_NR(cmd) < NVAVP_IOCTL_MIN_NR ||
+           _IOC_NR(cmd) > NVAVP_IOCTL_MAX_NR)
+               return -EFAULT;
+
+       switch (cmd) {
+       case NVAVP_IOCTL_SET_NVMAP_FD:
+               ret = nvavp_set_nvmapfd_ioctl(filp, cmd, arg);
+               break;
+       case NVAVP_IOCTL_PUSH_BUFFER_SUBMIT:
+               ret = nvavp_pushbuffer_submit_ioctl(filp, cmd, arg);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+       return ret;
+}
+
+static struct nvmap_client *avp_early_nvmap_drv;
+static struct nvmap_handle_ref *avp_early_kernel_handle;
+static void *avp_early_kernel_data;
+static phys_addr_t avp_early_kernel_phys;
+
+void avp_early_init(void)
+{
+       int ret;
+
+       avp_early_nvmap_drv = nvmap_create_client(nvmap_dev, "avp_early");
+       if (IS_ERR_OR_NULL(avp_early_nvmap_drv))
+               pr_crit("%s: nvmap_create_client error\n", __func__);
+
+       avp_early_kernel_handle =
+               nvmap_create_handle(avp_early_nvmap_drv, SZ_1M);
+       if (IS_ERR_OR_NULL(avp_early_kernel_handle))
+               pr_crit("%s: nvmap_create_handle error\n", __func__);
+
+       ret = nvmap_alloc_handle_id(avp_early_nvmap_drv,
+                               nvmap_ref_to_id(avp_early_kernel_handle),
+                               NVMAP_HEAP_IOVMM, PAGE_SIZE,
+                               NVMAP_HANDLE_WRITE_COMBINE);
+       if (ret)
+               pr_crit("%s: nvmap_alloc_handle_id error\n", __func__);
+
+       avp_early_kernel_data = nvmap_mmap(avp_early_kernel_handle);
+       if (!avp_early_kernel_data)
+               pr_crit("%s: nvmap_mmap error\n", __func__);
+
+       avp_early_kernel_phys =
+               nvmap_pin(avp_early_nvmap_drv, avp_early_kernel_handle);
+       if (IS_ERR_OR_NULL((void *)avp_early_kernel_phys))
+               pr_crit("%s: nvmap_pin error\n", __func__);
+
+       pr_info("%s: allocated memory at %x for AVP kernel\n",
+               __func__, avp_early_kernel_phys);
+}
+
+static const struct file_operations tegra_nvavp_fops = {
+       .owner          = THIS_MODULE,
+       .open           = tegra_nvavp_open,
+       .release        = tegra_nvavp_release,
+       .unlocked_ioctl = tegra_nvavp_ioctl,
+};
+
+static int tegra_nvavp_probe(struct nvhost_device *ndev)
+{
+       struct nvavp_info *nvavp;
+       int irq;
+       unsigned int heap_mask;
+       int ret = 0;
+
+       irq = nvhost_get_irq_byname(ndev, "mbox_from_avp_pending");
+       if (irq < 0) {
+               dev_err(&ndev->dev, "invalid nvhost data\n");
+               return -EINVAL;
+       }
+
+
+       nvavp = kzalloc(sizeof(struct nvavp_info), GFP_KERNEL);
+       if (!nvavp) {
+               dev_err(&ndev->dev, "cannot allocate avp_info\n");
+               return -ENOMEM;
+       }
+
+       memset(nvavp, 0, sizeof(*nvavp));
+
+       nvavp->nvhost_syncpt = &ndev->host->syncpt;
+       if (!nvavp->nvhost_syncpt) {
+               dev_err(&ndev->dev, "cannot get syncpt handle\n");
+               ret = -ENOENT;
+               goto err_get_syncpt;
+       }
+
+#if defined(CONFIG_TEGRA_AVP_KERNEL_ON_MMU) /* Tegra2 with AVP MMU */
+       heap_mask = NVMAP_HEAP_CARVEOUT_GENERIC;
+#elif defined(CONFIG_TEGRA_AVP_KERNEL_ON_SMMU) /* Tegra3 with SMMU */
+       heap_mask = NVMAP_HEAP_IOVMM;
+#else /* nvmem= carveout */
+       heap_mask = 0;
+#endif
+       switch (heap_mask) {
+       case NVMAP_HEAP_IOVMM:
+               nvavp->nvmap = avp_early_nvmap_drv;
+               nvavp->os_info.handle = avp_early_kernel_handle;
+               nvavp->os_info.data = avp_early_kernel_data;
+               nvavp->os_info.phys = avp_early_kernel_phys;
+               break;
+       case NVMAP_HEAP_CARVEOUT_GENERIC:
+               nvavp->nvmap = nvmap_create_client(nvmap_dev, "nvavp_drv");
+               if (IS_ERR(nvavp->nvmap)) {
+                       dev_err(&ndev->dev, "cannot create drv nvmap client\n");
+                       ret = PTR_ERR(nvavp->nvmap);
+                       goto err_nvmap_create_drv_client;
+               }
+
+               nvavp->os_info.handle = nvmap_alloc(nvavp->nvmap, SZ_1M, SZ_1M,
+                                               NVMAP_HANDLE_WRITE_COMBINE);
+               if (IS_ERR_OR_NULL(nvavp->os_info.handle)) {
+                       dev_err(&ndev->dev, "cannot create AVP os handle\n");
+                       ret = PTR_ERR(nvavp->os_info.handle);
+                       goto err_nvmap_alloc;
+               }
+
+               nvavp->os_info.data = nvmap_mmap(nvavp->os_info.handle);
+               if (!nvavp->os_info.data) {
+                       dev_err(&ndev->dev, "cannot map AVP os handle\n");
+                       ret = -ENOMEM;
+                       goto err_nvmap_mmap;
+               }
+
+               nvavp->os_info.phys = nvmap_pin(nvavp->nvmap,
+                                       nvavp->os_info.handle);
+               if (IS_ERR_OR_NULL((void *)nvavp->os_info.phys)) {
+                       dev_err(&ndev->dev, "cannot pin AVP os handle\n");
+                       ret = PTR_ERR((void *)nvavp->os_info.phys);
+                       goto err_nvmap_pin;
+               }
+
+               dev_info(&ndev->dev,
+                       "allocated carveout memory at %lx for AVP os\n",
+                       (unsigned long)nvavp->os_info.phys);
+               break;
+       default:
+               dev_err(&ndev->dev, "invalid/non-supported heap for AVP os\n");
+               ret = -EINVAL;
+               goto err_get_syncpt;
+       }
+
+       nvavp->mbox_from_avp_pend_irq = irq;
+       mutex_init(&nvavp->open_lock);
+       mutex_init(&nvavp->pushbuffer_lock);
+
+       /* TODO DO NOT USE NVAVP DEVICE */
+       nvavp->cop_clk = clk_get(&ndev->dev, "cop");
+       if (IS_ERR(nvavp->cop_clk)) {
+               dev_err(&ndev->dev, "cannot get cop clock\n");
+               ret = -ENOENT;
+               goto err_get_cop_clk;
+       }
+
+       nvavp->vde_clk = clk_get(&ndev->dev, "vde");
+       if (IS_ERR(nvavp->vde_clk)) {
+               dev_err(&ndev->dev, "cannot get vde clock\n");
+               ret = -ENOENT;
+               goto err_get_vde_clk;
+       }
+
+       nvavp->bsev_clk = clk_get(&ndev->dev, "bsev");
+       if (IS_ERR(nvavp->bsev_clk)) {
+               dev_err(&ndev->dev, "cannot get bsev clock\n");
+               ret = -ENOENT;
+               goto err_get_bsev_clk;
+       }
+
+       nvavp_halt_avp(nvavp);
+
+       nvavp->misc_dev.minor = MISC_DYNAMIC_MINOR;
+       nvavp->misc_dev.name = "tegra_avpchannel";
+       nvavp->misc_dev.fops = &tegra_nvavp_fops;
+       nvavp->misc_dev.mode = S_IRWXUGO;
+       nvavp->misc_dev.parent = &ndev->dev;
+
+       ret = misc_register(&nvavp->misc_dev);
+       if (ret) {
+               dev_err(&ndev->dev, "unable to register misc device!\n");
+               goto err_misc_reg;
+       }
+
+       ret = request_irq(irq, nvavp_mbox_pending_isr, 0,
+                         TEGRA_NVAVP_NAME, nvavp);
+       if (ret) {
+               dev_err(&ndev->dev, "cannot register irq handler\n");
+               goto err_req_irq_pend;
+       }
+       disable_irq(nvavp->mbox_from_avp_pend_irq);
+
+       nvhost_set_drvdata(ndev, nvavp);
+       nvavp->nvhost_dev = ndev;
+
+       return 0;
+
+err_req_irq_pend:
+       misc_deregister(&nvavp->misc_dev);
+err_misc_reg:
+       clk_put(nvavp->bsev_clk);
+err_get_bsev_clk:
+       clk_put(nvavp->vde_clk);
+err_get_vde_clk:
+       clk_put(nvavp->cop_clk);
+err_get_cop_clk:
+       nvmap_unpin(nvavp->nvmap, nvavp->os_info.handle);
+err_nvmap_pin:
+       nvmap_munmap(nvavp->os_info.handle, nvavp->os_info.data);
+err_nvmap_mmap:
+       nvmap_free(nvavp->nvmap, nvavp->os_info.handle);
+err_nvmap_alloc:
+       nvmap_client_put(nvavp->nvmap);
+err_nvmap_create_drv_client:
+err_get_syncpt:
+       kfree(nvavp);
+       return ret;
+}
+
+static int tegra_nvavp_remove(struct nvhost_device *ndev)
+{
+       struct nvavp_info *nvavp = nvhost_get_drvdata(ndev);
+
+       if (!nvavp)
+               return 0;
+
+       mutex_lock(&nvavp->open_lock);
+       if (nvavp->refcount) {
+               mutex_unlock(&nvavp->open_lock);
+               return -EBUSY;
+       }
+       mutex_unlock(&nvavp->open_lock);
+
+       misc_deregister(&nvavp->misc_dev);
+
+       clk_put(nvavp->vde_clk);
+       clk_put(nvavp->cop_clk);
+
+       nvmap_client_put(nvavp->nvmap);
+
+       kfree(nvavp);
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int tegra_nvavp_suspend(struct nvhost_device *ndev, pm_message_t state)
+{
+       return 0;
+}
+
+static int tegra_nvavp_resume(struct nvhost_device *ndev)
+{
+       return 0;
+}
+#endif
+
+static struct nvhost_driver tegra_nvavp_driver = {
+       .driver = {
+               .name   = TEGRA_NVAVP_NAME,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = tegra_nvavp_probe,
+       .remove         = tegra_nvavp_remove,
+#ifdef CONFIG_PM
+       .suspend        = tegra_nvavp_suspend,
+       .resume         = tegra_nvavp_resume,
+#endif
+};
+
+static int __init tegra_nvavp_init(void)
+{
+       return nvhost_driver_register(&tegra_nvavp_driver);
+}
+
+static void __exit tegra_nvavp_exit(void)
+{
+       nvhost_driver_unregister(&tegra_nvavp_driver);
+}
+
+module_init(tegra_nvavp_init);
+module_exit(tegra_nvavp_exit);
+
+MODULE_AUTHOR("NVIDIA");
+MODULE_DESCRIPTION("Channel based AVP driver for Tegra");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/media/video/tegra/nvavp/nvavp_os.h b/drivers/media/video/tegra/nvavp/nvavp_os.h
new file mode 100644 (file)
index 0000000..a1ededd
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * drivers/media/video/tegra/nvavp/nvavp_os.h
+ *
+ * Copyright (C) 2011 NVIDIA Corp.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef __MEDIA_VIDEO_TEGRA_NVAVP_OS_H
+#define __MEDIA_VIDEO_TEGRA_NVAVP_OS_H
+
+#include <linux/types.h>
+
+#include "../../../../video/tegra/nvmap/nvmap.h"
+
+#define NVE2_AVP                               (0x0000E276)
+
+struct nv_e276_control {
+       u32 reserved00[5];
+       u32 dma_start;
+       u32 reserved01[2];
+       u32 dma_end;
+       u32 reserved02[7];
+       u32 put;
+       u32 reserved03[15];
+       u32 get;
+       u32 reserved04[13];
+       u32 idle_clk_enable;
+       u32 iram_clk_gating;
+       u32 idle;
+       u32 outbox_data;
+       u32 app_intr_enable;
+       u32 app_start_time;
+       u32 app_in_iram;
+       u32 iram_ucode_addr;
+       u32 iram_ucode_size;
+       u32 dbg_state[57];
+       u32 os_method_data[16];
+       u32 app_method_data[128];
+};
+
+#define NVE26E_HOST1X_INCR_SYNCPT              (0x00000000)
+#define NVE26E_HOST1X_INCR_SYNCPT_COND_OP_DONE (0x00000001)
+
+#define NVE26E_CH_OPCODE_IMM(addr, value) \
+       /* op, addr, count */ \
+       ((4UL << 28) | ((addr) << 16) | (value))
+
+#define NVE26E_CH_OPCODE_GATHER(off, ins, type, cnt) \
+       /* op, offset, insert, type, count */ \
+       ((6UL << 28) | ((off) << 16) | ((ins) << 15) | ((type) << 14) | cnt)
+
+
+/* Interrupt codes through inbox/outbox data codes (cpu->avp or avp->cpu) */
+#define NVE276_OS_INTERRUPT_NOP                        (0x00000000) /* wake up avp */
+#define NVE276_OS_INTERRUPT_TIMEOUT            (0x00000001)
+#define NVE276_OS_INTERRUPT_SEMAPHORE_AWAKEN   (0x00000002)
+#define NVE276_OS_INTERRUPT_EXECUTE_AWAKEN     (0x00000004)
+#define NVE276_OS_INTERRUPT_DEBUG_STRING       (0x00000008)
+#define NVE276_OS_INTERRUPT_VDE_SHUTDOWN       (0x00000010)
+#define NVE276_OS_INTERRUPT_AVP_BREAKPOINT     (0x00800000)
+#define NVE276_OS_INTERRUPT_AVP_FATAL_ERROR    (0x01000000)
+
+struct nvavp_os_info {
+       u32                     entry_offset;
+       u32                     control_offset;
+       u32                     debug_offset;
+
+       struct nvmap_handle_ref *handle;
+       void                    *data;
+       phys_addr_t             phys;
+       phys_addr_t             reset_addr;
+};
+
+#endif /* __MEDIA_VIDEO_TEGRA_NVAVP_OS_H */
diff --git a/include/linux/tegra_nvavp.h b/include/linux/tegra_nvavp.h
new file mode 100644 (file)
index 0000000..475a7be
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * include/linux/tegra_nvavp.h
+ *
+ * Copyright (C) 2011 NVIDIA Corp.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef __LINUX_TEGRA_NVAVP_H
+#define __LINUX_TEGRA_NVAVP_H
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+#define NVAVP_MAX_RELOCATION_COUNT 64
+
+struct nvavp_cmdbuf {
+       __u32 mem;
+       __u32 offset;
+       __u32 words;
+};
+
+struct nvavp_reloc {
+       __u32 cmdbuf_mem;
+       __u32 cmdbuf_offset;
+       __u32 target;
+       __u32 target_offset;
+};
+
+struct nvavp_syncpt {
+       __u32 id;
+       __u32 value;
+};
+
+struct nvavp_pushbuffer_submit_hdr {
+       struct nvavp_cmdbuf     cmdbuf;
+       struct nvavp_reloc      *relocs;
+       __u32                   num_relocs;
+       struct nvavp_syncpt     *syncpt;
+};
+
+struct nvavp_set_nvmap_fd_args {
+       __u32 fd;
+};
+
+#define NVAVP_IOCTL_MAGIC              'n'
+
+#define NVAVP_IOCTL_SET_NVMAP_FD       _IOW(NVAVP_IOCTL_MAGIC, 0x60, \
+                                       struct nvavp_set_nvmap_fd_args)
+#define NVAVP_IOCTL_PUSH_BUFFER_SUBMIT _IOWR(NVAVP_IOCTL_MAGIC, 0x63, \
+                                       struct nvavp_pushbuffer_submit_hdr)
+
+#define NVAVP_IOCTL_MIN_NR             _IOC_NR(NVAVP_IOCTL_SET_NVMAP_FD)
+#define NVAVP_IOCTL_MAX_NR             _IOC_NR(NVAVP_IOCTL_PUSH_BUFFER_SUBMIT)
+
+#endif /* __LINUX_TEGRA_NVAVP_H */