[U-Boot] [RFC PATCH] sf: New SF-NOR framework

Jagannadha Sutradharudu Teki jagannadh.teki at gmail.com
Tue Nov 11 21:50:35 CET 2014


This is long lasting work that I did last few months back,
I'm sure it's where much need now.

- spi driver: drivers/spi/fsl_qspi.c
- flash attributes in spi_slave {} and
- etc ...
making spi subsystem becomes more flash specific rather operating
as a generic spi bus. So SF-NOR divides normal spi flash operations
through generic SPI API's(sf_spi.c) and more spi flash(sf) specific
operations through SF NOR API's.

So the controllers those are operating more on flash needs to
write a driver on drivers/mtd/spi/ example fsl_qspi.c

I have not tested more accuratly as of now, will come back again
with new feature additions/removal, zynq_qspi additions and more...

Note: dm-spi ops can gets effected with this new framework
{ .ops            = &spi_flash_std_ops, } and will fix that in next
version patches.

Signed-off-by: Jagannadha Sutradharudu Teki <jagannadh.teki at gmail.com>
---
 doc/SPI/README.sf-nor     |  51 ++++++
 drivers/mtd/spi/Makefile  |   4 +-
 drivers/mtd/spi/sf_core.c | 389 ++++++++++++++++++++++++++++++++++++++++++++++
 drivers/mtd/spi/sf_core.h | 263 +++++++++++++++++++++++++++++++
 drivers/mtd/spi/sf_ops.c  | 147 +++++++-----------
 drivers/mtd/spi/sf_spi.c  | 230 +++++++++++++++++++++++++++
 include/spi_flash.h       |  15 +-
 7 files changed, 996 insertions(+), 103 deletions(-)
 create mode 100644 doc/SPI/README.sf-nor
 create mode 100644 drivers/mtd/spi/sf_core.c
 create mode 100644 drivers/mtd/spi/sf_core.h
 create mode 100644 drivers/mtd/spi/sf_spi.c

