[coreboot-gerrit] Patch set updated for coreboot: f5a50a3 drivers/spi: Add support for adesto SPI flash parts

Christopher Douglass (cdouglass.orion@gmail.com) gerrit at coreboot.org
Tue Feb 18 16:48:31 CET 2014


Christopher Douglass (cdouglass.orion at gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/5225

-gerrit

commit f5a50a3d7ead21e69ce35459e855a8486fa36f11
Author: Chris Douglass <cdouglass.orion at gmail.com>
Date:   Fri Feb 14 13:51:26 2014 -0500

    drivers/spi: Add support for adesto SPI flash parts
    
    Adds support for the following Adesto Technologies
    SPI Flash parts.
    
    AT25DF081
    AT25DF321
    AT25DF641
    
    It has been tested on an Orion VPX7654 board populated
    with an AT25DF321A part. The "08" and "64" densities have not
    been tested.
    
    These parts are the successors of the Atmel AT26DF line that
    was spun out or purchased by Adesto.
    
    In this patch, adesto.c is identical to winbond.c with part
    entries for the Adesto parts. The datasheet for the AT25DF parts
    includes a "100MHz" programming command in addition to the "85MHz"
    command that is currently used but this patch does not add support
    for that enhanced programming mode.
    
    Change-Id: If82d075fd9000030480c412c645dcae2c8bb7439
    Signed-off-by: Christopher Douglass <cdouglass.orion at gmail.com>
---
 src/drivers/spi/Kconfig              |   8 ++
 src/drivers/spi/Makefile.inc         |   2 +
 src/drivers/spi/adesto.c             | 197 +++++++++++++++++++++++++++++++++++
 src/drivers/spi/spi_flash.c          |   3 +
 src/drivers/spi/spi_flash_internal.h |   1 +
 5 files changed, 211 insertions(+)

diff --git a/src/drivers/spi/Kconfig b/src/drivers/spi/Kconfig
index a99199a..95568f0 100644
--- a/src/drivers/spi/Kconfig
+++ b/src/drivers/spi/Kconfig
@@ -94,3 +94,11 @@ config SPI_FLASH_GIGADEVICE
 	help
 	  Select this option if your chipset driver needs to store certain
 	  data in the SPI flash and your SPI flash is made by Gigadevice.
+
+config SPI_FLASH_ADESTO
+	bool
+	default y
+	depends on SPI_FLASH
+	help
+	  Select this option if your chipset driver needs to store certain
+	  data in the SPI flash and your SPI flash is made by Adesto Technologies.
diff --git a/src/drivers/spi/Makefile.inc b/src/drivers/spi/Makefile.inc
index 1a34ab5..65eb0b3 100644
--- a/src/drivers/spi/Makefile.inc
+++ b/src/drivers/spi/Makefile.inc
@@ -9,6 +9,7 @@ ramstage-$(CONFIG_SPI_FLASH_SST) += sst.c
 ramstage-$(CONFIG_SPI_FLASH_STMICRO) += stmicro.c
 ramstage-$(CONFIG_SPI_FLASH_WINBOND) += winbond.c
 ramstage-$(CONFIG_SPI_FLASH_GIGADEVICE) += gigadevice.c
+ramstage-$(CONFIG_SPI_FLASH_ADESTO) += adesto.c
 ramstage-$(CONFIG_SPI_FRAM_RAMTRON) += ramtron.c
 
 ifeq ($(CONFIG_SPI_FLASH_SMM),y)
@@ -22,6 +23,7 @@ smm-$(CONFIG_SPI_FLASH_SPANSION) += spansion.c
 smm-$(CONFIG_SPI_FLASH_SST) += sst.c
 smm-$(CONFIG_SPI_FLASH_STMICRO) += stmicro.c
 smm-$(CONFIG_SPI_FLASH_WINBOND) += winbond.c
+smm-$(CONFIG_SPI_FLASH_ADESTO) += adesto.c
 smm-$(CONFIG_SPI_FRAM_RAMTRON) += ramtron.c
 smm-$(CONFIG_SPI_FLASH_GIGADEVICE) += gigadevice.c
 endif
\ No newline at end of file
diff --git a/src/drivers/spi/adesto.c b/src/drivers/spi/adesto.c
new file mode 100644
index 0000000..83be8b8
--- /dev/null
+++ b/src/drivers/spi/adesto.c
@@ -0,0 +1,197 @@
+/*
+ * adesto.c
+ * Driver for Adesto Technologies SPI flash
+ * Copyright 2014 Orion Technologies, LLC
+ * Author: Chris Douglass <cdouglass <at> oriontechnologies.com>
+ *
+ * based on winbond.c
+ * Copyright 2008, Network Appliance Inc.
+ * Author: Jason McMullan <mcmullan <at> netapp.com>
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <stdlib.h>
+#include <spi_flash.h>
+#include "spi_flash_internal.h"
+
+/* at25dfxx-specific commands */
+#define CMD_AT25DF_WREN		0x06	/* Write Enable */
+#define CMD_AT25DF_WRDI		0x04	/* Write Disable */
+#define CMD_AT25DF_RDSR		0x05	/* Read Status Register */
+#define CMD_AT25DF_WRSR		0x01	/* Write Status Register */
+#define CMD_AT25DF_READ		0x03	/* Read Data Bytes */
+#define CMD_AT25DF_FAST_READ	0x0b	/* Read Data Bytes at Higher Speed */
+#define CMD_AT25DF_PP		0x02	/* Page Program */
+#define CMD_AT25DF_SE		0x20	/* Sector (4K) Erase */
+#define CMD_AT25DF_BE		0xd8	/* Block (64K) Erase */
+#define CMD_AT25DF_CE		0xc7	/* Chip Erase */
+#define CMD_AT25DF_DP		0xb9	/* Deep Power-down */
+#define CMD_AT25DF_RES		0xab	/* Release from DP, and Read Signature */
+
+struct adesto_spi_flash_params {
+	uint16_t	id;
+	/* Log2 of page size in power-of-two mode */
+	uint8_t		l2_page_size;
+	uint16_t	pages_per_sector;
+	uint16_t	sectors_per_block;
+	uint16_t	nr_blocks;
+	const char	*name;
+};
+
+/* spi_flash needs to be first so upper layers can free() it */
+struct adesto_spi_flash {
+	struct spi_flash flash;
+	const struct adesto_spi_flash_params *params;
+};
+
+static inline struct adesto_spi_flash *
+to_adesto_spi_flash(struct spi_flash *flash)
+{
+	return container_of(flash, struct adesto_spi_flash, flash);
+}
+
+static const struct adesto_spi_flash_params adesto_spi_flash_table[] = {
+	{
+		.id			= 0x4501,
+		.l2_page_size		= 8,
+		.pages_per_sector	= 16,
+		.sectors_per_block	= 16,
+		.nr_blocks		= 16,
+		.name			= "AT25DF081",
+	},
+	{
+		.id			= 0x4701,
+		.l2_page_size		= 8,
+		.pages_per_sector	= 16,
+		.sectors_per_block	= 16,
+		.nr_blocks		= 64,
+		.name			= "AT25DF321",
+	},
+	{
+		.id			= 0x4800,
+		.l2_page_size		= 8,
+		.pages_per_sector	= 16,
+		.sectors_per_block	= 16,
+		.nr_blocks		= 128,
+		.name			= "AT25DF641",
+	},
+};
+
+static int adesto_write(struct spi_flash *flash,
+		u32 offset, size_t len, const void *buf)
+{
+	struct adesto_spi_flash *stm = to_adesto_spi_flash(flash);
+	unsigned long byte_addr;
+	unsigned long page_size;
+	size_t chunk_len;
+	size_t actual;
+	int ret;
+	u8 cmd[4];
+
+	page_size = min(1 << stm->params->l2_page_size, CONTROLLER_PAGE_LIMIT);
+	byte_addr = offset % page_size;
+
+	flash->spi->rw = SPI_WRITE_FLAG;
+	ret = spi_claim_bus(flash->spi);
+	if (ret) {
+		printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n");
+		return ret;
+	}
+
+	for (actual = 0; actual < len; actual += chunk_len) {
+		chunk_len = min(len - actual, page_size - byte_addr);
+
+		cmd[0] = CMD_AT25DF_PP;
+		cmd[1] = (offset >> 16) & 0xff;
+		cmd[2] = (offset >> 8) & 0xff;
+		cmd[3] = offset & 0xff;
+#if CONFIG_DEBUG_SPI_FLASH
+		printk(BIOS_SPEW, "PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x }"
+		        " chunk_len = %zu\n", buf + actual,
+			cmd[0], cmd[1], cmd[2], cmd[3], chunk_len);
+#endif
+
+		ret = spi_flash_cmd(flash->spi, CMD_AT25DF_WREN, NULL, 0);
+		if (ret < 0) {
+			printk(BIOS_WARNING, "SF: Enabling Write failed\n");
+			goto out;
+		}
+
+		ret = spi_flash_cmd_write(flash->spi, cmd, 4,
+				buf + actual, chunk_len);
+		if (ret < 0) {
+			printk(BIOS_WARNING, "SF: adesto Page Program failed\n");
+			goto out;
+		}
+
+		ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
+		if (ret)
+			goto out;
+
+		offset += chunk_len;
+		byte_addr = 0;
+	}
+
+#if CONFIG_DEBUG_SPI_FLASH
+	printk(BIOS_SPEW, "SF: adesto: Successfully programmed %zu bytes @"
+			" 0x%lx\n", len, (unsigned long)(offset - len));
+#endif
+	ret = 0;
+
+out:
+	spi_release_bus(flash->spi);
+	return ret;
+}
+
+static int adesto_erase(struct spi_flash *flash, u32 offset, size_t len)
+{
+	return spi_flash_cmd_erase(flash, CMD_AT25DF_SE, offset, len);
+}
+
+struct spi_flash *spi_flash_probe_adesto(struct spi_slave *spi, u8 *idcode)
+{
+	const struct adesto_spi_flash_params *params;
+	unsigned page_size;
+	struct adesto_spi_flash *stm;
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(adesto_spi_flash_table); i++) {
+		params = &adesto_spi_flash_table[i];
+		if (params->id == ((idcode[1] << 8) | idcode[2]))
+			break;
+	}
+
+	if (i == ARRAY_SIZE(adesto_spi_flash_table)) {
+		printk(BIOS_WARNING, "SF: Unsupported adesto ID %02x%02x\n",
+				idcode[1], idcode[2]);
+		return NULL;
+	}
+
+	stm = malloc(sizeof(struct adesto_spi_flash));
+	if (!stm) {
+		printk(BIOS_WARNING, "SF: Failed to allocate memory\n");
+		return NULL;
+	}
+
+	stm->params = params;
+	stm->flash.spi = spi;
+	stm->flash.name = params->name;
+
+	/* Assuming power-of-two page size initially. */
+	page_size = 1 << params->l2_page_size;
+
+	stm->flash.write = adesto_write;
+	stm->flash.erase = adesto_erase;
+#if CONFIG_SPI_FLASH_NO_FAST_READ
+	stm->flash.read = spi_flash_cmd_read_slow;
+#else
+	stm->flash.read = spi_flash_cmd_read_fast;
+#endif
+	stm->flash.sector_size = (1 << stm->params->l2_page_size) *
+		stm->params->pages_per_sector;
+	stm->flash.size = page_size * params->pages_per_sector
+				* params->sectors_per_block
+				* params->nr_blocks;
+
+	return &stm->flash;
+}
diff --git a/src/drivers/spi/spi_flash.c b/src/drivers/spi/spi_flash.c
index ada4f3a..7a4904f 100644
--- a/src/drivers/spi/spi_flash.c
+++ b/src/drivers/spi/spi_flash.c
@@ -243,6 +243,9 @@ static struct {
 #if CONFIG_SPI_FLASH_STMICRO
 	{ 0, 0xff, spi_flash_probe_stmicro, },
 #endif
+#if CONFIG_SPI_FLASH_ADESTO
+	{ 0, 0x1f, spi_flash_probe_adesto, },
+#endif
 };
 #define IDCODE_LEN (IDCODE_CONT_LEN + IDCODE_PART_LEN)
 
diff --git a/src/drivers/spi/spi_flash_internal.h b/src/drivers/spi/spi_flash_internal.h
index 37ffee6..fe4a51f 100644
--- a/src/drivers/spi/spi_flash_internal.h
+++ b/src/drivers/spi/spi_flash_internal.h
@@ -80,4 +80,5 @@ struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 *idcode);
 struct spi_flash *spi_flash_probe_winbond(struct spi_slave *spi, u8 *idcode);
 struct spi_flash *spi_flash_probe_gigadevice(struct spi_slave *spi,
 					     u8 *idcode);
+struct spi_flash *spi_flash_probe_adesto(struct spi_slave *spi, u8 *idcode);
 struct spi_flash *spi_fram_probe_ramtron(struct spi_slave *spi, u8 *idcode);



More information about the coreboot-gerrit mailing list