Commit 1e172731 authored by Philipp Zabel's avatar Philipp Zabel Committed by Mauro Carvalho Chehab

[media] coda: Add runtime pm support

This patch allows to use the runtime pm and generic pm domain frameworks
to completely gate power to the VPU if it is unused. This functionality
is available on i.MX6.
Signed-off-by: default avatarPhilipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: default avatarKamil Debski <k.debski@samsung.com>
Signed-off-by: default avatarMauro Carvalho Chehab <m.chehab@samsung.com>
parent 14604e3a
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/videodev2.h> #include <linux/videodev2.h>
#include <linux/of.h> #include <linux/of.h>
...@@ -2767,6 +2768,13 @@ static int coda_open(struct file *file) ...@@ -2767,6 +2768,13 @@ static int coda_open(struct file *file)
ctx->reg_idx = idx; ctx->reg_idx = idx;
} }
/* Power up and upload firmware if necessary */
ret = pm_runtime_get_sync(&dev->plat_dev->dev);
if (ret < 0) {
v4l2_err(&dev->v4l2_dev, "failed to power up: %d\n", ret);
goto err_pm_get;
}
ret = clk_prepare_enable(dev->clk_per); ret = clk_prepare_enable(dev->clk_per);
if (ret) if (ret)
goto err_clk_per; goto err_clk_per;
...@@ -2836,6 +2844,8 @@ static int coda_open(struct file *file) ...@@ -2836,6 +2844,8 @@ static int coda_open(struct file *file)
err_clk_ahb: err_clk_ahb:
clk_disable_unprepare(dev->clk_per); clk_disable_unprepare(dev->clk_per);
err_clk_per: err_clk_per:
pm_runtime_put_sync(&dev->plat_dev->dev);
err_pm_get:
v4l2_fh_del(&ctx->fh); v4l2_fh_del(&ctx->fh);
v4l2_fh_exit(&ctx->fh); v4l2_fh_exit(&ctx->fh);
clear_bit(ctx->idx, &dev->instance_mask); clear_bit(ctx->idx, &dev->instance_mask);
...@@ -2877,6 +2887,7 @@ static int coda_release(struct file *file) ...@@ -2877,6 +2887,7 @@ static int coda_release(struct file *file)
v4l2_ctrl_handler_free(&ctx->ctrls); v4l2_ctrl_handler_free(&ctx->ctrls);
clk_disable_unprepare(dev->clk_ahb); clk_disable_unprepare(dev->clk_ahb);
clk_disable_unprepare(dev->clk_per); clk_disable_unprepare(dev->clk_per);
pm_runtime_put_sync(&dev->plat_dev->dev);
v4l2_fh_del(&ctx->fh); v4l2_fh_del(&ctx->fh);
v4l2_fh_exit(&ctx->fh); v4l2_fh_exit(&ctx->fh);
clear_bit(ctx->idx, &dev->instance_mask); clear_bit(ctx->idx, &dev->instance_mask);
...@@ -3191,7 +3202,7 @@ static int coda_hw_init(struct coda_dev *dev) ...@@ -3191,7 +3202,7 @@ static int coda_hw_init(struct coda_dev *dev)
ret = clk_prepare_enable(dev->clk_per); ret = clk_prepare_enable(dev->clk_per);
if (ret) if (ret)
return ret; goto err_clk_per;
ret = clk_prepare_enable(dev->clk_ahb); ret = clk_prepare_enable(dev->clk_ahb);
if (ret) if (ret)
...@@ -3317,6 +3328,7 @@ static int coda_hw_init(struct coda_dev *dev) ...@@ -3317,6 +3328,7 @@ static int coda_hw_init(struct coda_dev *dev)
err_clk_ahb: err_clk_ahb:
clk_disable_unprepare(dev->clk_per); clk_disable_unprepare(dev->clk_per);
err_clk_per:
return ret; return ret;
} }
...@@ -3342,10 +3354,29 @@ static void coda_fw_callback(const struct firmware *fw, void *context) ...@@ -3342,10 +3354,29 @@ static void coda_fw_callback(const struct firmware *fw, void *context)
memcpy(dev->codebuf.vaddr, fw->data, fw->size); memcpy(dev->codebuf.vaddr, fw->data, fw->size);
release_firmware(fw); release_firmware(fw);
ret = coda_hw_init(dev); if (pm_runtime_enabled(&pdev->dev) && pdev->dev.pm_domain) {
if (ret) { /*
v4l2_err(&dev->v4l2_dev, "HW initialization failed\n"); * Enabling power temporarily will cause coda_hw_init to be
return; * called via coda_runtime_resume by the pm domain.
*/
ret = pm_runtime_get_sync(&dev->plat_dev->dev);
if (ret < 0) {
v4l2_err(&dev->v4l2_dev, "failed to power on: %d\n",
ret);
return;
}
pm_runtime_put_sync(&dev->plat_dev->dev);
} else {
/*
* If runtime pm is disabled or pm_domain is not set,
* initialize once manually.
*/
ret = coda_hw_init(dev);
if (ret < 0) {
v4l2_err(&dev->v4l2_dev, "HW initialization failed\n");
return;
}
} }
dev->vfd.fops = &coda_fops, dev->vfd.fops = &coda_fops,
...@@ -3583,6 +3614,8 @@ static int coda_probe(struct platform_device *pdev) ...@@ -3583,6 +3614,8 @@ static int coda_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, dev); platform_set_drvdata(pdev, dev);
pm_runtime_enable(&pdev->dev);
return coda_firmware_request(dev); return coda_firmware_request(dev);
} }
...@@ -3593,6 +3626,7 @@ static int coda_remove(struct platform_device *pdev) ...@@ -3593,6 +3626,7 @@ static int coda_remove(struct platform_device *pdev)
video_unregister_device(&dev->vfd); video_unregister_device(&dev->vfd);
if (dev->m2m_dev) if (dev->m2m_dev)
v4l2_m2m_release(dev->m2m_dev); v4l2_m2m_release(dev->m2m_dev);
pm_runtime_disable(&pdev->dev);
if (dev->alloc_ctx) if (dev->alloc_ctx)
vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
v4l2_device_unregister(&dev->v4l2_dev); v4l2_device_unregister(&dev->v4l2_dev);
...@@ -3606,6 +3640,26 @@ static int coda_remove(struct platform_device *pdev) ...@@ -3606,6 +3640,26 @@ static int coda_remove(struct platform_device *pdev)
return 0; return 0;
} }
#ifdef CONFIG_PM_RUNTIME
static int coda_runtime_resume(struct device *dev)
{
struct coda_dev *cdev = dev_get_drvdata(dev);
int ret = 0;
if (dev->pm_domain) {
ret = coda_hw_init(cdev);
if (ret)
v4l2_err(&cdev->v4l2_dev, "HW initialization failed\n");
}
return ret;
}
#endif
static const struct dev_pm_ops coda_pm_ops = {
SET_RUNTIME_PM_OPS(NULL, coda_runtime_resume, NULL)
};
static struct platform_driver coda_driver = { static struct platform_driver coda_driver = {
.probe = coda_probe, .probe = coda_probe,
.remove = coda_remove, .remove = coda_remove,
...@@ -3613,6 +3667,7 @@ static struct platform_driver coda_driver = { ...@@ -3613,6 +3667,7 @@ static struct platform_driver coda_driver = {
.name = CODA_NAME, .name = CODA_NAME,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_match_table = of_match_ptr(coda_dt_ids), .of_match_table = of_match_ptr(coda_dt_ids),
.pm = &coda_pm_ops,
}, },
.id_table = coda_platform_ids, .id_table = coda_platform_ids,
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment