diff options
author | Vandana Salve <vsalve@nvidia.com> | 2012-05-25 19:04:06 +0530 |
---|---|---|
committer | Lokesh Pathak <lpathak@nvidia.com> | 2012-07-30 08:36:41 -0700 |
commit | 8055acfa05c82997bdcfbce5093b9cd963251d2a (patch) | |
tree | 27e94b4175a062dae7ff5d7dee1688f02ed999c6 | |
parent | 1811650b54e3d988dfd6dc9ecb8c7d0e4986d8a1 (diff) |
media: video: nvavp: Add bsea/vcp clocks for Audio
1) Enable bsea/vcp clocks for Audio support by ioctl
2) Send kernel event NVE276_OS_INTERRUPT_APP_NOTIFY
to user space
3) Suspend Resume support
bug 964514
Change-Id: I72fb790baa093b4bcd99a128c886dc049fa0fbb6
Signed-off-by: Vandana Salve <vsalve@nvidia.com>
Reviewed-on: http://git-master/r/108493
cherry picked from commit 4432c5fa5e9072ff019d994f3bc8239bd34ddad1
Reviewed-on: http://git-master/r/114589
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
-rw-r--r-- | drivers/media/video/tegra/nvavp/nvavp_dev.c | 149 | ||||
-rw-r--r-- | include/linux/tegra_nvavp.h | 8 |
2 files changed, 141 insertions, 16 deletions
diff --git a/drivers/media/video/tegra/nvavp/nvavp_dev.c b/drivers/media/video/tegra/nvavp/nvavp_dev.c index 9a54f8e3d025..4501abb9a735 100644 --- a/drivers/media/video/tegra/nvavp/nvavp_dev.c +++ b/drivers/media/video/tegra/nvavp/nvavp_dev.c @@ -1,7 +1,7 @@ /* * drivers/media/video/tegra/nvavp/nvavp_dev.c * - * Copyright (C) 2011-2012 NVIDIA Corp. + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. * * 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 @@ -101,6 +101,10 @@ struct nvavp_info { struct clk *bsev_clk; struct clk *vde_clk; struct clk *cop_clk; +#if defined(CONFIG_TEGRA_NVAVP_AUDIO) + struct clk *bsea_clk; + struct clk *vcp_clk; +#endif /* used for dvfs */ struct clk *sclk; @@ -115,6 +119,7 @@ struct nvavp_info { int video_initialized; #if defined(CONFIG_TEGRA_NVAVP_AUDIO) int audio_initialized; + struct work_struct app_notify_work; #endif struct work_struct clock_disable_work; @@ -263,14 +268,26 @@ static void nvavp_clks_disable(struct nvavp_info *nvavp) } } -static u32 nvavp_check_idle(struct nvavp_info *nvavp) +static u32 nvavp_check_idle(struct nvavp_info *nvavp, int channel_id) { - struct nvavp_channel *channel_info = nvavp_get_channel_info(nvavp, NVAVP_VIDEO_CHANNEL); + struct nvavp_channel *channel_info = nvavp_get_channel_info(nvavp, channel_id); struct nv_e276_control *control = channel_info->os_control; return (control->put == control->get) ? 1 : 0; } +#if defined(CONFIG_TEGRA_NVAVP_AUDIO) +static void app_notify_handler(struct work_struct *work) +{ + struct nvavp_info *nvavp; + + nvavp = container_of(work, struct nvavp_info, + app_notify_work); + + kobject_uevent(&nvavp->nvhost_dev->dev.kobj, KOBJ_CHANGE); +} +#endif + static void clock_disable_handler(struct work_struct *work) { struct nvavp_info *nvavp; @@ -282,7 +299,7 @@ static void clock_disable_handler(struct work_struct *work) mutex_lock(&channel_info->pushbuffer_lock); mutex_lock(&nvavp->open_lock); - if (nvavp_check_idle(nvavp) && nvavp->pending) { + if (nvavp_check_idle(nvavp, NVAVP_VIDEO_CHANNEL) && nvavp->pending) { nvavp->pending = false; nvavp_clks_disable(nvavp); } @@ -328,6 +345,13 @@ static int nvavp_service(struct nvavp_info *nvavp) dev_err(&nvavp->nvhost_dev->dev, "AVP timeout\n"); writel(inbox & NVAVP_INBOX_VALID, NVAVP_OS_INBOX); +#if defined(CONFIG_TEGRA_NVAVP_AUDIO) + if (inbox & NVE276_OS_INTERRUPT_APP_NOTIFY) { + pr_debug("nvavp_service NVE276_OS_INTERRUPT_APP_NOTIFY\n"); + schedule_work(&nvavp->app_notify_work); + } +#endif + return 0; } @@ -970,18 +994,14 @@ static void nvavp_uninit(struct nvavp_info *nvavp) if (video_initialized) { pr_debug("nvavp_uninit nvavp->video_initialized\n"); cancel_work_sync(&nvavp->clock_disable_work); - nvavp_halt_vde(nvavp); - - clk_disable(nvavp->sclk); - clk_disable(nvavp->emc_clk); - nvavp_set_video_init_status(nvavp, 0); video_initialized = 0; } #if defined(CONFIG_TEGRA_NVAVP_AUDIO) if (audio_initialized) { + cancel_work_sync(&nvavp->app_notify_work); nvavp_set_audio_init_status(nvavp, 0); audio_initialized = 0; } @@ -990,6 +1010,9 @@ static void nvavp_uninit(struct nvavp_info *nvavp) /* Video and Audio both becomes uninitialized */ if (video_initialized == audio_initialized) { pr_debug("nvavp_uninit both channels unitialized\n"); + + clk_disable(nvavp->sclk); + clk_disable(nvavp->emc_clk); disable_irq(nvavp->mbox_from_avp_pend_irq); nvavp_pushbuffer_deinit(nvavp); nvavp_halt_avp(nvavp); @@ -1250,6 +1273,62 @@ static int nvavp_force_clock_stay_on_ioctl(struct file *filp, unsigned int cmd, return 0; } +#if defined(CONFIG_TEGRA_NVAVP_AUDIO) +static int nvavp_enable_audio_clocks(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct nvavp_clientctx *clientctx = filp->private_data; + struct nvavp_info *nvavp = clientctx->nvavp; + struct nvavp_clock_args config; + + if (copy_from_user(&config, (void __user *)arg, sizeof(struct nvavp_clock_args))) + return -EFAULT; + + dev_dbg(&nvavp->nvhost_dev->dev, "%s: clk_id=%d\n", + __func__, config.id); + + if (config.id == NVAVP_MODULE_ID_VCP) + clk_enable(nvavp->vcp_clk); + else if (config.id == NVAVP_MODULE_ID_BSEA) + clk_enable(nvavp->bsea_clk); + + return 0; +} + +static int nvavp_disable_audio_clocks(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct nvavp_clientctx *clientctx = filp->private_data; + struct nvavp_info *nvavp = clientctx->nvavp; + struct nvavp_clock_args config; + + if (copy_from_user(&config, (void __user *)arg, sizeof(struct nvavp_clock_args))) + return -EFAULT; + + dev_dbg(&nvavp->nvhost_dev->dev, "%s: clk_id=%d\n", + __func__, config.id); + + if (config.id == NVAVP_MODULE_ID_VCP) + clk_disable(nvavp->vcp_clk); + else if (config.id == NVAVP_MODULE_ID_BSEA) + clk_disable(nvavp->bsea_clk); + + return 0; +} +#else +static int nvavp_enable_audio_clocks(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + return 0; +} + +static int nvavp_disable_audio_clocks(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + return 0; +} +#endif + static int tegra_nvavp_open(struct inode *inode, struct file *filp, int channel_id) { struct miscdevice *miscdev = filp->private_data; @@ -1367,6 +1446,12 @@ static long tegra_nvavp_ioctl(struct file *filp, unsigned int cmd, case NVAVP_IOCTL_FORCE_CLOCK_STAY_ON: ret = nvavp_force_clock_stay_on_ioctl(filp, cmd, arg); break; + case NVAVP_IOCTL_ENABLE_AUDIO_CLOCKS: + ret = nvavp_enable_audio_clocks(filp, cmd, arg); + break; + case NVAVP_IOCTL_DISABLE_AUDIO_CLOCKS: + ret = nvavp_disable_audio_clocks(filp, cmd, arg); + break; default: ret = -EINVAL; break; @@ -1540,6 +1625,22 @@ static int tegra_nvavp_probe(struct nvhost_device *ndev, goto err_get_emc_clk; } +#if defined(CONFIG_TEGRA_NVAVP_AUDIO) + nvavp->bsea_clk = clk_get(&ndev->dev, "bsea"); + if (IS_ERR(nvavp->bsea_clk)) { + dev_err(&ndev->dev, "cannot get bsea clock\n"); + ret = -ENOENT; + goto err_get_bsea_clk; + } + + nvavp->vcp_clk = clk_get(&ndev->dev, "vcp"); + if (IS_ERR(nvavp->vcp_clk)) { + dev_err(&ndev->dev, "cannot get vcp clock\n"); + ret = -ENOENT; + goto err_get_vcp_clk; + } +#endif + nvavp->clk_enabled = 0; nvavp_halt_avp(nvavp); @@ -1558,6 +1659,7 @@ static int tegra_nvavp_probe(struct nvhost_device *ndev, } #if defined(CONFIG_TEGRA_NVAVP_AUDIO) + INIT_WORK(&nvavp->app_notify_work, app_notify_handler); 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; @@ -1591,6 +1693,12 @@ err_audio_misc_reg: #endif misc_deregister(&nvavp->video_misc_dev); err_misc_reg: +#if defined(CONFIG_TEGRA_NVAVP_AUDIO) + clk_put(nvavp->vcp_clk); +err_get_vcp_clk: + clk_put(nvavp->bsea_clk); +err_get_bsea_clk: +#endif clk_put(nvavp->emc_clk); err_get_emc_clk: clk_put(nvavp->sclk); @@ -1639,6 +1747,8 @@ static int tegra_nvavp_remove(struct nvhost_device *ndev) #if defined(CONFIG_TEGRA_NVAVP_AUDIO) misc_deregister(&nvavp->audio_misc_dev); + clk_put(nvavp->vcp_clk); + clk_put(nvavp->bsea_clk); #endif clk_put(nvavp->bsev_clk); clk_put(nvavp->vde_clk); @@ -1662,14 +1772,22 @@ static int tegra_nvavp_suspend(struct nvhost_device *ndev, pm_message_t state) mutex_lock(&nvavp->open_lock); if (nvavp->refcount) { - if (!nvavp->clk_enabled) + if (!nvavp->clk_enabled) { +#if defined(CONFIG_TEGRA_NVAVP_AUDIO) + if (nvavp_check_idle(nvavp, NVAVP_AUDIO_CHANNEL)) + nvavp_uninit(nvavp); + else + ret = -EBUSY; +#else nvavp_uninit(nvavp); - else +#endif + } + else { ret = -EBUSY; + } } mutex_unlock(&nvavp->open_lock); - return ret; } @@ -1679,9 +1797,12 @@ static int tegra_nvavp_resume(struct nvhost_device *ndev) mutex_lock(&nvavp->open_lock); - if (nvavp->refcount) + if (nvavp->refcount) { nvavp_init(nvavp, NVAVP_VIDEO_CHANNEL); - +#if defined(CONFIG_TEGRA_NVAVP_AUDIO) + nvavp_init(nvavp, NVAVP_AUDIO_CHANNEL); +#endif + } mutex_unlock(&nvavp->open_lock); return 0; diff --git a/include/linux/tegra_nvavp.h b/include/linux/tegra_nvavp.h index 6774d0eaa7ef..250eee379de9 100644 --- a/include/linux/tegra_nvavp.h +++ b/include/linux/tegra_nvavp.h @@ -1,7 +1,7 @@ /* * include/linux/tegra_nvavp.h * - * Copyright (C) 2011 NVIDIA Corp. + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. * * 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 @@ -89,8 +89,12 @@ struct nvavp_clock_stay_on_state_args { __u32) #define NVAVP_IOCTL_FORCE_CLOCK_STAY_ON _IOW(NVAVP_IOCTL_MAGIC, 0x67, \ struct nvavp_clock_stay_on_state_args) +#define NVAVP_IOCTL_ENABLE_AUDIO_CLOCKS _IOWR(NVAVP_IOCTL_MAGIC, 0x68, \ + struct nvavp_clock_args) +#define NVAVP_IOCTL_DISABLE_AUDIO_CLOCKS _IOWR(NVAVP_IOCTL_MAGIC, 0x69, \ + struct nvavp_clock_args) #define NVAVP_IOCTL_MIN_NR _IOC_NR(NVAVP_IOCTL_SET_NVMAP_FD) -#define NVAVP_IOCTL_MAX_NR _IOC_NR(NVAVP_IOCTL_FORCE_CLOCK_STAY_ON) +#define NVAVP_IOCTL_MAX_NR _IOC_NR(NVAVP_IOCTL_DISABLE_AUDIO_CLOCKS) #endif /* __LINUX_TEGRA_NVAVP_H */ |