diff options
Diffstat (limited to 'drivers/dma/at_hdmac.c')
-rw-r--r-- | drivers/dma/at_hdmac.c | 211 |
1 files changed, 149 insertions, 62 deletions
diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index e923cda930f9..c787f38a186a 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c | |||
@@ -14,6 +14,7 @@ | |||
14 | * found on AT91SAM9263. | 14 | * found on AT91SAM9263. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <dt-bindings/dma/at91.h> | ||
17 | #include <linux/clk.h> | 18 | #include <linux/clk.h> |
18 | #include <linux/dmaengine.h> | 19 | #include <linux/dmaengine.h> |
19 | #include <linux/dma-mapping.h> | 20 | #include <linux/dma-mapping.h> |
@@ -54,6 +55,7 @@ MODULE_PARM_DESC(init_nr_desc_per_channel, | |||
54 | 55 | ||
55 | /* prototypes */ | 56 | /* prototypes */ |
56 | static dma_cookie_t atc_tx_submit(struct dma_async_tx_descriptor *tx); | 57 | static dma_cookie_t atc_tx_submit(struct dma_async_tx_descriptor *tx); |
58 | static void atc_issue_pending(struct dma_chan *chan); | ||
57 | 59 | ||
58 | 60 | ||
59 | /*----------------------------------------------------------------------*/ | 61 | /*----------------------------------------------------------------------*/ |
@@ -230,6 +232,95 @@ static void atc_dostart(struct at_dma_chan *atchan, struct at_desc *first) | |||
230 | vdbg_dump_regs(atchan); | 232 | vdbg_dump_regs(atchan); |
231 | } | 233 | } |
232 | 234 | ||
235 | /* | ||
236 | * atc_get_current_descriptors - | ||
237 | * locate the descriptor which equal to physical address in DSCR | ||
238 | * @atchan: the channel we want to start | ||
239 | * @dscr_addr: physical descriptor address in DSCR | ||
240 | */ | ||
241 | static struct at_desc *atc_get_current_descriptors(struct at_dma_chan *atchan, | ||
242 | u32 dscr_addr) | ||
243 | { | ||
244 | struct at_desc *desc, *_desc, *child, *desc_cur = NULL; | ||
245 | |||
246 | list_for_each_entry_safe(desc, _desc, &atchan->active_list, desc_node) { | ||
247 | if (desc->lli.dscr == dscr_addr) { | ||
248 | desc_cur = desc; | ||
249 | break; | ||
250 | } | ||
251 | |||
252 | list_for_each_entry(child, &desc->tx_list, desc_node) { | ||
253 | if (child->lli.dscr == dscr_addr) { | ||
254 | desc_cur = child; | ||
255 | break; | ||
256 | } | ||
257 | } | ||
258 | } | ||
259 | |||
260 | return desc_cur; | ||
261 | } | ||
262 | |||
263 | /* | ||
264 | * atc_get_bytes_left - | ||
265 | * Get the number of bytes residue in dma buffer, | ||
266 | * @chan: the channel we want to start | ||
267 | */ | ||
268 | static int atc_get_bytes_left(struct dma_chan *chan) | ||
269 | { | ||
270 | struct at_dma_chan *atchan = to_at_dma_chan(chan); | ||
271 | struct at_dma *atdma = to_at_dma(chan->device); | ||
272 | int chan_id = atchan->chan_common.chan_id; | ||
273 | struct at_desc *desc_first = atc_first_active(atchan); | ||
274 | struct at_desc *desc_cur; | ||
275 | int ret = 0, count = 0; | ||
276 | |||
277 | /* | ||
278 | * Initialize necessary values in the first time. | ||
279 | * remain_desc record remain desc length. | ||
280 | */ | ||
281 | if (atchan->remain_desc == 0) | ||
282 | /* First descriptor embedds the transaction length */ | ||
283 | atchan->remain_desc = desc_first->len; | ||
284 | |||
285 | /* | ||
286 | * This happens when current descriptor transfer complete. | ||
287 | * The residual buffer size should reduce current descriptor length. | ||
288 | */ | ||
289 | if (unlikely(test_bit(ATC_IS_BTC, &atchan->status))) { | ||
290 | clear_bit(ATC_IS_BTC, &atchan->status); | ||
291 | desc_cur = atc_get_current_descriptors(atchan, | ||
292 | channel_readl(atchan, DSCR)); | ||
293 | if (!desc_cur) { | ||
294 | ret = -EINVAL; | ||
295 | goto out; | ||
296 | } | ||
297 | atchan->remain_desc -= (desc_cur->lli.ctrla & ATC_BTSIZE_MAX) | ||
298 | << (desc_first->tx_width); | ||
299 | if (atchan->remain_desc < 0) { | ||
300 | ret = -EINVAL; | ||
301 | goto out; | ||
302 | } else { | ||
303 | ret = atchan->remain_desc; | ||
304 | } | ||
305 | } else { | ||
306 | /* | ||
307 | * Get residual bytes when current | ||
308 | * descriptor transfer in progress. | ||
309 | */ | ||
310 | count = (channel_readl(atchan, CTRLA) & ATC_BTSIZE_MAX) | ||
311 | << (desc_first->tx_width); | ||
312 | ret = atchan->remain_desc - count; | ||
313 | } | ||
314 | /* | ||
315 | * Check fifo empty. | ||
316 | */ | ||
317 | if (!(dma_readl(atdma, CHSR) & AT_DMA_EMPT(chan_id))) | ||
318 | atc_issue_pending(chan); | ||
319 | |||
320 | out: | ||
321 | return ret; | ||
322 | } | ||
323 | |||
233 | /** | 324 | /** |
234 | * atc_chain_complete - finish work for one transaction chain | 325 | * atc_chain_complete - finish work for one transaction chain |
235 | * @atchan: channel we work on | 326 | * @atchan: channel we work on |
@@ -327,37 +418,6 @@ static void atc_complete_all(struct at_dma_chan *atchan) | |||
327 | } | 418 | } |
328 | 419 | ||
329 | /** | 420 | /** |
330 | * atc_cleanup_descriptors - cleanup up finished descriptors in active_list | ||
331 | * @atchan: channel to be cleaned up | ||
332 | * | ||
333 | * Called with atchan->lock held and bh disabled | ||
334 | */ | ||
335 | static void atc_cleanup_descriptors(struct at_dma_chan *atchan) | ||
336 | { | ||
337 | struct at_desc *desc, *_desc; | ||
338 | struct at_desc *child; | ||
339 | |||
340 | dev_vdbg(chan2dev(&atchan->chan_common), "cleanup descriptors\n"); | ||
341 | |||
342 | list_for_each_entry_safe(desc, _desc, &atchan->active_list, desc_node) { | ||
343 | if (!(desc->lli.ctrla & ATC_DONE)) | ||
344 | /* This one is currently in progress */ | ||
345 | return; | ||
346 | |||
347 | list_for_each_entry(child, &desc->tx_list, desc_node) | ||
348 | if (!(child->lli.ctrla & ATC_DONE)) | ||
349 | /* Currently in progress */ | ||
350 | return; | ||
351 | |||
352 | /* | ||
353 | * No descriptors so far seem to be in progress, i.e. | ||
354 | * this chain must be done. | ||
355 | */ | ||
356 | atc_chain_complete(atchan, desc); | ||
357 | } | ||
358 | } | ||
359 | |||
360 | /** | ||
361 | * atc_advance_work - at the end of a transaction, move forward | 421 | * atc_advance_work - at the end of a transaction, move forward |
362 | * @atchan: channel where the transaction ended | 422 | * @atchan: channel where the transaction ended |
363 | * | 423 | * |
@@ -496,6 +556,8 @@ static irqreturn_t at_dma_interrupt(int irq, void *dev_id) | |||
496 | /* Give information to tasklet */ | 556 | /* Give information to tasklet */ |
497 | set_bit(ATC_IS_ERROR, &atchan->status); | 557 | set_bit(ATC_IS_ERROR, &atchan->status); |
498 | } | 558 | } |
559 | if (pending & AT_DMA_BTC(i)) | ||
560 | set_bit(ATC_IS_BTC, &atchan->status); | ||
499 | tasklet_schedule(&atchan->tasklet); | 561 | tasklet_schedule(&atchan->tasklet); |
500 | ret = IRQ_HANDLED; | 562 | ret = IRQ_HANDLED; |
501 | } | 563 | } |
@@ -615,6 +677,7 @@ atc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, | |||
615 | /* First descriptor of the chain embedds additional information */ | 677 | /* First descriptor of the chain embedds additional information */ |
616 | first->txd.cookie = -EBUSY; | 678 | first->txd.cookie = -EBUSY; |
617 | first->len = len; | 679 | first->len = len; |
680 | first->tx_width = src_width; | ||
618 | 681 | ||
619 | /* set end-of-link to the last link descriptor of list*/ | 682 | /* set end-of-link to the last link descriptor of list*/ |
620 | set_desc_eol(desc); | 683 | set_desc_eol(desc); |
@@ -761,6 +824,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, | |||
761 | /* First descriptor of the chain embedds additional information */ | 824 | /* First descriptor of the chain embedds additional information */ |
762 | first->txd.cookie = -EBUSY; | 825 | first->txd.cookie = -EBUSY; |
763 | first->len = total_len; | 826 | first->len = total_len; |
827 | first->tx_width = reg_width; | ||
764 | 828 | ||
765 | /* first link descriptor of list is responsible of flags */ | 829 | /* first link descriptor of list is responsible of flags */ |
766 | first->txd.flags = flags; /* client is in control of this ack */ | 830 | first->txd.flags = flags; /* client is in control of this ack */ |
@@ -919,6 +983,7 @@ atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, | |||
919 | /* First descriptor of the chain embedds additional information */ | 983 | /* First descriptor of the chain embedds additional information */ |
920 | first->txd.cookie = -EBUSY; | 984 | first->txd.cookie = -EBUSY; |
921 | first->len = buf_len; | 985 | first->len = buf_len; |
986 | first->tx_width = reg_width; | ||
922 | 987 | ||
923 | return &first->txd; | 988 | return &first->txd; |
924 | 989 | ||
@@ -1032,34 +1097,36 @@ atc_tx_status(struct dma_chan *chan, | |||
1032 | struct dma_tx_state *txstate) | 1097 | struct dma_tx_state *txstate) |
1033 | { | 1098 | { |
1034 | struct at_dma_chan *atchan = to_at_dma_chan(chan); | 1099 | struct at_dma_chan *atchan = to_at_dma_chan(chan); |
1035 | dma_cookie_t last_used; | ||
1036 | dma_cookie_t last_complete; | ||
1037 | unsigned long flags; | 1100 | unsigned long flags; |
1038 | enum dma_status ret; | 1101 | enum dma_status ret; |
1039 | 1102 | int bytes = 0; | |
1040 | spin_lock_irqsave(&atchan->lock, flags); | ||
1041 | 1103 | ||
1042 | ret = dma_cookie_status(chan, cookie, txstate); | 1104 | ret = dma_cookie_status(chan, cookie, txstate); |
1043 | if (ret != DMA_SUCCESS) { | 1105 | if (ret == DMA_SUCCESS) |
1044 | atc_cleanup_descriptors(atchan); | 1106 | return ret; |
1107 | /* | ||
1108 | * There's no point calculating the residue if there's | ||
1109 | * no txstate to store the value. | ||
1110 | */ | ||
1111 | if (!txstate) | ||
1112 | return DMA_ERROR; | ||
1045 | 1113 | ||
1046 | ret = dma_cookie_status(chan, cookie, txstate); | 1114 | spin_lock_irqsave(&atchan->lock, flags); |
1047 | } | ||
1048 | 1115 | ||
1049 | last_complete = chan->completed_cookie; | 1116 | /* Get number of bytes left in the active transactions */ |
1050 | last_used = chan->cookie; | 1117 | bytes = atc_get_bytes_left(chan); |
1051 | 1118 | ||
1052 | spin_unlock_irqrestore(&atchan->lock, flags); | 1119 | spin_unlock_irqrestore(&atchan->lock, flags); |
1053 | 1120 | ||
1054 | if (ret != DMA_SUCCESS) | 1121 | if (unlikely(bytes < 0)) { |
1055 | dma_set_residue(txstate, atc_first_active(atchan)->len); | 1122 | dev_vdbg(chan2dev(chan), "get residual bytes error\n"); |
1056 | 1123 | return DMA_ERROR; | |
1057 | if (atc_chan_is_paused(atchan)) | 1124 | } else { |
1058 | ret = DMA_PAUSED; | 1125 | dma_set_residue(txstate, bytes); |
1126 | } | ||
1059 | 1127 | ||
1060 | dev_vdbg(chan2dev(chan), "tx_status %d: cookie = %d (d%d, u%d)\n", | 1128 | dev_vdbg(chan2dev(chan), "tx_status %d: cookie = %d residue = %d\n", |
1061 | ret, cookie, last_complete ? last_complete : 0, | 1129 | ret, cookie, bytes); |
1062 | last_used ? last_used : 0); | ||
1063 | 1130 | ||
1064 | return ret; | 1131 | return ret; |
1065 | } | 1132 | } |
@@ -1120,7 +1187,7 @@ static int atc_alloc_chan_resources(struct dma_chan *chan) | |||
1120 | */ | 1187 | */ |
1121 | BUG_ON(!atslave->dma_dev || atslave->dma_dev != atdma->dma_common.dev); | 1188 | BUG_ON(!atslave->dma_dev || atslave->dma_dev != atdma->dma_common.dev); |
1122 | 1189 | ||
1123 | /* if cfg configuration specified take it instad of default */ | 1190 | /* if cfg configuration specified take it instead of default */ |
1124 | if (atslave->cfg) | 1191 | if (atslave->cfg) |
1125 | cfg = atslave->cfg; | 1192 | cfg = atslave->cfg; |
1126 | } | 1193 | } |
@@ -1143,6 +1210,7 @@ static int atc_alloc_chan_resources(struct dma_chan *chan) | |||
1143 | 1210 | ||
1144 | spin_lock_irqsave(&atchan->lock, flags); | 1211 | spin_lock_irqsave(&atchan->lock, flags); |
1145 | atchan->descs_allocated = i; | 1212 | atchan->descs_allocated = i; |
1213 | atchan->remain_desc = 0; | ||
1146 | list_splice(&tmp_list, &atchan->free_list); | 1214 | list_splice(&tmp_list, &atchan->free_list); |
1147 | dma_cookie_init(chan); | 1215 | dma_cookie_init(chan); |
1148 | spin_unlock_irqrestore(&atchan->lock, flags); | 1216 | spin_unlock_irqrestore(&atchan->lock, flags); |
@@ -1185,6 +1253,7 @@ static void atc_free_chan_resources(struct dma_chan *chan) | |||
1185 | list_splice_init(&atchan->free_list, &list); | 1253 | list_splice_init(&atchan->free_list, &list); |
1186 | atchan->descs_allocated = 0; | 1254 | atchan->descs_allocated = 0; |
1187 | atchan->status = 0; | 1255 | atchan->status = 0; |
1256 | atchan->remain_desc = 0; | ||
1188 | 1257 | ||
1189 | dev_vdbg(chan2dev(chan), "free_chan_resources: done\n"); | 1258 | dev_vdbg(chan2dev(chan), "free_chan_resources: done\n"); |
1190 | } | 1259 | } |
@@ -1223,14 +1292,31 @@ static struct dma_chan *at_dma_xlate(struct of_phandle_args *dma_spec, | |||
1223 | atslave = devm_kzalloc(&dmac_pdev->dev, sizeof(*atslave), GFP_KERNEL); | 1292 | atslave = devm_kzalloc(&dmac_pdev->dev, sizeof(*atslave), GFP_KERNEL); |
1224 | if (!atslave) | 1293 | if (!atslave) |
1225 | return NULL; | 1294 | return NULL; |
1295 | |||
1296 | atslave->cfg = ATC_DST_H2SEL_HW | ATC_SRC_H2SEL_HW; | ||
1226 | /* | 1297 | /* |
1227 | * We can fill both SRC_PER and DST_PER, one of these fields will be | 1298 | * We can fill both SRC_PER and DST_PER, one of these fields will be |
1228 | * ignored depending on DMA transfer direction. | 1299 | * ignored depending on DMA transfer direction. |
1229 | */ | 1300 | */ |
1230 | per_id = dma_spec->args[1]; | 1301 | per_id = dma_spec->args[1] & AT91_DMA_CFG_PER_ID_MASK; |
1231 | atslave->cfg = ATC_FIFOCFG_HALFFIFO | ATC_DST_H2SEL_HW | 1302 | atslave->cfg |= ATC_DST_PER_MSB(per_id) | ATC_DST_PER(per_id) |
1232 | | ATC_SRC_H2SEL_HW | ATC_DST_PER(per_id) | 1303 | | ATC_SRC_PER_MSB(per_id) | ATC_SRC_PER(per_id); |
1233 | | ATC_SRC_PER(per_id); | 1304 | /* |
1305 | * We have to translate the value we get from the device tree since | ||
1306 | * the half FIFO configuration value had to be 0 to keep backward | ||
1307 | * compatibility. | ||
1308 | */ | ||
1309 | switch (dma_spec->args[1] & AT91_DMA_CFG_FIFOCFG_MASK) { | ||
1310 | case AT91_DMA_CFG_FIFOCFG_ALAP: | ||
1311 | atslave->cfg |= ATC_FIFOCFG_LARGESTBURST; | ||
1312 | break; | ||
1313 | case AT91_DMA_CFG_FIFOCFG_ASAP: | ||
1314 | atslave->cfg |= ATC_FIFOCFG_ENOUGHSPACE; | ||
1315 | break; | ||
1316 | case AT91_DMA_CFG_FIFOCFG_HALF: | ||
1317 | default: | ||
1318 | atslave->cfg |= ATC_FIFOCFG_HALFFIFO; | ||
1319 | } | ||
1234 | atslave->dma_dev = &dmac_pdev->dev; | 1320 | atslave->dma_dev = &dmac_pdev->dev; |
1235 | 1321 | ||
1236 | chan = dma_request_channel(mask, at_dma_filter, atslave); | 1322 | chan = dma_request_channel(mask, at_dma_filter, atslave); |
@@ -1374,7 +1460,9 @@ static int __init at_dma_probe(struct platform_device *pdev) | |||
1374 | err = PTR_ERR(atdma->clk); | 1460 | err = PTR_ERR(atdma->clk); |
1375 | goto err_clk; | 1461 | goto err_clk; |
1376 | } | 1462 | } |
1377 | clk_enable(atdma->clk); | 1463 | err = clk_prepare_enable(atdma->clk); |
1464 | if (err) | ||
1465 | goto err_clk_prepare; | ||
1378 | 1466 | ||
1379 | /* force dma off, just in case */ | 1467 | /* force dma off, just in case */ |
1380 | at_dma_off(atdma); | 1468 | at_dma_off(atdma); |
@@ -1472,10 +1560,10 @@ err_of_dma_controller_register: | |||
1472 | dma_async_device_unregister(&atdma->dma_common); | 1560 | dma_async_device_unregister(&atdma->dma_common); |
1473 | dma_pool_destroy(atdma->dma_desc_pool); | 1561 | dma_pool_destroy(atdma->dma_desc_pool); |
1474 | err_pool_create: | 1562 | err_pool_create: |
1475 | platform_set_drvdata(pdev, NULL); | ||
1476 | free_irq(platform_get_irq(pdev, 0), atdma); | 1563 | free_irq(platform_get_irq(pdev, 0), atdma); |
1477 | err_irq: | 1564 | err_irq: |
1478 | clk_disable(atdma->clk); | 1565 | clk_disable_unprepare(atdma->clk); |
1566 | err_clk_prepare: | ||
1479 | clk_put(atdma->clk); | 1567 | clk_put(atdma->clk); |
1480 | err_clk: | 1568 | err_clk: |
1481 | iounmap(atdma->regs); | 1569 | iounmap(atdma->regs); |
@@ -1497,7 +1585,6 @@ static int at_dma_remove(struct platform_device *pdev) | |||
1497 | dma_async_device_unregister(&atdma->dma_common); | 1585 | dma_async_device_unregister(&atdma->dma_common); |
1498 | 1586 | ||
1499 | dma_pool_destroy(atdma->dma_desc_pool); | 1587 | dma_pool_destroy(atdma->dma_desc_pool); |
1500 | platform_set_drvdata(pdev, NULL); | ||
1501 | free_irq(platform_get_irq(pdev, 0), atdma); | 1588 | free_irq(platform_get_irq(pdev, 0), atdma); |
1502 | 1589 | ||
1503 | list_for_each_entry_safe(chan, _chan, &atdma->dma_common.channels, | 1590 | list_for_each_entry_safe(chan, _chan, &atdma->dma_common.channels, |
@@ -1512,7 +1599,7 @@ static int at_dma_remove(struct platform_device *pdev) | |||
1512 | list_del(&chan->device_node); | 1599 | list_del(&chan->device_node); |
1513 | } | 1600 | } |
1514 | 1601 | ||
1515 | clk_disable(atdma->clk); | 1602 | clk_disable_unprepare(atdma->clk); |
1516 | clk_put(atdma->clk); | 1603 | clk_put(atdma->clk); |
1517 | 1604 | ||
1518 | iounmap(atdma->regs); | 1605 | iounmap(atdma->regs); |
@@ -1531,7 +1618,7 @@ static void at_dma_shutdown(struct platform_device *pdev) | |||
1531 | struct at_dma *atdma = platform_get_drvdata(pdev); | 1618 | struct at_dma *atdma = platform_get_drvdata(pdev); |
1532 | 1619 | ||
1533 | at_dma_off(platform_get_drvdata(pdev)); | 1620 | at_dma_off(platform_get_drvdata(pdev)); |
1534 | clk_disable(atdma->clk); | 1621 | clk_disable_unprepare(atdma->clk); |
1535 | } | 1622 | } |
1536 | 1623 | ||
1537 | static int at_dma_prepare(struct device *dev) | 1624 | static int at_dma_prepare(struct device *dev) |
@@ -1588,7 +1675,7 @@ static int at_dma_suspend_noirq(struct device *dev) | |||
1588 | 1675 | ||
1589 | /* disable DMA controller */ | 1676 | /* disable DMA controller */ |
1590 | at_dma_off(atdma); | 1677 | at_dma_off(atdma); |
1591 | clk_disable(atdma->clk); | 1678 | clk_disable_unprepare(atdma->clk); |
1592 | return 0; | 1679 | return 0; |
1593 | } | 1680 | } |
1594 | 1681 | ||
@@ -1618,7 +1705,7 @@ static int at_dma_resume_noirq(struct device *dev) | |||
1618 | struct dma_chan *chan, *_chan; | 1705 | struct dma_chan *chan, *_chan; |
1619 | 1706 | ||
1620 | /* bring back DMA controller */ | 1707 | /* bring back DMA controller */ |
1621 | clk_enable(atdma->clk); | 1708 | clk_prepare_enable(atdma->clk); |
1622 | dma_writel(atdma, EN, AT_DMA_ENABLE); | 1709 | dma_writel(atdma, EN, AT_DMA_ENABLE); |
1623 | 1710 | ||
1624 | /* clear any pending interrupt */ | 1711 | /* clear any pending interrupt */ |