diff --git a/doc/SPI/README.sf-nor b/doc/SPI/README.sf-nor
new file mode 100644
index 0000000..ded60f1
--- /dev/null
+++ b/doc/SPI/README.sf-nor
@@ -0,0 +1,51 @@
+SF-NOR framework:
+================
+
+1. Introduction
+
+Due to vast increasing of new spi flash features and operations the current
+serial flash framework in u-boot is difficult to manage the relation between
+spi bus vs spi flash(one of the connected slave). All newly added features
+are effecting spi_slave {} to become flash specific rather than generic spi bus.
+
+So there is a new framework that divides normal flash operations through generic
+SPI API's and more spi flash(sf) specific operations through SF NOR API's.
+
+This division of operations are taken care by new framework called "sf-nor".
+
+2. SF NOR
+
+		 _______________
+		|		|
+		|    cmd_sf.c	|
+		|_______________|
+			|
+			|
+		 _______V_______
+		|		|
+		|  spi_flash.h	|
+		|_______________|
+			|
+			|
+	       _________V_________	
+	      |		          |
+	      |    sf_core        |
+	      |    (sf_core.c)    |
+	      |___________________|
+		     |	       |	
+		     |	       |
+		 ____V____     |
+		|	  |    |
+		| sf_spi.c|    |
+		|_________|    |
+		     |	       |
+		     |	       |
+		     V	       V	
+	    drivers/spi/*    drivers/mtd/spi/zynq_qspi.c
+
+common/cmd_sf.c: spi flash command interface
+include/spi_flash.h: spi flash api interface
+drivers/mtd/spi/sf_core.c: SF Core
+drivers/mtd/spi/sf_spi.c: sf emulation for all drivers/spi/*
+drivers/spi: spi drivers
+drivers/mtd/spi/zynq_qspi.c: zynq qspi controller driver
diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile
index 15789a0..2ddeadf 100644
--- a/drivers/mtd/spi/Makefile
+++ b/drivers/mtd/spi/Makefile
@@ -13,9 +13,9 @@ obj-$(CONFIG_SPL_SPI_BOOT)	+= fsl_espi_spl.o
 endif
 
 #ifndef CONFIG_DM_SPI
-obj-$(CONFIG_SPI_FLASH) += sf_probe.o
+obj-$(CONFIG_SPI_FLASH) += sf_core.o
 #endif
-obj-$(CONFIG_CMD_SF) += sf.o
+obj-$(CONFIG_CMD_SF) += sf_spi.o
 obj-$(CONFIG_SPI_FLASH) += sf_ops.o sf_params.o
 obj-$(CONFIG_SPI_FRAM_RAMTRON) += ramtron.o
 obj-$(CONFIG_SPI_FLASH_SANDBOX) += sandbox.o
diff --git a/drivers/mtd/spi/sf_core.c b/drivers/mtd/spi/sf_core.c
new file mode 100644
index 0000000..dcc78a7
--- /dev/null
+++ b/drivers/mtd/spi/sf_core.c
@@ -0,0 +1,389 @@
+/*
+ * SPI flash probing
+ *
+ * Copyright (C) 2008 Atmel Corporation
+ * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik
+ * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <malloc.h>
+#include <spi.h>
+#include <spi_flash.h>
+#include <asm/io.h>
+
+#include "sf_core.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Read commands array */
+static u8 spi_read_cmds_array[] = {
+	CMD_READ_ARRAY_SLOW,
+	CMD_READ_DUAL_OUTPUT_FAST,
+	CMD_READ_DUAL_IO_FAST,
+	CMD_READ_QUAD_OUTPUT_FAST,
+	CMD_READ_QUAD_IO_FAST,
+};
+
+#ifdef CONFIG_SPI_FLASH_MACRONIX
+static int spi_flash_set_qeb_mxic(struct sf_nor *nor)
+{
+	u8 qeb_status;
+	int ret;
+
+	ret = spi_flash_cmd_read_status(flash, &qeb_status);
+	if (ret < 0)
+		return ret;
+
+	if (qeb_status & STATUS_QEB_MXIC) {
+		debug("SF: mxic: QEB is already set\n");
+	} else {
+		ret = spi_flash_cmd_write_status(flash, STATUS_QEB_MXIC);
+		if (ret < 0)
+			return ret;
+	}
+
+	return ret;
+}
+#endif
+
+#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND)
+static int spi_flash_set_qeb_winspan(struct spi_flash *flash)
+{
+	u8 qeb_status;
+	int ret;
+
+	ret = spi_flash_cmd_read_config(flash, &qeb_status);
+	if (ret < 0)
+		return ret;
+
+	if (qeb_status & STATUS_QEB_WINSPAN) {
+		debug("SF: winspan: QEB is already set\n");
+	} else {
+		ret = spi_flash_cmd_write_config(flash, STATUS_QEB_WINSPAN);
+		if (ret < 0)
+			return ret;
+	}
+
+	return ret;
+}
+#endif
+
+static int spi_flash_set_qeb(struct sf_nor *nor, u8 idcode0)
+{
+	switch (idcode0) {
+#ifdef CONFIG_SPI_FLASH_MACRONIX
+	case SPI_FLASH_CFI_MFR_MACRONIX:
+		return spi_flash_set_qeb_mxic(nor);
+#endif
+#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND)
+	case SPI_FLASH_CFI_MFR_SPANSION:
+	case SPI_FLASH_CFI_MFR_WINBOND:
+		return spi_flash_set_qeb_winspan(nor);
+#endif
+#ifdef CONFIG_SPI_FLASH_STMICRO
+	case SPI_FLASH_CFI_MFR_STMICRO:
+		debug("SF: QEB is volatile for %02x flash\n", idcode0);
+		return 0;
+#endif
+	default:
+		printf("SF: Need set QEB func for %02x flash\n", idcode0);
+		return -1;
+	}
+}
+
+static int spi_flash_validate_params(struct sf_nor *nor, u8 *idcode)
+{
+	struct spi_flash *flash = nor->priv;
+	struct spi_slave *spi = flash->spi;
+	const struct spi_flash_params *params;
+	u8 cmd;
+	u16 jedec = idcode[1] << 8 | idcode[2];
+	u16 ext_jedec = idcode[3] << 8 | idcode[4];
+
+	/* Validate params from spi_flash_params table */
+	params = spi_flash_params_table;
+	for (; params->name != NULL; params++) {
+		if ((params->jedec >> 16) == idcode[0]) {
+			if ((params->jedec & 0xFFFF) == jedec) {
+				if (params->ext_jedec == 0)
+					break;
+				else if (params->ext_jedec == ext_jedec)
+					break;
+			}
+		}
+	}
+
+	if (!params->name) {
+		printf("SF: Unsupported flash IDs: ");
+		printf("manuf %02x, jedec %04x, ext_jedec %04x\n",
+		       idcode[0], jedec, ext_jedec);
+		return -EPROTONOSUPPORT;
+	}
+
+	/* Assign spi data */
+	flash->spi = spi;
+	flash->name = params->name;
+	nor->memory_map = spi->memory_map;
+	nor->dual_flash = flash->spi->option;
+
+	/* Assign spi_flash ops */
+#ifndef CONFIG_DM_SPI_FLASH
+	flash->write = sf_nor_write;
+#if defined(CONFIG_SPI_FLASH_SST)
+	if (params->flags & SST_WP)
+		flash->write = sst_write_wp;
+#endif
+	flash->erase = sf_nor_erase;
+	flash->read = sf_nor_read;
+#endif
+
+	/* Compute the flash size */
+	nor->shift = (nor->dual_flash & SF_DUAL_PARALLEL_FLASH) ? 1 : 0;
+	/*
+	 * The Spansion S25FL032P and S25FL064P have 256b pages, yet use the
+	 * 0x4d00 Extended JEDEC code. The rest of the Spansion flashes with
+	 * the 0x4d00 Extended JEDEC code have 512b pages. All of the others
+	 * have 256b pages.
+	 */
+	if (ext_jedec == 0x4d00) {
+		if ((jedec == 0x0215) || (jedec == 0x216))
+			nor->page_size = 256;
+		else
+			nor->page_size = 512;
+	} else {
+		nor->page_size = 256;
+	}
+	nor->page_size <<= nor->shift;
+	nor->sector_size = params->sector_size << nor->shift;
+	flash->size = nor->sector_size * params->nr_sectors << nor->shift;
+#ifdef CONFIG_SF_DUAL_FLASH
+	if (nor->dual_flash & SF_DUAL_STACKED_FLASH)
+		flash->size <<= 1;
+#endif
+
+	/* Compute erase sector and command */
+	if (params->flags & SECT_4K) {
+		nor->erase_cmd = CMD_ERASE_4K;
+		flash->erase_size = 4096 << nor->shift;
+	} else if (params->flags & SECT_32K) {
+		nor->erase_cmd = CMD_ERASE_32K;
+		flash->erase_size = 32768 << nor->shift;
+	} else {
+		nor->erase_cmd = CMD_ERASE_64K;
+		flash->erase_size = nor->sector_size;
+	}
+
+	/* Look for the fastest read cmd */
+	cmd = fls(params->e_rd_cmd & flash->spi->op_mode_rx);
+	if (cmd) {
+		cmd = spi_read_cmds_array[cmd - 1];
+		nor->read_cmd = cmd;
+	} else {
+		/* Go for default supported read cmd */
+		nor->read_cmd = CMD_READ_ARRAY_FAST;
+	}
+
+	/* Not require to look for fastest only two write cmds yet */
+	if (params->flags & WR_QPP && flash->spi->op_mode_tx & SPI_OPM_TX_QPP)
+		nor->write_cmd = CMD_QUAD_PAGE_PROGRAM;
+	else
+		/* Go for default supported write cmd */
+		nor->write_cmd = CMD_PAGE_PROGRAM;
+
+	/* Read dummy_byte: dummy byte is determined based on the
+	 * dummy cycles of a particular command.
+	 * Fast commands - dummy_byte = dummy_cycles/8
+	 * I/O commands- dummy_byte = (dummy_cycles * no.of lines)/8
+	 * For I/O commands except cmd[0] everything goes on no.of lines
+	 * based on particular command but incase of fast commands except
+	 * data all go on single line irrespective of command.
+	 */
+	switch (nor->read_cmd) {
+	case CMD_READ_QUAD_IO_FAST:
+		nor->dummy_byte = 2;
+		break;
+	case CMD_READ_ARRAY_SLOW:
+		nor->dummy_byte = 0;
+		break;
+	default:
+		nor->dummy_byte = 1;
+	}
+
+	/* Poll cmd selection */
+	nor->poll_cmd = CMD_READ_STATUS;
+#ifdef CONFIG_SPI_FLASH_STMICRO
+	if (params->flags & E_FSR)
+		nor->poll_cmd = CMD_FLAG_STATUS;
+#endif
+
+	/* Configure the BAR - discover bank cmds and read current bank */
+#ifdef CONFIG_SPI_FLASH_BAR
+	u8 curr_bank = 0;
+	if (flash->size > SPI_FLASH_16MB_BOUN) {
+		int ret;
+
+		nor->bank_read_cmd = (idcode[0] == 0x01) ?
+					CMD_BANKADDR_BRRD : CMD_EXTNADDR_RDEAR;
+		nor->bank_write_cmd = (idcode[0] == 0x01) ?
+					CMD_BANKADDR_BRWR : CMD_EXTNADDR_WREAR;
+
+		ret = spi_flash_read_common(flash, &nor->bank_read_cmd, 1,
+					    &curr_bank, 1);
+		if (ret) {
+			debug("SF: fail to read bank addr register\n");
+			return ret;
+		}
+		nor->bank_curr = curr_bank;
+	} else {
+		nor->bank_curr = curr_bank;
+	}
+#endif
+
+	/* Flash powers up read-only, so clear BP# bits */
+#if defined(CONFIG_SPI_FLASH_ATMEL) || \
+	defined(CONFIG_SPI_FLASH_MACRONIX) || \
+	defined(CONFIG_SPI_FLASH_SST)
+		spi_flash_cmd_write_status(nor, 0);
+#endif
+
+	return 0;
+}
+
+#ifdef CONFIG_OF_CONTROL
+int spi_flash_decode_fdt(const void *blob, struct sf_nor *nor)
+{
+	struct spi_flash *flash = nor->priv;
+	fdt_addr_t addr;
+	fdt_size_t size;
+	int node;
+
+	/* If there is no node, do nothing */
+	node = fdtdec_next_compatible(blob, 0, COMPAT_GENERIC_SPI_FLASH);
+	if (node < 0)
+		return 0;
+
+	addr = fdtdec_get_addr_size(blob, node, "memory-map", &size);
+	if (addr == FDT_ADDR_T_NONE) {
+		debug("%s: Cannot decode address\n", __func__);
+		return 0;
+	}
+
+	if (flash->size != size) {
+		debug("%s: Memory map must cover entire device\n", __func__);
+		return -1;
+	}
+	nor->memory_map = map_sysmem(addr, size);
+
+	return 0;
+}
+#endif /* CONFIG_OF_CONTROL */
+
+#ifdef CONFIG_SYS_SPI_ST_ENABLE_WP_PIN
+/* enable the W#/Vpp signal to disable writing to the status register */
+static int spi_enable_wp_pin(struct spi_flash *flash)
+{
+	u8 status;
+	int ret;
+
+	ret = spi_flash_cmd_read_status(flash, &status);
+	if (ret < 0)
+		return ret;
+
+	ret = spi_flash_cmd_write_status(flash, STATUS_SRWD);
+	if (ret < 0)
+		return ret;
+
+	ret = spi_flash_cmd_write_disable(flash);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+#else
+static int spi_enable_wp_pin(struct spi_flash *flash)
+{
+	return 0;
+}
+#endif
+
+/**
+ * spi_flash_probe_slave() - Probe for a SPI flash device on a bus
+ *
+ * @spi: Bus to probe
+ * @flashp: Pointer to place to put flash info, which may be NULL if the
+ * space should be allocated
+ */
+int sf_nor_scan(struct sf_nor *nor)
+{
+	struct spi_flash *flash = nor->priv;
+	u8 cmd, idcode[5];
+	int ret;
+
+	/* Read the ID codes */
+	cmd = CMD_READ_ID;
+	ret = nor->read(nor, &cmd, 1, idcode, 5);
+	if (ret) {
+		printf("SF: Failed to get idcodes\n");
+		goto err_read_id;
+	}
+
+#ifdef DEBUG
+	printf("SF: Got idcodes\n");
+	print_buffer(0, idcode, 1, sizeof(idcode), 0);
+#endif
+
+	if (spi_flash_validate_params(nor, idcode)) {
+		ret = -EINVAL;
+		goto err_read_id;
+	}
+
+	/* Set the quad enable bit - only for quad commands */
+	if ((nor->read_cmd == CMD_READ_QUAD_OUTPUT_FAST) ||
+	    (nor->read_cmd == CMD_READ_QUAD_IO_FAST) ||
+	    (nor->write_cmd == CMD_QUAD_PAGE_PROGRAM)) {
+		if (spi_flash_set_qeb(nor, idcode[0])) {
+			debug("SF: Fail to set QEB for %02x\n", idcode[0]);
+			ret = -EINVAL;
+			goto err_read_id;
+		}
+	}
+
+#ifdef CONFIG_OF_CONTROL
+	if (spi_flash_decode_fdt(gd->fdt_blob, nor)) {
+		debug("SF: FDT decode error\n");
+		ret = -EINVAL;
+		goto err_read_id;
+	}
+#endif
+#ifndef CONFIG_SPL_BUILD
+	printf("SF: Detected %s with page size ", flash->name);
+	print_size(nor->page_size, ", erase size ");
+	print_size(flash->erase_size, ", total ");
+	print_size(flash->size, "");
+	if (nor->memory_map)
+		printf(", mapped at %p", nor->memory_map);
+	puts("\n");
+#endif
+#ifndef CONFIG_SPI_FLASH_BAR
+	if (((nor->dual_flash == SF_SINGLE_FLASH) &&
+	     (flash->size > SPI_FLASH_16MB_BOUN)) ||
+	     ((nor->dual_flash > SF_SINGLE_FLASH) &&
+	     (flash->size > SPI_FLASH_16MB_BOUN << 1))) {
+		puts("SF: Warning - Only lower 16MiB accessible,");
+		puts(" Full access #define CONFIG_SPI_FLASH_BAR\n");
+	}
+#endif
+	if (spi_enable_wp_pin(flash))
+		puts("Enable WP pin failed\n");
+
+	return 0;
+
+err_read_id:
+	return ret;
+}
diff --git a/drivers/mtd/spi/sf_core.h b/drivers/mtd/spi/sf_core.h
new file mode 100644
index 0000000..05af241
--- /dev/null
+++ b/drivers/mtd/spi/sf_core.h
@@ -0,0 +1,263 @@
+/*
+ * SPI flash internal definitions
+ *
+ * Copyright (C) 2008 Atmel Corporation
+ * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _SF_INTERNAL_H_
+#define _SF_INTERNAL_H_
+
+#include <linux/types.h>
+#include <linux/compiler.h>
+
+/* Dual SPI flash memories - see SPI_COMM_DUAL_... */
+enum spi_dual_flash {
+	SF_SINGLE_FLASH	= 0,
+	SF_DUAL_STACKED_FLASH	= 1 << 0,
+	SF_DUAL_PARALLEL_FLASH	= 1 << 1,
+};
+
+/* Enum list - Full read commands */
+enum spi_read_cmds {
+	ARRAY_SLOW		= 1 << 0,
+	DUAL_OUTPUT_FAST	= 1 << 1,
+	DUAL_IO_FAST		= 1 << 2,
+	QUAD_OUTPUT_FAST	= 1 << 3,
+	QUAD_IO_FAST		= 1 << 4,
+};
+
+#define RD_EXTN	(ARRAY_SLOW | DUAL_OUTPUT_FAST | DUAL_IO_FAST)
+#define RD_FULL	(RD_EXTN | QUAD_OUTPUT_FAST | QUAD_IO_FAST)
+
+/* sf param flags */
+enum {
+	SECT_4K		= 1 << 0,
+	SECT_32K	= 1 << 1,
+	E_FSR		= 1 << 2,
+	WR_QPP		= 1 << 3,
+};
+
+#define SPI_FLASH_3B_ADDR_LEN		3
+#define SPI_FLASH_CMD_LEN		(1 + SPI_FLASH_3B_ADDR_LEN)
+#define SPI_FLASH_16MB_BOUN		0x1000000
+
+/* CFI Manufacture ID's */
+#define SPI_FLASH_CFI_MFR_SPANSION	0x01
+#define SPI_FLASH_CFI_MFR_STMICRO	0x20
+#define SPI_FLASH_CFI_MFR_MACRONIX	0xc2
+#define SPI_FLASH_CFI_MFR_WINBOND	0xef
+
+/* Erase commands */
+#define CMD_ERASE_4K			0x20
+#define CMD_ERASE_32K			0x52
+#define CMD_ERASE_CHIP			0xc7
+#define CMD_ERASE_64K			0xd8
+
+/* Write commands */
+#define CMD_WRITE_STATUS		0x01
+#define CMD_PAGE_PROGRAM		0x02
+#define CMD_WRITE_DISABLE		0x04
+#define CMD_READ_STATUS		0x05
+#define CMD_QUAD_PAGE_PROGRAM		0x32
+#define CMD_READ_STATUS1		0x35
+#define CMD_WRITE_ENABLE		0x06
+#define CMD_READ_CONFIG		0x35
+#define CMD_FLAG_STATUS		0x70
+
+/* Read commands */
+#define CMD_READ_ARRAY_SLOW		0x03
+#define CMD_READ_ARRAY_FAST		0x0b
+#define CMD_READ_DUAL_OUTPUT_FAST	0x3b
+#define CMD_READ_DUAL_IO_FAST		0xbb
+#define CMD_READ_QUAD_OUTPUT_FAST	0x6b
+#define CMD_READ_QUAD_IO_FAST		0xeb
+#define CMD_READ_ID			0x9f
+
+/* Bank addr access commands */
+#ifdef CONFIG_SPI_FLASH_BAR
+# define CMD_BANKADDR_BRWR		0x17
+# define CMD_BANKADDR_BRRD		0x16
+# define CMD_EXTNADDR_WREAR		0xC5
+# define CMD_EXTNADDR_RDEAR		0xC8
+#endif
+
+/* Common status */
+#define STATUS_WIP			(1 << 0)
+#define STATUS_QEB_WINSPAN		(1 << 1)
+#define STATUS_QEB_MXIC		(1 << 6)
+#define STATUS_PEC			(1 << 7)
+
+#ifdef CONFIG_SYS_SPI_ST_ENABLE_WP_PIN
+#define STATUS_SRWD			(1 << 7) /* SR write protect */
+#endif
+
+/* Flash timeout values */
+#define SPI_FLASH_PROG_TIMEOUT		(2 * CONFIG_SYS_HZ)
+#define SPI_FLASH_PAGE_ERASE_TIMEOUT		(5 * CONFIG_SYS_HZ)
+#define SPI_FLASH_SECTOR_ERASE_TIMEOUT	(10 * CONFIG_SYS_HZ)
+
+/* SST specific */
+#ifdef CONFIG_SPI_FLASH_SST
+# define SST_WP		0x01	/* Supports AAI word program */
+# define CMD_SST_BP		0x02    /* Byte Program */
+# define CMD_SST_AAI_WP	0xAD	/* Auto Address Incr Word Program */
+
+int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len,
+		const void *buf);
+#endif
+
+/**
+ * struct spi_flash_params - SPI/QSPI flash device params structure
+ *
+ * @name:		Device name ([MANUFLETTER][DEVTYPE][DENSITY][EXTRAINFO])
+ * @jedec:		Device jedec ID (0x[1byte_manuf_id][2byte_dev_id])
+ * @ext_jedec:		Device ext_jedec ID
+ * @sector_size:	Sector size of this device
+ * @nr_sectors:	No.of sectors on this device
+ * @e_rd_cmd:		Enum list for read commands
+ * @flags:		Important param, for flash specific behaviour
+ */
+struct spi_flash_params {
+	const char *name;
+	u32 jedec;
+	u16 ext_jedec;
+	u32 sector_size;
+	u32 nr_sectors;
+	u8 e_rd_cmd;
+	u16 flags;
+};
+
+extern const struct spi_flash_params spi_flash_params_table[];
+
+/* Send a single-byte command to the device and read the response */
+int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len);
+
+/*
+ * Send a multi-byte command to the device and read the response. Used
+ * for flash array reads, etc.
+ */
+int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd,
+		size_t cmd_len, void *data, size_t data_len);
+
+/*
+ * Send a multi-byte command to the device followed by (optional)
+ * data. Used for programming the flash array, etc.
+ */
+int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len,
+		const void *data, size_t data_len);
+
+
+/* Flash erase(sectors) operation, support all possible erase commands */
+int sf_nor_erase(struct spi_flash *flash, u32 offset, size_t len);
+
+/* Read the status register */
+int spi_flash_cmd_read_status(struct sf_nor *nor, u8 *rs);
+
+/* Program the status register */
+int spi_flash_cmd_write_status(struct sf_nor *nor, u8 ws);
+
+/* Read the config register */
+int spi_flash_cmd_read_config(struct sf_nor *nor, u8 *rc);
+
+/* Program the config register */
+int spi_flash_cmd_write_config(struct sf_nor *nor, u8 wc);
+
+/* Enable writing on the SPI flash */
+static inline int spi_flash_cmd_write_enable(struct spi_flash *flash)
+{
+	return spi_flash_cmd(flash->spi, CMD_WRITE_ENABLE, NULL, 0);
+}
+
+/* Disable writing on the SPI flash */
+static inline int spi_flash_cmd_write_disable(struct spi_flash *flash)
+{
+	return spi_flash_cmd(flash->spi, CMD_WRITE_DISABLE, NULL, 0);
+}
+
+/*
+ * Send the read status command to the device and wait for the wip
+ * (write-in-progress) bit to clear itself.
+ */
+int spi_flash_cmd_wait_ready(struct sf_nor *nor, unsigned long timeout);
+
+/*
+ * Used for spi_flash write operation
+ * - SPI claim
+ * - spi_flash_cmd_write_enable
+ * - spi_flash_cmd_write
+ * - spi_flash_cmd_wait_ready
+ * - SPI release
+ */
+int sf_nor_write_common(struct sf_nor *nor, const u8 *cmd,
+		size_t cmd_len, const void *buf, size_t buf_len);
+
+/*
+ * Flash write operation, support all possible write commands.
+ * Write the requested data out breaking it up into multiple write
+ * commands as needed per the write size.
+ */
+int sf_nor_write(struct spi_flash *flash, u32 offset,
+		size_t len, const void *buf);
+
+/*
+ * Same as spi_flash_cmd_read() except it also claims/releases the SPI
+ * bus. Used as common part of the ->read() operation.
+ */
+int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd,
+		size_t cmd_len, void *data, size_t data_len);
+
+/* Flash read operation, support all possible read commands */
+int sf_nor_read(struct spi_flash *flash, u32 offset,
+		size_t len, void *data);
+
+
+/**
+ * struct sf_nor - SF NOR structure
+ *
+ * @spi:		SPI slave
+ * @poll_cmd:		Poll cmd - for flash erase/program
+ * @erase_cmd:		Erase cmd 4K, 32K, 64K
+ * @read_cmd:		Read cmd - Array Fast, Extn read and quad read.
+ * @write_cmd:		Write cmd - page and quad program.
+ * @read:		Flash read ops: Read len bytes at offset into buf
+ *			Supported cmds: Fast Array Read
+ * @write:		Flash write ops: Write len bytes from buf into offeset
+ *			Supported cmds: Page Program
+ * @erase:		Flash erase ops: Erase len bytes from offset
+ *			Supported cmds: Sector erase 4K, 32K, 64K
+ * return 0 - Sucess, 1 - Failure
+ */
+struct sf_nor {
+	u32 page_size;
+	u32 sector_size;
+
+	u8 dual_flash;
+	u8 shift;
+
+#ifdef CONFIG_SPI_FLASH_BAR
+        u8 bank_read_cmd;
+        u8 bank_write_cmd;
+        u8 bank_curr;
+#endif
+	u8 poll_cmd;
+	u8 erase_cmd;
+	u8 read_cmd;
+	u8 write_cmd;
+	u8 dummy_byte;
+
+	void *memory_map;
+	int (*read)(struct sf_nor *nor, const u8 *cmd, size_t cmd_len,
+			void *data, size_t data_len);
+	int (*write)(struct sf_nor *nor, const u8 *cmd, size_t cmd_len,
+			const void *data, size_t data_len);
+	int (*wait_till_ready)(struct sf_nor *nor);
+	void *priv;
+};
+
+/* Scan for sf nor flash */
+int sf_nor_scan(struct sf_nor *nor);
+
+#endif /* _SF_INTERNAL_H_ */
diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/sf_ops.c
index 85cf22d..2ae2d66 100644
--- a/drivers/mtd/spi/sf_ops.c
+++ b/drivers/mtd/spi/sf_ops.c
@@ -15,7 +15,7 @@
 #include <spi_flash.h>
 #include <watchdog.h>
 
