summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPrashant Gaikwad <pgaikwad@nvidia.com>2011-09-27 17:44:54 +0530
committerVarun Colbert <vcolbert@nvidia.com>2011-10-12 16:07:53 -0700
commit708d81648aa6c92af5b1ff148ffa7d5046687cbd (patch)
tree151738f4bec51a1ce24792f73dd473f4f944e43a
parent14f2148d5268f7c0aa7a5f78fbf40e0b1e218184 (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.c97
-rw-r--r--include/linux/tegra_nvavp.h20
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 */