diff mbox

[U-Boot,V6,3/5] nand spl: add NAND Library to new SPL

Message ID 1311842291-24837-4-git-send-email-simonschwarzcor@gmail.com
State Superseded
Headers show

Commit Message

Simon Schwarz July 28, 2011, 8:38 a.m. UTC
Insert some NAND driver sources into NAND SPL library.

Signed-off-by: Simon Schwarz <simonschwarzcor@gmail.com>
---
V1 changes:
CHG Default to HW ecc in SPL build
ADD nand_read_buf16 function, read buffer
ADD omap_dev_ready function, indicte if chip is ready

V2 changes:
DEL GPMC_WAIT0_PIN_ACTIVE define
CHG omap_dev_ready() renamed to  omap_spl_dev_ready(), does not use the
	GPMC_WAIT0_PIN_ACTIVE-define anymore
CHG ogpmc_read_buf16 renamed omap_spl_read_buf16
ADD omap_spl_read_buf, 8x buf read function
ADD CONFIG_SPL_POWER_SUPPORT and CONFIG_SPL_NAND_SUPPORT to SPL
CHG cosmetic
CHG nand_base and nand_bbt aren't needed for SPL anymore
CHG omap_nand_switch_ecc is not compiled for SPL
ADD entry for CONFIG_SPL_POWER_SUPPORT and CONFIG_SPL_NAND_SUPPORT to README.SPL

V3 changes:
DEL cosmetic (empty line)

V4 changes:
nothing

V5 changes:
CHG nand_ecc.o is only compiled for SPL if CONFIG_OMAP34XX is set

V6 changes:
ADD nand_spl.c - git add, finally
DEL nand_ecc barrier ifdef for OMAP3

Transition from V1 to V2 also includes that this patch is now based on
	- the new SPL layout by Aneesh V and Daniel Schwierzeck
	- the OMAP4 SPL patches by Aneesh V

