[coreboot-gerrit] New patch to review for coreboot: 11aa8de spi_flash: Differentiate between atomic/manual sequencing

Marc Jones (marc.jones@se-eng.com) gerrit at coreboot.org
Tue Dec 16 23:35:41 CET 2014


Marc Jones (marc.jones at se-eng.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/7828

-gerrit

commit 11aa8deca65f3d3af4c3244d1616c6c6f073875d
Author: David Hendricks <dhendrix at chromium.org>
Date:   Fri Mar 21 19:13:34 2014 -0700

    spi_flash: Differentiate between atomic/manual sequencing
    
    This adds a wrapper function and a Kconfig variable to differentiate
    between SPI controllers which use atomic cycle sequencing versus
    those where the transaction sequence is controlled manually. Currently
    this boils down to x86 vs. non-x86.
    
    Yes, it's hideous. The current API only worked because, for better or
    worse, x86 platforms have been homogeneous in this regard since they
    started using SPI as an alternative to FWH for boot flash. Now that
    we have non-x86 platforms which use general purpose SPI controllers,
    we should overhaul the entire SPI infrastructure to be more adaptable.
    
    BUG=none
    BRANCH=none
    TEST=tested on nyan and link
    Signed-off-by: David Hendricks <dhendrix at chromium.org>
    
    Original-Change-Id: If8ccc9400a9d04772a195941a42bc82d5ecc1958
    Original-Reviewed-on: https://chromium-review.googlesource.com/195283
    Original-Reviewed-by: David Hendricks <dhendrix at chromium.org>
    Original-Commit-Queue: David Hendricks <dhendrix at chromium.org>
    Original-Tested-by: David Hendricks <dhendrix at chromium.org>
    (cherry picked from commit 4170c59d06206667755402712083452da9fcd941)
    Signed-off-by: Marc Jones <marc.jones at se-eng.com>
    
    Change-Id: I54e2d3d9f9a0153a56f7a51b80f6ee6d997ad358
---
 src/drivers/spi/Kconfig     | 10 ++++++++++
 src/drivers/spi/spi_flash.c | 47 ++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 54 insertions(+), 3 deletions(-)

diff --git a/src/drivers/spi/Kconfig b/src/drivers/spi/Kconfig
index f96bf9f..cc8703f 100644
--- a/src/drivers/spi/Kconfig
+++ b/src/drivers/spi/Kconfig
@@ -26,6 +26,16 @@ config SPI_FLASH
 
 if SPI_FLASH
 
+config SPI_ATOMIC_SEQUENCING
+	bool
+	default y if ARCH_X86
+	default n if !ARCH_X86
+	help
+	  Select this option if the SPI controller uses "atomic sequencing."
+	  Atomic sequencing is when the sequence of commands is pre-programmed
+	  in the SPI controller. Hardware manages the transaction instead of
+	  software. This is common on x86 platforms.
+
 config SPI_FLASH_MEMORY_MAPPED
 	bool
 	default y if ARCH_X86
diff --git a/src/drivers/spi/spi_flash.c b/src/drivers/spi/spi_flash.c
index de19b2b..0d67c43 100644
--- a/src/drivers/spi/spi_flash.c
+++ b/src/drivers/spi/spi_flash.c
@@ -25,9 +25,50 @@ static void spi_flash_addr(u32 addr, u8 *cmd)
 	cmd[3] = addr >> 0;
 }
 
+/*
+ * If atomic sequencing is used, the cycle type is known to the SPI
+ * controller so that it can perform consecutive transfers and arbitrate
+ * automatically. Otherwise the SPI controller transfers whatever the
+ * user requests immediately, without regard to sequence. Atomic
+ * sequencing is commonly used on x86 platforms.
+ *
+ * SPI flash commands are simple two-step sequences. The command byte is
+ * always written first and may be followed by an address. Then data is
+ * either read or written. For atomic sequencing we'll pass everything into
+ * spi_xfer() at once and let the controller handle the details. Otherwise
+ * we will write all output bytes first and then read if necessary.
+ *
+ * FIXME: This really should be abstracted better, but that will
+ * require overhauling the entire SPI infrastructure.
+ */
+static int do_spi_flash_cmd(struct spi_slave *spi, const void *dout,
+		unsigned int bytes_out, void *din, unsigned int bytes_in)
+{
+	int ret = 1;
+
+#if CONFIG_SPI_ATOMIC_SEQUENCING == 1
+	if (spi_xfer(spi, dout, bytes_out, din, bytes_in) < 0)
+		goto done;
+#else
+	if (dout && bytes_out) {
+		if (spi_xfer(spi, dout, bytes_out, NULL, 0) < 0)
+			goto done;
+	}
+
+	if (din && bytes_in) {
+		if (spi_xfer(spi, NULL, 0, din, bytes_in) < 0)
+			goto done;
+	}
+#endif
+
+	ret = 0;
+done:
+	return ret;
+}
+
 int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len)
 {
-	int ret = spi_xfer(spi, &cmd, sizeof(cmd), response, len);
+	int ret = do_spi_flash_cmd(spi, &cmd, sizeof(cmd), response, len);
 	if (ret)
 		printk(BIOS_WARNING, "SF: Failed to send command %02x: %d\n", cmd, ret);
 
@@ -37,7 +78,7 @@ int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len)
 int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd,
 		size_t cmd_len, void *data, size_t data_len)
 {
-	int ret = spi_xfer(spi, cmd, cmd_len, data, data_len);
+	int ret = do_spi_flash_cmd(spi, cmd, cmd_len, data, data_len);
 	if (ret) {
 		printk(BIOS_WARNING, "SF: Failed to send read command (%zu bytes): %d\n",
 				data_len, ret);
@@ -54,7 +95,7 @@ int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len,
 	memcpy(buff, cmd, cmd_len);
 	memcpy(buff + cmd_len, data, data_len);
 
-	ret = spi_xfer(spi, buff, cmd_len + data_len, NULL, 0);
+	ret = do_spi_flash_cmd(spi, buff, cmd_len + data_len, NULL, 0);
 	if (ret) {
 		printk(BIOS_WARNING, "SF: Failed to send write command (%zu bytes): %d\n",
 				data_len, ret);



More information about the coreboot-gerrit mailing list