tegra: spi: Wait for the DMA to finish emptying the RX FIFO.

When using DMA to do a SPI transfer, we were waiting for the actual transfer
to finish but weren't waiting for the DMA engine to empty the RX FIFO within
the SPI controller. We were then stopping the DMA and loosing that part of the
data. This change replaces the "stop" function of the DMA channel structures
with a "finish" function which does the same thing as stop but also makes sure
the transfer is finished first.

BUG=None
TEST=Before this change, doing an RW boot failed because the data was
incompletely loaded from flash. After this change, RW booting worked.
BRANCH=None

Change-Id: I46ddc0ee2752448aad5193b7bf40796ffd177194
Signed-off-by: Gabe Black <gabeblack@google.com>
Reviewed-on: https://chromium-review.googlesource.com/174918
Reviewed-by: David Hendricks <dhendrix@chromium.org>
Commit-Queue: Gabe Black <gabeblack@chromium.org>
Tested-by: Gabe Black <gabeblack@chromium.org>
diff --git a/src/drivers/bus/spi/tegra.c b/src/drivers/bus/spi/tegra.c
index 6eb2295..e000902 100644
--- a/src/drivers/bus/spi/tegra.c
+++ b/src/drivers/bus/spi/tegra.c
@@ -296,7 +296,7 @@
 		cin = bus->dma_controller->claim(bus->dma_controller);
 		if (!cin || tegra_spi_dma_config(cin, in, &regs->rx_fifo,
 						 size, 0, bus->dma_slave_id)) {
-			cout->stop(cout);
+			cout->finish(cout);
 			bus->dma_controller->release(bus->dma_controller, cout);
 			return -1;
 		}
@@ -318,11 +318,11 @@
 	wait_for_transfer(regs, size >> SPI_PACKET_LOG_SIZE_BYTES);
 
 	if (cout) {
-		cout->stop(cout);
+		cout->finish(cout);
 		bus->dma_controller->release(bus->dma_controller, cout);
 	}
 	if (cin) {
-		cin->stop(cin);
+		cin->finish(cin);
 		bus->dma_controller->release(bus->dma_controller, cin);
 	}
 
diff --git a/src/drivers/dma/tegra_apb.c b/src/drivers/dma/tegra_apb.c
index 6017f13..d7100a4 100644
--- a/src/drivers/dma/tegra_apb.c
+++ b/src/drivers/dma/tegra_apb.c
@@ -70,9 +70,10 @@
 	return 0;
 }
 
-static int tegra_apb_dma_stop(TegraApbDmaChannel *me)
+static int tegra_apb_dma_finish(TegraApbDmaChannel *me)
 {
 	uint32_t csr = readl(&me->regs->csr);
+	writel(csr | APBDMACHAN_CSR_HOLD, &me->regs->csr);
 	writel(csr & ~APBDMACHAN_CSR_ENB, &me->regs->csr);
 	return 0;
 }
@@ -100,7 +101,7 @@
 	for (int i = 0; i < count; i++) {
 		TegraApbDmaChannel *channel = &channels->channels[i];
 		channel->start = &tegra_apb_dma_start;
-		channel->stop = &tegra_apb_dma_stop;
+		channel->finish = &tegra_apb_dma_finish;
 		channel->busy = &tegra_apb_dma_busy;
 
 		channel->regs = bases[i];
diff --git a/src/drivers/dma/tegra_apb.h b/src/drivers/dma/tegra_apb.h
index 6d93276..9c1beb7 100644
--- a/src/drivers/dma/tegra_apb.h
+++ b/src/drivers/dma/tegra_apb.h
@@ -160,7 +160,7 @@
 
 typedef struct TegraApbDmaChannel {
 	int (*start)(struct TegraApbDmaChannel *me);
-	int (*stop)(struct TegraApbDmaChannel *me);
+	int (*finish)(struct TegraApbDmaChannel *me);
 	int (*busy)(struct TegraApbDmaChannel *me);
 
 	TegraApbDmaRegs *regs;