From 09884d385dc872be9452d0d053c913119cce4689 Mon Sep 17 00:00:00 2001 From: Vandana Salve Date: Thu, 3 May 2012 16:07:48 +0530 Subject: media: video: nvavp: Add audio channel support Added support for audio channel. Push buffers can be submitted on audio channel. bug 964514 Change-Id: Ib13b6ed41678e9dcc170fddc64ab4646f960838b Signed-off-by: Vandana Salve Reviewed-on: http://git-master/r/97534 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Bharat Nihalani Tested-by: Bharat Nihalani GVS: Gerrit_Virtual_Submit Reviewed-by: Gajanan Bhat --- drivers/media/video/tegra/nvavp/Kconfig | 11 + drivers/media/video/tegra/nvavp/nvavp_dev.c | 509 ++++++++++++++++++++-------- 2 files changed, 381 insertions(+), 139 deletions(-) (limited to 'drivers') 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); -- cgit v1.2.3