-#include "sf_internal.h"
+#include "sf_core.h"
 
 static void spi_flash_addr(u32 addr, u8 *cmd)
 {
@@ -25,13 +25,13 @@ static void spi_flash_addr(u32 addr, u8 *cmd)
 	cmd[3] = addr >> 0;
 }
 
-int spi_flash_cmd_read_status(struct spi_flash *flash, u8 *rs)
+int spi_flash_cmd_read_status(struct sf_nor *nor, u8 *rs)
 {
 	int ret;
 	u8 cmd;
 
 	cmd = CMD_READ_STATUS;
-	ret = spi_flash_read_common(flash, &cmd, 1, rs, 1);
+	ret = nor->read(nor, &cmd, 1, rs, 1);
 	if (ret < 0) {
 		debug("SF: fail to read status register\n");
 		return ret;
@@ -40,13 +40,13 @@ int spi_flash_cmd_read_status(struct spi_flash *flash, u8 *rs)
 	return 0;
 }
 
-int spi_flash_cmd_write_status(struct spi_flash *flash, u8 ws)
+int spi_flash_cmd_write_status(struct sf_nor *nor, u8 ws)
 {
 	u8 cmd;
 	int ret;
 
 	cmd = CMD_WRITE_STATUS;
-	ret = spi_flash_write_common(flash, &cmd, 1, &ws, 1);
+	ret = sf_nor_write_common(nor, &cmd, 1, &ws, 1);
 	if (ret < 0) {
 		debug("SF: fail to write status register\n");
 		return ret;
@@ -62,7 +62,7 @@ int spi_flash_cmd_read_config(struct spi_flash *flash, u8 *rc)
 	u8 cmd;
 
 	cmd = CMD_READ_CONFIG;
-	ret = spi_flash_read_common(flash, &cmd, 1, rc, 1);
+	ret = nor->read(flash, &cmd, 1, rc, 1);
 	if (ret < 0) {
 		debug("SF: fail to read config register\n");
 		return ret;
@@ -71,19 +71,19 @@ int spi_flash_cmd_read_config(struct spi_flash *flash, u8 *rc)
 	return 0;
 }
 
-int spi_flash_cmd_write_config(struct spi_flash *flash, u8 wc)
+int spi_flash_cmd_write_config(struct sf_nor *nor, u8 wc)
 {
 	u8 data[2];
 	u8 cmd;
 	int ret;
 
-	ret = spi_flash_cmd_read_status(flash, &data[0]);
+	ret = spi_flash_cmd_read_status(nor, &data[0]);
 	if (ret < 0)
 		return ret;
 
 	cmd = CMD_WRITE_STATUS;
 	data[1] = wc;
-	ret = spi_flash_write_common(flash, &cmd, 1, &data, 2);
+	ret = sf_nor_write_common(nor, &cmd, 1, &data, 2);
 	if (ret) {
 		debug("SF: fail to write config register\n");
 		return ret;
@@ -99,18 +99,18 @@ static int spi_flash_cmd_bankaddr_write(struct spi_flash *flash, u8 bank_sel)
 	u8 cmd;
 	int ret;
 
-	if (flash->bank_curr == bank_sel) {
+	if (nor->bank_curr == bank_sel) {
 		debug("SF: not require to enable bank%d\n", bank_sel);
 		return 0;
 	}
 
-	cmd = flash->bank_write_cmd;
-	ret = spi_flash_write_common(flash, &cmd, 1, &bank_sel, 1);
+	cmd = nor->bank_write_cmd;
+	ret = sf_nor_write_common(flash, &cmd, 1, &bank_sel, 1);
 	if (ret < 0) {
 		debug("SF: fail to write bank register\n");
 		return ret;
 	}
-	flash->bank_curr = bank_sel;
+	nor->bank_curr = bank_sel;
 
 	return 0;
 }
@@ -120,7 +120,7 @@ static int spi_flash_bank(struct spi_flash *flash, u32 offset)
 	u8 bank_sel;
 	int ret;
 
-	bank_sel = offset / (SPI_FLASH_16MB_BOUN << flash->shift);
+	bank_sel = offset / (SPI_FLASH_16MB_BOUN << nor->shift);
 
 	ret = spi_flash_cmd_bankaddr_write(flash, bank_sel);
 	if (ret) {
@@ -135,7 +135,7 @@ static int spi_flash_bank(struct spi_flash *flash, u32 offset)
 #ifdef CONFIG_SF_DUAL_FLASH
 static void spi_flash_dual_flash(struct spi_flash *flash, u32 *addr)
 {
-	switch (flash->dual_flash) {
+	switch (nor->dual_flash) {
 	case SF_DUAL_STACKED_FLASH:
 		if (*addr >= (flash->size >> 1)) {
 			*addr -= flash->size >> 1;
@@ -145,17 +145,18 @@ static void spi_flash_dual_flash(struct spi_flash *flash, u32 *addr)
 		}
 		break;
 	case SF_DUAL_PARALLEL_FLASH:
-		*addr >>= flash->shift;
+		*addr >>= nor->shift;
 		break;
 	default:
-		debug("SF: Unsupported dual_flash=%d\n", flash->dual_flash);
+		debug("SF: Unsupported dual_flash=%d\n", nor->dual_flash);
 		break;
 	}
 }
 #endif
 
-int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout)
+int spi_flash_cmd_wait_ready(struct sf_nor *nor, unsigned long timeout)
 {
+	struct spi_flash *flash = nor->priv;
 	struct spi_slave *spi = flash->spi;
 	unsigned long timebase;
 	unsigned long flags = SPI_XFER_BEGIN;
@@ -163,7 +164,7 @@ int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout)
 	u8 status;
 	u8 check_status = 0x0;
 	u8 poll_bit = STATUS_WIP;
-	u8 cmd = flash->poll_cmd;
+	u8 cmd = nor->poll_cmd;
 
 	if (cmd == CMD_FLAG_STATUS) {
 		poll_bit = STATUS_PEC;
@@ -204,35 +205,28 @@ int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout)
 	return -1;
 }
 
-int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd,
+int sf_nor_write_common(struct sf_nor *nor, const u8 *cmd,
 		size_t cmd_len, const void *buf, size_t buf_len)
 {
-	struct spi_slave *spi = flash->spi;
 	unsigned long timeout = SPI_FLASH_PROG_TIMEOUT;
 	int ret;
 
 	if (buf == NULL)
 		timeout = SPI_FLASH_PAGE_ERASE_TIMEOUT;
 
-	ret = spi_claim_bus(flash->spi);
-	if (ret) {
-		debug("SF: unable to claim SPI bus\n");
-		return ret;
-	}
-
-	ret = spi_flash_cmd_write_enable(flash);
+	ret = nor->read(nor, (u8 *)CMD_WRITE_ENABLE, 1, NULL, 0);
 	if (ret < 0) {
 		debug("SF: enabling write failed\n");
 		return ret;
 	}
 
-	ret = spi_flash_cmd_write(spi, cmd, cmd_len, buf, buf_len);
+	ret = nor->write(nor, cmd, cmd_len, buf, buf_len);
 	if (ret < 0) {
 		debug("SF: write cmd failed\n");
 		return ret;
 	}
 
-	ret = spi_flash_cmd_wait_ready(flash, timeout);
+	ret = spi_flash_cmd_wait_ready(nor, timeout);
 	if (ret < 0) {
 		debug("SF: write %s timed out\n",
 		      timeout == SPI_FLASH_PROG_TIMEOUT ?
@@ -240,13 +234,12 @@ int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd,
 		return ret;
 	}
 
-	spi_release_bus(spi);
-
 	return ret;
 }
 
-int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
+int sf_nor_erase(struct spi_flash *flash, u32 offset, size_t len)
 {
+	struct sf_nor *nor = flash->nor;
 	u32 erase_size, erase_addr;
 	u8 cmd[SPI_FLASH_CMD_LEN];
 	int ret = -1;
@@ -257,12 +250,12 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
 		return -1;
 	}
 
-	cmd[0] = flash->erase_cmd;
+	cmd[0] = nor->erase_cmd;
 	while (len) {
 		erase_addr = offset;
 
 #ifdef CONFIG_SF_DUAL_FLASH
-		if (flash->dual_flash > SF_SINGLE_FLASH)
+		if (nor->dual_flash > SF_SINGLE_FLASH)
 			spi_flash_dual_flash(flash, &erase_addr);
 #endif
 #ifdef CONFIG_SPI_FLASH_BAR
@@ -275,7 +268,7 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
 		debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1],
 		      cmd[2], cmd[3], erase_addr);
 
-		ret = spi_flash_write_common(flash, cmd, sizeof(cmd), NULL, 0);
+		ret = sf_nor_write_common(nor, cmd, sizeof(cmd), NULL, 0);
 		if (ret < 0) {
 			debug("SF: erase failed\n");
 			break;
@@ -288,23 +281,23 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
 	return ret;
 }
 
-int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
-		size_t len, const void *buf)
+int sf_nor_write(struct spi_flash *flash, u32 offset, size_t len, const void *buf)
 {
+	struct sf_nor *nor = flash->nor;
 	unsigned long byte_addr, page_size;
 	u32 write_addr;
 	size_t chunk_len, actual;
 	u8 cmd[SPI_FLASH_CMD_LEN];
 	int ret = -1;
 
-	page_size = flash->page_size;
+	page_size = nor->page_size;
 
-	cmd[0] = flash->write_cmd;
+	cmd[0] = nor->write_cmd;
 	for (actual = 0; actual < len; actual += chunk_len) {
 		write_addr = offset;
 
 #ifdef CONFIG_SF_DUAL_FLASH
-		if (flash->dual_flash > SF_SINGLE_FLASH)
+		if (nor->dual_flash > SF_SINGLE_FLASH)
 			spi_flash_dual_flash(flash, &write_addr);
 #endif
 #ifdef CONFIG_SPI_FLASH_BAR
@@ -323,8 +316,7 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
 		debug("SF: 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);
 
-		ret = spi_flash_write_common(flash, cmd, sizeof(cmd),
-					buf + actual, chunk_len);
+		ret = sf_nor_write_common(nor, cmd, sizeof(cmd), buf + actual, chunk_len);
 		if (ret < 0) {
 			debug("SF: write failed\n");
 			break;
@@ -336,64 +328,42 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
 	return ret;
 }
 
-int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd,
-		size_t cmd_len, void *data, size_t data_len)
-{
-	struct spi_slave *spi = flash->spi;
-	int ret;
-
-	ret = spi_claim_bus(flash->spi);
-	if (ret) {
-		debug("SF: unable to claim SPI bus\n");
-		return ret;
-	}
-
-	ret = spi_flash_cmd_read(spi, cmd, cmd_len, data, data_len);
-	if (ret < 0) {
-		debug("SF: read cmd failed\n");
-		return ret;
-	}
-
-	spi_release_bus(spi);
-
-	return ret;
-}
-
-int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
+int sf_nor_read(struct spi_flash *flash, u32 offset,
 		size_t len, void *data)
 {
+	struct sf_nor *nor = flash->nor;
 	u8 *cmd, cmdsz;
 	u32 remain_len, read_len, read_addr;
 	int bank_sel = 0;
 	int ret = -1;
 
 	/* Handle memory-mapped SPI */
-	if (flash->memory_map) {
+	if (nor->memory_map) {
 		ret = spi_claim_bus(flash->spi);
 		if (ret) {
 			debug("SF: unable to claim SPI bus\n");
 			return ret;
 		}
 		spi_xfer(flash->spi, 0, NULL, NULL, SPI_XFER_MMAP);
-		memcpy(data, flash->memory_map + offset, len);
+		memcpy(data, nor->memory_map + offset, len);
 		spi_xfer(flash->spi, 0, NULL, NULL, SPI_XFER_MMAP_END);
 		spi_release_bus(flash->spi);
 		return 0;
 	}
 
-	cmdsz = SPI_FLASH_CMD_LEN + flash->dummy_byte;
+	cmdsz = SPI_FLASH_CMD_LEN + nor->dummy_byte;
 	cmd = calloc(1, cmdsz);
 	if (!cmd) {
 		debug("SF: Failed to allocate cmd\n");
 		return -ENOMEM;
 	}
 
-	cmd[0] = flash->read_cmd;
+	cmd[0] = nor->read_cmd;
 	while (len) {
 		read_addr = offset;
 
 #ifdef CONFIG_SF_DUAL_FLASH
-		if (flash->dual_flash > SF_SINGLE_FLASH)
+		if (nor->dual_flash > SF_SINGLE_FLASH)
 			spi_flash_dual_flash(flash, &read_addr);
 #endif
 #ifdef CONFIG_SPI_FLASH_BAR
@@ -401,7 +371,7 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
 		if (bank_sel < 0)
 			return ret;
 #endif
-		remain_len = ((SPI_FLASH_16MB_BOUN << flash->shift) *
+		remain_len = ((SPI_FLASH_16MB_BOUN << nor->shift) *
 				(bank_sel + 1)) - offset;
 		if (len < remain_len)
 			read_len = len;
@@ -410,7 +380,7 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
 
 		spi_flash_addr(read_addr, cmd);
 
-		ret = spi_flash_read_common(flash, cmd, cmdsz, data, read_len);
+		ret = nor->read(nor, cmd, cmdsz, data, read_len);
 		if (ret < 0) {
 			debug("SF: read failed\n");
 			break;
@@ -426,8 +396,9 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
 }
 
 #ifdef CONFIG_SPI_FLASH_SST
-static int sst_byte_write(struct spi_flash *flash, u32 offset, const void *buf)
+static int sst_byte_write(struct sf_nor *nor, u32 offset, const void *buf)
 {
+	struct spi_flash *flash = nor->priv;
 	int ret;
 	u8 cmd[4] = {
 		CMD_SST_BP,
@@ -439,20 +410,21 @@ static int sst_byte_write(struct spi_flash *flash, u32 offset, const void *buf)
 	debug("BP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n",
 	      spi_w8r8(flash->spi, CMD_READ_STATUS), buf, cmd[0], offset);
 
-	ret = spi_flash_cmd_write_enable(flash);
+	ret = nor->read(nor, (u8 *)CMD_WRITE_ENABLE, 1, NULL, 0);
 	if (ret)
 		return ret;
 
-	ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd), buf, 1);
+	ret = nor->write(nor, cmd, sizeof(cmd), buf, 1);
 	if (ret)
 		return ret;
 
-	return spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
+	return spi_flash_cmd_wait_ready(nor, SPI_FLASH_PROG_TIMEOUT);
 }
 
 int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len,
 		const void *buf)
 {
+	struct sf_nor *nor = flash->nor;
 	size_t actual, cmd_len;
 	int ret;
 	u8 cmd[4];
@@ -466,15 +438,17 @@ int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len,
 	/* If the data is not word aligned, write out leading single byte */
 	actual = offset % 2;
 	if (actual) {
-		ret = sst_byte_write(flash, offset, buf);
+		ret = sst_byte_write(nor, offset, buf);
 		if (ret)
 			goto done;
 	}
 	offset += actual;
 
-	ret = spi_flash_cmd_write_enable(flash);
-	if (ret)
-		goto done;
+	ret = nor->read(nor, (u8 *)CMD_WRITE_ENABLE, 1, NULL, 0);
+	if (ret < 0) {
+		debug("SF: enabling write failed\n");
+		return ret;
+	}
 
 	cmd_len = 4;
 	cmd[0] = CMD_SST_AAI_WP;
@@ -487,14 +461,14 @@ int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len,
 		      spi_w8r8(flash->spi, CMD_READ_STATUS), buf + actual,
 		      cmd[0], offset);
 
-		ret = spi_flash_cmd_write(flash->spi, cmd, cmd_len,
+		ret = nor->write(nor, cmd, cmd_len,
 					buf + actual, 2);
 		if (ret) {
 			debug("SF: sst word program failed\n");
 			break;
 		}
 
-		ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
+		ret = spi_flash_cmd_wait_ready(nor, SPI_FLASH_PROG_TIMEOUT);
 		if (ret)
 			break;
 
@@ -503,17 +477,16 @@ int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len,
 	}
 
 	if (!ret)
-		ret = spi_flash_cmd_write_disable(flash);
+		ret = nor->read(nor, (u8 *)CMD_WRITE_DISABLE, 1, NULL, 0);
 
 	/* If there is a single trailing byte, write it out */
 	if (!ret && actual != len)
-		ret = sst_byte_write(flash, offset, buf + actual);
+		ret = sst_byte_write(nor, offset, buf + actual);
 
  done:
 	debug("SF: sst: program %s %zu bytes @ 0x%zx\n",
 	      ret ? "failure" : "success", len, offset - actual);
 
-	spi_release_bus(flash->spi);
 	return ret;
 }
 #endif
diff --git a/drivers/mtd/spi/sf_spi.c b/drivers/mtd/spi/sf_spi.c
new file mode 100644
index 0000000..d525b61
--- /dev/null
+++ b/drivers/mtd/spi/sf_spi.c
@@ -0,0 +1,230 @@
+/*
+ * SPI flash interface
+ *
+ * Copyright (C) 2008 Atmel Corporation
+ * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <malloc.h>
+#include <spi.h>
+#include <spi_flash.h>
+#include "sf_core.h"
+
+static int spi_sf_read_write(struct spi_slave *spi,
+				const u8 *cmd, size_t cmd_len,
+				const u8 *data_out, u8 *data_in,
+				size_t data_len)
+{
+	unsigned long flags = SPI_XFER_BEGIN;
+	int ret;
+
+	if (data_len == 0)
+		flags |= SPI_XFER_END;
+
+	ret = spi_xfer(spi, cmd_len * 8, cmd, NULL, flags);
+	if (ret) {
+		printf("SF: Failed to send command (%zu bytes): %d\n",
+		      cmd_len, ret);
+	} else if (data_len != 0) {
+		ret = spi_xfer(spi, data_len * 8, data_out, data_in,
+					SPI_XFER_END);
+		if (ret)
+			printf("SF: Failed to transfer %zu bytes of data: %d\n",
+			      data_len, ret);
+	}
+
+	return ret;
+}
+
+static int spi_sf_read(struct sf_nor *nor, const u8 *cmd, size_t cmd_len,
+		void *data, size_t data_len)
+{
+	struct spi_flash *flash = nor->priv;
+	struct spi_slave *spi = flash->spi;
+	int ret;
+
+	/* claim spi bus */
+	ret = spi_claim_bus(spi);
+	if (ret) {
+		printf("SF_SPI: failed to claim SPI bus\n");
+		return ret; 
+	}
+
+	ret = spi_sf_read_write(spi, cmd, cmd_len, NULL, data, data_len);
+	if (ret < 0) {
+		printf("SF_SPI: failed to read sf_nor\n");
+		spi_release_bus(spi);
+		return ret;
+	}
+
+	/* release spi bus */
+	spi_release_bus(spi);
+
+	return ret;
+}
+
+static int spi_sf_write(struct sf_nor *nor, const u8 *cmd, size_t cmd_len,
+		const void *data, size_t data_len)
+{
+	struct spi_flash *flash = nor->priv;
+	struct spi_slave *spi = flash->spi;
+	int ret;
+
+	/* claim spi bus */
+	ret = spi_claim_bus(spi);
+	if (ret) {
+		printf("SF_SPI: failed to claim SPI bus\n");
+		return ret; 
+	}
+
+	ret = spi_sf_read_write(spi, cmd, cmd_len, data, NULL, data_len);
+	if (ret < 0) {
+		printf("SF_SPI: failed to write sf_nor\n");
+		spi_release_bus(spi);
+		return ret;
+	}
+
+	/* release spi bus */
+	spi_release_bus(spi);
+
+	return ret;
+}
+
+int spi_flash_probe_slave(struct spi_slave *spi, struct spi_flash *flash)
+{
+	struct sf_nor *nor;
+	int ret;
+
+	/* Setup spi_slave */
+	if (!spi) {
+		printf("SF: Failed to set up slave\n");
+		return -ENODEV;
+	}
+
+	nor = flash->nor;
+	nor->read = spi_sf_read;
+	nor->write = spi_sf_write;
+
+	nor->priv = flash;
+	flash->spi = spi;
+
+	/* scan for nor flash */
+	ret = sf_nor_scan(nor);
+	if (ret < 0) {
+		printf("SF_SPI: sf_nor_scan failed\n");
+		spi_release_bus(spi);
+		return ret;
+	}
+
+	spi_release_bus(spi);
+
+	return 0;
+}
+
+#ifndef CONFIG_DM_SPI_FLASH
+struct spi_flash *spi_flash_probe_tail(struct spi_slave *bus)
+{
+	struct spi_flash *flash;
+
+	/* Allocate space if needed (not used by sf-uclass */
+	flash = calloc(1, sizeof(*flash));
+	if (!flash) {
+		debug("SF: Failed to allocate spi_flash\n");
+		return NULL;
+	}
+
+	if (spi_flash_probe_slave(bus, flash)) {
+		spi_free_slave(bus);
+		free(flash);
+		return NULL;
+	}
+
+	return flash;
+}
+
+struct spi_flash *spi_flash_probe(unsigned int busnum, unsigned int cs,
+		unsigned int max_hz, unsigned int spi_mode)
+{
+	struct spi_slave *bus;
+
+	bus = spi_setup_slave(busnum, cs, max_hz, spi_mode);
+	return spi_flash_probe_tail(bus);
+}
+
+#ifdef CONFIG_OF_SPI_FLASH
+struct spi_flash *spi_flash_probe_fdt(const void *blob, int slave_node,
+				      int spi_node)
+{
+	struct spi_slave *bus;
+
+	bus = spi_setup_slave_fdt(blob, slave_node, spi_node);
+	return spi_flash_probe_tail(bus);
+}
+#endif
+
+void spi_flash_free(struct spi_flash *flash)
+{
+	spi_free_slave(flash->spi);
+	free(flash);
+}
+
+#else /* defined CONFIG_DM_SPI_FLASH */
+
+static int spi_flash_std_read(struct udevice *dev, u32 offset, size_t len,
+			      void *buf)
+{
+	struct spi_flash *flash = dev->uclass_priv;
+
+	return spi_flash_cmd_read_ops(flash, offset, len, buf);
+}
+
+int spi_flash_std_write(struct udevice *dev, u32 offset, size_t len,
+			const void *buf)
+{
+	struct spi_flash *flash = dev->uclass_priv;
+
+	return spi_flash_cmd_write_ops(flash, offset, len, buf);
+}
+
+int spi_flash_std_erase(struct udevice *dev, u32 offset, size_t len)
+{
+	struct spi_flash *flash = dev->uclass_priv;
+
+	return spi_flash_cmd_erase_ops(flash, offset, len);
+}
+
+int spi_flash_std_probe(struct udevice *dev)
+{
+	struct spi_slave *slave = dev_get_parentdata(dev);
+	struct spi_flash *flash;
+
+	flash = dev->uclass_priv;
+	flash->dev = dev;
+	debug("%s: slave=%p, cs=%d\n", __func__, slave, slave->cs);
+	return spi_flash_probe_slave(slave, flash);
+}
+
+static const struct dm_spi_flash_ops spi_flash_std_ops = {
+	.read = spi_flash_std_read,
+	.write = spi_flash_std_write,
+	.erase = spi_flash_std_erase,
+};
+
+static const struct udevice_id spi_flash_std_ids[] = {
+	{ .compatible = "spi-flash" },
+	{ }
+};
+
+U_BOOT_DRIVER(spi_flash_std) = {
+	.name		= "spi_flash_std",
+	.id		= UCLASS_SPI_FLASH,
+	.of_match	= spi_flash_std_ids,
+	.probe		= spi_flash_std_probe,
+	.priv_auto_alloc_size = sizeof(struct spi_flash),
+	.ops		= &spi_flash_std_ops,
+};
+#endif /* CONFIG_DM_SPI_FLASH */
diff --git a/include/spi_flash.h b/include/spi_flash.h
index 5913b39..90ce389 100644
--- a/include/spi_flash.h
+++ b/include/spi_flash.h
@@ -68,26 +68,13 @@ struct spi_flash {
 #else
 	struct spi_slave *spi;
 #endif
+	struct sf_nor *nor;
 	const char *name;
-	u8 dual_flash;
-	u8 shift;
 
 	u32 size;
-	u32 page_size;
 	u32 sector_size;
 	u32 erase_size;
-#ifdef CONFIG_SPI_FLASH_BAR
-	u8 bank_read_cmd;
-	u8 bank_write_cmd;
-	u8 bank_curr;
-#endif
-	u8 poll_cmd;
-	u8 erase_cmd;
-	u8 read_cmd;
-	u8 write_cmd;
-	u8 dummy_byte;
 
-	void *memory_map;
 #ifndef CONFIG_DM_SPI_FLASH
 	/*
 	 * These are not strictly needed for driver model, but keep them here
-- 
1.9.1



More information about the U-Boot mailing list