aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKedareswara rao Appana <appana.durga.rao@xilinx.com>2017-12-07 00:29:57 -0500
committerVinod Koul <vinod.koul@intel.com>2017-12-17 22:58:09 -0500
commit64c6f7da8c2cab6bcf9c04b2eb8ea9afca31c186 (patch)
tree6a6f89228181bdc8ba5105606769e35137ac121a
parent4fbd8d194f06c8a3fd2af1ce560ddb31f7ec8323 (diff)
dmaengine: zynqmp_dma: Add runtime pm support
This patch adds runtime pm support in the driver. Signed-off-by: Kedareswara rao Appana <appanad@xilinx.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
-rw-r--r--drivers/dma/xilinx/zynqmp_dma.c160
1 files changed, 128 insertions, 32 deletions
diff --git a/drivers/dma/xilinx/zynqmp_dma.c b/drivers/dma/xilinx/zynqmp_dma.c
index 1ee1241ca797..4fa14bf91073 100644
--- a/drivers/dma/xilinx/zynqmp_dma.c
+++ b/drivers/dma/xilinx/zynqmp_dma.c
@@ -23,6 +23,7 @@
23#include <linux/slab.h> 23#include <linux/slab.h>
24#include <linux/clk.h> 24#include <linux/clk.h>
25#include <linux/io-64-nonatomic-lo-hi.h> 25#include <linux/io-64-nonatomic-lo-hi.h>
26#include <linux/pm_runtime.h>
26 27
27#include "../dmaengine.h" 28#include "../dmaengine.h"
28 29
@@ -138,6 +139,8 @@
138#define ZYNQMP_DMA_BUS_WIDTH_64 64 139#define ZYNQMP_DMA_BUS_WIDTH_64 64
139#define ZYNQMP_DMA_BUS_WIDTH_128 128 140#define ZYNQMP_DMA_BUS_WIDTH_128 128
140 141
142#define ZDMA_PM_TIMEOUT 100
143
141#define ZYNQMP_DMA_DESC_SIZE(chan) (chan->desc_size) 144#define ZYNQMP_DMA_DESC_SIZE(chan) (chan->desc_size)
142 145
143#define to_chan(chan) container_of(chan, struct zynqmp_dma_chan, \ 146#define to_chan(chan) container_of(chan, struct zynqmp_dma_chan, \
@@ -211,8 +214,6 @@ struct zynqmp_dma_desc_sw {
211 * @bus_width: Bus width 214 * @bus_width: Bus width
212 * @src_burst_len: Source burst length 215 * @src_burst_len: Source burst length
213 * @dst_burst_len: Dest burst length 216 * @dst_burst_len: Dest burst length
214 * @clk_main: Pointer to main clock
215 * @clk_apb: Pointer to apb clock
216 */ 217 */
217struct zynqmp_dma_chan { 218struct zynqmp_dma_chan {
218 struct zynqmp_dma_device *zdev; 219 struct zynqmp_dma_device *zdev;
@@ -237,8 +238,6 @@ struct zynqmp_dma_chan {
237 u32 bus_width; 238 u32 bus_width;
238 u32 src_burst_len; 239 u32 src_burst_len;
239 u32 dst_burst_len; 240 u32 dst_burst_len;
240 struct clk *clk_main;
241 struct clk *clk_apb;
242}; 241};
243 242
244/** 243/**
@@ -246,11 +245,15 @@ struct zynqmp_dma_chan {
246 * @dev: Device Structure 245 * @dev: Device Structure
247 * @common: DMA device structure 246 * @common: DMA device structure
248 * @chan: Driver specific DMA channel 247 * @chan: Driver specific DMA channel
248 * @clk_main: Pointer to main clock
249 * @clk_apb: Pointer to apb clock
249 */ 250 */
250struct zynqmp_dma_device { 251struct zynqmp_dma_device {
251 struct device *dev; 252 struct device *dev;
252 struct dma_device common; 253 struct dma_device common;
253 struct zynqmp_dma_chan *chan; 254 struct zynqmp_dma_chan *chan;
255 struct clk *clk_main;
256 struct clk *clk_apb;
254}; 257};
255 258
256static inline void zynqmp_dma_writeq(struct zynqmp_dma_chan *chan, u32 reg, 259static 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)
461{ 464{
462 struct zynqmp_dma_chan *chan = to_chan(dchan); 465 struct zynqmp_dma_chan *chan = to_chan(dchan);
463 struct zynqmp_dma_desc_sw *desc; 466 struct zynqmp_dma_desc_sw *desc;
464 int i; 467 int i, ret;
468
469 ret = pm_runtime_get_sync(chan->dev);
470 if (ret < 0)
471 return ret;
465 472
466 chan->sw_desc_pool = kzalloc(sizeof(*desc) * ZYNQMP_DMA_NUM_DESCS, 473 chan->sw_desc_pool = kzalloc(sizeof(*desc) * ZYNQMP_DMA_NUM_DESCS,
467 GFP_KERNEL); 474 GFP_KERNEL);
@@ -664,6 +671,8 @@ static void zynqmp_dma_free_chan_resources(struct dma_chan *dchan)
664 (2 * ZYNQMP_DMA_DESC_SIZE(chan) * ZYNQMP_DMA_NUM_DESCS), 671 (2 * ZYNQMP_DMA_DESC_SIZE(chan) * ZYNQMP_DMA_NUM_DESCS),
665 chan->desc_pool_v, chan->desc_pool_p); 672 chan->desc_pool_v, chan->desc_pool_p);
666 kfree(chan->sw_desc_pool); 673 kfree(chan->sw_desc_pool);
674 pm_runtime_mark_last_busy(chan->dev);
675 pm_runtime_put_autosuspend(chan->dev);
667} 676}
668 677
669/** 678/**
@@ -841,8 +850,6 @@ static void zynqmp_dma_chan_remove(struct zynqmp_dma_chan *chan)
841 devm_free_irq(chan->zdev->dev, chan->irq, chan); 850 devm_free_irq(chan->zdev->dev, chan->irq, chan);
842 tasklet_kill(&chan->tasklet); 851 tasklet_kill(&chan->tasklet);
843 list_del(&chan->common.device_node); 852 list_del(&chan->common.device_node);
844 clk_disable_unprepare(chan->clk_apb);
845 clk_disable_unprepare(chan->clk_main);
846} 853}
847 854
848/** 855/**
@@ -907,30 +914,6 @@ static int zynqmp_dma_chan_probe(struct zynqmp_dma_device *zdev,
907 "zynqmp-dma", chan); 914 "zynqmp-dma", chan);
908 if (err) 915 if (err)
909 return err; 916 return err;
910 chan->clk_main = devm_clk_get(&pdev->dev, "clk_main");
911 if (IS_ERR(chan->clk_main)) {
912 dev_err(&pdev->dev, "main clock not found.\n");
913 return PTR_ERR(chan->clk_main);
914 }
915
916 chan->clk_apb = devm_clk_get(&pdev->dev, "clk_apb");
917 if (IS_ERR(chan->clk_apb)) {
918 dev_err(&pdev->dev, "apb clock not found.\n");
919 return PTR_ERR(chan->clk_apb);
920 }
921
922 err = clk_prepare_enable(chan->clk_main);
923 if (err) {
924 dev_err(&pdev->dev, "Unable to enable main clock.\n");
925 return err;
926 }
927
928 err = clk_prepare_enable(chan->clk_apb);
929 if (err) {
930 clk_disable_unprepare(chan->clk_main);
931 dev_err(&pdev->dev, "Unable to enable apb clock.\n");
932 return err;
933 }
934 917
935 chan->desc_size = sizeof(struct zynqmp_dma_desc_ll); 918 chan->desc_size = sizeof(struct zynqmp_dma_desc_ll);
936 chan->idle = true; 919 chan->idle = true;
@@ -953,6 +936,87 @@ static struct dma_chan *of_zynqmp_dma_xlate(struct of_phandle_args *dma_spec,
953} 936}
954 937
955/** 938/**
939 * zynqmp_dma_suspend - Suspend method for the driver
940 * @dev: Address of the device structure
941 *
942 * Put the driver into low power mode.
943 * Return: 0 on success and failure value on error
944 */
945static int __maybe_unused zynqmp_dma_suspend(struct device *dev)
946{
947 if (!device_may_wakeup(dev))
948 return pm_runtime_force_suspend(dev);
949
950 return 0;
951}
952
953/**
954 * zynqmp_dma_resume - Resume from suspend
955 * @dev: Address of the device structure
956 *
957 * Resume operation after suspend.
958 * Return: 0 on success and failure value on error
959 */
960static int __maybe_unused zynqmp_dma_resume(struct device *dev)
961{
962 if (!device_may_wakeup(dev))
963 return pm_runtime_force_resume(dev);
964
965 return 0;
966}
967
968/**
969 * zynqmp_dma_runtime_suspend - Runtime suspend method for the driver
970 * @dev: Address of the device structure
971 *
972 * Put the driver into low power mode.
973 * Return: 0 always
974 */
975static int __maybe_unused zynqmp_dma_runtime_suspend(struct device *dev)
976{
977 struct zynqmp_dma_device *zdev = dev_get_drvdata(dev);
978
979 clk_disable_unprepare(zdev->clk_main);
980 clk_disable_unprepare(zdev->clk_apb);
981
982 return 0;
983}
984
985/**
986 * zynqmp_dma_runtime_resume - Runtime suspend method for the driver
987 * @dev: Address of the device structure
988 *
989 * Put the driver into low power mode.
990 * Return: 0 always
991 */
992static int __maybe_unused zynqmp_dma_runtime_resume(struct device *dev)
993{
994 struct zynqmp_dma_device *zdev = dev_get_drvdata(dev);
995 int err;
996
997 err = clk_prepare_enable(zdev->clk_main);
998 if (err) {
999 dev_err(dev, "Unable to enable main clock.\n");
1000 return err;
1001 }
1002
1003 err = clk_prepare_enable(zdev->clk_apb);
1004 if (err) {
1005 dev_err(dev, "Unable to enable apb clock.\n");
1006 clk_disable_unprepare(zdev->clk_main);
1007 return err;
1008 }
1009
1010 return 0;
1011}
1012
1013static const struct dev_pm_ops zynqmp_dma_dev_pm_ops = {
1014 SET_SYSTEM_SLEEP_PM_OPS(zynqmp_dma_suspend, zynqmp_dma_resume)
1015 SET_RUNTIME_PM_OPS(zynqmp_dma_runtime_suspend,
1016 zynqmp_dma_runtime_resume, NULL)
1017};
1018
1019/**
956 * zynqmp_dma_probe - Driver probe function 1020 * zynqmp_dma_probe - Driver probe function
957 * @pdev: Pointer to the platform_device structure 1021 * @pdev: Pointer to the platform_device structure
958 * 1022 *
@@ -984,12 +1048,33 @@ static int zynqmp_dma_probe(struct platform_device *pdev)
984 p->device_config = zynqmp_dma_device_config; 1048 p->device_config = zynqmp_dma_device_config;
985 p->dev = &pdev->dev; 1049 p->dev = &pdev->dev;
986 1050
1051 zdev->clk_main = devm_clk_get(&pdev->dev, "clk_main");
1052 if (IS_ERR(zdev->clk_main)) {
1053 dev_err(&pdev->dev, "main clock not found.\n");
1054 return PTR_ERR(zdev->clk_main);
1055 }
1056
1057 zdev->clk_apb = devm_clk_get(&pdev->dev, "clk_apb");
1058 if (IS_ERR(zdev->clk_apb)) {
1059 dev_err(&pdev->dev, "apb clock not found.\n");
1060 return PTR_ERR(zdev->clk_apb);
1061 }
1062
987 platform_set_drvdata(pdev, zdev); 1063 platform_set_drvdata(pdev, zdev);
1064 pm_runtime_set_autosuspend_delay(zdev->dev, ZDMA_PM_TIMEOUT);
1065 pm_runtime_use_autosuspend(zdev->dev);
1066 pm_runtime_enable(zdev->dev);
1067 pm_runtime_get_sync(zdev->dev);
1068 if (!pm_runtime_enabled(zdev->dev)) {
1069 ret = zynqmp_dma_runtime_resume(zdev->dev);
1070 if (ret)
1071 return ret;
1072 }
988 1073
989 ret = zynqmp_dma_chan_probe(zdev, pdev); 1074 ret = zynqmp_dma_chan_probe(zdev, pdev);
990 if (ret) { 1075 if (ret) {
991 dev_err(&pdev->dev, "Probing channel failed\n"); 1076 dev_err(&pdev->dev, "Probing channel failed\n");
992 goto free_chan_resources; 1077 goto err_disable_pm;
993 } 1078 }
994 1079
995 p->dst_addr_widths = BIT(zdev->chan->bus_width / 8); 1080 p->dst_addr_widths = BIT(zdev->chan->bus_width / 8);
@@ -1005,12 +1090,19 @@ static int zynqmp_dma_probe(struct platform_device *pdev)
1005 goto free_chan_resources; 1090 goto free_chan_resources;
1006 } 1091 }
1007 1092
1093 pm_runtime_mark_last_busy(zdev->dev);
1094 pm_runtime_put_sync_autosuspend(zdev->dev);
1095
1008 dev_info(&pdev->dev, "ZynqMP DMA driver Probe success\n"); 1096 dev_info(&pdev->dev, "ZynqMP DMA driver Probe success\n");
1009 1097
1010 return 0; 1098 return 0;
1011 1099
1012free_chan_resources: 1100free_chan_resources:
1013 zynqmp_dma_chan_remove(zdev->chan); 1101 zynqmp_dma_chan_remove(zdev->chan);
1102err_disable_pm:
1103 if (!pm_runtime_enabled(zdev->dev))
1104 zynqmp_dma_runtime_suspend(zdev->dev);
1105 pm_runtime_disable(zdev->dev);
1014 return ret; 1106 return ret;
1015} 1107}
1016 1108
@@ -1028,6 +1120,9 @@ static int zynqmp_dma_remove(struct platform_device *pdev)
1028 dma_async_device_unregister(&zdev->common); 1120 dma_async_device_unregister(&zdev->common);
1029 1121
1030 zynqmp_dma_chan_remove(zdev->chan); 1122 zynqmp_dma_chan_remove(zdev->chan);
1123 pm_runtime_disable(zdev->dev);
1124 if (!pm_runtime_enabled(zdev->dev))
1125 zynqmp_dma_runtime_suspend(zdev->dev);
1031 1126
1032 return 0; 1127 return 0;
1033} 1128}
@@ -1042,6 +1137,7 @@ static struct platform_driver zynqmp_dma_driver = {
1042 .driver = { 1137 .driver = {
1043 .name = "xilinx-zynqmp-dma", 1138 .name = "xilinx-zynqmp-dma",
1044 .of_match_table = zynqmp_dma_of_match, 1139 .of_match_table = zynqmp_dma_of_match,
1140 .pm = &zynqmp_dma_dev_pm_ops,
1045 }, 1141 },
1046 .probe = zynqmp_dma_probe, 1142 .probe = zynqmp_dma_probe,
1047 .remove = zynqmp_dma_remove, 1143 .remove = zynqmp_dma_remove,