[coreboot-gerrit] New patch to review for coreboot: t210: SPI driver cleanup

Patrick Georgi (pgeorgi@google.com) gerrit at coreboot.org
Thu Jul 16 18:13:03 CEST 2015


Patrick Georgi (pgeorgi at google.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/10947

-gerrit

commit 8cd41b901adb7f0f1180a61aa7f06a65e07508aa
Author: Furquan Shaikh <furquan at google.com>
Date:   Mon Jul 13 10:14:16 2015 -0700

    t210: SPI driver cleanup
    
    1. Get rid of spi_delay - Instead have a tight loop to check for the
    spi status
    2. The first check for SPI operation complete i.e. FIFOs have been
    processed is the SPI_STATUS_RDY bit. Thus, tegra_spi_wait should check
    for this bit before reading BLOCK_COUNT or any other fifo count field.
    3. Flush both TX and RX FIFOs for SEND and RECV operations for PIO and
    DMA.
    4. No need to check for rx_fifo_count == spi_byte_count to determine
    pio_finish operation. RDY bit should be sufficient to ensure that the
    SPI operation is complete. Added assert to ensure we never hit the
    case of RDY bit being set, yet rx_fifo_count != spi_byte_count for
    PIO.
    
    BUG=chrome-os-partner:41877
    BRANCH=None
    TEST=Compiles successfully and reboot test runs successfully for 10K+ iterations.
    
    Change-Id: I1adb9672c1503b562309a8bc6c22fe7d2271768e
    Signed-off-by: Patrick Georgi <pgeorgi at chromium.org>
    Original-Commit-Id: de1515605e17e0c6b81874f9f3c49fd0c1b92756
    Original-Change-Id: I5853d0df1bfd6020a17e478040bc4c1834563fe4
    Original-Signed-off-by: Furquan Shaikh <furquan at google.com>
    Original-Reviewed-on: https://chromium-review.googlesource.com/285141
    Original-Reviewed-by: Jimmy Zhang <jimmzhang at nvidia.com>
    Original-Tested-by: Jimmy Zhang <jimmzhang at nvidia.com>
    Original-Reviewed-by: Furquan Shaikh <furquan at chromium.org>
    Original-Tested-by: Furquan Shaikh <furquan at chromium.org>
    Original-Commit-Queue: Furquan Shaikh <furquan at chromium.org>
    Original-Trybot-Ready: Furquan Shaikh <furquan at chromium.org>
---
 src/soc/nvidia/tegra210/spi.c | 99 ++++++++++++++++++-------------------------
 1 file changed, 41 insertions(+), 58 deletions(-)

diff --git a/src/soc/nvidia/tegra210/spi.c b/src/soc/nvidia/tegra210/spi.c
index ffb4d47..5946ef0 100644
--- a/src/soc/nvidia/tegra210/spi.c
+++ b/src/soc/nvidia/tegra210/spi.c
@@ -212,12 +212,6 @@ static struct tegra_spi_channel * const to_tegra_spi(int bus) {
 	return &tegra_spi_channels[bus - 1];
 }
 
-static unsigned int tegra_spi_speed(unsigned int bus)
-{
-	/* FIXME: implement this properly, for now use max value (50MHz) */
-	return 50000000;
-}
-
 int spi_claim_bus(struct spi_slave *slave)
 {
 	struct tegra_spi_regs *regs = to_tegra_spi(slave->bus)->regs;
@@ -329,36 +323,22 @@ static inline unsigned int spi_byte_count(struct tegra_spi_channel *spi)
 		(SPI_STATUS_BLOCK_COUNT << SPI_STATUS_BLOCK_COUNT_SHIFT);
 }
 
-/*
- * This calls udelay() with a calculated value based on the SPI speed and
- * number of bytes remaining to be transferred. It assumes that if the
- * calculated delay period is less than MIN_DELAY_US then it is probably
- * not worth the overhead of yielding.
- */
-#define MIN_DELAY_US 250
-static void spi_delay(struct tegra_spi_channel *spi,
-				unsigned int bytes_remaining)
-{
-	unsigned int ns_per_byte, delay_us;
-
-	ns_per_byte = 1000000000 / (tegra_spi_speed(spi->slave.bus) / 8);
-	delay_us = (ns_per_byte * bytes_remaining) / 1000;
-
-	if (delay_us < MIN_DELAY_US)
-		return;
-
-	udelay(delay_us);
-}
-
 static void tegra_spi_wait(struct tegra_spi_channel *spi)
 {
-	unsigned int count, dma_blk;
+	uint32_t dma_blk_count = 1 + (read32(&spi->regs->dma_blk) &
+				      (SPI_DMA_CTL_BLOCK_SIZE_MASK <<
+				       SPI_DMA_CTL_BLOCK_SIZE_SHIFT));
 
-	dma_blk = 1 + (read32(&spi->regs->dma_blk) &
-		(SPI_DMA_CTL_BLOCK_SIZE_MASK << SPI_DMA_CTL_BLOCK_SIZE_SHIFT));
+	while ((read32(&spi->regs->trans_status) & SPI_STATUS_RDY) !=
+	       SPI_STATUS_RDY)
+		;
 
-	while ((count = spi_byte_count(spi)) != dma_blk)
-		spi_delay(spi, dma_blk - count);
+	/*
+	 * If RDY bit is set, we should never encounter the condition that
+	 * blocks processed is not equal to the number programmed in dma_blk
+	 * register.
+	 */
+	ASSERT(spi_byte_count(spi) == dma_blk_count);
 }
 
 
@@ -367,24 +347,32 @@ static int fifo_error(struct tegra_spi_channel *spi)
 	return read32(&spi->regs->fifo_status) & SPI_FIFO_STATUS_ERR ? 1 : 0;
 }
 
