diff options
author | Arnd Bergmann <arnd@arndb.de> | 2013-03-26 10:53:57 -0400 |
---|---|---|
committer | Vinod Koul <vinod.koul@intel.com> | 2013-04-15 00:21:19 -0400 |
commit | f776076b9fa82d630651c9af56359d80fce86d68 (patch) | |
tree | cb88a7aaa7840ace28833955396c84fd8cef7f9b /drivers/dma | |
parent | bd2e6b664055a115a85be81af0ceb022726c5aef (diff) |
dmaengine: dw_dmac: simplify master selection
The patch to add the common DMA binding added a dummy dw_dma_slave
structure into the dw_dma_chan structure in order to configure the
masters correctly. It turns out that this can be simplified if we
pick the DMA masters in the dwc_alloc_chan_resources function instead
and save them in the dw_dma_chan structure directly.
This could be simplified further once all users that today use
dw_dma_slave for configuration get converted to device tree based
setup instead.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
Cc: linux-arm-kernel@lists.infradead.org
Acked-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Diffstat (limited to 'drivers/dma')
-rw-r--r-- | drivers/dma/dw_dmac.c | 76 | ||||
-rw-r--r-- | drivers/dma/dw_dmac_regs.h | 5 |
2 files changed, 33 insertions, 48 deletions
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c index 274fd7dd81f6..951ef5bc8afb 100644 --- a/drivers/dma/dw_dmac.c +++ b/drivers/dma/dw_dmac.c | |||
@@ -49,29 +49,22 @@ static inline unsigned int dwc_get_sms(struct dw_dma_slave *slave) | |||
49 | return slave ? slave->src_master : 1; | 49 | return slave ? slave->src_master : 1; |
50 | } | 50 | } |
51 | 51 | ||
52 | #define SRC_MASTER 0 | 52 | static inline void dwc_set_masters(struct dw_dma_chan *dwc) |
53 | #define DST_MASTER 1 | ||
54 | |||
55 | static inline unsigned int dwc_get_master(struct dma_chan *chan, int master) | ||
56 | { | 53 | { |
57 | struct dw_dma *dw = to_dw_dma(chan->device); | 54 | struct dw_dma *dw = to_dw_dma(dwc->chan.device); |
58 | struct dw_dma_slave *dws = chan->private; | 55 | struct dw_dma_slave *dws = dwc->chan.private; |
59 | unsigned int m; | 56 | unsigned char mmax = dw->nr_masters - 1; |
60 | |||
61 | if (master == SRC_MASTER) | ||
62 | m = dwc_get_sms(dws); | ||
63 | else | ||
64 | m = dwc_get_dms(dws); | ||
65 | 57 | ||
66 | return min_t(unsigned int, dw->nr_masters - 1, m); | 58 | if (dwc->request_line == ~0) { |
59 | dwc->src_master = min_t(unsigned char, mmax, dwc_get_sms(dws)); | ||
60 | dwc->dst_master = min_t(unsigned char, mmax, dwc_get_dms(dws)); | ||
61 | } | ||
67 | } | 62 | } |
68 | 63 | ||
69 | #define DWC_DEFAULT_CTLLO(_chan) ({ \ | 64 | #define DWC_DEFAULT_CTLLO(_chan) ({ \ |
70 | struct dw_dma_chan *_dwc = to_dw_dma_chan(_chan); \ | 65 | struct dw_dma_chan *_dwc = to_dw_dma_chan(_chan); \ |
71 | struct dma_slave_config *_sconfig = &_dwc->dma_sconfig; \ | 66 | struct dma_slave_config *_sconfig = &_dwc->dma_sconfig; \ |
72 | bool _is_slave = is_slave_direction(_dwc->direction); \ | 67 | bool _is_slave = is_slave_direction(_dwc->direction); \ |
73 | int _dms = dwc_get_master(_chan, DST_MASTER); \ | ||
74 | int _sms = dwc_get_master(_chan, SRC_MASTER); \ | ||
75 | u8 _smsize = _is_slave ? _sconfig->src_maxburst : \ | 68 | u8 _smsize = _is_slave ? _sconfig->src_maxburst : \ |
76 | DW_DMA_MSIZE_16; \ | 69 | DW_DMA_MSIZE_16; \ |
77 | u8 _dmsize = _is_slave ? _sconfig->dst_maxburst : \ | 70 | u8 _dmsize = _is_slave ? _sconfig->dst_maxburst : \ |
@@ -81,8 +74,8 @@ static inline unsigned int dwc_get_master(struct dma_chan *chan, int master) | |||
81 | | DWC_CTLL_SRC_MSIZE(_smsize) \ | 74 | | DWC_CTLL_SRC_MSIZE(_smsize) \ |
82 | | DWC_CTLL_LLP_D_EN \ | 75 | | DWC_CTLL_LLP_D_EN \ |
83 | | DWC_CTLL_LLP_S_EN \ | 76 | | DWC_CTLL_LLP_S_EN \ |
84 | | DWC_CTLL_DMS(_dms) \ | 77 | | DWC_CTLL_DMS(_dwc->dst_master) \ |
85 | | DWC_CTLL_SMS(_sms)); \ | 78 | | DWC_CTLL_SMS(_dwc->src_master)); \ |
86 | }) | 79 | }) |
87 | 80 | ||
88 | /* | 81 | /* |
@@ -92,13 +85,6 @@ static inline unsigned int dwc_get_master(struct dma_chan *chan, int master) | |||
92 | */ | 85 | */ |
93 | #define NR_DESCS_PER_CHANNEL 64 | 86 | #define NR_DESCS_PER_CHANNEL 64 |
94 | 87 | ||
95 | static inline unsigned int dwc_get_data_width(struct dma_chan *chan, int master) | ||
96 | { | ||
97 | struct dw_dma *dw = to_dw_dma(chan->device); | ||
98 | |||
99 | return dw->data_width[dwc_get_master(chan, master)]; | ||
100 | } | ||
101 | |||
102 | /*----------------------------------------------------------------------*/ | 88 | /*----------------------------------------------------------------------*/ |
103 | 89 | ||
104 | static struct device *chan2dev(struct dma_chan *chan) | 90 | static struct device *chan2dev(struct dma_chan *chan) |
@@ -172,13 +158,7 @@ static void dwc_initialize(struct dw_dma_chan *dwc) | |||
172 | if (dwc->initialized == true) | 158 | if (dwc->initialized == true) |
173 | return; | 159 | return; |
174 | 160 | ||
175 | if (dws && dws->cfg_hi == ~0 && dws->cfg_lo == ~0) { | 161 | if (dws) { |
176 | /* Autoconfigure based on request line from DT */ | ||
177 | if (dwc->direction == DMA_MEM_TO_DEV) | ||
178 | cfghi = DWC_CFGH_DST_PER(dwc->request_line); | ||
179 | else if (dwc->direction == DMA_DEV_TO_MEM) | ||
180 | cfghi = DWC_CFGH_SRC_PER(dwc->request_line); | ||
181 | } else if (dws) { | ||
182 | /* | 162 | /* |
183 | * We need controller-specific data to set up slave | 163 | * We need controller-specific data to set up slave |
184 | * transfers. | 164 | * transfers. |
@@ -189,9 +169,9 @@ static void dwc_initialize(struct dw_dma_chan *dwc) | |||
189 | cfglo |= dws->cfg_lo & ~DWC_CFGL_CH_PRIOR_MASK; | 169 | cfglo |= dws->cfg_lo & ~DWC_CFGL_CH_PRIOR_MASK; |
190 | } else { | 170 | } else { |
191 | if (dwc->direction == DMA_MEM_TO_DEV) | 171 | if (dwc->direction == DMA_MEM_TO_DEV) |
192 | cfghi = DWC_CFGH_DST_PER(dwc->dma_sconfig.slave_id); | 172 | cfghi = DWC_CFGH_DST_PER(dwc->request_line); |
193 | else if (dwc->direction == DMA_DEV_TO_MEM) | 173 | else if (dwc->direction == DMA_DEV_TO_MEM) |
194 | cfghi = DWC_CFGH_SRC_PER(dwc->dma_sconfig.slave_id); | 174 | cfghi = DWC_CFGH_SRC_PER(dwc->request_line); |
195 | } | 175 | } |
196 | 176 | ||
197 | channel_writel(dwc, CFG_LO, cfglo); | 177 | channel_writel(dwc, CFG_LO, cfglo); |
@@ -745,6 +725,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, | |||
745 | size_t len, unsigned long flags) | 725 | size_t len, unsigned long flags) |
746 | { | 726 | { |
747 | struct dw_dma_chan *dwc = to_dw_dma_chan(chan); | 727 | struct dw_dma_chan *dwc = to_dw_dma_chan(chan); |
728 | struct dw_dma *dw = to_dw_dma(chan->device); | ||
748 | struct dw_desc *desc; | 729 | struct dw_desc *desc; |
749 | struct dw_desc *first; | 730 | struct dw_desc *first; |
750 | struct dw_desc *prev; | 731 | struct dw_desc *prev; |
@@ -767,8 +748,8 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, | |||
767 | 748 | ||
768 | dwc->direction = DMA_MEM_TO_MEM; | 749 | dwc->direction = DMA_MEM_TO_MEM; |
769 | 750 | ||
770 | data_width = min_t(unsigned int, dwc_get_data_width(chan, SRC_MASTER), | 751 | data_width = min_t(unsigned int, dw->data_width[dwc->src_master], |
771 | dwc_get_data_width(chan, DST_MASTER)); | 752 | dw->data_width[dwc->dst_master]); |
772 | 753 | ||
773 | src_width = dst_width = min_t(unsigned int, data_width, | 754 | src_width = dst_width = min_t(unsigned int, data_width, |
774 | dwc_fast_fls(src | dest | len)); | 755 | dwc_fast_fls(src | dest | len)); |
@@ -826,6 +807,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, | |||
826 | unsigned long flags, void *context) | 807 | unsigned long flags, void *context) |
827 | { | 808 | { |
828 | struct dw_dma_chan *dwc = to_dw_dma_chan(chan); | 809 | struct dw_dma_chan *dwc = to_dw_dma_chan(chan); |
810 | struct dw_dma *dw = to_dw_dma(chan->device); | ||
829 | struct dma_slave_config *sconfig = &dwc->dma_sconfig; | 811 | struct dma_slave_config *sconfig = &dwc->dma_sconfig; |
830 | struct dw_desc *prev; | 812 | struct dw_desc *prev; |
831 | struct dw_desc *first; | 813 | struct dw_desc *first; |
@@ -859,7 +841,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, | |||
859 | ctllo |= sconfig->device_fc ? DWC_CTLL_FC(DW_DMA_FC_P_M2P) : | 841 | ctllo |= sconfig->device_fc ? DWC_CTLL_FC(DW_DMA_FC_P_M2P) : |
860 | DWC_CTLL_FC(DW_DMA_FC_D_M2P); | 842 | DWC_CTLL_FC(DW_DMA_FC_D_M2P); |
861 | 843 | ||
862 | data_width = dwc_get_data_width(chan, SRC_MASTER); | 844 | data_width = dw->data_width[dwc->src_master]; |
863 | 845 | ||
864 | for_each_sg(sgl, sg, sg_len, i) { | 846 | for_each_sg(sgl, sg, sg_len, i) { |
865 | struct dw_desc *desc; | 847 | struct dw_desc *desc; |
@@ -919,7 +901,7 @@ slave_sg_todev_fill_desc: | |||
919 | ctllo |= sconfig->device_fc ? DWC_CTLL_FC(DW_DMA_FC_P_P2M) : | 901 | ctllo |= sconfig->device_fc ? DWC_CTLL_FC(DW_DMA_FC_P_P2M) : |
920 | DWC_CTLL_FC(DW_DMA_FC_D_P2M); | 902 | DWC_CTLL_FC(DW_DMA_FC_D_P2M); |
921 | 903 | ||
922 | data_width = dwc_get_data_width(chan, DST_MASTER); | 904 | data_width = dw->data_width[dwc->dst_master]; |
923 | 905 | ||
924 | for_each_sg(sgl, sg, sg_len, i) { | 906 | for_each_sg(sgl, sg, sg_len, i) { |
925 | struct dw_desc *desc; | 907 | struct dw_desc *desc; |
@@ -1020,6 +1002,10 @@ set_runtime_config(struct dma_chan *chan, struct dma_slave_config *sconfig) | |||
1020 | memcpy(&dwc->dma_sconfig, sconfig, sizeof(*sconfig)); | 1002 | memcpy(&dwc->dma_sconfig, sconfig, sizeof(*sconfig)); |
1021 | dwc->direction = sconfig->direction; | 1003 | dwc->direction = sconfig->direction; |
1022 | 1004 | ||
1005 | /* Take the request line from slave_id member */ | ||
1006 | if (dwc->request_line == ~0) | ||
1007 | dwc->request_line = sconfig->slave_id; | ||
1008 | |||
1023 | convert_burst(&dwc->dma_sconfig.src_maxburst); | 1009 | convert_burst(&dwc->dma_sconfig.src_maxburst); |
1024 | convert_burst(&dwc->dma_sconfig.dst_maxburst); | 1010 | convert_burst(&dwc->dma_sconfig.dst_maxburst); |
1025 | convert_slave_id(dwc); | 1011 | convert_slave_id(dwc); |
@@ -1170,6 +1156,8 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan) | |||
1170 | * doesn't mean what you think it means), and status writeback. | 1156 | * doesn't mean what you think it means), and status writeback. |
1171 | */ | 1157 | */ |
1172 | 1158 | ||
1159 | dwc_set_masters(dwc); | ||
1160 | |||
1173 | spin_lock_irqsave(&dwc->lock, flags); | 1161 | spin_lock_irqsave(&dwc->lock, flags); |
1174 | i = dwc->descs_allocated; | 1162 | i = dwc->descs_allocated; |
1175 | while (dwc->descs_allocated < NR_DESCS_PER_CHANNEL) { | 1163 | while (dwc->descs_allocated < NR_DESCS_PER_CHANNEL) { |
@@ -1227,6 +1215,7 @@ static void dwc_free_chan_resources(struct dma_chan *chan) | |||
1227 | list_splice_init(&dwc->free_list, &list); | 1215 | list_splice_init(&dwc->free_list, &list); |
1228 | dwc->descs_allocated = 0; | 1216 | dwc->descs_allocated = 0; |
1229 | dwc->initialized = false; | 1217 | dwc->initialized = false; |
1218 | dwc->request_line = ~0; | ||
1230 | 1219 | ||
1231 | /* Disable interrupts */ | 1220 | /* Disable interrupts */ |
1232 | channel_clear_bit(dw, MASK.XFER, dwc->mask); | 1221 | channel_clear_bit(dw, MASK.XFER, dwc->mask); |
@@ -1254,23 +1243,15 @@ struct dw_dma_of_filter_args { | |||
1254 | static bool dw_dma_of_filter(struct dma_chan *chan, void *param) | 1243 | static bool dw_dma_of_filter(struct dma_chan *chan, void *param) |
1255 | { | 1244 | { |
1256 | struct dw_dma_chan *dwc = to_dw_dma_chan(chan); | 1245 | struct dw_dma_chan *dwc = to_dw_dma_chan(chan); |
1257 | struct dw_dma *dw = to_dw_dma(chan->device); | ||
1258 | struct dw_dma_of_filter_args *fargs = param; | 1246 | struct dw_dma_of_filter_args *fargs = param; |
1259 | struct dw_dma_slave *dws = &dwc->slave; | ||
1260 | 1247 | ||
1261 | /* Ensure the device matches our channel */ | 1248 | /* Ensure the device matches our channel */ |
1262 | if (chan->device != &fargs->dw->dma) | 1249 | if (chan->device != &fargs->dw->dma) |
1263 | return false; | 1250 | return false; |
1264 | 1251 | ||
1265 | dws->dma_dev = dw->dma.dev; | ||
1266 | dws->cfg_hi = ~0; | ||
1267 | dws->cfg_lo = ~0; | ||
1268 | dws->src_master = fargs->src; | ||
1269 | dws->dst_master = fargs->dst; | ||
1270 | |||
1271 | dwc->request_line = fargs->req; | 1252 | dwc->request_line = fargs->req; |
1272 | 1253 | dwc->src_master = fargs->src; | |
1273 | chan->private = dws; | 1254 | dwc->dst_master = fargs->dst; |
1274 | 1255 | ||
1275 | return true; | 1256 | return true; |
1276 | } | 1257 | } |
@@ -1784,6 +1765,7 @@ static int dw_probe(struct platform_device *pdev) | |||
1784 | channel_clear_bit(dw, CH_EN, dwc->mask); | 1765 | channel_clear_bit(dw, CH_EN, dwc->mask); |
1785 | 1766 | ||
1786 | dwc->direction = DMA_TRANS_NONE; | 1767 | dwc->direction = DMA_TRANS_NONE; |
1768 | dwc->request_line = ~0; | ||
1787 | 1769 | ||
1788 | /* Hardware configuration */ | 1770 | /* Hardware configuration */ |
1789 | if (autocfg) { | 1771 | if (autocfg) { |
diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h index 4d02c3669b75..9b0e12e85e31 100644 --- a/drivers/dma/dw_dmac_regs.h +++ b/drivers/dma/dw_dmac_regs.h | |||
@@ -212,8 +212,11 @@ struct dw_dma_chan { | |||
212 | /* hardware configuration */ | 212 | /* hardware configuration */ |
213 | unsigned int block_size; | 213 | unsigned int block_size; |
214 | bool nollp; | 214 | bool nollp; |
215 | |||
216 | /* custom slave configuration */ | ||
215 | unsigned int request_line; | 217 | unsigned int request_line; |
216 | struct dw_dma_slave slave; | 218 | unsigned char src_master; |
219 | unsigned char dst_master; | ||
217 | 220 | ||
218 | /* configuration passed via DMA_SLAVE_CONFIG */ | 221 | /* configuration passed via DMA_SLAVE_CONFIG */ |
219 | struct dma_slave_config dma_sconfig; | 222 | struct dma_slave_config dma_sconfig; |