diff options
author | Viresh Kumar <viresh.kumar@st.com> | 2012-02-01 05:42:26 -0500 |
---|---|---|
committer | Vinod Koul <vinod.koul@linux.intel.com> | 2012-02-22 07:45:38 -0500 |
commit | 327e6970258618da810f72e86cf2a8b803927e14 (patch) | |
tree | ce5d4ac48b3b21a3d70d0acceebaa8b9e212daa1 /drivers/dma/dw_dmac.c | |
parent | 6bc711f6bd9dd393e1f9bbae354906affcd02aa5 (diff) |
dmaengine/dw_dmac: Add support for DMA_SLAVE_CONFIG
This patch adds support for DMA_SLAVE_CONFIG in dwc DMAC controller. Fields in
struct dw_dma_slave for passing similar data are preserved in this patch untill
all existing users are fixed.
That will be handled later in this patchset.
Signed-off-by: Viresh Kumar <viresh.kumar@st.com>
Signed-off-by: Vinod Koul <vinod.koul@linux.intel.com>
Diffstat (limited to 'drivers/dma/dw_dmac.c')
-rw-r--r-- | drivers/dma/dw_dmac.c | 119 |
1 files changed, 90 insertions, 29 deletions
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c index 9f4310f013f5..0e4b5c6a2f86 100644 --- a/drivers/dma/dw_dmac.c +++ b/drivers/dma/dw_dmac.c | |||
@@ -9,6 +9,7 @@ | |||
9 | * it under the terms of the GNU General Public License version 2 as | 9 | * it under the terms of the GNU General Public License version 2 as |
10 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
11 | */ | 11 | */ |
12 | #include <linux/bitops.h> | ||
12 | #include <linux/clk.h> | 13 | #include <linux/clk.h> |
13 | #include <linux/delay.h> | 14 | #include <linux/delay.h> |
14 | #include <linux/dmaengine.h> | 15 | #include <linux/dmaengine.h> |
@@ -33,19 +34,23 @@ | |||
33 | * which does not support descriptor writeback. | 34 | * which does not support descriptor writeback. |
34 | */ | 35 | */ |
35 | 36 | ||
36 | #define DWC_DEFAULT_CTLLO(private) ({ \ | 37 | #define DWC_DEFAULT_CTLLO(_chan) ({ \ |
37 | struct dw_dma_slave *__slave = (private); \ | 38 | struct dw_dma_slave *__slave = (_chan->private); \ |
38 | int dms = __slave ? __slave->dst_master : 0; \ | 39 | struct dw_dma_chan *_dwc = to_dw_dma_chan(_chan); \ |
39 | int sms = __slave ? __slave->src_master : 1; \ | 40 | struct dma_slave_config *_sconfig = &_dwc->dma_sconfig; \ |
40 | u8 smsize = __slave ? __slave->src_msize : DW_DMA_MSIZE_16; \ | 41 | int _dms = __slave ? __slave->dst_master : 0; \ |
41 | u8 dmsize = __slave ? __slave->dst_msize : DW_DMA_MSIZE_16; \ | 42 | int _sms = __slave ? __slave->src_master : 1; \ |
43 | u8 _smsize = __slave ? _sconfig->src_maxburst : \ | ||
44 | DW_DMA_MSIZE_16; \ | ||
45 | u8 _dmsize = __slave ? _sconfig->dst_maxburst : \ | ||
46 | DW_DMA_MSIZE_16; \ | ||
42 | \ | 47 | \ |
43 | (DWC_CTLL_DST_MSIZE(dmsize) \ | 48 | (DWC_CTLL_DST_MSIZE(_dmsize) \ |
44 | | DWC_CTLL_SRC_MSIZE(smsize) \ | 49 | | DWC_CTLL_SRC_MSIZE(_smsize) \ |
45 | | DWC_CTLL_LLP_D_EN \ | 50 | | DWC_CTLL_LLP_D_EN \ |
46 | | DWC_CTLL_LLP_S_EN \ | 51 | | DWC_CTLL_LLP_S_EN \ |
47 | | DWC_CTLL_DMS(dms) \ | 52 | | DWC_CTLL_DMS(_dms) \ |
48 | | DWC_CTLL_SMS(sms)); \ | 53 | | DWC_CTLL_SMS(_sms)); \ |
49 | }) | 54 | }) |
50 | 55 | ||
51 | /* | 56 | /* |
@@ -656,7 +661,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, | |||
656 | else | 661 | else |
657 | src_width = dst_width = 0; | 662 | src_width = dst_width = 0; |
658 | 663 | ||
659 | ctllo = DWC_DEFAULT_CTLLO(chan->private) | 664 | ctllo = DWC_DEFAULT_CTLLO(chan) |
660 | | DWC_CTLL_DST_WIDTH(dst_width) | 665 | | DWC_CTLL_DST_WIDTH(dst_width) |
661 | | DWC_CTLL_SRC_WIDTH(src_width) | 666 | | DWC_CTLL_SRC_WIDTH(src_width) |
662 | | DWC_CTLL_DST_INC | 667 | | DWC_CTLL_DST_INC |
@@ -717,6 +722,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, | |||
717 | { | 722 | { |
718 | struct dw_dma_chan *dwc = to_dw_dma_chan(chan); | 723 | struct dw_dma_chan *dwc = to_dw_dma_chan(chan); |
719 | struct dw_dma_slave *dws = chan->private; | 724 | struct dw_dma_slave *dws = chan->private; |
725 | struct dma_slave_config *sconfig = &dwc->dma_sconfig; | ||
720 | struct dw_desc *prev; | 726 | struct dw_desc *prev; |
721 | struct dw_desc *first; | 727 | struct dw_desc *first; |
722 | u32 ctllo; | 728 | u32 ctllo; |
@@ -732,17 +738,20 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, | |||
732 | if (unlikely(!dws || !sg_len)) | 738 | if (unlikely(!dws || !sg_len)) |
733 | return NULL; | 739 | return NULL; |
734 | 740 | ||
735 | reg_width = dws->reg_width; | ||
736 | prev = first = NULL; | 741 | prev = first = NULL; |
737 | 742 | ||
738 | switch (direction) { | 743 | switch (direction) { |
739 | case DMA_MEM_TO_DEV: | 744 | case DMA_MEM_TO_DEV: |
740 | ctllo = (DWC_DEFAULT_CTLLO(chan->private) | 745 | reg_width = __fls(sconfig->dst_addr_width); |
746 | reg = sconfig->dst_addr; | ||
747 | ctllo = (DWC_DEFAULT_CTLLO(chan) | ||
741 | | DWC_CTLL_DST_WIDTH(reg_width) | 748 | | DWC_CTLL_DST_WIDTH(reg_width) |
742 | | DWC_CTLL_DST_FIX | 749 | | DWC_CTLL_DST_FIX |
743 | | DWC_CTLL_SRC_INC | 750 | | DWC_CTLL_SRC_INC); |
744 | | DWC_CTLL_FC(dws->fc)); | 751 | |
745 | reg = dws->tx_reg; | 752 | ctllo |= sconfig->device_fc ? DWC_CTLL_FC(DW_DMA_FC_P_M2P) : |
753 | DWC_CTLL_FC(DW_DMA_FC_D_M2P); | ||
754 | |||
746 | for_each_sg(sgl, sg, sg_len, i) { | 755 | for_each_sg(sgl, sg, sg_len, i) { |
747 | struct dw_desc *desc; | 756 | struct dw_desc *desc; |
748 | u32 len, dlen, mem; | 757 | u32 len, dlen, mem; |
@@ -800,13 +809,16 @@ slave_sg_todev_fill_desc: | |||
800 | } | 809 | } |
801 | break; | 810 | break; |
802 | case DMA_DEV_TO_MEM: | 811 | case DMA_DEV_TO_MEM: |
803 | ctllo = (DWC_DEFAULT_CTLLO(chan->private) | 812 | reg_width = __fls(sconfig->src_addr_width); |
813 | reg = sconfig->src_addr; | ||
814 | ctllo = (DWC_DEFAULT_CTLLO(chan) | ||
804 | | DWC_CTLL_SRC_WIDTH(reg_width) | 815 | | DWC_CTLL_SRC_WIDTH(reg_width) |
805 | | DWC_CTLL_DST_INC | 816 | | DWC_CTLL_DST_INC |
806 | | DWC_CTLL_SRC_FIX | 817 | | DWC_CTLL_SRC_FIX); |
807 | | DWC_CTLL_FC(dws->fc)); | 818 | |
819 | ctllo |= sconfig->device_fc ? DWC_CTLL_FC(DW_DMA_FC_P_P2M) : | ||
820 | DWC_CTLL_FC(DW_DMA_FC_D_P2M); | ||
808 | 821 | ||
809 | reg = dws->rx_reg; | ||
810 | for_each_sg(sgl, sg, sg_len, i) { | 822 | for_each_sg(sgl, sg, sg_len, i) { |
811 | struct dw_desc *desc; | 823 | struct dw_desc *desc; |
812 | u32 len, dlen, mem; | 824 | u32 len, dlen, mem; |
@@ -884,6 +896,39 @@ err_desc_get: | |||
884 | return NULL; | 896 | return NULL; |
885 | } | 897 | } |
886 | 898 | ||
899 | /* | ||
900 | * Fix sconfig's burst size according to dw_dmac. We need to convert them as: | ||
901 | * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3. | ||
902 | * | ||
903 | * NOTE: burst size 2 is not supported by controller. | ||
904 | * | ||
905 | * This can be done by finding least significant bit set: n & (n - 1) | ||
906 | */ | ||
907 | static inline void convert_burst(u32 *maxburst) | ||
908 | { | ||
909 | if (*maxburst > 1) | ||
910 | *maxburst = fls(*maxburst) - 2; | ||
911 | else | ||
912 | *maxburst = 0; | ||
913 | } | ||
914 | |||
915 | static int | ||
916 | set_runtime_config(struct dma_chan *chan, struct dma_slave_config *sconfig) | ||
917 | { | ||
918 | struct dw_dma_chan *dwc = to_dw_dma_chan(chan); | ||
919 | |||
920 | /* Check if it is chan is configured for slave transfers */ | ||
921 | if (!chan->private) | ||
922 | return -EINVAL; | ||
923 | |||
924 | memcpy(&dwc->dma_sconfig, sconfig, sizeof(*sconfig)); | ||
925 | |||
926 | convert_burst(&dwc->dma_sconfig.src_maxburst); | ||
927 | convert_burst(&dwc->dma_sconfig.dst_maxburst); | ||
928 | |||
929 | return 0; | ||
930 | } | ||
931 | |||
887 | static int dwc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, | 932 | static int dwc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, |
888 | unsigned long arg) | 933 | unsigned long arg) |
889 | { | 934 | { |
@@ -933,8 +978,11 @@ static int dwc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, | |||
933 | /* Flush all pending and queued descriptors */ | 978 | /* Flush all pending and queued descriptors */ |
934 | list_for_each_entry_safe(desc, _desc, &list, desc_node) | 979 | list_for_each_entry_safe(desc, _desc, &list, desc_node) |
935 | dwc_descriptor_complete(dwc, desc, false); | 980 | dwc_descriptor_complete(dwc, desc, false); |
936 | } else | 981 | } else if (cmd == DMA_SLAVE_CONFIG) { |
982 | return set_runtime_config(chan, (struct dma_slave_config *)arg); | ||
983 | } else { | ||
937 | return -ENXIO; | 984 | return -ENXIO; |
985 | } | ||
938 | 986 | ||
939 | return 0; | 987 | return 0; |
940 | } | 988 | } |
@@ -1167,11 +1215,11 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan, | |||
1167 | enum dma_transfer_direction direction) | 1215 | enum dma_transfer_direction direction) |
1168 | { | 1216 | { |
1169 | struct dw_dma_chan *dwc = to_dw_dma_chan(chan); | 1217 | struct dw_dma_chan *dwc = to_dw_dma_chan(chan); |
1218 | struct dma_slave_config *sconfig = &dwc->dma_sconfig; | ||
1170 | struct dw_cyclic_desc *cdesc; | 1219 | struct dw_cyclic_desc *cdesc; |
1171 | struct dw_cyclic_desc *retval = NULL; | 1220 | struct dw_cyclic_desc *retval = NULL; |
1172 | struct dw_desc *desc; | 1221 | struct dw_desc *desc; |
1173 | struct dw_desc *last = NULL; | 1222 | struct dw_desc *last = NULL; |
1174 | struct dw_dma_slave *dws = chan->private; | ||
1175 | unsigned long was_cyclic; | 1223 | unsigned long was_cyclic; |
1176 | unsigned int reg_width; | 1224 | unsigned int reg_width; |
1177 | unsigned int periods; | 1225 | unsigned int periods; |
@@ -1195,7 +1243,12 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan, | |||
1195 | } | 1243 | } |
1196 | 1244 | ||
1197 | retval = ERR_PTR(-EINVAL); | 1245 | retval = ERR_PTR(-EINVAL); |
1198 | reg_width = dws->reg_width; | 1246 | |
1247 | if (direction == DMA_MEM_TO_DEV) | ||
1248 | reg_width = __ffs(sconfig->dst_addr_width); | ||
1249 | else | ||
1250 | reg_width = __ffs(sconfig->src_addr_width); | ||
1251 | |||
1199 | periods = buf_len / period_len; | 1252 | periods = buf_len / period_len; |
1200 | 1253 | ||
1201 | /* Check for too big/unaligned periods and unaligned DMA buffer. */ | 1254 | /* Check for too big/unaligned periods and unaligned DMA buffer. */ |
@@ -1228,26 +1281,34 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan, | |||
1228 | 1281 | ||
1229 | switch (direction) { | 1282 | switch (direction) { |
1230 | case DMA_MEM_TO_DEV: | 1283 | case DMA_MEM_TO_DEV: |
1231 | desc->lli.dar = dws->tx_reg; | 1284 | desc->lli.dar = sconfig->dst_addr; |
1232 | desc->lli.sar = buf_addr + (period_len * i); | 1285 | desc->lli.sar = buf_addr + (period_len * i); |
1233 | desc->lli.ctllo = (DWC_DEFAULT_CTLLO(chan->private) | 1286 | desc->lli.ctllo = (DWC_DEFAULT_CTLLO(chan) |
1234 | | DWC_CTLL_DST_WIDTH(reg_width) | 1287 | | DWC_CTLL_DST_WIDTH(reg_width) |
1235 | | DWC_CTLL_SRC_WIDTH(reg_width) | 1288 | | DWC_CTLL_SRC_WIDTH(reg_width) |
1236 | | DWC_CTLL_DST_FIX | 1289 | | DWC_CTLL_DST_FIX |
1237 | | DWC_CTLL_SRC_INC | 1290 | | DWC_CTLL_SRC_INC |
1238 | | DWC_CTLL_FC(dws->fc) | ||
1239 | | DWC_CTLL_INT_EN); | 1291 | | DWC_CTLL_INT_EN); |
1292 | |||
1293 | desc->lli.ctllo |= sconfig->device_fc ? | ||
1294 | DWC_CTLL_FC(DW_DMA_FC_P_M2P) : | ||
1295 | DWC_CTLL_FC(DW_DMA_FC_D_M2P); | ||
1296 | |||
1240 | break; | 1297 | break; |
1241 | case DMA_DEV_TO_MEM: | 1298 | case DMA_DEV_TO_MEM: |
1242 | desc->lli.dar = buf_addr + (period_len * i); | 1299 | desc->lli.dar = buf_addr + (period_len * i); |
1243 | desc->lli.sar = dws->rx_reg; | 1300 | desc->lli.sar = sconfig->src_addr; |
1244 | desc->lli.ctllo = (DWC_DEFAULT_CTLLO(chan->private) | 1301 | desc->lli.ctllo = (DWC_DEFAULT_CTLLO(chan) |
1245 | | DWC_CTLL_SRC_WIDTH(reg_width) | 1302 | | DWC_CTLL_SRC_WIDTH(reg_width) |
1246 | | DWC_CTLL_DST_WIDTH(reg_width) | 1303 | | DWC_CTLL_DST_WIDTH(reg_width) |
1247 | | DWC_CTLL_DST_INC | 1304 | | DWC_CTLL_DST_INC |
1248 | | DWC_CTLL_SRC_FIX | 1305 | | DWC_CTLL_SRC_FIX |
1249 | | DWC_CTLL_FC(dws->fc) | ||
1250 | | DWC_CTLL_INT_EN); | 1306 | | DWC_CTLL_INT_EN); |
1307 | |||
1308 | desc->lli.ctllo |= sconfig->device_fc ? | ||
1309 | DWC_CTLL_FC(DW_DMA_FC_P_P2M) : | ||
1310 | DWC_CTLL_FC(DW_DMA_FC_D_P2M); | ||
1311 | |||
1251 | break; | 1312 | break; |
1252 | default: | 1313 | default: |
1253 | break; | 1314 | break; |