summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/media/video/tegra/nvavp/Kconfig11
-rw-r--r--drivers/media/video/tegra/nvavp/nvavp_dev.c509
2 files changed, 381 insertions, 139 deletions
diff --git a/drivers/media/video/tegra/nvavp/Kconfig b/drivers/media/video/tegra/nvavp/Kconfig
index 2d3af3f79fb3..294253a0de49 100644
--- a/drivers/media/video/tegra/nvavp/Kconfig
+++ b/drivers/media/video/tegra/nvavp/Kconfig
@@ -8,3 +8,14 @@ config TEGRA_NVAVP
/dev/tegra_avpchannel.
If unsure, say N
+
+config TEGRA_NVAVP_AUDIO
+ bool "Enable Audio Channel support for Tegra NVAVP driver"
+ depends on TEGRA_NVAVP
+ default n
+ help
+ Enables support for the push-buffer mechanism based driver for the Tegra
+ audio multimedia framework. Exports the Tegra nvavp interface on device node
+ /dev/tegra_audio_avpchannel.
+
+ If unsure, say N
diff --git a/drivers/media/video/tegra/nvavp/nvavp_dev.c b/drivers/media/video/tegra/nvavp/nvavp_dev.c
index 4bea3cb2ab59..e2bad8150d3a 100644
--- a/drivers/media/video/tegra/nvavp/nvavp_dev.c
+++ b/drivers/media/video/tegra/nvavp/nvavp_dev.c
@@ -72,6 +72,34 @@
/* AVP behavior params */
#define NVAVP_OS_IDLE_TIMEOUT 100 /* milli-seconds */
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+/* Two control channels: Audio and Video channels */
+#define NVAVP_NUM_CHANNELS 2
+
+#define NVAVP_AUDIO_CHANNEL 1
+
+#define IS_AUDIO_CHANNEL_ID(channel_id) (channel_id == NVAVP_AUDIO_CHANNEL ? 1: 0)
+#else
+#define NVAVP_NUM_CHANNELS 1
+#endif
+
+/* Channel ID 0 represents the Video channel control area */
+#define NVAVP_VIDEO_CHANNEL 0
+/* Channel ID 1 represents the Audio channel control area */
+
+#define IS_VIDEO_CHANNEL_ID(channel_id) (channel_id == NVAVP_VIDEO_CHANNEL ? 1: 0)
+
+
+struct nvavp_channel {
+ 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 nvavp_info {
u32 clk_enabled;
struct clk *bsev_clk;
@@ -88,8 +116,10 @@ struct nvavp_info {
struct mutex open_lock;
int refcount;
- int initialized;
-
+ int video_initialized;
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ int audio_initialized;
+#endif
struct work_struct clock_disable_work;
/* os information */
@@ -101,22 +131,18 @@ struct nvavp_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 nvavp_channel channel_info[NVAVP_NUM_CHANNELS];
struct nvhost_syncpt *nvhost_syncpt;
u32 syncpt_id;
u32 syncpt_value;
struct nvhost_device *nvhost_dev;
- struct miscdevice misc_dev;
- atomic_t clock_stay_on_refcount;
+ struct miscdevice video_misc_dev;
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ struct miscdevice audio_misc_dev;
+#endif
+ atomic_t clock_stay_on_refcount;
};
struct nvavp_clientctx {
@@ -127,8 +153,77 @@ struct nvavp_clientctx {
int num_relocs;
struct nvavp_info *nvavp;
int clock_stay_on;
+ int channel_id;
};
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+static int nvavp_get_audio_init_status(struct nvavp_info *nvavp)
+{
+ return nvavp->audio_initialized;
+}
+
+static void nvavp_set_audio_init_status(struct nvavp_info *nvavp, int status)
+{
+ nvavp->audio_initialized = status;
+}
+#endif
+
+static void nvavp_set_video_init_status(struct nvavp_info *nvavp, int status)
+{
+ nvavp->video_initialized = status;
+}
+
+static int nvavp_get_video_init_status(struct nvavp_info *nvavp)
+{
+ return nvavp->video_initialized;
+}
+
+static struct nvavp_channel *nvavp_get_channel_info(struct nvavp_info *nvavp, int channel_id)
+{
+ return &nvavp->channel_info[channel_id];
+}
+
+static void nvavp_set_channel_control_area(struct nvavp_info *nvavp, int channel_id)
+{
+ struct nv_e276_control *control;
+ struct nvavp_os_info *os = &nvavp->os_info;
+ u32 temp;
+ void *ptr;
+ struct nvavp_channel *channel_info;
+
+ ptr = os->data + os->control_offset + (sizeof(struct nv_e276_control) * channel_id);
+
+ channel_info = nvavp_get_channel_info(nvavp, channel_id);
+ channel_info->os_control = (struct nv_e276_control *)ptr;
+
+ control = channel_info->os_control;
+
+ /* init get and put pointers */
+ writel(0x0, &control->put);
+ writel(0x0, &control->get);
+
+ pr_debug("nvavp_set_channel_control_area for channel_id (%d):\
+ control->put (0x%x) control->get (0x%x)\n",
+ channel_id, &control->put, &control->get);
+
+ /* enable avp VDE clock control and disable iram clock gating */
+ writel(0x0, &control->idle_clk_enable);
+ writel(0x0, &control->iram_clk_gating);
+
+ /* enable avp idle timeout interrupt */
+ writel(0x1, &control->idle_notify_enable);
+ writel(NVAVP_OS_IDLE_TIMEOUT, &control->idle_notify_delay);
+
+ /* init dma start and end pointers */
+ writel(channel_info->pushbuf_phys, &control->dma_start);
+ writel((channel_info->pushbuf_phys + NVAVP_PUSHBUFFER_SIZE),
+ &control->dma_end);
+
+ writel(0x00, &channel_info->pushbuf_index);
+ temp = NVAVP_PUSHBUFFER_SIZE - NVAVP_PUSHBUFFER_MIN_UPDATE_SPACE;
+ writel(temp, &channel_info->pushbuf_fence);
+}
+
static struct clk *nvavp_clk_get(struct nvavp_info *nvavp, int id)
{
if (!nvavp)
@@ -171,7 +266,8 @@ static void nvavp_clk_ctrl(struct nvavp_info *nvavp, u32 clk_en)
static u32 nvavp_check_idle(struct nvavp_info *nvavp)
{
- struct nv_e276_control *control = nvavp->os_control;
+ struct nvavp_channel *channel_info = nvavp_get_channel_info(nvavp, NVAVP_VIDEO_CHANNEL);
+ struct nv_e276_control *control = channel_info->os_control;
return ((control->put == control->get)
&& (!atomic_read(&nvavp->clock_stay_on_refcount))) ? 1 : 0;
}
@@ -179,13 +275,15 @@ static u32 nvavp_check_idle(struct nvavp_info *nvavp)
static void clock_disable_handler(struct work_struct *work)
{
struct nvavp_info *nvavp;
+ struct nvavp_channel *channel_info;
nvavp = container_of(work, struct nvavp_info,
clock_disable_work);
- mutex_lock(&nvavp->pushbuffer_lock);
+ channel_info = nvavp_get_channel_info(nvavp, NVAVP_VIDEO_CHANNEL);
+ mutex_lock(&channel_info->pushbuffer_lock);
nvavp_clk_ctrl(nvavp, !nvavp_check_idle(nvavp));
- mutex_unlock(&nvavp->pushbuffer_lock);
+ mutex_unlock(&channel_info->pushbuffer_lock);
}
static int nvavp_service(struct nvavp_info *nvavp)
@@ -203,6 +301,10 @@ static int nvavp_service(struct nvavp_info *nvavp)
if (inbox & NVE276_OS_INTERRUPT_VIDEO_IDLE)
schedule_work(&nvavp->clock_disable_work);
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ if (inbox & NVE276_OS_INTERRUPT_AUDIO_IDLE)
+ pr_debug("nvavp_service NVE276_OS_INTERRUPT_AUDIO_IDLE\n");
+#endif
if (inbox & NVE276_OS_INTERRUPT_DEBUG_STRING) {
/* Should only occur with debug AVP OS builds */
debug_print = os->data;
@@ -325,99 +427,91 @@ static int nvavp_reset_vde(struct nvavp_info *nvavp)
return 0;
}
-static int nvavp_pushbuffer_alloc(struct nvavp_info *nvavp)
+static int nvavp_pushbuffer_alloc(struct nvavp_info *nvavp, int channel_id)
{
int ret = 0;
- nvavp->pushbuf_handle = nvmap_alloc(nvavp->nvmap, NVAVP_PUSHBUFFER_SIZE,
- SZ_1M, NVMAP_HANDLE_UNCACHEABLE, 0);
- if (IS_ERR(nvavp->pushbuf_handle)) {
+ struct nvavp_channel *channel_info = nvavp_get_channel_info(
+ nvavp, channel_id);
+
+ channel_info->pushbuf_handle = nvmap_alloc(nvavp->nvmap,
+ NVAVP_PUSHBUFFER_SIZE,
+ SZ_1M, NVMAP_HANDLE_UNCACHEABLE,
+ 0);
+ if (IS_ERR(channel_info->pushbuf_handle)) {
dev_err(&nvavp->nvhost_dev->dev,
"cannot create pushbuffer handle\n");
- ret = PTR_ERR(nvavp->pushbuf_handle);
+ ret = PTR_ERR(channel_info->pushbuf_handle);
goto err_pushbuf_alloc;
}
- nvavp->pushbuf_data = (u8 *)nvmap_mmap(nvavp->pushbuf_handle);
- if (!nvavp->pushbuf_data) {
+ channel_info->pushbuf_data = (u8 *)nvmap_mmap(
+ channel_info->pushbuf_handle);
+
+ if (!channel_info->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)) {
+ channel_info->pushbuf_phys = nvmap_pin(nvavp->nvmap,
+ channel_info->pushbuf_handle);
+ if (IS_ERR((void *)channel_info->pushbuf_phys)) {
dev_err(&nvavp->nvhost_dev->dev,
"cannot pin pushbuffer handle\n");
- ret = PTR_ERR((void *)nvavp->pushbuf_phys);
+ ret = PTR_ERR((void *)channel_info->pushbuf_phys);
goto err_pushbuf_pin;
}
- memset(nvavp->pushbuf_data, 0, NVAVP_PUSHBUFFER_SIZE);
+ memset(channel_info->pushbuf_data, 0, NVAVP_PUSHBUFFER_SIZE);
return 0;
err_pushbuf_pin:
- nvmap_munmap(nvavp->pushbuf_handle, nvavp->pushbuf_data);
+ nvmap_munmap(channel_info->pushbuf_handle, channel_info->pushbuf_data);
err_pushbuf_mmap:
- nvmap_free(nvavp->nvmap, nvavp->pushbuf_handle);
+ nvmap_free(nvavp->nvmap, channel_info->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);
+ int channel_id;
+
+ for (channel_id = 0; channel_id < NVAVP_NUM_CHANNELS; channel_id++) {
+ if (nvavp->channel_info[channel_id].pushbuf_data) {
+ nvmap_unpin(nvavp->nvmap,
+ nvavp->channel_info[channel_id].pushbuf_handle);
+ nvmap_munmap(
+ nvavp->channel_info[channel_id].pushbuf_handle,
+ nvavp->channel_info[channel_id].pushbuf_data);
+ nvmap_free(nvavp->nvmap,
+ nvavp->channel_info[channel_id].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;
+ int ret, channel_id;
- control = nvavp->os_control;
- memset(control, 0, sizeof(struct nvavp_os_info));
-
- /* init get and put pointers */
- writel(0x0, &control->put);
- writel(0x0, &control->get);
-
- /* enable avp VDE clock control and disable iram clock gating */
- writel(0x0, &control->idle_clk_enable);
- writel(0x0, &control->iram_clk_gating);
-
- /* enable avp idle timeout interrupt */
- writel(0x1, &control->idle_notify_enable);
- writel(NVAVP_OS_IDLE_TIMEOUT, &control->idle_notify_delay);
-
- /* 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);
+ for (channel_id = 0; channel_id < NVAVP_NUM_CHANNELS; channel_id++) {
+ ret = nvavp_pushbuffer_alloc(nvavp, channel_id);
+ if (ret) {
+ dev_err(&nvavp->nvhost_dev->dev,
+ "unable to alloc pushbuffer\n");
+ return ret;
+ }
+ nvavp_set_channel_control_area(nvavp, channel_id);
+ if (IS_VIDEO_CHANNEL_ID(channel_id)) {
+ nvavp->syncpt_id = NVSYNCPT_AVP_0;
+ nvavp->syncpt_value = nvhost_syncpt_read(
+ nvavp->nvhost_syncpt,
+ nvavp->syncpt_id);
+ }
+ }
return 0;
}
@@ -428,37 +522,47 @@ static void nvavp_pushbuffer_deinit(struct nvavp_info *nvavp)
static int nvavp_pushbuffer_update(struct nvavp_info *nvavp, u32 phys_addr,
u32 gather_count, struct nvavp_syncpt *syncpt,
- u32 ext_ucode_flag)
+ u32 ext_ucode_flag, int channel_id)
{
- struct nv_e276_control *control = nvavp->os_control;
+ struct nvavp_channel *channel_info;
+ struct nv_e276_control *control;
u32 gather_cmd, setucode_cmd, sync = 0;
u32 wordcount = 0;
u32 index, value = -1;
- mutex_lock(&nvavp->pushbuffer_lock);
+ channel_info = nvavp_get_channel_info(nvavp, channel_id);
+
+ control = channel_info->os_control;
+ pr_debug("nvavp_pushbuffer_update for channel_id (%d):\
+ control->put (0x%x) control->get (0x%x)\n",
+ channel_id, &control->put, &control->get);
+
+ mutex_lock(&channel_info->pushbuffer_lock);
/* check for pushbuffer wrapping */
- if (nvavp->pushbuf_index >= nvavp->pushbuf_fence)
- nvavp->pushbuf_index = 0;
+ if (channel_info->pushbuf_index >= channel_info->pushbuf_fence)
+ channel_info->pushbuf_index = 0;
if (!ext_ucode_flag) {
setucode_cmd =
NVE26E_CH_OPCODE_INCR(NVE276_SET_MICROCODE_A, 3);
- index = wordcount + nvavp->pushbuf_index;
- writel(setucode_cmd, (nvavp->pushbuf_data + index));
+ index = wordcount + channel_info->pushbuf_index;
+ writel(setucode_cmd, (channel_info->pushbuf_data + index));
wordcount += sizeof(u32);
- index = wordcount + nvavp->pushbuf_index;
- writel(0, (nvavp->pushbuf_data + index));
+ index = wordcount + channel_info->pushbuf_index;
+ writel(0, (channel_info->pushbuf_data + index));
wordcount += sizeof(u32);
- index = wordcount + nvavp->pushbuf_index;
- writel(nvavp->ucode_info.phys, (nvavp->pushbuf_data + index));
+ index = wordcount + channel_info->pushbuf_index;
+ writel(nvavp->ucode_info.phys,
+ (channel_info->pushbuf_data + index));
wordcount += sizeof(u32);
- index = wordcount + nvavp->pushbuf_index;
- writel(nvavp->ucode_info.size, (nvavp->pushbuf_data + index));
+ index = wordcount + channel_info->pushbuf_index;
+ writel(nvavp->ucode_info.size,
+ (channel_info->pushbuf_data + index));
wordcount += sizeof(u32);
}
@@ -473,39 +577,52 @@ static int nvavp_pushbuffer_update(struct nvavp_info *nvavp, u32 phys_addr,
}
/* write commands out */
- index = wordcount + nvavp->pushbuf_index;
- writel(gather_cmd, (nvavp->pushbuf_data + index));
+ index = wordcount + channel_info->pushbuf_index;
+ writel(gather_cmd, (channel_info->pushbuf_data + index));
wordcount += sizeof(u32);
- index = wordcount + nvavp->pushbuf_index;
- writel(phys_addr, (nvavp->pushbuf_data + index));
+ index = wordcount + channel_info->pushbuf_index;
+ writel(phys_addr, (channel_info->pushbuf_data + index));
wordcount += sizeof(u32);
if (syncpt) {
- index = wordcount + nvavp->pushbuf_index;
- writel(sync, (nvavp->pushbuf_data + index));
+ index = wordcount + channel_info->pushbuf_index;
+ writel(sync, (channel_info->pushbuf_data + index));
wordcount += sizeof(u32);
}
/* enable clocks to VDE/BSEV */
- nvavp_clk_ctrl(nvavp, 1);
+ if (IS_VIDEO_CHANNEL_ID(channel_id))
+ nvavp_clk_ctrl(nvavp, 1);
/* update put pointer */
- nvavp->pushbuf_index = (nvavp->pushbuf_index + wordcount) &
+ channel_info->pushbuf_index = (channel_info->pushbuf_index + wordcount)&
(NVAVP_PUSHBUFFER_SIZE - 1);
- writel(nvavp->pushbuf_index, &control->put);
+
+ writel(channel_info->pushbuf_index, &control->put);
wmb();
/* wake up avp */
- writel(0xA0000001, NVAVP_OS_OUTBOX);
+ if (IS_VIDEO_CHANNEL_ID(channel_id)) {
+ pr_debug("Wake up Video Channel\n");
+ writel(0xA0000001, NVAVP_OS_OUTBOX);
+ }
+ else {
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ if (IS_AUDIO_CHANNEL_ID(channel_id)) {
+ pr_debug("Wake up Audio Channel\n");
+ writel(0xA0000002, NVAVP_OS_OUTBOX);
+ }
+#endif
+ }
/* Fill out fence struct */
if (syncpt) {
syncpt->id = nvavp->syncpt_id;
syncpt->value = value;
}
- mutex_unlock(&nvavp->pushbuffer_lock);
+ mutex_unlock(&channel_info->pushbuffer_lock);
return 0;
}
@@ -530,14 +647,14 @@ static int nvavp_load_ucode(struct nvavp_info *nvavp)
sprintf(fw_ucode_file, "nvavp_vid_ucode.bin");
ret = request_firmware(&nvavp_ucode_fw, fw_ucode_file,
- nvavp->misc_dev.this_device);
+ nvavp->video_misc_dev.this_device);
if (ret) {
/* Try alternative version */
sprintf(fw_ucode_file, "nvavp_vid_ucode_alt.bin");
ret = request_firmware(&nvavp_ucode_fw,
fw_ucode_file,
- nvavp->misc_dev.this_device);
+ nvavp->video_misc_dev.this_device);
if (ret) {
dev_err(&nvavp->nvhost_dev->dev,
@@ -635,7 +752,7 @@ static int nvavp_load_os(struct nvavp_info *nvavp, char *fw_os_file)
if (!os_info->os_bin) {
ret = request_firmware(&nvavp_os_fw, fw_os_file,
- nvavp->misc_dev.this_device);
+ nvavp->video_misc_dev.this_device);
if (ret) {
dev_err(&nvavp->nvhost_dev->dev,
"cannot read os firmware '%s'\n", fw_os_file);
@@ -700,14 +817,28 @@ err_req_fw:
return ret;
}
-static int nvavp_init(struct nvavp_info *nvavp)
+
+static int nvavp_os_init(struct nvavp_info *nvavp)
{
char fw_os_file[32];
int ret = 0;
+ int video_initialized, audio_initialized = 0;
+
+ video_initialized = nvavp_get_video_init_status(nvavp);
- if (nvavp->initialized)
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ audio_initialized = nvavp_get_audio_init_status(nvavp);
+#endif
+ pr_debug("video_initialized(%d) audio_initialized(%d)\n",
+ video_initialized, audio_initialized);
+
+ /* Video and Audio both are initialized */
+ if (video_initialized || audio_initialized)
return ret;
+ /* Video or Audio both are uninitialized */
+ pr_debug("video_initialized == audio_initialized (%d)\n",
+ nvavp->video_initialized);
#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 */
@@ -751,7 +882,6 @@ static int nvavp_init(struct nvavp_info *nvavp)
nvavp->os_info.reset_addr = nvavp->os_info.phys;
nvavp->os_info.data = ioremap(nvavp->os_info.phys, SZ_1M);
#endif
-
ret = nvavp_load_os(nvavp, fw_os_file);
if (ret) {
dev_err(&nvavp->nvhost_dev->dev,
@@ -765,21 +895,45 @@ static int nvavp_init(struct nvavp_info *nvavp)
"unable to init pushbuffer\n");
goto err_exit;
}
+ tegra_init_legacy_irq_cop();
+ enable_irq(nvavp->mbox_from_avp_pend_irq);
+err_exit:
+ return ret;
+}
+
+static int nvavp_init(struct nvavp_info *nvavp, int channel_id)
+{
+ int ret = 0;
- ret = nvavp_load_ucode(nvavp);
+ ret = nvavp_os_init(nvavp);
if (ret) {
dev_err(&nvavp->nvhost_dev->dev,
- "unable to load ucode\n");
- goto err_exit;
+ "unable to load os firmware and allocate buffers\n");
}
- tegra_init_legacy_irq_cop();
+ if (IS_VIDEO_CHANNEL_ID(channel_id) &&
+ (!nvavp_get_video_init_status(nvavp)) ) {
+ pr_debug("nvavp_init : channel_ID (%d)\n", channel_id);
+ ret = nvavp_load_ucode(nvavp);
+ if (ret) {
+ dev_err(&nvavp->nvhost_dev->dev,
+ "unable to load ucode\n");
+ goto err_exit;
+ }
- nvavp_reset_vde(nvavp);
- nvavp_reset_avp(nvavp, nvavp->os_info.reset_addr);
- enable_irq(nvavp->mbox_from_avp_pend_irq);
+ nvavp_reset_vde(nvavp);
+ nvavp_reset_avp(nvavp, nvavp->os_info.reset_addr);
- nvavp->initialized = 1;
+ nvavp_set_video_init_status(nvavp, 1);
+ }
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ if (IS_AUDIO_CHANNEL_ID(channel_id) &&
+ (!nvavp_get_audio_init_status(nvavp))) {
+ pr_debug("nvavp_init : channel_ID (%d)\n", channel_id);
+ nvavp_reset_avp(nvavp, nvavp->os_info.reset_addr);
+ nvavp_set_audio_init_status(nvavp, 1);
+ }
+#endif
err_exit:
return ret;
@@ -787,22 +941,48 @@ err_exit:
static void nvavp_uninit(struct nvavp_info *nvavp)
{
- if (!nvavp->initialized)
+ int video_initialized, audio_initialized = 0;
+
+ video_initialized = nvavp_get_video_init_status(nvavp);
+
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ audio_initialized = nvavp_get_audio_init_status(nvavp);
+#endif
+
+ pr_debug("nvavp_uninit video_initialized(%d) audio_initialized(%d)\n",
+ video_initialized, audio_initialized);
+
+ /* Video and Audio both are uninitialized */
+ if (!video_initialized && !audio_initialized)
return;
- disable_irq(nvavp->mbox_from_avp_pend_irq);
+ if (video_initialized) {
+ pr_debug("nvavp_uninit nvavp->video_initialized\n");
+ cancel_work_sync(&nvavp->clock_disable_work);
- cancel_work_sync(&nvavp->clock_disable_work);
+ nvavp_halt_vde(nvavp);
- nvavp_pushbuffer_deinit(nvavp);
+ clk_disable(nvavp->sclk);
+ clk_disable(nvavp->emc_clk);
- nvavp_halt_vde(nvavp);
- nvavp_halt_avp(nvavp);
+ nvavp_set_video_init_status(nvavp, 0);
+ video_initialized = 0;
+ }
- clk_disable(nvavp->sclk);
- clk_disable(nvavp->emc_clk);
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ if (audio_initialized) {
+ nvavp_set_audio_init_status(nvavp, 0);
+ audio_initialized = 0;
+ }
+#endif
- nvavp->initialized = 0;
+ /* Video and Audio both becomes uninitialized */
+ if (video_initialized == audio_initialized) {
+ pr_debug("nvavp_uninit both channels unitialized\n");
+ disable_irq(nvavp->mbox_from_avp_pend_irq);
+ nvavp_pushbuffer_deinit(nvavp);
+ nvavp_halt_avp(nvavp);
+ }
}
static int nvavp_set_clock_ioctl(struct file *filp, unsigned int cmd,
@@ -993,7 +1173,8 @@ static int nvavp_pushbuffer_submit_ioctl(struct file *filp, unsigned int cmd,
ret = nvavp_pushbuffer_update(nvavp,
(phys_addr + hdr.cmdbuf.offset),
hdr.cmdbuf.words, &syncpt,
- (hdr.flags & NVAVP_UCODE_EXT));
+ (hdr.flags & NVAVP_UCODE_EXT),
+ clientctx->channel_id);
if (copy_to_user((void __user *)user_hdr->syncpt, &syncpt,
sizeof(struct nvavp_syncpt))) {
@@ -1004,7 +1185,8 @@ static int nvavp_pushbuffer_submit_ioctl(struct file *filp, unsigned int cmd,
ret = nvavp_pushbuffer_update(nvavp,
(phys_addr + hdr.cmdbuf.offset),
hdr.cmdbuf.words, NULL,
- (hdr.flags & NVAVP_UCODE_EXT));
+ (hdr.flags & NVAVP_UCODE_EXT),
+ clientctx->channel_id);
}
err_reloc_info:
@@ -1058,7 +1240,7 @@ static int nvavp_force_clock_stay_on_ioctl(struct file *filp, unsigned int cmd,
return 0;
}
-static int tegra_nvavp_open(struct inode *inode, struct file *filp)
+static int tegra_nvavp_open(struct inode *inode, struct file *filp, int channel_id)
{
struct miscdevice *miscdev = filp->private_data;
struct nvavp_info *nvavp = dev_get_drvdata(miscdev->parent);
@@ -1075,8 +1257,11 @@ static int tegra_nvavp_open(struct inode *inode, struct file *filp)
mutex_lock(&nvavp->open_lock);
- if (!nvavp->refcount)
- ret = nvavp_init(nvavp);
+ pr_debug("tegra_nvavp_open channel_id (%d)\n", channel_id);
+
+ clientctx->channel_id = channel_id;
+
+ ret = nvavp_init(nvavp, channel_id);
if (!ret)
nvavp->refcount++;
@@ -1092,6 +1277,20 @@ static int tegra_nvavp_open(struct inode *inode, struct file *filp)
return ret;
}
+static int tegra_nvavp_video_open(struct inode *inode, struct file *filp)
+{
+ pr_debug("tegra_nvavp_video_open NVAVP_VIDEO_CHANNEL\n");
+ return tegra_nvavp_open(inode, filp, NVAVP_VIDEO_CHANNEL);
+}
+
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+static int tegra_nvavp_audio_open(struct inode *inode, struct file *filp)
+{
+ pr_debug("tegra_nvavp_audio_open NVAVP_AUDIO_CHANNEL\n");
+ return tegra_nvavp_open(inode, filp, NVAVP_AUDIO_CHANNEL);
+}
+#endif
+
static int tegra_nvavp_release(struct inode *inode, struct file *filp)
{
struct nvavp_clientctx *clientctx = filp->private_data;
@@ -1164,13 +1363,22 @@ static long tegra_nvavp_ioctl(struct file *filp, unsigned int cmd,
return ret;
}
-static const struct file_operations tegra_nvavp_fops = {
+static const struct file_operations tegra_video_nvavp_fops = {
.owner = THIS_MODULE,
- .open = tegra_nvavp_open,
+ .open = tegra_nvavp_video_open,
.release = tegra_nvavp_release,
.unlocked_ioctl = tegra_nvavp_ioctl,
};
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+static const struct file_operations tegra_audio_nvavp_fops = {
+ .owner = THIS_MODULE,
+ .open = tegra_nvavp_audio_open,
+ .release = tegra_nvavp_release,
+ .unlocked_ioctl = tegra_nvavp_ioctl,
+};
+#endif
+
static int tegra_nvavp_probe(struct nvhost_device *ndev,
struct nvhost_device_id *id_table)
{
@@ -1178,7 +1386,7 @@ static int tegra_nvavp_probe(struct nvhost_device *ndev,
int irq;
unsigned int heap_mask;
u32 iovmm_addr;
- int ret = 0;
+ int ret = 0, channel_id;
irq = nvhost_get_irq_byname(ndev, "mbox_from_nvavp_pending");
if (irq < 0) {
@@ -1289,7 +1497,9 @@ static int tegra_nvavp_probe(struct nvhost_device *ndev,
nvavp->mbox_from_avp_pend_irq = irq;
mutex_init(&nvavp->open_lock);
- mutex_init(&nvavp->pushbuffer_lock);
+
+ for (channel_id = 0; channel_id < NVAVP_NUM_CHANNELS; channel_id++)
+ mutex_init(&nvavp->channel_info[channel_id].pushbuffer_lock);
/* TODO DO NOT USE NVAVP DEVICE */
nvavp->cop_clk = clk_get(&ndev->dev, "cop");
@@ -1332,18 +1542,32 @@ static int tegra_nvavp_probe(struct nvhost_device *ndev,
INIT_WORK(&nvavp->clock_disable_work, clock_disable_handler);
- 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;
+ nvavp->video_misc_dev.minor = MISC_DYNAMIC_MINOR;
+ nvavp->video_misc_dev.name = "tegra_avpchannel";
+ nvavp->video_misc_dev.fops = &tegra_video_nvavp_fops;
+ nvavp->video_misc_dev.mode = S_IRWXUGO;
+ nvavp->video_misc_dev.parent = &ndev->dev;
- ret = misc_register(&nvavp->misc_dev);
+ ret = misc_register(&nvavp->video_misc_dev);
if (ret) {
dev_err(&ndev->dev, "unable to register misc device!\n");
goto err_misc_reg;
}
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ nvavp->audio_misc_dev.minor = MISC_DYNAMIC_MINOR;
+ nvavp->audio_misc_dev.name = "tegra_audio_avpchannel";
+ nvavp->audio_misc_dev.fops = &tegra_audio_nvavp_fops;
+ nvavp->audio_misc_dev.mode = S_IRWXUGO;
+ nvavp->audio_misc_dev.parent = &ndev->dev;
+
+ ret = misc_register(&nvavp->audio_misc_dev);
+ if (ret) {
+ dev_err(&ndev->dev, "unable to register misc device!\n");
+ goto err_audio_misc_reg;
+ }
+#endif
+
ret = request_irq(irq, nvavp_mbox_pending_isr, 0,
TEGRA_NVAVP_NAME, nvavp);
if (ret) {
@@ -1358,7 +1582,11 @@ static int tegra_nvavp_probe(struct nvhost_device *ndev,
return 0;
err_req_irq_pend:
- misc_deregister(&nvavp->misc_dev);
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ misc_deregister(&nvavp->audio_misc_dev);
+err_audio_misc_reg:
+#endif
+ misc_deregister(&nvavp->video_misc_dev);
err_misc_reg:
clk_put(nvavp->emc_clk);
err_get_emc_clk:
@@ -1404,8 +1632,11 @@ static int tegra_nvavp_remove(struct nvhost_device *ndev)
nvavp_unload_ucode(nvavp);
nvavp_unload_os(nvavp);
- misc_deregister(&nvavp->misc_dev);
+ misc_deregister(&nvavp->video_misc_dev);
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ misc_deregister(&nvavp->audio_misc_dev);
+#endif
clk_put(nvavp->bsev_clk);
clk_put(nvavp->vde_clk);
clk_put(nvavp->cop_clk);
@@ -1446,7 +1677,7 @@ static int tegra_nvavp_resume(struct nvhost_device *ndev)
mutex_lock(&nvavp->open_lock);
if (nvavp->refcount)
- nvavp_init(nvavp);
+ nvavp_init(nvavp, NVAVP_VIDEO_CHANNEL);
mutex_unlock(&nvavp->open_lock);