浏览代码

spi: exynos: Minimise access to SPI FIFO level

Accessing SPI registers is slow, but access to the FIFO level register
in particular seems to be extraordinarily expensive (I measure up to
600ns). Perhaps it is required to synchronise with the SPI byte output
logic which might run at 1/8th of the 40MHz SPI speed (just a guess).

Reduce access to this register by filling up and emptying FIFOs
more completely, rather than just one word each time around the inner
loop.

Since the rxfifo value will now likely be much greater that what we read
before we fill the txfifo, we only fill the txfifo halfway. This is
because if the txfifo is empty, but the rxfifo has data in it, then writing
too much data to the txfifo may overflow the rxfifo as data arrives.

This speeds up SPI flash reading from about 1MB/s to about 2MB/s on snow.

Signed-off-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Rajeshwari S Shinde <rajeshwari.s@samsung.com>
Reviewed-by: Jagannadha Sutradharudu Teki <jagannadh.teki@gmail.com>
Rajeshwari Shinde 11 年之前
父节点
当前提交
120af1572a
共有 1 个文件被更改,包括 15 次插入12 次删除
  1. 15 12
      drivers/spi/exynos_spi.c

+ 15 - 12
drivers/spi/exynos_spi.c

@@ -247,24 +247,27 @@ static int spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
 
 
 		/* Keep the fifos full/empty. */
 		/* Keep the fifos full/empty. */
 		spi_get_fifo_levels(regs, &rx_lvl, &tx_lvl);
 		spi_get_fifo_levels(regs, &rx_lvl, &tx_lvl);
-		if (tx_lvl < spi_slave->fifo_size && out_bytes) {
+		while (tx_lvl < spi_slave->fifo_size/2 && out_bytes) {
 			temp = txp ? *txp++ : 0xff;
 			temp = txp ? *txp++ : 0xff;
 			writel(temp, &regs->tx_data);
 			writel(temp, &regs->tx_data);
 			out_bytes--;
 			out_bytes--;
+			tx_lvl++;
 		}
 		}
 		if (rx_lvl > 0) {
 		if (rx_lvl > 0) {
-			temp = readl(&regs->rx_data);
-			if (spi_slave->skip_preamble) {
-				if (temp == SPI_PREAMBLE_END_BYTE) {
-					spi_slave->skip_preamble = 0;
-					stopping = 0;
+			while (rx_lvl > 0) {
+				temp = readl(&regs->rx_data);
+				if (spi_slave->skip_preamble) {
+					if (temp == SPI_PREAMBLE_END_BYTE) {
+						spi_slave->skip_preamble = 0;
+						stopping = 0;
+					}
+				} else {
+					if (rxp || stopping)
+						*rxp++ = temp;
+					in_bytes--;
 				}
 				}
-			} else {
-				if (rxp || stopping)
-					*rxp++ = temp;
-				in_bytes--;
-			}
-			toread--;
+				toread--;
+				rx_lvl--;
 		} else if (!toread) {
 		} else if (!toread) {
 			/*
 			/*
 			 * We have run out of input data, but haven't read
 			 * We have run out of input data, but haven't read