diff options
author | Prashant Gaikwad <pgaikwad@nvidia.com> | 2011-09-27 17:44:54 +0530 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:49:21 -0800 |
commit | 244f6c0b7fe68372dd5e50168789563af725d73c (patch) | |
tree | aa555c3c80de0a54bf0257ae7ede23eeb1eeb4dc /drivers | |
parent | 959a044d36a3d3201f36e187d57b66abdda77b3e (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>
Rebase-Id: Rcd1d8e536641d109c7e1db7ccaf3a8e54a169acc
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/video/tegra/nvavp/nvavp_dev.c | 97 |
1 files changed, 97 insertions, 0 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); |