diff mbox

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

Message ID 1415739035-9636-1-git-send-email-jagannadh.teki@gmail.com
State RFC
Delegated to: Jagannadha Sutradharudu Teki
Headers show

Commit Message

Jagan Teki Nov. 11, 2014, 8:50 p.m. UTC
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@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

Comments

Marek Vasut Nov. 11, 2014, 9:22 p.m. UTC | #1
On Tuesday, November 11, 2014 at 09:50:35 PM, Jagannadha Sutradharudu Teki 
wrote:
> 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@gmail.com>

I have but a general question -- why did you not just import the spi-nor
framework from Linux ?

Best regards,
Marek Vasut
Jagan Teki Nov. 11, 2014, 9:37 p.m. UTC | #2
On 12 November 2014 02:52, Marek Vasut <marex@denx.de> wrote:
> On Tuesday, November 11, 2014 at 09:50:35 PM, Jagannadha Sutradharudu Teki
> wrote:
>> 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@gmail.com>
>
> I have but a general question -- why did you not just import the spi-nor
> framework from Linux ?

Well, importing spi-nor from Linux is may not be a good idea as we
have a working stuff
at our end along with different dependencies and I'm sure this will
becomes similar way as
spi-nor at some point of time.

thanks!
Marek Vasut Nov. 11, 2014, 10:56 p.m. UTC | #3
On Tuesday, November 11, 2014 at 10:37:33 PM, Jagan Teki wrote:
> On 12 November 2014 02:52, Marek Vasut <marex@denx.de> wrote:
> > On Tuesday, November 11, 2014 at 09:50:35 PM, Jagannadha Sutradharudu
> > Teki
> > 
> > wrote:
> >> 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@gmail.com>
> > 
> > I have but a general question -- why did you not just import the spi-nor
> > framework from Linux ?
> 
> Well, importing spi-nor from Linux is may not be a good idea as we
> have a working stuff
> at our end along with different dependencies and I'm sure this will
> becomes similar way as
> spi-nor at some point of time.

What you said doesn't add up to me -- you introduced a completely new framework 
in this patch, right ? So what exact "working stuff" do we have if this is a 
completely new code ?

Compared to that, the SPI NOR framework in Linux is being actively maintained 
and actively used for a while now, so it's actually a proven code already. Also, 
we just recently resynced MTD subsystem with Linux, adding the SPI NOR framework 
which is based on that same MTD framework would probably be pretty 
straighforward.

Best regards,
Marek Vasut
Jagan Teki Nov. 12, 2014, 12:19 a.m. UTC | #4
On 12 November 2014 04:26, Marek Vasut <marex@denx.de> wrote:
> On Tuesday, November 11, 2014 at 10:37:33 PM, Jagan Teki wrote:
>> On 12 November 2014 02:52, Marek Vasut <marex@denx.de> wrote:
>> > On Tuesday, November 11, 2014 at 09:50:35 PM, Jagannadha Sutradharudu
>> > Teki
>> >
>> > wrote:
>> >> 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@gmail.com>
>> >
>> > I have but a general question -- why did you not just import the spi-nor
>> > framework from Linux ?
>>
>> Well, importing spi-nor from Linux is may not be a good idea as we
>> have a working stuff
>> at our end along with different dependencies and I'm sure this will
>> becomes similar way as
>> spi-nor at some point of time.
>
> What you said doesn't add up to me -- you introduced a completely new framework
> in this patch, right ? So what exact "working stuff" do we have if this is a
> completely new code ?

Yes - this is a new framework with exiting working code by maintain sf_nor {} to
common for spi_sf drivers and flash based drivers.

Not completely new code, It's a re-arranged proven/working existing
code, please understand this.
re-arranged as we have an issue with spi is handling more flash stuff.

>
> Compared to that, the SPI NOR framework in Linux is being actively maintained
> and actively used for a while now, so it's actually a proven code already. Also,
> we just recently resynced MTD subsystem with Linux, adding the SPI NOR framework
> which is based on that same MTD framework would probably be pretty
> straighforward.

Even sf stuff in u-boot is actively maintained and code in sf and
Linux are almost similar
except Linux specific stuff. I don't see any point to import the Linux
stuff as we have working
and actively maintained stuff. By addition of this I'm sure something
proved will not effect.

thanks!
Marek Vasut Nov. 12, 2014, 10:16 p.m. UTC | #5
On Wednesday, November 12, 2014 at 01:19:02 AM, Jagan Teki wrote:
> On 12 November 2014 04:26, Marek Vasut <marex@denx.de> wrote:
> > On Tuesday, November 11, 2014 at 10:37:33 PM, Jagan Teki wrote:
> >> On 12 November 2014 02:52, Marek Vasut <marex@denx.de> wrote:
> >> > On Tuesday, November 11, 2014 at 09:50:35 PM, Jagannadha Sutradharudu
> >> > Teki
> >> > 
> >> > wrote:
> >> >> 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@gmail.com>
> >> > 
> >> > I have but a general question -- why did you not just import the
> >> > spi-nor framework from Linux ?
> >> 
> >> Well, importing spi-nor from Linux is may not be a good idea as we
> >> have a working stuff
> >> at our end along with different dependencies and I'm sure this will
> >> becomes similar way as
> >> spi-nor at some point of time.
> > 
> > What you said doesn't add up to me -- you introduced a completely new
> > framework in this patch, right ? So what exact "working stuff" do we
> > have if this is a completely new code ?
> 
> Yes - this is a new framework with exiting working code by maintain sf_nor
> {} to common for spi_sf drivers and flash based drivers.
> 
> Not completely new code, It's a re-arranged proven/working existing
> code, please understand this.
> re-arranged as we have an issue with spi is handling more flash stuff.

