Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+20 −3
Original line number Diff line number Diff line
@@ -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);