summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVitja Makarov <vitja.makarov@gmail.com>2009-04-06 19:00:31 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2009-04-07 08:31:04 -0700
commit8cf5858c51f88208fe56b195251ab4f21265386c (patch)
tree6095e2a5f9cb5d0b19afef30fd74bb360c4a42db
parent3bcfa9e47a7d1be6faef3be6c4b2049e585e2f38 (diff)
downloadlinux-8cf5858c51f88208fe56b195251ab4f21265386c.tar.bz2
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: Vitja Makarov <vitja.makarov@gmail.com> Signed-off-by: Mike Frysinger <vapier.adi@gmail.com> Signed-off-by: Bryan Wu <cooloney@kernel.org> Cc: David Brownell <david-b@pacbell.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/spi/spi_bfin5xx.c23
1 files changed, 20 insertions, 3 deletions
diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c
index 3410b0c55ed2..e440718b3209 100644
--- a/drivers/spi/spi_bfin5xx.c
+++ b/drivers/spi/spi_bfin5xx.c
@@ -26,6 +26,10 @@
#include <asm/portmux.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_AUTHOR "Bryan Wu, Luke Yang"
#define DRV_DESC "Blackfin BF5xx on-chip SPI Controller Driver"
@@ -738,9 +742,10 @@ static void pump_transfers(unsigned long data)
width, transfer->len);
/*
- * Try to map dma buffer and do a dma transfer if
- * successful use different way to r/w according to
- * drv_data->cur_chip->enable_dma
+ * Try to map dma buffer and do a dma transfer. If successful use,
+ * different way to r/w according to the enable_dma settings and if
+ * 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
&& drv_data->len > 6) {
@@ -795,6 +800,12 @@ static void pump_transfers(unsigned long data)
/* set transfer mode, and enable SPI */
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 */
write_TDBR(drv_data, 0xFFFF);
@@ -815,6 +826,12 @@ static void pump_transfers(unsigned long data)
} else if (drv_data->tx != NULL) {
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 */
dma_enable_irq(drv_data->dma_channel);
dma_config = (RESTART | dma_width | DI_EN);