summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorPrashant Gaikwad <pgaikwad@nvidia.com>2011-09-27 17:44:54 +0530
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:49:21 -0800
commit244f6c0b7fe68372dd5e50168789563af725d73c (patch)
treeaa555c3c80de0a54bf0257ae7ede23eeb1eeb4dc /drivers
parent959a044d36a3d3201f36e187d57b66abdda77b3e (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.c97
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);