OK, I will not argue about which one is more proven, that's not the point here.

> > Compared to that, the SPI NOR framework in Linux is being actively
> > maintained and actively used for a while now, so it's actually a proven
> > code already. Also, we just recently resynced MTD subsystem with Linux,
> > adding the SPI NOR framework which is based on that same MTD framework
> > would probably be pretty straighforward.
> 
> Even sf stuff in u-boot is actively maintained and code in sf and
> Linux are almost similar
> except Linux specific stuff. I don't see any point to import the Linux
> stuff as we have working
> and actively maintained stuff. By addition of this I'm sure something
> proved will not effect.

Given that the MTD code is imported from Linux, pulling in another part of
that MTD code (the SPI NOR framework) would trim down the divergence of the
codebase. This would make things easier in the long run too, since we could
then just sync with Linux and the bugfixes and new features could be simply 
imported from Linux too . It would make things easier for contributors too, 
since they won't have to learn two codebases, but just one (the linux one).

Best regards,
Marek Vasut
Jagan Teki Nov. 16, 2014, 6:58 p.m. UTC | #6
Hi Marek,

On 13 November 2014 03:46, Marek Vasut <marex@denx.de> wrote:
> On Wednesday, November 12, 2014 at 01:19:02 AM, Jagan Teki wrote:
>> On 12 November 2014 04:26, Marek Vasut <marex@denx.de> wrote:
>> > On Tuesday, November 11, 2014 at 10:37:33 PM, Jagan Teki wrote:
>> >> On 12 November 2014 02:52, Marek Vasut <marex@denx.de> wrote:
>> >> > On Tuesday, November 11, 2014 at 09:50:35 PM, Jagannadha Sutradharudu
>> >> > Teki
>> >> >
>> >> > wrote:
>> >> >> 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@gmail.com>
>> >> >
>> >> > I have but a general question -- why did you not just import the
>> >> > spi-nor framework from Linux ?
>> >>
>> >> Well, importing spi-nor from Linux is may not be a good idea as we
>> >> have a working stuff
>> >> at our end along with different dependencies and I'm sure this will
>> >> becomes similar way as
>> >> spi-nor at some point of time.
>> >
>> > What you said doesn't add up to me -- you introduced a completely new
>> > framework in this patch, right ? So what exact "working stuff" do we
>> > have if this is a completely new code ?
>>
>> Yes - this is a new framework with exiting working code by maintain sf_nor
>> {} to common for spi_sf drivers and flash based drivers.
>>
>> Not completely new code, It's a re-arranged proven/working existing
>> code, please understand this.
>> re-arranged as we have an issue with spi is handling more flash stuff.
>
> OK, I will not argue about which one is more proven, that's not the point here.

My intend is not about that, I'm saying sf is long running working
stuff not more than that.

>
>> > Compared to that, the SPI NOR framework in Linux is being actively
>> > maintained and actively used for a while now, so it's actually a proven
>> > code already. Also, we just recently resynced MTD subsystem with Linux,
>> > adding the SPI NOR framework which is based on that same MTD framework
>> > would probably be pretty straighforward.
>>
>> Even sf stuff in u-boot is actively maintained and code in sf and
>> Linux are almost similar
>> except Linux specific stuff. I don't see any point to import the Linux
>> stuff as we have working
>> and actively maintained stuff. By addition of this I'm sure something
>> proved will not effect.
>
> Given that the MTD code is imported from Linux, pulling in another part of
> that MTD code (the SPI NOR framework) would trim down the divergence of the
> codebase. This would make things easier in the long run too, since we could
> then just sync with Linux and the bugfixes and new features could be simply
> imported from Linux too . It would make things easier for contributors too,
> since they won't have to learn two codebases, but just one (the linux one).

Yes, I agree with the points you noted, thank you about that.

But, we cannot compare serial flash handing in Linux vs U-boot in all
the aspects.
Unlike Linux - U-Boot the core serial flash handling is need to talk
to lot of aspects
like cmd_sf, cmd_spi, drivers/spi, some parts from u-boot code and
recently links with
driver models.

Having all these sense, current serial flash stuff is well handling
all these and well tested
on the respective hardware. So this new framework is not going change
the derivatives apart
from moving real flash stuff to out side of spi subsystem.

I think you knew all these stuff, but explaining here to identify the
more code relations wrt sf.

If we import spi-nor from Linux I need to take care all the stuff from
base, which is going
to another work that also needs lot of testing. And also spi-nor is
standardized since last less
than a year and it is also growing. U-boot sf is well tested one and
if we make changes wrt
current code and have same flash features compared to Linux and one
point the framework
will become stronger.

MTD code, can be straight forward to add it to sf, no much work
required I suppose.

From all these points, I'm going tell one point here is - As u-boot sf
is a tested framework and have
positive feature support till now, and then if we modify this by
excluding flash features from spi
then it will become a well structure framework and I'm sure for that.

thanks!
diff mbox

Patch

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