[coreboot-gerrit] New patch to review for coreboot: 804809a spi: add Kconfig variable for dual-output read enable

Isaac Christensen (isaac.christensen@se-eng.com) gerrit at coreboot.org
Mon Sep 15 23:34:34 CEST 2014


Isaac Christensen (isaac.christensen at se-eng.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/6909

-gerrit

commit 804809a6de0954455ecb128a929f71aaf602fd4d
Author: David Hendricks <dhendrix at chromium.org>
Date:   Fri Nov 22 18:41:38 2013 -0800

    spi: add Kconfig variable for dual-output read enable
    
    Add a Kconfig variable so that driver code knows whether
    or not to use dual-output reads.
    
    Signed-off-by: David Hendricks <dhendrix at chromium.org>
    
    Old-Change-Id: I31d23bfedd91521d719378ec573e33b381ebd2c5
    Reviewed-on: https://chromium-review.googlesource.com/177834
    Reviewed-by: David Hendricks <dhendrix at chromium.org>
    Commit-Queue: David Hendricks <dhendrix at chromium.org>
    Tested-by: David Hendricks <dhendrix at chromium.org>
    (cherry picked from commit de6869a3350041c6823427787971efc9fcf469b8)
    
    tegra124: implement x2 mode for SPI transfers on CBFS media
    
    This implements x2 mode when reading CBFS media over SPI.
    
    In theory this effectively doubles our throughput, though the initial
    results were almost negligibly better. Using a logic analyzer we see
    a pattern of 12 clocks, ~70ns delay, 4 clocks, ~310ns delay. So if we
    want to see further gains here then we'll probably need to tune AHB
    arbitration and utilization to eliminate bubbles/stalls when copying
    from APB DMA.
    
    Signed-off-by: David Hendricks <dhendrix at chromium.org>
    
    Old-Change-Id: I33d6ae30923fc42b4dc7103d029085985472cf3e
    Reviewed-on: https://chromium-review.googlesource.com/177835
    Reviewed-by: Tom Warren <twarren at nvidia.com>
    Reviewed-by: David Hendricks <dhendrix at chromium.org>
    Commit-Queue: David Hendricks <dhendrix at chromium.org>
    Tested-by: David Hendricks <dhendrix at chromium.org>
    (cherry picked from commit 29289223362b12e84da5cbb130f285c6b9d314cc)
    
    nyan: turn on dual-output reads for SPI flash
    
    Nyan's SPI chip is capable of dual-output reads, so let's use it.
    
    Signed-off-by: David Hendricks <dhendrix at chromium.org>
    
    Old-Change-Id: I51a97c05aa25442d8ddcc4e3e35a2507d91a64df
    Reviewed-on: https://chromium-review.googlesource.com/177836
    Reviewed-by: David Hendricks <dhendrix at chromium.org>
    Commit-Queue: David Hendricks <dhendrix at chromium.org>
    Tested-by: David Hendricks <dhendrix at chromium.org>
    (cherry picked from commit 62de0889a9cfc5686800645d05e21e272e4beb5c)
    
    Squashed three commits to enable dual output spi reads for nyan.
    Also fixed the spi_xfer interface that has been updated to use bytes
    instead of bits.
    
    Change-Id: I750a177576175b297f61e1b10eac6db15e75aa6e
    Signed-off-by: Isaac Christensen <isaac.christensen at se-eng.com>
---
 src/drivers/spi/Kconfig           |  9 +++++++
 src/mainboard/google/nyan/Kconfig |  2 ++
 src/soc/nvidia/tegra124/spi.c     | 53 ++++++++++++++++++++++++++++++---------
 src/soc/nvidia/tegra124/spi.h     |  1 +
 4 files changed, 53 insertions(+), 12 deletions(-)

diff --git a/src/drivers/spi/Kconfig b/src/drivers/spi/Kconfig
index 6b31053..d832e0c 100644
--- a/src/drivers/spi/Kconfig
+++ b/src/drivers/spi/Kconfig
@@ -103,4 +103,13 @@ config SPI_FLASH_WINBOND
 	  Select this option if your chipset driver needs to store certain
 	  data in the SPI flash and your SPI flash is made by Winbond.
 
+config SPI_FLASH_FAST_READ_DUAL_OUTPUT_3B
+	bool
+	default n
+	depends on SPI_FLASH
+	help
+	  Select this option if your SPI flash supports the fast read dual-
+	  output command (opcode 0x3b) where the opcode and address are sent
+	  to the chip on MOSI and data is received on both MOSI and MISO.
+
 endif # SPI_FLASH
diff --git a/src/mainboard/google/nyan/Kconfig b/src/mainboard/google/nyan/Kconfig
index 1a7b260..320039f 100644
--- a/src/mainboard/google/nyan/Kconfig
+++ b/src/mainboard/google/nyan/Kconfig
@@ -28,6 +28,8 @@ config BOARD_SPECIFIC_OPTIONS # dummy
 	select MAINBOARD_HAS_BOOTBLOCK_INIT
 	select MAINBOARD_DO_NATIVE_VGA_INIT
 	select BOARD_ROMSIZE_KB_1024
+	select SPI_FLASH
+	select SPI_FLASH_FAST_READ_DUAL_OUTPUT_3B
 
 config MAINBOARD_DIR
 	string
diff --git a/src/soc/nvidia/tegra124/spi.c b/src/soc/nvidia/tegra124/spi.c
index c13f2c3..ae8a9a7 100644
--- a/src/soc/nvidia/tegra124/spi.c
+++ b/src/soc/nvidia/tegra124/spi.c
@@ -710,18 +710,20 @@ static int xfer_finish(struct tegra_spi_channel *spi)
 	return ret;
 }
 
