diff options
author | Prashant Gaikwad <pgaikwad@nvidia.com> | 2011-09-27 17:44:54 +0530 |
---|---|---|
committer | Varun Colbert <vcolbert@nvidia.com> | 2011-10-12 16:07:53 -0700 |
commit | 708d81648aa6c92af5b1ff148ffa7d5046687cbd (patch) | |
tree | 151738f4bec51a1ce24792f73dd473f4f944e43a | |
parent | 14f2148d5268f7c0aa7a5f78fbf40e0b1e218184 (diff) |
media: video: nvavp: Add ioctl to set/get clock rate
These ioctls provides interface to user space for
VDE/AVP/EMC clock rate anagement. This helps to save power.
Bug 876405
Change-Id: Ic36cd78bf78a3c04dac49dd4b3040542130bc855
Reviewed-on: http://git-master/r/54697
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
Tested-by: Bharat Nihalani <bnihalani@nvidia.com>
Reviewed-by: Mayuresh Kulkarni <mkulkarni@nvidia.com>
-rw-r--r-- | drivers/media/video/tegra/nvavp/nvavp_dev.c | 97 | ||||
-rw-r--r-- | include/linux/tegra_nvavp.h | 20 |
2 files changed, 116 insertions, 1 deletions
diff --git a/drivers/media/video/tegra/nvavp/nvavp_dev.c b/drivers/media/video/tegra/nvavp/nvavp_dev.c index e4d2afd4d797..e59e73c153e3 100644 --- a/drivers/media/video/tegra/nvavp/nvavp_dev.c +++ b/drivers/media/video/tegra/nvavp/nvavp_dev.c @@ -72,6 +72,10 @@ struct nvavp_info { struct clk *vde_clk; struct clk *cop_clk; + /* used for dvfs */ + struct clk *sclk; + struct clk *emc_clk; + int mbox_from_avp_pend_irq; struct mutex open_lock; @@ -112,6 +116,21 @@ struct nvavp_clientctx { struct nvavp_info *nvavp; }; +static struct clk *nvavp_clk_get(struct nvavp_info *nvavp, int id) +{ + if (!nvavp) + return NULL; + + if (id == NVAVP_MODULE_ID_AVP) + return nvavp->sclk; + if (id == NVAVP_MODULE_ID_VDE) + return nvavp->vde_clk; + if (id == NVAVP_MODULE_ID_EMC) + return nvavp->emc_clk; + + return NULL; +} + static int nvavp_service(struct nvavp_info *nvavp) { struct nvavp_os_info *os = &nvavp->os_info; @@ -170,6 +189,9 @@ static void nvavp_halt_avp(struct nvavp_info *nvavp) writel(FLOW_MODE_STOP, FLOW_CTRL_HALT_COP_EVENTS); tegra_periph_reset_assert(nvavp->cop_clk); + clk_disable(nvavp->sclk); + clk_disable(nvavp->emc_clk); + writel(0, NVAVP_OS_OUTBOX); writel(0, NVAVP_OS_INBOX); } @@ -193,6 +215,9 @@ static int nvavp_reset_avp(struct nvavp_info *nvavp, unsigned long reset_addr) writel(reset_addr, TEGRA_NVAVP_RESET_VECTOR_ADDR); + clk_enable(nvavp->sclk); + clk_enable(nvavp->emc_clk); + tegra_periph_reset_assert(nvavp->cop_clk); udelay(2); tegra_periph_reset_deassert(nvavp->cop_clk); @@ -671,6 +696,54 @@ static void nvavp_uninit(struct nvavp_info *nvavp) nvavp_halt_avp(nvavp); } +static int nvavp_set_clock_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct nvavp_clientctx *clientctx = filp->private_data; + struct nvavp_info *nvavp = clientctx->nvavp; + struct clk *c; + struct nvavp_clock_args config; + + if (copy_from_user(&config, (void __user *)arg, sizeof(struct nvavp_clock_args))) + return -EFAULT; + + c = nvavp_clk_get(nvavp, config.id); + if (IS_ERR_OR_NULL(c)) + return -EINVAL; + + clk_set_rate(c, config.rate); + + config.rate = clk_get_rate(c); + + if (copy_to_user((void __user *)arg, &config, sizeof(struct nvavp_clock_args))) + return -EFAULT; + + return 0; +} + +static int nvavp_get_clock_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct nvavp_clientctx *clientctx = filp->private_data; + struct nvavp_info *nvavp = clientctx->nvavp; + struct clk *c; + struct nvavp_clock_args config; + + if (copy_from_user(&config, (void __user *)arg, sizeof(struct nvavp_clock_args))) + return -EFAULT; + + c = nvavp_clk_get(nvavp, config.id); + if (IS_ERR_OR_NULL(c)) + return -EINVAL; + + config.rate = clk_get_rate(c); + + if (copy_to_user((void __user *)arg, &config, sizeof(struct nvavp_clock_args))) + return -EFAULT; + + return 0; +} + static int nvavp_get_syncpointid_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { @@ -902,6 +975,12 @@ static long tegra_nvavp_ioctl(struct file *filp, unsigned int cmd, case NVAVP_IOCTL_PUSH_BUFFER_SUBMIT: ret = nvavp_pushbuffer_submit_ioctl(filp, cmd, arg); break; + case NVAVP_IOCTL_SET_CLOCK: + ret = nvavp_set_clock_ioctl(filp, cmd, arg); + break; + case NVAVP_IOCTL_GET_CLOCK: + ret = nvavp_get_clock_ioctl(filp, cmd, arg); + break; default: ret = -EINVAL; break; @@ -1062,6 +1141,20 @@ static int tegra_nvavp_probe(struct nvhost_device *ndev) goto err_get_bsev_clk; } + nvavp->sclk = clk_get(&ndev->dev, "sclk"); + if (IS_ERR(nvavp->sclk)) { + dev_err(&ndev->dev, "cannot get avp.sclk clock\n"); + ret = -ENOENT; + goto err_get_sclk; + } + + nvavp->emc_clk = clk_get(&ndev->dev, "emc"); + if (IS_ERR(nvavp->emc_clk)) { + dev_err(&ndev->dev, "cannot get emc clock\n"); + ret = -ENOENT; + goto err_get_emc_clk; + } + nvavp_halt_avp(nvavp); nvavp->misc_dev.minor = MISC_DYNAMIC_MINOR; @@ -1092,6 +1185,10 @@ static int tegra_nvavp_probe(struct nvhost_device *ndev) err_req_irq_pend: misc_deregister(&nvavp->misc_dev); err_misc_reg: + clk_put(nvavp->emc_clk); +err_get_emc_clk: + clk_put(nvavp->sclk); +err_get_sclk: clk_put(nvavp->bsev_clk); err_get_bsev_clk: clk_put(nvavp->vde_clk); diff --git a/include/linux/tegra_nvavp.h b/include/linux/tegra_nvavp.h index e207f145f4ca..32dc4c62b4bd 100644 --- a/include/linux/tegra_nvavp.h +++ b/include/linux/tegra_nvavp.h @@ -20,6 +20,15 @@ #define NVAVP_FLAG_NONE 0x00000000 #define NVAVP_UCODE_EXT 0x00000001 /*use external ucode provided */ +enum { + NVAVP_MODULE_ID_AVP = 2, + NVAVP_MODULE_ID_VCP = 3, + NVAVP_MODULE_ID_BSEA = 27, + NVAVP_MODULE_ID_VDE = 28, + NVAVP_MODULE_ID_MPE = 29, + NVAVP_MODULE_ID_EMC = 75, +}; + struct nvavp_cmdbuf { __u32 mem; __u32 offset; @@ -50,6 +59,11 @@ struct nvavp_set_nvmap_fd_args { __u32 fd; }; +struct nvavp_clock_args { + __u32 id; + __u32 rate; +}; + #define NVAVP_IOCTL_MAGIC 'n' #define NVAVP_IOCTL_SET_NVMAP_FD _IOW(NVAVP_IOCTL_MAGIC, 0x60, \ @@ -58,9 +72,13 @@ struct nvavp_set_nvmap_fd_args { __u32) #define NVAVP_IOCTL_PUSH_BUFFER_SUBMIT _IOWR(NVAVP_IOCTL_MAGIC, 0x63, \ struct nvavp_pushbuffer_submit_hdr) +#define NVAVP_IOCTL_SET_CLOCK _IOWR(NVAVP_IOCTL_MAGIC, 0x64, \ + struct nvavp_clock_args) +#define NVAVP_IOCTL_GET_CLOCK _IOR(NVAVP_IOCTL_MAGIC, 0x65, \ + 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_PUSH_BUFFER_SUBMIT) +#define NVAVP_IOCTL_MAX_NR _IOC_NR(NVAVP_IOCTL_GET_CLOCK) #endif /* __LINUX_TEGRA_NVAVP_H */ |