+static void flush_fifos(struct tegra_spi_channel *spi)
+{
+	const uint32_t flush_mask = SPI_FIFO_STATUS_TX_FIFO_FLUSH |
+		SPI_FIFO_STATUS_RX_FIFO_FLUSH;
+
+	uint32_t fifo_status = read32(&spi->regs->fifo_status);
+	fifo_status |= flush_mask;
+	write32(&spi->regs->fifo_status, flush_mask);
+
+	while (read32(&spi->regs->fifo_status) & flush_mask)
+		;
+}
+
 static int tegra_spi_pio_prepare(struct tegra_spi_channel *spi,
 			unsigned int bytes, enum spi_direction dir)
 {
 	u8 *p = spi->out_buf;
 	unsigned int todo = MIN(bytes, SPI_MAX_TRANSFER_BYTES_FIFO);
-	u32 flush_mask, enable_mask;
+	u32 enable_mask;
 
-	if (dir == SPI_SEND) {
-		flush_mask = SPI_FIFO_STATUS_TX_FIFO_FLUSH;
+	flush_fifos(spi);
+
+	if (dir == SPI_SEND)
 		enable_mask = SPI_CMD1_TX_EN;
-	} else {
-		flush_mask = SPI_FIFO_STATUS_RX_FIFO_FLUSH;
+	else
 		enable_mask = SPI_CMD1_RX_EN;
-	}
-
-	setbits_le32(&spi->regs->fifo_status, flush_mask);
-	while (read32(&spi->regs->fifo_status) & flush_mask)
-		;
 
 	/*
 	 * BLOCK_SIZE in SPI_DMA_BLK register applies to both DMA and
@@ -439,24 +427,17 @@ static inline u32 rx_fifo_count(struct tegra_spi_channel *spi)
 static int tegra_spi_pio_finish(struct tegra_spi_channel *spi)
 {
 	u8 *p = spi->in_buf;
-	struct stopwatch sw;
 
 	clrbits_le32(&spi->regs->command1, SPI_CMD1_RX_EN | SPI_CMD1_TX_EN);
 
-	/*
-	 * Allow some time in case the Rx FIFO does not yet have
-	 * all packets pushed into it. See chrome-os-partner:24215.
-	 */
-	stopwatch_init_usecs_expire(&sw, SPI_FIFO_XFER_TIMEOUT_US);
-	do {
-		if (rx_fifo_count(spi) == spi_byte_count(spi))
-			break;
-	} while (!stopwatch_expired(&sw));
+	ASSERT(rx_fifo_count(spi) == spi_byte_count(spi));
 
-	while (!(read32(&spi->regs->fifo_status) &
-				SPI_FIFO_STATUS_RX_FIFO_EMPTY)) {
-		*p = read8(&spi->regs->rx_fifo);
-		p++;
+	if (p) {
+		while (!(read32(&spi->regs->fifo_status) &
+			 SPI_FIFO_STATUS_RX_FIFO_EMPTY)) {
+			*p = read8(&spi->regs->rx_fifo);
+			p++;
+		}
 	}
 
 	if (fifo_error(spi)) {
@@ -509,6 +490,8 @@ static int tegra_spi_dma_prepare(struct tegra_spi_channel *spi,
 	todo = ALIGN_DOWN(todo, TEGRA_DMA_ALIGN_BYTES);
 	wcount = ALIGN_DOWN(todo - TEGRA_DMA_ALIGN_BYTES, TEGRA_DMA_ALIGN_BYTES);
 
+	flush_fifos(spi);
+
 	if (dir == SPI_SEND) {
 		spi->dma_out = dma_claim();
 		if (!spi->dma_out)
@@ -605,7 +588,7 @@ static int tegra_spi_dma_finish(struct tegra_spi_channel *spi)
 	if (spi->dma_in) {
 		while ((read32(&spi->dma_in->regs->dma_byte_sta) < todo) ||
 				dma_busy(spi->dma_in))
-			;	/* this shouldn't take long, no udelay */
+			;
 		dma_stop(spi->dma_in);
 		clrbits_le32(&spi->regs->command1, SPI_CMD1_RX_EN);
 		/* Disable secure access for the channel. */
@@ -617,7 +600,7 @@ static int tegra_spi_dma_finish(struct tegra_spi_channel *spi)
 	if (spi->dma_out) {
 		while ((read32(&spi->dma_out->regs->dma_byte_sta) < todo) ||
 				dma_busy(spi->dma_out))
-			spi_delay(spi, todo - spi_byte_count(spi));
+			;
 		clrbits_le32(&spi->regs->command1, SPI_CMD1_TX_EN);
 		dma_stop(spi->dma_out);
 		/* Disable secure access for the channel. */



More information about the coreboot-gerrit mailing list