+unsigned int spi_crop_chunk(unsigned int cmd_len, unsigned int buf_len)
+{
+	return buf_len;
+}
+
 int spi_xfer(struct spi_slave *slave, const void *dout,
-		unsigned int bitsout, void *din, unsigned int bitsin)
+		unsigned int out_bytes, void *din, unsigned int in_bytes)
 {
-	unsigned int out_bytes = bitsout / 8, in_bytes = bitsin / 8;
 	struct tegra_spi_channel *spi = to_tegra_spi(slave->bus);
 	u8 *out_buf = (u8 *)dout;
 	u8 *in_buf = (u8 *)din;
 	unsigned int todo;
 	int ret = 0, frame_started = 1;
 
-	ASSERT(bitsout % 8 == 0 && bitsin % 8 == 0);
-
 	/* tegra bus numbers start at 1 */
 	ASSERT(slave->bus >= 1 && slave->bus <= ARRAY_SIZE(tegra_spi_channels));
 
@@ -842,19 +844,37 @@ static int tegra_spi_cbfs_close(struct cbfs_media *media)
 	return 0;
 }
 
-#define JEDEC_READ		0x03
-#define JEDEC_READ_OUTSIZE	0x04
-/*      JEDEC_READ_INSIZE : any length */
+#define JEDEC_READ			0x03
+#define JEDEC_READ_OUTSIZE		0x04
+#define JEDEC_FAST_READ_DUAL		0x3b
+#define JEDEC_FAST_READ_DUAL_OUTSIZE	0x05
 
 static size_t tegra_spi_cbfs_read(struct cbfs_media *media, void *dest,
 				   size_t offset, size_t count)
 {
 	struct tegra_spi_media *spi = (struct tegra_spi_media *)media->context;
-	u8 spi_read_cmd[JEDEC_READ_OUTSIZE];
+	u8 spi_read_cmd[JEDEC_FAST_READ_DUAL_OUTSIZE];
+	unsigned int read_cmd_bytes;
 	int ret = count;
+	struct tegra_spi_channel *channel;
+
+	channel = to_tegra_spi(spi->slave->bus);
 
-	/* TODO: Dual mode (BOTH_EN_BIT) and packed mode */
-	spi_read_cmd[0] = JEDEC_READ;
+	if (channel->dual_mode) {
+		/*
+		 * Command 0x3b will interleave data only, command 0xbb will
+		 * interleave the address as well. It's nice to see the address
+		 * plainly when debugging, and we're mostly concerned with
+		 * large transfers so the optimization of using 0xbb isn't
+		 * really worthwhile.
+		 */
+		spi_read_cmd[0] = JEDEC_FAST_READ_DUAL;
+		spi_read_cmd[4] = 0x00;	/* dummy byte */
+		read_cmd_bytes = JEDEC_FAST_READ_DUAL_OUTSIZE;
+	} else {
+		spi_read_cmd[0] = JEDEC_READ;
+		read_cmd_bytes = JEDEC_READ_OUTSIZE;
+	}
 	spi_read_cmd[1] = (offset >> 16) & 0xff;
 	spi_read_cmd[2] = (offset >> 8) & 0xff;
 	spi_read_cmd[3] = offset & 0xff;
@@ -863,18 +883,23 @@ static size_t tegra_spi_cbfs_read(struct cbfs_media *media, void *dest,
 	spi_cs_activate(spi->slave);
 
 	if (spi_xfer(spi->slave, spi_read_cmd,
-			sizeof(spi_read_cmd) * 8, NULL, 0) < 0) {
+			read_cmd_bytes, NULL, 0) < 0) {
 		ret = -1;
 		printk(BIOS_ERR, "%s: Failed to transfer %u bytes\n",
 				__func__, sizeof(spi_read_cmd));
 		goto tegra_spi_cbfs_read_exit;
 	}
 
-	if (spi_xfer(spi->slave, NULL, 0, dest, count * 8)) {
+	if (channel->dual_mode) {
+		setbits_le32(&channel->regs->command1, SPI_CMD1_BOTH_EN_BIT);
+	}
+	if (spi_xfer(spi->slave, NULL, 0, dest, count)) {
 		ret = -1;
 		printk(BIOS_ERR, "%s: Failed to transfer %u bytes\n",
 				__func__, count);
 	}
+	if (channel->dual_mode)
+		clrbits_le32(&channel->regs->command1, SPI_CMD1_BOTH_EN_BIT);
 
 tegra_spi_cbfs_read_exit:
 	/* de-assert /CS */
@@ -924,6 +949,10 @@ int initialize_tegra_spi_cbfs_media(struct cbfs_media *media,
 	media->map = tegra_spi_cbfs_map;
 	media->unmap = tegra_spi_cbfs_unmap;
 
+#if CONFIG_SPI_FLASH_FAST_READ_DUAL_OUTPUT_3B == 1
+	channel->dual_mode = 1;
+#endif
+
 	return 0;
 }
 
diff --git a/src/soc/nvidia/tegra124/spi.h b/src/soc/nvidia/tegra124/spi.h
index b722240..fa238f2 100644
--- a/src/soc/nvidia/tegra124/spi.h
+++ b/src/soc/nvidia/tegra124/spi.h
@@ -56,6 +56,7 @@ struct tegra_spi_channel {
 	/* stuff that is specific to the attached device */
 	int rx_frame_header_enable;
 	u8 frame_header;
+	int dual_mode;		/* for x2 transfers with bit interleaving */
 
 	/* context (used internally) */
 	u8 *in_buf, *out_buf;



More information about the coreboot-gerrit mailing list