This Patch is related to "[U-Boot,4/5] devkit8000 nand_spl: Add SPL NAND support
to omap_gpmc driver"
(http://article.gmane.org/gmane.comp.boot-loaders.u-boot/102115) in V1
---
 doc/README.SPL               |    2 +
 drivers/mtd/nand/Makefile    |    6 +-
 drivers/mtd/nand/nand_spl.c  |  268 ++++++++++++++++++++++++++++++++++++++++++
 drivers/mtd/nand/omap_gpmc.c |   68 +++++++++++
 spl/Makefile                 |    2 +
 5 files changed, 345 insertions(+), 1 deletions(-)
 create mode 100644 drivers/mtd/nand/nand_spl.c

Comments

Aneesh V July 28, 2011, 11:54 a.m. UTC | #1
On Thursday 28 July 2011 02:08 PM, Simon Schwarz wrote:
> Insert some NAND driver sources into NAND SPL library.
>
> Signed-off-by: Simon Schwarz<simonschwarzcor@gmail.com>

[snip ..]

> +
> +int nand_curr_device = -1;

Is nand_curr_device used anywhere?

> +static int nand_ecc_pos[] = CONFIG_SYS_NAND_ECCPOS;
> +static nand_info_t info;
> +nand_info_t nand_info[CONFIG_SYS_MAX_NAND_DEVICE];

Is nand_info used anywhere?

> +static struct nand_chip nand_chip;

Is nand_chip used anywhere? I see that this definition is shadowed in
function nand_init().

> +
> +#if (CONFIG_SYS_NAND_PAGE_SIZE<= 512)

[snip ..]

> +/*
> + * omap_spl_read_buf16 - [DEFAULT] read chip data into buffer
> + * @mtd:    MTD device structure
> + * @buf:    buffer to store date

typo: date instead of data.

> + * @len:    number of bytes to read
> + *
> + * Default read function for 16bit buswith
> + *
> + * This function is based on nand_read_buf16 from nand_base.c. This version
> + * reads 32bit not 16bit although the bus only has 16bit.
> + */
> +static void omap_spl_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
> +{
> +	int i;
> +	struct nand_chip *chip = mtd->priv;
> +	u32 *p = (u32 *) buf;

Why this variable p?

> +	len>>= 2;
> +
> +	for (i = 0; i<  len; i++)
> +		p[i] = readl(chip->IO_ADDR_R);
> +}

Should this function be called omap_spl_read_buf32() ?
Or still better, should this be added as nand_read_buf32() in
nand_base.c itself?

> +
> +/*
> + * omap_spl_read_buf - [DEFAULT] read chip data into buffer
> + * @mtd:    MTD device structure
> + * @buf:    buffer to store date
> + * @len:    number of bytes to read
> + *
> + * Default read function for 8bit buswith
> + *
> + * This is the same function as this from nand_base.c nand_read_buf
> + */
> +static void omap_spl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
> +{
> +	int i;
> +	struct nand_chip *chip = mtd->priv;
> +
> +	for (i = 0; i<  len; i++)
> +		buf[i] = readb(chip->IO_ADDR_R);
> +}
> +#endif

What is the difference between this function and nand_read_buf() in
nand_base.c ?

best regards,
Aneesh
Simon Schwarz July 28, 2011, 2:04 p.m. UTC | #2
Hi Aneesh,

On 07/28/2011 01:54 PM, Aneesh V wrote:
> On Thursday 28 July 2011 02:08 PM, Simon Schwarz wrote:
>> Insert some NAND driver sources into NAND SPL library.
>>
>> Signed-off-by: Simon Schwarz<simonschwarzcor@gmail.com>
>
> [snip ..]
>
>> +
>> +int nand_curr_device = -1;
>
> Is nand_curr_device used anywhere?

Was used in nand.c - this isn't included anymore -> deleted

>
>> +static int nand_ecc_pos[] = CONFIG_SYS_NAND_ECCPOS;
>> +static nand_info_t info;
>> +nand_info_t nand_info[CONFIG_SYS_MAX_NAND_DEVICE];
>
> Is nand_info used anywhere?

Same as above -> deleted.

>
>> +static struct nand_chip nand_chip;
>
> Is nand_chip used anywhere? I see that this definition is shadowed in
> function nand_init().

Deleted the double definition.

nand_chip is used in:
- nand_command
- nand_is_bad_block
- nand_read_page
- nand_init
- nand_deselect

>
>> +
>> +#if (CONFIG_SYS_NAND_PAGE_SIZE<= 512)
>
> [snip ..]
>
>> +/*
>> + * omap_spl_read_buf16 - [DEFAULT] read chip data into buffer
>> + * @mtd: MTD device structure
>> + * @buf: buffer to store date
>
> typo: date instead of data.
>

see below for solution (btw. this typo comes from nand_base.c)

>> + * @len: number of bytes to read
>> + *
>> + * Default read function for 16bit buswith
>> + *
>> + * This function is based on nand_read_buf16 from nand_base.c. This
>> version
>> + * reads 32bit not 16bit although the bus only has 16bit.
>> + */
>> +static void omap_spl_read_buf16(struct mtd_info *mtd, uint8_t *buf,
>> int len)
>> +{
>> + int i;
>> + struct nand_chip *chip = mtd->priv;
>> + u32 *p = (u32 *) buf;
>
> Why this variable p?
It is used to cast the 8-bit buffer variable into a 32bit one. Actually 
the same is done for the 16bit implementation. (There it is the adaption 
to the bus width - why 32bit here see below)
>
>> + len>>= 2;
>> +
>> + for (i = 0; i< len; i++)
>> + p[i] = readl(chip->IO_ADDR_R);
>> +}
>
> Should this function be called omap_spl_read_buf32() ?
> Or still better, should this be added as nand_read_buf32() in
> nand_base.c itself?

Oh. There I played around with the Access Size Adaptation of the GPMC - 
It is still a x16 interface - this is what the 16 refers to IMHO. But 
for sake of simplicity I will change this back to 16bit access - I don't 
think that there is a big performance impact although I didn't measure it.

I cloned them because the functions in nand_base.c are static.

My solution: deleted the cloned functions - use these from nand_base by 
removing the static modifier and add them to nand.h

This leaves nand_base.c inconsistent - some functions are static, some 
not - maybe we should un-static all read/write functions as they are 
normally used in SPL?

>> +
>> +/*
>> + * omap_spl_read_buf - [DEFAULT] read chip data into buffer
>> + * @mtd: MTD device structure
>> + * @buf: buffer to store date
>> + * @len: number of bytes to read
>> + *
>> + * Default read function for 8bit buswith
>> + *
>> + * This is the same function as this from nand_base.c nand_read_buf
>> + */
>> +static void omap_spl_read_buf(struct mtd_info *mtd, uint8_t *buf, int
>> len)
>> +{
>> + int i;
>> + struct nand_chip *chip = mtd->priv;
>> +
>> + for (i = 0; i< len; i++)
>> + buf[i] = readb(chip->IO_ADDR_R);
>> +}
>> +#endif
>
> What is the difference between this function and nand_read_buf() in
> nand_base.c ?
none - static is the problem. Did the same as with the x16 version above.

>
> best regards,
> Aneesh

Regards & thx for the review!
Simon
Aneesh V July 28, 2011, 4:18 p.m. UTC | #3
On Thursday 28 July 2011 07:34 PM, Simon Schwarz wrote:
> Hi Aneesh,
>
> On 07/28/2011 01:54 PM, Aneesh V wrote:
>> On Thursday 28 July 2011 02:08 PM, Simon Schwarz wrote:
>>> Insert some NAND driver sources into NAND SPL library.
>>>
>>> Signed-off-by: Simon Schwarz<simonschwarzcor@gmail.com>
>>
>> [snip ..]
>>
>>> +
>>> +int nand_curr_device = -1;
>>
>> Is nand_curr_device used anywhere?
>
> Was used in nand.c - this isn't included anymore -> deleted
>
>>
>>> +static int nand_ecc_pos[] = CONFIG_SYS_NAND_ECCPOS;
>>> +static nand_info_t info;
>>> +nand_info_t nand_info[CONFIG_SYS_MAX_NAND_DEVICE];
>>
>> Is nand_info used anywhere?
>
> Same as above -> deleted.
>
>>
>>> +static struct nand_chip nand_chip;
>>
>> Is nand_chip used anywhere? I see that this definition is shadowed in
>> function nand_init().
>
> Deleted the double definition.
>
> nand_chip is used in:
> - nand_command
> - nand_is_bad_block
> - nand_read_page
> - nand_init
> - nand_deselect
>
>>
>>> +
>>> +#if (CONFIG_SYS_NAND_PAGE_SIZE<= 512)
>>
>> [snip ..]
>>
>>> +/*
>>> + * omap_spl_read_buf16 - [DEFAULT] read chip data into buffer
>>> + * @mtd: MTD device structure
>>> + * @buf: buffer to store date
>>
>> typo: date instead of data.
>>
>
> see below for solution (btw. this typo comes from nand_base.c)
>
>>> + * @len: number of bytes to read
>>> + *
>>> + * Default read function for 16bit buswith
>>> + *
>>> + * This function is based on nand_read_buf16 from nand_base.c. This
>>> version
>>> + * reads 32bit not 16bit although the bus only has 16bit.
>>> + */
>>> +static void omap_spl_read_buf16(struct mtd_info *mtd, uint8_t *buf,
>>> int len)
>>> +{
>>> + int i;
>>> + struct nand_chip *chip = mtd->priv;
>>> + u32 *p = (u32 *) buf;
>>
>> Why this variable p?
> It is used to cast the 8-bit buffer variable into a 32bit one. Actually
> the same is done for the 16bit implementation. (There it is the adaption
> to the bus width - why 32bit here see below)
>>
>>> + len>>= 2;
>>> +
>>> + for (i = 0; i< len; i++)
>>> + p[i] = readl(chip->IO_ADDR_R);
>>> +}
>>
>> Should this function be called omap_spl_read_buf32() ?
>> Or still better, should this be added as nand_read_buf32() in
>> nand_base.c itself?
>
> Oh. There I played around with the Access Size Adaptation of the GPMC -
> It is still a x16 interface - this is what the 16 refers to IMHO. But

Ok. I have to admit that I am not a NAND expert and I do not understand
this code well.

> for sake of simplicity I will change this back to 16bit access - I don't
> think that there is a big performance impact although I didn't measure it.

No. If it's an OMAP specific optimization, I don't see a reason to
remove it. Looks like that may actually improve performance. However,
you may have to take into account of the alignment of buffer, the size
requested etc. Please have a look at the implementation in drivers/mtd
/nand/davinci_nand.c(although the implementation here seems to be for
8-bit devices, something similar may be possible for 16-bit)

>
> I cloned them because the functions in nand_base.c are static.
>
> My solution: deleted the cloned functions - use these from nand_base by
> removing the static modifier and add them to nand.h

I hope there won't be any name-space conflict due to this.

best regards,
Aneesh
Scott Wood July 28, 2011, 7:16 p.m. UTC | #4
On Thu, 28 Jul 2011 10:38:09 +0200
Simon Schwarz <simonschwarzcor@googlemail.com> wrote:

> +CONFIG_SPL_POWER_SUPPORT (drivers/power/libpower.o)

Not sure what this has to do with NAND.

> +int nand_curr_device = -1;
> +static int nand_ecc_pos[] = CONFIG_SYS_NAND_ECCPOS;
> +static nand_info_t info;
> +nand_info_t nand_info[CONFIG_SYS_MAX_NAND_DEVICE];
> +static struct nand_chip nand_chip;

It doesn't look like nand_info or nand_curr_device are used.

> +/* nand_boot()-function from the old nand_spl ripped apart into
> + * - nand_init()
> + * - nand_spl_load_image()
> + * - nand_deselect()
> + */

References to what the code used to look like should go in the commit
message -- they're not relevant to someone reading this code years from
now.

Splitting this up is going to add bytes -- is it really needed?

> +void nand_init(void)
> +{
> +	struct nand_chip nand_chip;

This is shadowing the file-scope nand_chip.

> +	/*
> +	 * Init board specific nand support
> +	 */
> +	nand_chip.select_chip = NULL;
> +	info.priv = &nand_chip;
> +	nand_chip.IO_ADDR_R = nand_chip.IO_ADDR_W =
> +		(void  __iomem *)CONFIG_SYS_NAND_BASE;
> +	nand_chip.dev_ready = NULL;	/* preset to NULL */
> +	nand_chip.options = 0;

Once you switch to the BSS nand_cihp, you can get rid of the
zero init.

> +/* Copy image from NAND to RAM
> + * offs: Offset in NAND flash
> + * size: size of image
> + * dst: destination pointer to RAM
> + */
> +void nand_spl_load_image(loff_t offs, unsigned int size, uchar *dst)
> +{
> +	nand_load(&info, offs, size, dst);
> +}

Just strip the mtd_info parameter from nand_load -- no need for a wrapper.

-Scott
Simon Schwarz July 29, 2011, 9:12 a.m. UTC | #5
On 07/28/2011 09:16 PM, Scott Wood wrote:
> On Thu, 28 Jul 2011 10:38:09 +0200
> Simon Schwarz<simonschwarzcor@googlemail.com>  wrote:
>
>> +CONFIG_SPL_POWER_SUPPORT (drivers/power/libpower.o)
>
> Not sure what this has to do with NAND.

right. This used by devkit8000 - will change the subject to "spl: add 
NAND and POWER library to new SPL"

>> +int nand_curr_device = -1;
>> +static int nand_ecc_pos[] = CONFIG_SYS_NAND_ECCPOS;
>> +static nand_info_t info;
>> +nand_info_t nand_info[CONFIG_SYS_MAX_NAND_DEVICE];
>> +static struct nand_chip nand_chip;
>
> It doesn't look like nand_info or nand_curr_device are used.

Already deleted.

>
>> +/* nand_boot()-function from the old nand_spl ripped apart into
>> + * - nand_init()
>> + * - nand_spl_load_image()
>> + * - nand_deselect()
>> + */
>
> References to what the code used to look like should go in the commit
> message -- they're not relevant to someone reading this code years from
> now.
Changed.
>
> Splitting this up is going to add bytes -- is it really needed?
>
Yes it is. Since nand_boot did everything in the old spl. Now we have to 
use the functions from the outside.

The payload also can differ much more - u-boot image + environment. 
linux image with FDT image etc. It is also necessary for using 
parse_header by Aneesh.

>> +void nand_init(void)
>> +{
>> +	struct nand_chip nand_chip;
>
> This is shadowing the file-scope nand_chip.
Already deleted
>
>> +	/*
>> +	 * Init board specific nand support
>> +	 */
>> +	nand_chip.select_chip = NULL;
>> +	info.priv =&nand_chip;
>> +	nand_chip.IO_ADDR_R = nand_chip.IO_ADDR_W =
>> +		(void  __iomem *)CONFIG_SYS_NAND_BASE;
>> +	nand_chip.dev_ready = NULL;	/* preset to NULL */
>> +	nand_chip.options = 0;
>
> Once you switch to the BSS nand_cihp, you can get rid of the
> zero init.

do you mean when bss_init is done? If yes I will delete these.

>
>> +/* Copy image from NAND to RAM
>> + * offs: Offset in NAND flash
>> + * size: size of image
>> + * dst: destination pointer to RAM
>> + */
>> +void nand_spl_load_image(loff_t offs, unsigned int size, uchar *dst)
>> +{
>> +	nand_load(&info, offs, size, dst);
>> +}
>
> Just strip the mtd_info parameter from nand_load -- no need for a wrapper.

Since this was criticised by many -  I will drop the old interface and 
get rid of mtd_info everywhere in nand_spl_simple.c

>
> -Scott
>

Regards & thx for review!
Simon
Wolfgang Denk July 29, 2011, 9:27 a.m. UTC | #6
Dear Simon Schwarz,

In message <4E327989.6070300@gmail.com> you wrote:
> On 07/28/2011 09:16 PM, Scott Wood wrote:
> > On Thu, 28 Jul 2011 10:38:09 +0200
> > Simon Schwarz<simonschwarzcor@googlemail.com>  wrote:
> >
> >> +CONFIG_SPL_POWER_SUPPORT (drivers/power/libpower.o)
> >
> > Not sure what this has to do with NAND.
> 
> right. This used by devkit8000 - will change the subject to "spl: add 
> NAND and POWER library to new SPL"

Should we not rather split this into two separate patches?

Best regards,

Wolfgang Denk
Simon Schwarz July 29, 2011, 12:17 p.m. UTC | #7
Hi Aneesh,

On 07/28/2011 06:18 PM, Aneesh V wrote:
[snip]
>>
>> Oh. There I played around with the Access Size Adaptation of the GPMC -
>> It is still a x16 interface - this is what the 16 refers to IMHO. But
>
> Ok. I have to admit that I am not a NAND expert and I do not understand
> this code well.
>
>> for sake of simplicity I will change this back to 16bit access - I don't
>> think that there is a big performance impact although I didn't measure
>> it.
>
> No. If it's an OMAP specific optimization, I don't see a reason to
> remove it. Looks like that may actually improve performance. However,
> you may have to take into account of the alignment of buffer, the size
> requested etc. Please have a look at the implementation in drivers/mtd
> /nand/davinci_nand.c(although the implementation here seems to be for
> 8-bit devices, something similar may be possible for 16-bit)

I literally just played around with that ;)

I will add it in the standard version here.

For my BA I will have to evaluate if it has a performance impact anyway 
- if it has I will send a patch later.

>
>>
>> I cloned them because the functions in nand_base.c are static.
>>
>> My solution: deleted the cloned functions - use these from nand_base by
>> removing the static modifier and add them to nand.h
>
> I hope there won't be any name-space conflict due to this.

Me too. For devkit8000 there is none - BUILDALL will show.

>
> best regards,
> Aneesh


Regards
Simon
Simon Schwarz July 29, 2011, 12:27 p.m. UTC | #8
Dear Wolfgang Denk,

On 07/29/2011 11:27 AM, Wolfgang Denk wrote:
> Dear Simon Schwarz,
>
> In message<4E327989.6070300@gmail.com>  you wrote:
>> On 07/28/2011 09:16 PM, Scott Wood wrote:
>>> On Thu, 28 Jul 2011 10:38:09 +0200
>>> Simon Schwarz<simonschwarzcor@googlemail.com>   wrote:
>>>
>>>> +CONFIG_SPL_POWER_SUPPORT (drivers/power/libpower.o)
>>>
>>> Not sure what this has to do with NAND.
>>
>> right. This used by devkit8000 - will change the subject to "spl: add
>> NAND and POWER library to new SPL"
>
> Should we not rather split this into two separate patches?

Will do.

>
> Best regards,
>
> Wolfgang Denk
>

Regards
Simon
diff mbox

Patch

diff --git a/doc/README.SPL b/doc/README.SPL
index ce8e19f..2987f43 100644
--- a/doc/README.SPL
+++ b/doc/README.SPL
@@ -60,3 +60,5 @@  CONFIG_SPL_SPI_FLASH_SUPPORT (drivers/mtd/spi/libspi_flash.o)
 CONFIG_SPL_SPI_SUPPORT (drivers/spi/libspi.o)
 CONFIG_SPL_FAT_SUPPORT (fs/fat/libfat.o)
 CONFIG_SPL_LIBGENERIC_SUPPORT (lib/libgeneric.o)
+CONFIG_SPL_POWER_SUPPORT (drivers/power/libpower.o)
+CONFIG_SPL_NAND_SUPPORT (drivers/mtd/nand/libnand.o)
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 8b598f6..cdc9a14 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -26,12 +26,16 @@  include $(TOPDIR)/config.mk
 LIB	:= $(obj)libnand.o
 
 ifdef CONFIG_CMD_NAND
+ifdef CONFIG_SPL_BUILD
+COBJS-y += nand_spl.o
+else
 COBJS-y += nand.o
 COBJS-y += nand_base.o
 COBJS-y += nand_bbt.o
-COBJS-y += nand_ecc.o
 COBJS-y += nand_ids.o
 COBJS-y += nand_util.o
+endif
+COBJS-y += nand_ecc.o
 
 COBJS-$(CONFIG_NAND_ATMEL) += atmel_nand.o
 COBJS-$(CONFIG_DRIVER_NAND_BFIN) += bfin_nand.o
diff --git a/drivers/mtd/nand/nand_spl.c b/drivers/mtd/nand/nand_spl.c
new file mode 100644
index 0000000..fc78885
--- /dev/null
+++ b/drivers/mtd/nand/nand_spl.c
@@ -0,0 +1,268 @@ 
+/*
+ * (C) Copyright 2006-2008
+ * Stefan Roese, DENX Software Engineering, sr@denx.de.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <nand.h>
+#include <asm/io.h>
+
+int nand_curr_device = -1;
+static int nand_ecc_pos[] = CONFIG_SYS_NAND_ECCPOS;
+static nand_info_t info;
+nand_info_t nand_info[CONFIG_SYS_MAX_NAND_DEVICE];
+static struct nand_chip nand_chip;
+
+#if (CONFIG_SYS_NAND_PAGE_SIZE <= 512)
+/*
+ * NAND command for small page NAND devices (512)
+ */
+static int nand_command(struct mtd_info *mtd, int block, int page, int offs,
+	u8 cmd)
+{
+	struct nand_chip *this = mtd->priv;
+	int page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT;
+
+	while (!this->dev_ready(mtd))
+		;
+
+	/* Begin command latch cycle */
+	this->cmd_ctrl(mtd, cmd, NAND_CTRL_CLE | NAND_CTRL_CHANGE);
+	/* Set ALE and clear CLE to start address cycle */
+	/* Column address */
+	this->cmd_ctrl(mtd, offs, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
+	this->cmd_ctrl(mtd, page_addr & 0xff, NAND_CTRL_ALE); /* A[16:9] */
+	this->cmd_ctrl(mtd, (page_addr >> 8) & 0xff,
+		       NAND_CTRL_ALE); /* A[24:17] */
+#ifdef CONFIG_SYS_NAND_4_ADDR_CYCLE
+	/* One more address cycle for devices > 32MiB */
+	this->cmd_ctrl(mtd, (page_addr >> 16) & 0x0f,
+		       NAND_CTRL_ALE); /* A[28:25] */
+#endif
+	/* Latch in address */
+	this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
+
+	/*
+	 * Wait a while for the data to be ready
+	 */
+	while (!this->dev_ready(mtd))
+		;
+
+	return 0;
+}
+#else
+/*
+ * NAND command for large page NAND devices (2k)
+ */
+static int nand_command(struct mtd_info *mtd, int block, int page, int offs,
+	u8 cmd)
+{
+	struct nand_chip *this = mtd->priv;
+	int page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT;
+	void (*hwctrl)(struct mtd_info *mtd, int cmd,
+			unsigned int ctrl) = this->cmd_ctrl;
+
+	while (!this->dev_ready(mtd))
+		;
+
+	/* Emulate NAND_CMD_READOOB */
+	if (cmd == NAND_CMD_READOOB) {
+		offs += CONFIG_SYS_NAND_PAGE_SIZE;
+		cmd = NAND_CMD_READ0;
+	}
+
+	/* Shift the offset from byte addressing to word addressing. */
+	if (this->options & NAND_BUSWIDTH_16)
+		offs >>= 1;
+
+	/* Begin command latch cycle */
+	hwctrl(mtd, cmd, NAND_CTRL_CLE | NAND_CTRL_CHANGE);
+	/* Set ALE and clear CLE to start address cycle */
+	/* Column address */
+	hwctrl(mtd, offs & 0xff,
+		       NAND_CTRL_ALE | NAND_CTRL_CHANGE); /* A[7:0] */
+	hwctrl(mtd, (offs >> 8) & 0xff, NAND_CTRL_ALE); /* A[11:9] */
+	/* Row address */
+	hwctrl(mtd, (page_addr & 0xff), NAND_CTRL_ALE); /* A[19:12] */
+	hwctrl(mtd, ((page_addr >> 8) & 0xff),
+		       NAND_CTRL_ALE); /* A[27:20] */
+#ifdef CONFIG_SYS_NAND_5_ADDR_CYCLE
+	/* One more address cycle for devices > 128MiB */
+	hwctrl(mtd, (page_addr >> 16) & 0x0f,
+		       NAND_CTRL_ALE); /* A[31:28] */
+#endif
+	/* Latch in address */
+	hwctrl(mtd, NAND_CMD_READSTART,
+		       NAND_CTRL_CLE | NAND_CTRL_CHANGE);
+	hwctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
+
+	/*
+	 * Wait a while for the data to be ready
+	 */
+	while (!this->dev_ready(mtd))
+		;
+
+	return 0;
+}
+#endif
+
+static int nand_is_bad_block(struct mtd_info *mtd, int block)
+{
+	struct nand_chip *this = mtd->priv;
+
+	nand_command(mtd, block, 0, CONFIG_SYS_NAND_BAD_BLOCK_POS,
+		NAND_CMD_READOOB);
+
+	/*
+	 * Read one byte (or two if it's a 16 bit chip).
+	 */
+	if (this->options & NAND_BUSWIDTH_16) {
+		if (readw(this->IO_ADDR_R) != 0xffff)
+			return 1;
+	} else {
+		if (readb(this->IO_ADDR_R) != 0xff)
+			return 1;
+	}
+
+	return 0;
+}
+
+static int nand_read_page(struct mtd_info *mtd, int block, int page, uchar *dst)
+{
+	struct nand_chip *this = mtd->priv;
+	u_char *ecc_calc;
+	u_char *ecc_code;
+	u_char *oob_data;
+	int i;
+	int eccsize = CONFIG_SYS_NAND_ECCSIZE;
+	int eccbytes = CONFIG_SYS_NAND_ECCBYTES;
+	int eccsteps = CONFIG_SYS_NAND_ECCSTEPS;
+	uint8_t *p = dst;
+	int stat;
+
+	nand_command(mtd, block, page, 0, NAND_CMD_READ0);
+
+	/* No malloc available for now, just use some temporary locations
+	 * in SDRAM
+	 */
+	ecc_calc = (u_char *)(CONFIG_SYS_SDRAM_BASE + 0x10000);
+	ecc_code = ecc_calc + 0x100;
+	oob_data = ecc_calc + 0x200;
+
+	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+		this->ecc.hwctl(mtd, NAND_ECC_READ);
+		this->read_buf(mtd, p, eccsize);
+		this->ecc.calculate(mtd, p, &ecc_calc[i]);
+	}
+	this->read_buf(mtd, oob_data, CONFIG_SYS_NAND_OOBSIZE);
+
+	/* Pick the ECC bytes out of the oob data */
+	for (i = 0; i < CONFIG_SYS_NAND_ECCTOTAL; i++)
+		ecc_code[i] = oob_data[nand_ecc_pos[i]];
+
+	eccsteps = CONFIG_SYS_NAND_ECCSTEPS;
+	p = dst;
+
+	for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+		/* No chance to do something with the possible error message
+		 * from correct_data(). We just hope that all possible errors
+		 * are corrected by this routine.
+		 */
+		stat = this->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
+	}
+
+	return 0;
+}
+
+static int nand_load(struct mtd_info *mtd, unsigned int offs,
+		     unsigned int uboot_size, uchar *dst)
+{
+	unsigned int block, lastblock;
+	unsigned int page;
+
+	/*
+	 * offs has to be aligned to a page address!
+	 */
+	block = offs / CONFIG_SYS_NAND_BLOCK_SIZE;
+	lastblock = (offs + uboot_size - 1) / CONFIG_SYS_NAND_BLOCK_SIZE;
+	page = (offs % CONFIG_SYS_NAND_BLOCK_SIZE) / CONFIG_SYS_NAND_PAGE_SIZE;
+
+	while (block <= lastblock) {
+		if (!nand_is_bad_block(mtd, block)) {
+			/*
+			 * Skip bad blocks
+			 */
+			while (page < CONFIG_SYS_NAND_PAGE_COUNT) {
+				nand_read_page(mtd, block, page, dst);
+				dst += CONFIG_SYS_NAND_PAGE_SIZE;
+				page++;
+			}
+
+			page = 0;
+		} else {
+			lastblock++;
+		}
+
+		block++;
+	}
+
+	return 0;
+}
+
+/* nand_boot()-function from the old nand_spl ripped apart into
+ * - nand_init()
+ * - nand_spl_load_image()
+ * - nand_deselect()
+ */
+void nand_init(void)
+{
+	struct nand_chip nand_chip;
+
+	/*
+	 * Init board specific nand support
+	 */
+	nand_chip.select_chip = NULL;
+	info.priv = &nand_chip;
+	nand_chip.IO_ADDR_R = nand_chip.IO_ADDR_W =
+		(void  __iomem *)CONFIG_SYS_NAND_BASE;
+	nand_chip.dev_ready = NULL;	/* preset to NULL */
+	nand_chip.options = 0;
+	board_nand_init(&nand_chip);
+
+	if (nand_chip.select_chip)
+		nand_chip.select_chip(&info, 0);
+}
+
+/* Copy image from NAND to RAM
+ * offs: Offset in NAND flash
+ * size: size of image
+ * dst: destination pointer to RAM
+ */
+void nand_spl_load_image(loff_t offs, unsigned int size, uchar *dst)
+{
+	nand_load(&info, offs, size, dst);
+}
+
+/* Unselect NAND chip after operation
+ */
+void nand_deselect(void)
+{
+	if (nand_chip.select_chip)
+		nand_chip.select_chip(&info, -1);
+
+}
diff --git a/drivers/mtd/nand/omap_gpmc.c b/drivers/mtd/nand/omap_gpmc.c
index 99b9cef..61eac35 100644
--- a/drivers/mtd/nand/omap_gpmc.c
+++ b/drivers/mtd/nand/omap_gpmc.c
@@ -61,6 +61,55 @@  static void omap_nand_hwcontrol(struct mtd_info *mtd, int32_t cmd,
 		writeb(cmd, this->IO_ADDR_W);
 }
 
+#ifdef CONFIG_SPL_BUILD
+/* Check wait pin as dev ready indicator */
+int omap_spl_dev_ready(struct mtd_info *mtd)
+{
+	return gpmc_cfg->status & (1 << 8);
+}
+
+/*
+ * omap_spl_read_buf16 - [DEFAULT] read chip data into buffer
+ * @mtd:    MTD device structure
+ * @buf:    buffer to store date
+ * @len:    number of bytes to read
+ *
+ * Default read function for 16bit buswith
+ *
+ * This function is based on nand_read_buf16 from nand_base.c. This version
+ * reads 32bit not 16bit although the bus only has 16bit.
+ */
+static void omap_spl_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	int i;
+	struct nand_chip *chip = mtd->priv;
+	u32 *p = (u32 *) buf;
+	len >>= 2;
+
+	for (i = 0; i < len; i++)
+		p[i] = readl(chip->IO_ADDR_R);
+}
+
+/*
+ * omap_spl_read_buf - [DEFAULT] read chip data into buffer
+ * @mtd:    MTD device structure
+ * @buf:    buffer to store date
+ * @len:    number of bytes to read
+ *
+ * Default read function for 8bit buswith
+ *
+ * This is the same function as this from nand_base.c nand_read_buf
+ */
+static void omap_spl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	int i;
+	struct nand_chip *chip = mtd->priv;
+
+	for (i = 0; i < len; i++)
+		buf[i] = readb(chip->IO_ADDR_R);
+}
+#endif
+
 /*
  * omap_hwecc_init - Initialize the Hardware ECC for NAND flash in
  *                   GPMC controller
@@ -224,6 +273,7 @@  static void omap_enable_hwecc(struct mtd_info *mtd, int32_t mode)
 	}
 }
 
+#ifndef CONFIG_SPL_BUILD
 /*
  * omap_nand_switch_ecc - switch the ECC operation b/w h/w ecc and s/w ecc.
  * The default is to come up on s/w ecc
@@ -280,6 +330,7 @@  void omap_nand_switch_ecc(int32_t hardware)
 
 	nand->options &= ~NAND_OWN_BUFFERS;
 }
+#endif /* CONFIG_SPL_BUILD */
 
 /*
  * Board-specific NAND initialization. The following members of the
@@ -338,7 +389,24 @@  int board_nand_init(struct nand_chip *nand)
 
 	nand->chip_delay = 100;
 	/* Default ECC mode */
