* [PATCH] dmaengine: zynqmp_dma: Add runtime pm support [not found] <1508310126-10926-1-git-send-email-appanad@xilinx.com> @ 2017-10-20 6:31 ` Michal Simek 2017-10-20 6:33 ` Michal Simek 0 siblings, 1 reply; 2+ messages in thread From: Michal Simek @ 2017-10-20 6:31 UTC (permalink / raw) To: linux-arm-kernel On 18.10.2017 09:02, Kedareswara rao Appana wrote: > This patch adds runtime pm support in the driver. > > Signed-off-by: Kedareswara rao Appana <appanad@xilinx.com> > --- > drivers/dma/xilinx/zynqmp_dma.c | 167 ++++++++++++++++++++++++++++++++-------- > 1 file changed, 135 insertions(+), 32 deletions(-) > > diff --git a/drivers/dma/xilinx/zynqmp_dma.c b/drivers/dma/xilinx/zynqmp_dma.c > index 1ee1241..dd73831 100644 > --- a/drivers/dma/xilinx/zynqmp_dma.c > +++ b/drivers/dma/xilinx/zynqmp_dma.c > @@ -23,6 +23,7 @@ > #include <linux/slab.h> > #include <linux/clk.h> > #include <linux/io-64-nonatomic-lo-hi.h> > +#include <linux/pm_runtime.h> > > #include "../dmaengine.h" > > @@ -138,6 +139,8 @@ > #define ZYNQMP_DMA_BUS_WIDTH_64 64 > #define ZYNQMP_DMA_BUS_WIDTH_128 128 > > +#define ZDMA_PM_TIMEOUT 100 > + > #define ZYNQMP_DMA_DESC_SIZE(chan) (chan->desc_size) > > #define to_chan(chan) container_of(chan, struct zynqmp_dma_chan, \ > @@ -211,8 +214,6 @@ struct zynqmp_dma_desc_sw { > * @bus_width: Bus width > * @src_burst_len: Source burst length > * @dst_burst_len: Dest burst length > - * @clk_main: Pointer to main clock > - * @clk_apb: Pointer to apb clock > */ > struct zynqmp_dma_chan { > struct zynqmp_dma_device *zdev; > @@ -237,8 +238,6 @@ struct zynqmp_dma_chan { > u32 bus_width; > u32 src_burst_len; > u32 dst_burst_len; > - struct clk *clk_main; > - struct clk *clk_apb; > }; > > /** > @@ -246,11 +245,15 @@ struct zynqmp_dma_chan { > * @dev: Device Structure > * @common: DMA device structure > * @chan: Driver specific DMA channel > + * @clk_main: Pointer to main clock > + * @clk_apb: Pointer to apb clock > */ > struct zynqmp_dma_device { > struct device *dev; > struct dma_device common; > struct zynqmp_dma_chan *chan; > + struct clk *clk_main; > + struct clk *clk_apb; > }; > > static inline void zynqmp_dma_writeq(struct zynqmp_dma_chan *chan, u32 reg, > @@ -461,7 +464,11 @@ static int zynqmp_dma_alloc_chan_resources(struct dma_chan *dchan) > { > struct zynqmp_dma_chan *chan = to_chan(dchan); > struct zynqmp_dma_desc_sw *desc; > - int i; > + int i, ret; > + > + ret = pm_runtime_get_sync(chan->dev); > + if (ret < 0) > + return ret; > > chan->sw_desc_pool = kzalloc(sizeof(*desc) * ZYNQMP_DMA_NUM_DESCS, > GFP_KERNEL); > @@ -664,6 +671,8 @@ static void zynqmp_dma_free_chan_resources(struct dma_chan *dchan) > (2 * ZYNQMP_DMA_DESC_SIZE(chan) * ZYNQMP_DMA_NUM_DESCS), > chan->desc_pool_v, chan->desc_pool_p); > kfree(chan->sw_desc_pool); > + pm_runtime_mark_last_busy(chan->dev); > + pm_runtime_put_autosuspend(chan->dev); > } > > /** > @@ -841,8 +850,6 @@ static void zynqmp_dma_chan_remove(struct zynqmp_dma_chan *chan) > devm_free_irq(chan->zdev->dev, chan->irq, chan); > tasklet_kill(&chan->tasklet); > list_del(&chan->common.device_node); > - clk_disable_unprepare(chan->clk_apb); > - clk_disable_unprepare(chan->clk_main); > } > > /** > @@ -907,30 +914,6 @@ static int zynqmp_dma_chan_probe(struct zynqmp_dma_device *zdev, > "zynqmp-dma", chan); > if (err) > return err; > - chan->clk_main = devm_clk_get(&pdev->dev, "clk_main"); > - if (IS_ERR(chan->clk_main)) { > - dev_err(&pdev->dev, "main clock not found.\n"); > - return PTR_ERR(chan->clk_main); > - } > - > - chan->clk_apb = devm_clk_get(&pdev->dev, "clk_apb"); > - if (IS_ERR(chan->clk_apb)) { > - dev_err(&pdev->dev, "apb clock not found.\n"); > - return PTR_ERR(chan->clk_apb); > - } > - > - err = clk_prepare_enable(chan->clk_main); > - if (err) { > - dev_err(&pdev->dev, "Unable to enable main clock.\n"); > - return err; > - } > - > - err = clk_prepare_enable(chan->clk_apb); > - if (err) { > - clk_disable_unprepare(chan->clk_main); > - dev_err(&pdev->dev, "Unable to enable apb clock.\n"); > - return err; > - } > > chan->desc_size = sizeof(struct zynqmp_dma_desc_ll); > chan->idle = true; > @@ -953,6 +936,87 @@ static struct dma_chan *of_zynqmp_dma_xlate(struct of_phandle_args *dma_spec, > } > > /** > + * zynqmp_dma_suspend - Suspend method for the driver > + * @dev: Address of the device structure > + * > + * Put the driver into low power mode. > + * Return: 0 on success and failure value on error > + */ > +static int __maybe_unused zynqmp_dma_suspend(struct device *dev) > +{ > + if (!device_may_wakeup(dev)) > + return pm_runtime_force_suspend(dev); > + > + return 0; > +} > + > +/** > + * zynqmp_dma_resume - Resume from suspend > + * @dev: Address of the device structure > + * > + * Resume operation after suspend. > + * Return: 0 on success and failure value on error > + */ > +static int __maybe_unused zynqmp_dma_resume(struct device *dev) > +{ > + if (!device_may_wakeup(dev)) > + return pm_runtime_force_resume(dev); > + > + return 0; > +} > + > +/** > + * zynqmp_dma_runtime_suspend - Runtime suspend method for the driver > + * @dev: Address of the device structure > + * > + * Put the driver into low power mode. > + * Return: 0 always > + */ > +static int __maybe_unused zynqmp_dma_runtime_suspend(struct device *dev) > +{ > + struct zynqmp_dma_device *zdev = dev_get_drvdata(dev); > + > + clk_disable_unprepare(zdev->clk_main); > + clk_disable_unprepare(zdev->clk_apb); > + > + return 0; > +} > + > +/** > + * zynqmp_dma_runtime_resume - Runtime suspend method for the driver > + * @dev: Address of the device structure > + * > + * Put the driver into low power mode. > + * Return: 0 always > + */ > +static int __maybe_unused zynqmp_dma_runtime_resume(struct device *dev) > +{ > + struct zynqmp_dma_device *zdev = dev_get_drvdata(dev); > + int err; > + > + err = clk_prepare_enable(zdev->clk_main); > + if (err) { > + dev_err(dev, "Unable to enable main clock.\n"); > + return err; > + } > + > + err = clk_prepare_enable(zdev->clk_apb); > + if (err) { > + dev_err(dev, "Unable to enable apb clock.\n"); > + clk_disable_unprepare(zdev->clk_main); > + return err; > + } > + > + return 0; > +} > + > +static const struct dev_pm_ops zynqmp_dma_dev_pm_ops = { > + SET_SYSTEM_SLEEP_PM_OPS(zynqmp_dma_suspend, zynqmp_dma_resume) > + SET_RUNTIME_PM_OPS(zynqmp_dma_runtime_suspend, > + zynqmp_dma_runtime_resume, NULL) > +}; > + > +/** > * zynqmp_dma_probe - Driver probe function > * @pdev: Pointer to the platform_device structure > * > @@ -984,12 +1048,39 @@ static int zynqmp_dma_probe(struct platform_device *pdev) > p->device_config = zynqmp_dma_device_config; > p->dev = &pdev->dev; > > + zdev->clk_main = devm_clk_get(&pdev->dev, "clk_main"); > + if (IS_ERR(zdev->clk_main)) { > + dev_err(&pdev->dev, "main clock not found.\n"); > + return PTR_ERR(zdev->clk_main); > + } > + > + zdev->clk_apb = devm_clk_get(&pdev->dev, "clk_apb"); > + if (IS_ERR(zdev->clk_apb)) { > + dev_err(&pdev->dev, "apb clock not found.\n"); > + return PTR_ERR(zdev->clk_apb); > + } > + > + ret = clk_prepare_enable(zdev->clk_main); > + if (ret) { > + dev_err(&pdev->dev, "Unable to enable main clock.\n"); > + return ret; > + } > + > + ret = clk_prepare_enable(zdev->clk_apb); > + if (ret) { > + dev_err(&pdev->dev, "Unable to enable apb clock.\n"); > + goto err_disable_clk; > + } > + > platform_set_drvdata(pdev, zdev); > + pm_runtime_set_autosuspend_delay(zdev->dev, ZDMA_PM_TIMEOUT); > + pm_runtime_use_autosuspend(zdev->dev); > + pm_runtime_enable(zdev->dev); > > ret = zynqmp_dma_chan_probe(zdev, pdev); > if (ret) { > dev_err(&pdev->dev, "Probing channel failed\n"); > - goto free_chan_resources; > + goto err_disable_pm; > } > > p->dst_addr_widths = BIT(zdev->chan->bus_width / 8); > @@ -1005,10 +1096,18 @@ static int zynqmp_dma_probe(struct platform_device *pdev) > goto free_chan_resources; > } > > + pm_runtime_mark_last_busy(zdev->dev); > + pm_runtime_put_sync_autosuspend(zdev->dev); > + > dev_info(&pdev->dev, "ZynqMP DMA driver Probe success\n"); > > return 0; > > +err_disable_clk: > + clk_disable_unprepare(zdev->clk_main); > +err_disable_pm: > + clk_disable_unprepare(zdev->clk_apb); > + pm_runtime_disable(zdev->dev); > free_chan_resources: > zynqmp_dma_chan_remove(zdev->chan); > return ret; > @@ -1028,6 +1127,9 @@ static int zynqmp_dma_remove(struct platform_device *pdev) > dma_async_device_unregister(&zdev->common); > > zynqmp_dma_chan_remove(zdev->chan); > + pm_runtime_disable(zdev->dev); > + clk_disable_unprepare(zdev->clk_apb); > + clk_disable_unprepare(zdev->clk_main); > > return 0; > } > @@ -1042,6 +1144,7 @@ static struct platform_driver zynqmp_dma_driver = { > .driver = { > .name = "xilinx-zynqmp-dma", > .of_match_table = zynqmp_dma_of_match, > + .pm = &zynqmp_dma_dev_pm_ops, > }, > .probe = zynqmp_dma_probe, > .remove = zynqmp_dma_remove, > CR number? M ^ permalink raw reply [flat|nested] 2+ messages in thread
* [PATCH] dmaengine: zynqmp_dma: Add runtime pm support 2017-10-20 6:31 ` [PATCH] dmaengine: zynqmp_dma: Add runtime pm support Michal Simek @ 2017-10-20 6:33 ` Michal Simek 0 siblings, 0 replies; 2+ messages in thread From: Michal Simek @ 2017-10-20 6:33 UTC (permalink / raw) To: linux-arm-kernel On 20.10.2017 08:31, Michal Simek wrote: > On 18.10.2017 09:02, Kedareswara rao Appana wrote: >> This patch adds runtime pm support in the driver. >> >> Signed-off-by: Kedareswara rao Appana <appanad@xilinx.com> >> --- >> drivers/dma/xilinx/zynqmp_dma.c | 167 ++++++++++++++++++++++++++++++++-------- >> 1 file changed, 135 insertions(+), 32 deletions(-) >> >> diff --git a/drivers/dma/xilinx/zynqmp_dma.c b/drivers/dma/xilinx/zynqmp_dma.c >> index 1ee1241..dd73831 100644 >> --- a/drivers/dma/xilinx/zynqmp_dma.c >> +++ b/drivers/dma/xilinx/zynqmp_dma.c >> @@ -23,6 +23,7 @@ >> #include <linux/slab.h> >> #include <linux/clk.h> >> #include <linux/io-64-nonatomic-lo-hi.h> >> +#include <linux/pm_runtime.h> >> >> #include "../dmaengine.h" >> >> @@ -138,6 +139,8 @@ >> #define ZYNQMP_DMA_BUS_WIDTH_64 64 >> #define ZYNQMP_DMA_BUS_WIDTH_128 128 >> >> +#define ZDMA_PM_TIMEOUT 100 >> + >> #define ZYNQMP_DMA_DESC_SIZE(chan) (chan->desc_size) >> >> #define to_chan(chan) container_of(chan, struct zynqmp_dma_chan, \ >> @@ -211,8 +214,6 @@ struct zynqmp_dma_desc_sw { >> * @bus_width: Bus width >> * @src_burst_len: Source burst length >> * @dst_burst_len: Dest burst length >> - * @clk_main: Pointer to main clock >> - * @clk_apb: Pointer to apb clock >> */ >> struct zynqmp_dma_chan { >> struct zynqmp_dma_device *zdev; >> @@ -237,8 +238,6 @@ struct zynqmp_dma_chan { >> u32 bus_width; >> u32 src_burst_len; >> u32 dst_burst_len; >> - struct clk *clk_main; >> - struct clk *clk_apb; >> }; >> >> /** >> @@ -246,11 +245,15 @@ struct zynqmp_dma_chan { >> * @dev: Device Structure >> * @common: DMA device structure >> * @chan: Driver specific DMA channel >> + * @clk_main: Pointer to main clock >> + * @clk_apb: Pointer to apb clock >> */ >> struct zynqmp_dma_device { >> struct device *dev; >> struct dma_device common; >> struct zynqmp_dma_chan *chan; >> + struct clk *clk_main; >> + struct clk *clk_apb; >> }; >> >> static inline void zynqmp_dma_writeq(struct zynqmp_dma_chan *chan, u32 reg, >> @@ -461,7 +464,11 @@ static int zynqmp_dma_alloc_chan_resources(struct dma_chan *dchan) >> { >> struct zynqmp_dma_chan *chan = to_chan(dchan); >> struct zynqmp_dma_desc_sw *desc; >> - int i; >> + int i, ret; >> + >> + ret = pm_runtime_get_sync(chan->dev); >> + if (ret < 0) >> + return ret; >> >> chan->sw_desc_pool = kzalloc(sizeof(*desc) * ZYNQMP_DMA_NUM_DESCS, >> GFP_KERNEL); >> @@ -664,6 +671,8 @@ static void zynqmp_dma_free_chan_resources(struct dma_chan *dchan) >> (2 * ZYNQMP_DMA_DESC_SIZE(chan) * ZYNQMP_DMA_NUM_DESCS), >> chan->desc_pool_v, chan->desc_pool_p); >> kfree(chan->sw_desc_pool); >> + pm_runtime_mark_last_busy(chan->dev); >> + pm_runtime_put_autosuspend(chan->dev); >> } >> >> /** >> @@ -841,8 +850,6 @@ static void zynqmp_dma_chan_remove(struct zynqmp_dma_chan *chan) >> devm_free_irq(chan->zdev->dev, chan->irq, chan); >> tasklet_kill(&chan->tasklet); >> list_del(&chan->common.device_node); >> - clk_disable_unprepare(chan->clk_apb); >> - clk_disable_unprepare(chan->clk_main); >> } >> >> /** >> @@ -907,30 +914,6 @@ static int zynqmp_dma_chan_probe(struct zynqmp_dma_device *zdev, >> "zynqmp-dma", chan); >> if (err) >> return err; >> - chan->clk_main = devm_clk_get(&pdev->dev, "clk_main"); >> - if (IS_ERR(chan->clk_main)) { >> - dev_err(&pdev->dev, "main clock not found.\n"); >> - return PTR_ERR(chan->clk_main); >> - } >> - >> - chan->clk_apb = devm_clk_get(&pdev->dev, "clk_apb"); >> - if (IS_ERR(chan->clk_apb)) { >> - dev_err(&pdev->dev, "apb clock not found.\n"); >> - return PTR_ERR(chan->clk_apb); >> - } >> - >> - err = clk_prepare_enable(chan->clk_main); >> - if (err) { >> - dev_err(&pdev->dev, "Unable to enable main clock.\n"); >> - return err; >> - } >> - >> - err = clk_prepare_enable(chan->clk_apb); >> - if (err) { >> - clk_disable_unprepare(chan->clk_main); >> - dev_err(&pdev->dev, "Unable to enable apb clock.\n"); >> - return err; >> - } >> >> chan->desc_size = sizeof(struct zynqmp_dma_desc_ll); >> chan->idle = true; >> @@ -953,6 +936,87 @@ static struct dma_chan *of_zynqmp_dma_xlate(struct of_phandle_args *dma_spec, >> } >> >> /** >> + * zynqmp_dma_suspend - Suspend method for the driver >> + * @dev: Address of the device structure >> + * >> + * Put the driver into low power mode. >> + * Return: 0 on success and failure value on error >> + */ >> +static int __maybe_unused zynqmp_dma_suspend(struct device *dev) >> +{ >> + if (!device_may_wakeup(dev)) >> + return pm_runtime_force_suspend(dev); >> + >> + return 0; >> +} >> + >> +/** >> + * zynqmp_dma_resume - Resume from suspend >> + * @dev: Address of the device structure >> + * >> + * Resume operation after suspend. >> + * Return: 0 on success and failure value on error >> + */ >> +static int __maybe_unused zynqmp_dma_resume(struct device *dev) >> +{ >> + if (!device_may_wakeup(dev)) >> + return pm_runtime_force_resume(dev); >> + >> + return 0; >> +} >> + >> +/** >> + * zynqmp_dma_runtime_suspend - Runtime suspend method for the driver >> + * @dev: Address of the device structure >> + * >> + * Put the driver into low power mode. >> + * Return: 0 always >> + */ >> +static int __maybe_unused zynqmp_dma_runtime_suspend(struct device *dev) >> +{ >> + struct zynqmp_dma_device *zdev = dev_get_drvdata(dev); >> + >> + clk_disable_unprepare(zdev->clk_main); >> + clk_disable_unprepare(zdev->clk_apb); >> + >> + return 0; >> +} >> + >> +/** >> + * zynqmp_dma_runtime_resume - Runtime suspend method for the driver >> + * @dev: Address of the device structure >> + * >> + * Put the driver into low power mode. >> + * Return: 0 always >> + */ >> +static int __maybe_unused zynqmp_dma_runtime_resume(struct device *dev) >> +{ >> + struct zynqmp_dma_device *zdev = dev_get_drvdata(dev); >> + int err; >> + >> + err = clk_prepare_enable(zdev->clk_main); >> + if (err) { >> + dev_err(dev, "Unable to enable main clock.\n"); >> + return err; >> + } >> + >> + err = clk_prepare_enable(zdev->clk_apb); >> + if (err) { >> + dev_err(dev, "Unable to enable apb clock.\n"); >> + clk_disable_unprepare(zdev->clk_main); >> + return err; >> + } >> + >> + return 0; >> +} >> + >> +static const struct dev_pm_ops zynqmp_dma_dev_pm_ops = { >> + SET_SYSTEM_SLEEP_PM_OPS(zynqmp_dma_suspend, zynqmp_dma_resume) >> + SET_RUNTIME_PM_OPS(zynqmp_dma_runtime_suspend, >> + zynqmp_dma_runtime_resume, NULL) >> +}; >> + >> +/** >> * zynqmp_dma_probe - Driver probe function >> * @pdev: Pointer to the platform_device structure >> * >> @@ -984,12 +1048,39 @@ static int zynqmp_dma_probe(struct platform_device *pdev) >> p->device_config = zynqmp_dma_device_config; >> p->dev = &pdev->dev; >> >> + zdev->clk_main = devm_clk_get(&pdev->dev, "clk_main"); >> + if (IS_ERR(zdev->clk_main)) { >> + dev_err(&pdev->dev, "main clock not found.\n"); >> + return PTR_ERR(zdev->clk_main); >> + } >> + >> + zdev->clk_apb = devm_clk_get(&pdev->dev, "clk_apb"); >> + if (IS_ERR(zdev->clk_apb)) { >> + dev_err(&pdev->dev, "apb clock not found.\n"); >> + return PTR_ERR(zdev->clk_apb); >> + } >> + >> + ret = clk_prepare_enable(zdev->clk_main); >> + if (ret) { >> + dev_err(&pdev->dev, "Unable to enable main clock.\n"); >> + return ret; >> + } >> + >> + ret = clk_prepare_enable(zdev->clk_apb); >> + if (ret) { >> + dev_err(&pdev->dev, "Unable to enable apb clock.\n"); >> + goto err_disable_clk; >> + } >> + >> platform_set_drvdata(pdev, zdev); >> + pm_runtime_set_autosuspend_delay(zdev->dev, ZDMA_PM_TIMEOUT); >> + pm_runtime_use_autosuspend(zdev->dev); >> + pm_runtime_enable(zdev->dev); >> >> ret = zynqmp_dma_chan_probe(zdev, pdev); >> if (ret) { >> dev_err(&pdev->dev, "Probing channel failed\n"); >> - goto free_chan_resources; >> + goto err_disable_pm; >> } >> >> p->dst_addr_widths = BIT(zdev->chan->bus_width / 8); >> @@ -1005,10 +1096,18 @@ static int zynqmp_dma_probe(struct platform_device *pdev) >> goto free_chan_resources; >> } >> >> + pm_runtime_mark_last_busy(zdev->dev); >> + pm_runtime_put_sync_autosuspend(zdev->dev); >> + >> dev_info(&pdev->dev, "ZynqMP DMA driver Probe success\n"); >> >> return 0; >> >> +err_disable_clk: >> + clk_disable_unprepare(zdev->clk_main); >> +err_disable_pm: >> + clk_disable_unprepare(zdev->clk_apb); >> + pm_runtime_disable(zdev->dev); >> free_chan_resources: >> zynqmp_dma_chan_remove(zdev->chan); >> return ret; >> @@ -1028,6 +1127,9 @@ static int zynqmp_dma_remove(struct platform_device *pdev) >> dma_async_device_unregister(&zdev->common); >> >> zynqmp_dma_chan_remove(zdev->chan); >> + pm_runtime_disable(zdev->dev); >> + clk_disable_unprepare(zdev->clk_apb); >> + clk_disable_unprepare(zdev->clk_main); >> >> return 0; >> } >> @@ -1042,6 +1144,7 @@ static struct platform_driver zynqmp_dma_driver = { >> .driver = { >> .name = "xilinx-zynqmp-dma", >> .of_match_table = zynqmp_dma_of_match, >> + .pm = &zynqmp_dma_dev_pm_ops, >> }, >> .probe = zynqmp_dma_probe, >> .remove = zynqmp_dma_remove, >> > > CR number? Please ignore this one - I thought it is coming to our soc vendor tree. :-) Cheers, Michal ^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2017-10-20 6:33 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <1508310126-10926-1-git-send-email-appanad@xilinx.com>
2017-10-20 6:31 ` [PATCH] dmaengine: zynqmp_dma: Add runtime pm support Michal Simek
2017-10-20 6:33 ` Michal Simek
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox