Commit 8cf5858c authored by Vitja Makarov's avatar Vitja Makarov Committed by Linus Torvalds

Blackfin SPI Driver: ensure cache coherency before doing DMA

Flush or invalidate caches before doing DMA transfer, if needed.

[Mike Frysinger <vapier.adi@gmail.com>: add comment to address the
issue "Full duplex only works for non-DMA transfers".]
Signed-off-by: default avatarVitja Makarov <vitja.makarov@gmail.com>
Signed-off-by: default avatarMike Frysinger <vapier.adi@gmail.com>
Signed-off-by: default avatarBryan Wu <cooloney@kernel.org>
Cc: David Brownell <david-b@pacbell.net>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 3bcfa9e4
...@@ -26,6 +26,10 @@ ...@@ -26,6 +26,10 @@
#include <asm/portmux.h> #include <asm/portmux.h>
#include <asm/bfin5xx_spi.h> #include <asm/bfin5xx_spi.h>
/* reserved_mem_dcache_on and cache friends */
#include <asm/cplbinit.h>
#include <asm/cacheflush.h>
#define DRV_NAME "bfin-spi" #define DRV_NAME "bfin-spi"
#define DRV_AUTHOR "Bryan Wu, Luke Yang" #define DRV_AUTHOR "Bryan Wu, Luke Yang"
#define DRV_DESC "Blackfin BF5xx on-chip SPI Controller Driver" #define DRV_DESC "Blackfin BF5xx on-chip SPI Controller Driver"
...@@ -738,9 +742,10 @@ static void pump_transfers(unsigned long data) ...@@ -738,9 +742,10 @@ static void pump_transfers(unsigned long data)
width, transfer->len); width, transfer->len);
/* /*
* Try to map dma buffer and do a dma transfer if * Try to map dma buffer and do a dma transfer. If successful use,
* successful use different way to r/w according to * different way to r/w according to the enable_dma settings and if
* drv_data->cur_chip->enable_dma * we are not doing a full duplex transfer (since the hardware does
* not support full duplex DMA transfers).
*/ */
if (!full_duplex && drv_data->cur_chip->enable_dma if (!full_duplex && drv_data->cur_chip->enable_dma
&& drv_data->len > 6) { && drv_data->len > 6) {
...@@ -795,6 +800,12 @@ static void pump_transfers(unsigned long data) ...@@ -795,6 +800,12 @@ static void pump_transfers(unsigned long data)
/* set transfer mode, and enable SPI */ /* set transfer mode, and enable SPI */
dev_dbg(&drv_data->pdev->dev, "doing DMA in.\n"); dev_dbg(&drv_data->pdev->dev, "doing DMA in.\n");
/* invalidate caches, if needed */
if (bfin_addr_dcachable((unsigned long) drv_data->rx))
invalidate_dcache_range((unsigned long) drv_data->rx,
(unsigned long) (drv_data->rx +
drv_data->len));
/* clear tx reg soformer data is not shifted out */ /* clear tx reg soformer data is not shifted out */
write_TDBR(drv_data, 0xFFFF); write_TDBR(drv_data, 0xFFFF);
...@@ -815,6 +826,12 @@ static void pump_transfers(unsigned long data) ...@@ -815,6 +826,12 @@ static void pump_transfers(unsigned long data)
} else if (drv_data->tx != NULL) { } else if (drv_data->tx != NULL) {
dev_dbg(&drv_data->pdev->dev, "doing DMA out.\n"); dev_dbg(&drv_data->pdev->dev, "doing DMA out.\n");
/* flush caches, if needed */
if (bfin_addr_dcachable((unsigned long) drv_data->tx))
flush_dcache_range((unsigned long) drv_data->tx,
(unsigned long) (drv_data->tx +
drv_data->len));
/* start dma */ /* start dma */
dma_enable_irq(drv_data->dma_channel); dma_enable_irq(drv_data->dma_channel);
dma_config = (RESTART | dma_width | DI_EN); dma_config = (RESTART | dma_width | DI_EN);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment