Loading drivers/dma/xilinx/zynqmp_dma.c +128 −32 Original line number Diff line number Diff line Loading @@ -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" Loading Loading @@ -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, \ Loading Loading @@ -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; Loading @@ -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; }; /** Loading @@ -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, Loading Loading @@ -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); Loading Loading @@ -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); } /** Loading Loading @@ -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); } /** Loading Loading @@ -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; Loading @@ -952,6 +935,87 @@ static struct dma_chan *of_zynqmp_dma_xlate(struct of_phandle_args *dma_spec, return dma_get_slave_channel(&zdev->chan->common); } /** * 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 Loading Loading @@ -984,12 +1048,33 @@ 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); } 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); pm_runtime_get_sync(zdev->dev); if (!pm_runtime_enabled(zdev->dev)) { ret = zynqmp_dma_runtime_resume(zdev->dev); if (ret) return ret; } 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); Loading @@ -1005,12 +1090,19 @@ 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; free_chan_resources: zynqmp_dma_chan_remove(zdev->chan); err_disable_pm: if (!pm_runtime_enabled(zdev->dev)) zynqmp_dma_runtime_suspend(zdev->dev); pm_runtime_disable(zdev->dev); return ret; } Loading @@ -1028,6 +1120,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); if (!pm_runtime_enabled(zdev->dev)) zynqmp_dma_runtime_suspend(zdev->dev); return 0; } Loading @@ -1042,6 +1137,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, Loading Loading
drivers/dma/xilinx/zynqmp_dma.c +128 −32 Original line number Diff line number Diff line Loading @@ -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" Loading Loading @@ -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, \ Loading Loading @@ -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; Loading @@ -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; }; /** Loading @@ -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, Loading Loading @@ -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); Loading Loading @@ -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); } /** Loading Loading @@ -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); } /** Loading Loading @@ -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; Loading @@ -952,6 +935,87 @@ static struct dma_chan *of_zynqmp_dma_xlate(struct of_phandle_args *dma_spec, return dma_get_slave_channel(&zdev->chan->common); } /** * 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 Loading Loading @@ -984,12 +1048,33 @@ 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); } 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); pm_runtime_get_sync(zdev->dev); if (!pm_runtime_enabled(zdev->dev)) { ret = zynqmp_dma_runtime_resume(zdev->dev); if (ret) return ret; } 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); Loading @@ -1005,12 +1090,19 @@ 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; free_chan_resources: zynqmp_dma_chan_remove(zdev->chan); err_disable_pm: if (!pm_runtime_enabled(zdev->dev)) zynqmp_dma_runtime_suspend(zdev->dev); pm_runtime_disable(zdev->dev); return ret; } Loading @@ -1028,6 +1120,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); if (!pm_runtime_enabled(zdev->dev)) zynqmp_dma_runtime_suspend(zdev->dev); return 0; } Loading @@ -1042,6 +1137,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, Loading