+#ifndef CONFIG_SPL_BUILD
 	nand->ecc.mode = NAND_ECC_SOFT;
+#else
+	nand->ecc.mode = NAND_ECC_HW;
+	nand->ecc.layout = &hw_nand_oob;
+	nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;
+	nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
+	nand->ecc.hwctl = omap_enable_hwecc;
+	nand->ecc.correct = omap_correct_data;
+	nand->ecc.calculate = omap_calculate_ecc;
+	omap_hwecc_init(nand);
+
+	if (nand->options & NAND_BUSWIDTH_16)
+		nand->read_buf = omap_spl_read_buf16;
+	else
+		nand->read_buf = omap_spl_read_buf;
+	nand->dev_ready = omap_spl_dev_ready;
+#endif
 
 	return 0;
 }
diff --git a/spl/Makefile b/spl/Makefile
index 87f13f6..0c0d3c4 100644
--- a/spl/Makefile
+++ b/spl/Makefile
@@ -46,6 +46,8 @@  LIBS-$(CONFIG_SPL_SPI_FLASH_SUPPORT) += drivers/mtd/spi/libspi_flash.o
 LIBS-$(CONFIG_SPL_SPI_SUPPORT) += drivers/spi/libspi.o
 LIBS-$(CONFIG_SPL_FAT_SUPPORT) += fs/fat/libfat.o
 LIBS-$(CONFIG_SPL_LIBGENERIC_SUPPORT) += lib/libgeneric.o
+LIBS-$(CONFIG_SPL_POWER_SUPPORT) += drivers/power/libpower.o
+LIBS-$(CONFIG_SPL_NAND_SUPPORT) += drivers/mtd/nand/libnand.o
 
 ifeq ($(SOC),omap3)
 LIBS-y += $(CPUDIR)/omap-common/libomap-common.o