[coreboot-gerrit] Patch set updated for coreboot: rockchip: spi: Add support for 16-bit APB reads

Patrick Georgi (pgeorgi@google.com) gerrit at coreboot.org
Tue Oct 4 21:28:34 CEST 2016


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

-gerrit

commit 354fbf65564e715ad1f0f9071106e33286a394f9
Author: Simon Glass <sjg at chromium.org>
Date:   Mon Sep 5 11:10:26 2016 -0600

    rockchip: spi: Add support for 16-bit APB reads
    
    With a SPI clock above about 24MHz the APB cannot keep up when doing
    individual byte transfers. Adjust the driver to use 16-bit reads when
    it can, to remove this bottleneck.
    
    Any transaction which involves writing bytes still uses 8-bit transfers,
    to simplify the code. These are the transfers that are not time-critical
    since they tend to be small. The case that really matters is reading from
    SPI flash.
    
    In general we can use 16-bit reads anytime we are transferring an even
    number of bytes. If the code detects an odd number of bytes, it tries to
    perform the operation in two steps: once in 16-bit mode with an even
    number of bytes, and once in 8-bit mode for the final byte. This allow
    us to use 16-bit reads even if asked to transfer (for example) 0xf423
    bytes.
    
    The limit on in_now and out_now is adjusted to 0xfffe to avoid an extra
    transfer when transferring ~>=64KB.
    
    CQ-DEPEND=CL:383232
    BUG=chrome-os-partner:56556
    BRANCH=none
    TEST=boot on gru and see that things still work correctly. I tested (with
    extra debugging) that the 16-bit case is being picked when it should be.
    
    Change-Id: If5effae9a84e4de06537fd594bedf7f01d6a9c88
    Signed-off-by: Patrick Georgi <pgeorgi at chromium.org>
    Original-Commit-Id: ec250b4931c7d99cc014e32ab597fca948299d08
    Original-Change-Id: Idc5b7e5d82cdbdc1e8fe8b2d6da819edf2d5570c
    Original-Signed-off-by: Simon Glass <sjg at chromium.org>
    Original-Reviewed-on: https://chromium-review.googlesource.com/381312
    Original-Commit-Ready: Julius Werner <jwerner at chromium.org>
    Original-Tested-by: Julius Werner <jwerner at chromium.org>
    Original-Reviewed-by: Julius Werner <jwerner at chromium.org>
---
 src/soc/rockchip/common/spi.c | 53 ++++++++++++++++++++++++++++++++-----------
 1 file changed, 40 insertions(+), 13 deletions(-)

diff --git a/src/soc/rockchip/common/spi.c b/src/soc/rockchip/common/spi.c
index 7dcaaad..57e9ca1 100644
--- a/src/soc/rockchip/common/spi.c
+++ b/src/soc/rockchip/common/spi.c
@@ -149,9 +149,6 @@ void rockchip_spi_init(unsigned int bus, unsigned int speed_hz)
 	/* First Bit Mode */
 	ctrlr0 |= (SPI_FBM_MSB << SPI_FBM_OFFSET);
 
-	/* Byte and Halfword Transform */
-	ctrlr0 |= (SPI_APB_8BIT << SPI_HALF_WORLD_TX_OFFSET);
-
 	/* Frame Format */
 	ctrlr0 |= (SPI_FRF_SPI << SPI_FRF_OFFSET);
 
@@ -220,7 +217,7 @@ static void set_transfer_mode(struct rockchip_spi *regs,
 }
 
 /* returns 0 to indicate success, <0 otherwise */
-static int do_xfer(struct rockchip_spi *regs, const void *dout,
+static int do_xfer(struct rockchip_spi *regs, bool use_16bit, const void *dout,
 		   unsigned int *bytes_out, void *din, unsigned int *bytes_in)
 {
 	uint8_t *in_buf = din;
@@ -251,12 +248,23 @@ static int do_xfer(struct rockchip_spi *regs, const void *dout,
 		 * sychronizing with the SPI clock which is pretty slow.
 		 */
 		if (*bytes_in && !(sr & SR_RF_EMPT)) {
-			int todo = read32(&regs->rxflr) & RXFLR_LEVEL_MASK;
-
-			*bytes_in -= todo;
-			xferred = todo;
-			while (todo-- > 0)
-				*in_buf++ = read32(&regs->rxdr) & 0xff;
+			int fifo = read32(&regs->rxflr) & RXFLR_LEVEL_MASK;
+			int val;
+
+			if (use_16bit)
+				xferred = fifo * 2;
+			else
+				xferred = fifo;
+			*bytes_in -= xferred;
+			while (fifo-- > 0) {
+				val = read32(&regs->rxdr);
+				if (use_16bit) {
+					*in_buf++ = val & 0xff;
+					*in_buf++ = (val >> 8) & 0xff;
+				} else {
+					*in_buf++ = val & 0xff;
+				}
+			}
 		}
 
 		min_xfer -= xferred;
@@ -290,12 +298,31 @@ int spi_xfer(struct spi_slave *slave, const void *dout,
 	 * seems to work fine.
 	 */
 	while (bytes_out || bytes_in) {
-		unsigned int in_now = MIN(bytes_in, 0xffff);
-		unsigned int out_now = MIN(bytes_out, 0xffff);
+		unsigned int in_now = MIN(bytes_in, 0xfffe);
+		unsigned int out_now = MIN(bytes_out, 0xfffe);
 		unsigned int in_rem, out_rem;
+		unsigned int mask;
+		bool use_16bit;
 
 		rockchip_spi_enable_chip(regs, 0);
 
+		/*
+		 * Use 16-bit transfers for higher-speed reads. If we are
+		 * transferring an odd number of bytes, try to make it even.
+		 */
+		use_16bit = false;
+		if (bytes_out == 0) {
+			if ((in_now & 1) && in_now > 1)
+				in_now--;
+			if (!(in_now & 1))
+				use_16bit = true;
+		}
+		mask = SPI_APB_8BIT << SPI_HALF_WORLD_TX_OFFSET;
+		if (use_16bit)
+			clrbits_le32(&regs->ctrlr0, mask);
+		else
+			setbits_le32(&regs->ctrlr0, mask);
+
 		/* Enable/disable transmitter and receiver as needed to
 		 * avoid sending or reading spurious bits. */
 		set_transfer_mode(regs, bytes_out, bytes_in);
@@ -307,7 +334,7 @@ int spi_xfer(struct spi_slave *slave, const void *dout,
 
 		in_rem = in_now;
 		out_rem = out_now;
-		ret = do_xfer(regs, dout, &out_rem, din, &in_rem);
+		ret = do_xfer(regs, use_16bit, dout, &out_rem, din, &in_rem);
 		if (ret < 0)
 			break;
 



More information about the coreboot-gerrit mailing list