diff mbox

[U-Boot,4/4] PXA: Adapt Voipac PXA270 to OneNAND SPL

Message ID 1320067393-18822-5-git-send-email-marek.vasut@gmail.com
State Changes Requested
Headers show

Commit Message

Marek Vasut Oct. 31, 2011, 1:23 p.m. UTC
Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
Cc: Albert ARIBAUD <albert.u.boot@aribaud.net>
---
 board/vpac270/Makefile    |    6 ++
 board/vpac270/onenand.c   |  136 +++++++++++++++++++++++++++++++++++++++++++++
 board/vpac270/vpac270.c   |    2 +
 include/configs/vpac270.h |   25 +++++++--
 4 files changed, 164 insertions(+), 5 deletions(-)
 create mode 100644 board/vpac270/onenand.c

Comments

Scott Wood Oct. 31, 2011, 11:03 p.m. UTC | #1
On 10/31/2011 08:23 AM, Marek Vasut wrote:
> Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
> Cc: Albert ARIBAUD <albert.u.boot@aribaud.net>
> ---
>  board/vpac270/Makefile    |    6 ++
>  board/vpac270/onenand.c   |  136 +++++++++++++++++++++++++++++++++++++++++++++
>  board/vpac270/vpac270.c   |    2 +
>  include/configs/vpac270.h |   25 +++++++--
>  4 files changed, 164 insertions(+), 5 deletions(-)
>  create mode 100644 board/vpac270/onenand.c
> 
> diff --git a/board/vpac270/Makefile b/board/vpac270/Makefile
> index b5c60fd..f25822f 100644
> --- a/board/vpac270/Makefile
> +++ b/board/vpac270/Makefile
> @@ -23,7 +23,13 @@ include $(TOPDIR)/config.mk
>  
>  LIB	= $(obj)lib$(BOARD).o
>  
> +ifndef	CONFIG_SPL_BUILD
>  COBJS	:= vpac270.o
> +endif
> +
> +ifdef	CONFIG_SPL_BUILD
> +COBJS	:= onenand.o
> +endif

else?

>  SRCS	:= $(COBJS:.o=.c)
>  OBJS	:= $(addprefix $(obj),$(COBJS))
> diff --git a/board/vpac270/onenand.c b/board/vpac270/onenand.c
> new file mode 100644
> index 0000000..50de2ab
> --- /dev/null
> +++ b/board/vpac270/onenand.c
> @@ -0,0 +1,136 @@
> +/*
> + * Voipac PXA270 OneNAND SPL
> + *
> + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
> + *
> + * See file CREDITS for list of people who contributed to this
> + * project.
> + *
> + * 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 <config.h>
> +#include <asm/io.h>
> +#include <onenand_uboot.h>
> +
> +extern void pxa_dram_init(void);
> +
> +inline void spl_copy_self(void)
> +{
> +	extern uint32_t _end;
> +	struct spl_onenand_data data;
> +	uint32_t page;
> +	uint32_t total_bytes = (uint32_t)&_end - CONFIG_SPL_TEXT_BASE;
> +	uint32_t total_pages;
> +	uint8_t *addr = (uint8_t *)CONFIG_SPL_TEXT_BASE;
> +	int ret;
> +
> +	spl_onenand_get_geometry(&data);
> +
> +	/* The page can be either 2k or 4k, avoid using DIV_ROUND_UP. */
> +	total_pages = total_bytes >> 11;
> +	if (data.pagesize == 4096)
> +		total_pages >>= 1;

total_bytes / 2048 and total_pages / 2 are more readable and should
generate exactly the same code.

> +	for (page = 0; page <= total_pages; page++) {
> +		ret = spl_onenand_read_page(0, page, addr, data.pagesize);
> +		if (ret)
> +			total_pages++;
> +		else
> +			addr += data.pagesize;
> +	}
> +}

You want to skip to the next block if spl_onenand_read_page() fails
(which can occur after you've already read some of the block).

How much of this is board-specific?

> +inline void spl_copy_uboot(void)
> +{
> +	uint8_t *addr = (uint8_t *)CONFIG_SYS_TEXT_BASE;
> +	struct spl_onenand_data data;
> +	uint32_t total_pages;
> +	uint32_t block;
> +	uint32_t page, rpage;
> +	int ret;
> +
> +	spl_onenand_get_geometry(&data);
> +
> +	/* The page can be either 2k or 4k, avoid using DIV_ROUND_UP. */
> +	total_pages = CONFIG_SPL_ONENAND_LOAD_SIZE >> 11;
> +	page = CONFIG_SPL_ONENAND_LOAD_ADDR >> 11;
> +	if (data.pagesize == 4096) {
> +		total_pages >>= 1;
> +		page >>= 1;
> +	}
> +
> +	for (; page <= total_pages; page++) {
> +		block = page >> 6;
> +		rpage = page & 0xff;
> +		ret = spl_onenand_read_page(block, rpage, addr, data.pagesize);
> +		if (ret)
> +			total_pages++;
> +		else
> +			addr += data.pagesize;
> +	}
> +}

What is so different about this compared to spl_copy_self, that warrants
such duplication?  Can't you just pass in offset, length, and
destination as parameters?  Or just have the OneNAND SPL driver export
nand_spl_load_image(), as any other NAND SPL driver would?

> +inline void board_init_f(unsigned long unused)
> +{
> +	uint32_t tmp;
> +
> +	asm volatile("mov %0, pc" : "=r"(tmp));
> +	tmp >>= 24;
> +
> +	/* The code runs from OneNAND RAM, copy SPL to SRAM and execute it. */
> +	if (tmp == 0) {
> +		spl_copy_self();
> +		asm volatile("mov pc, %0" : : "r"(CONFIG_SPL_TEXT_BASE));
> +	}

Is it not possible to use a simple memcpy for spl_copy_self()?  If the
CPU can run the code, you'd think it could read it.

> +inline void board_init_r(gd_t *id, ulong dest_addr)
> +{
> +	for (;;)
> +		;
> +}

This doesn't seem like a useful board_init_r().  If you don't need it,
maybe make sure it's not called, and save yourself some bytes in the
SPL.  Likewise for the other stub functions, where practical.

> +inline int printf(const char *fmt, ...)
> +{
> +	return 0;
> +}
> +
> +inline void __coloured_LED_init(void) {}
> +inline void __red_LED_on(void) {}
> +void coloured_LED_init(void)
> +	__attribute__((weak, alias("__coloured_LED_init")));
> +void red_LED_on(void)
> +	__attribute__((weak, alias("__red_LED_on")));
> +void hang(void) __attribute__ ((noreturn));
> +void hang(void)
> +{
> +	for (;;)
> +		;
> +}
> +
> +inline void icache_disable(void) {}
> +inline void dcache_disable(void) {}

Why are you specifying inline on just about everything, even functions
that are not used in this file?

Why are you not specifying static on things that are not needed outside
this file?

> diff --git a/board/vpac270/vpac270.c b/board/vpac270/vpac270.c
> index 43bbdff..f146009 100644
> --- a/board/vpac270/vpac270.c
> +++ b/board/vpac270/vpac270.c
> @@ -56,7 +56,9 @@ struct serial_device *default_serial_console(void)
>  extern void pxa_dram_init(void);
>  int dram_init(void)
>  {
> +#ifndef	CONFIG_ONENAND
>  	pxa_dram_init();
> +#endif
>  	gd->ram_size = PHYS_SDRAM_1_SIZE;
>  	return 0;
>  }

Should this really be about whether OneNAND support is present, or
should it be based on whether you're using the OneNAND SPL?

-Scott
Marek Vasut Nov. 1, 2011, 10:12 p.m. UTC | #2
> On 10/31/2011 08:23 AM, Marek Vasut wrote:
> > Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
> > Cc: Albert ARIBAUD <albert.u.boot@aribaud.net>
> > ---
[...]

> 
> > +	for (page = 0; page <= total_pages; page++) {
> > +		ret = spl_onenand_read_page(0, page, addr, data.pagesize);
> > +		if (ret)
> > +			total_pages++;
> > +		else
> > +			addr += data.pagesize;
> > +	}
> > +}
> 
> You want to skip to the next block if spl_onenand_read_page() fails
> (which can occur after you've already read some of the block).

I want to skip to next page, not next block.

> 
> How much of this is board-specific?
> 
> > +inline void spl_copy_uboot(void)
> > +{
> > +	uint8_t *addr = (uint8_t *)CONFIG_SYS_TEXT_BASE;
> > +	struct spl_onenand_data data;
> > +	uint32_t total_pages;
> > +	uint32_t block;
> > +	uint32_t page, rpage;
> > +	int ret;
> > +
> > +	spl_onenand_get_geometry(&data);
> > +
> > +	/* The page can be either 2k or 4k, avoid using DIV_ROUND_UP. */
> > +	total_pages = CONFIG_SPL_ONENAND_LOAD_SIZE >> 11;
> > +	page = CONFIG_SPL_ONENAND_LOAD_ADDR >> 11;
> > +	if (data.pagesize == 4096) {
> > +		total_pages >>= 1;
> > +		page >>= 1;
> > +	}
> > +
> > +	for (; page <= total_pages; page++) {
> > +		block = page >> 6;
> > +		rpage = page & 0xff;
> > +		ret = spl_onenand_read_page(block, rpage, addr, data.pagesize);
> > +		if (ret)
> > +			total_pages++;
> > +		else
> > +			addr += data.pagesize;
> > +	}
> > +}
> 
> What is so different about this compared to spl_copy_self, that warrants
> such duplication?  Can't you just pass in offset, length, and
> destination as parameters?  Or just have the OneNAND SPL driver export
> nand_spl_load_image(), as any other NAND SPL driver would?

Good idea.

> 
> > +inline void board_init_f(unsigned long unused)
> > +{
> > +	uint32_t tmp;
> > +
> > +	asm volatile("mov %0, pc" : "=r"(tmp));
> > +	tmp >>= 24;
> > +
> > +	/* The code runs from OneNAND RAM, copy SPL to SRAM and execute it. */
> > +	if (tmp == 0) {
> > +		spl_copy_self();
> > +		asm volatile("mov pc, %0" : : "r"(CONFIG_SPL_TEXT_BASE));
> > +	}
> 
> Is it not possible to use a simple memcpy for spl_copy_self()?  If the
> CPU can run the code, you'd think it could read it.

Not exactly. The OneNAND only exposes first 1kb of the contents (aka 1 half of 
the page 0 in my case). That's why I link all of the relevant code there and the 
rest of the SPL is aligned beyond that. Then I copy the whole SPL to SRAM and 
execute it again. Then I init DRAM, copy U-Boot there and run it. Simple, isn't 
it.

> 
> > +inline void board_init_r(gd_t *id, ulong dest_addr)
> > +{
> > +	for (;;)
> > +		;
> > +}
> 
> This doesn't seem like a useful board_init_r().  If you don't need it,
> maybe make sure it's not called, and save yourself some bytes in the
> SPL.  Likewise for the other stub functions, where practical.
> 
> > +inline int printf(const char *fmt, ...)
> > +{
> > +	return 0;
> > +}
> > +
> > +inline void __coloured_LED_init(void) {}
> > +inline void __red_LED_on(void) {}
> > +void coloured_LED_init(void)
> > +	__attribute__((weak, alias("__coloured_LED_init")));
> > +void red_LED_on(void)
> > +	__attribute__((weak, alias("__red_LED_on")));
> > +void hang(void) __attribute__ ((noreturn));
> > +void hang(void)
> > +{
> > +	for (;;)
> > +		;
> > +}
> > +
> > +inline void icache_disable(void) {}
> > +inline void dcache_disable(void) {}
> 
> Why are you specifying inline on just about everything, even functions
> that are not used in this file?

They are, by dram_init();

> 
> Why are you not specifying static on things that are not needed outside
> this file?

They are actually needed outside.
> 
> > diff --git a/board/vpac270/vpac270.c b/board/vpac270/vpac270.c
> > index 43bbdff..f146009 100644
> > --- a/board/vpac270/vpac270.c
> > +++ b/board/vpac270/vpac270.c
> > @@ -56,7 +56,9 @@ struct serial_device *default_serial_console(void)
> > 
> >  extern void pxa_dram_init(void);
> >  int dram_init(void)
> >  {
> > 
> > +#ifndef	CONFIG_ONENAND
> > 
> >  	pxa_dram_init();
> > 
> > +#endif
> > 
> >  	gd->ram_size = PHYS_SDRAM_1_SIZE;
> >  	return 0;
> >  
> >  }
> 
> Should this really be about whether OneNAND support is present, or
> should it be based on whether you're using the OneNAND SPL?

Basically, on this board this is the same thing.
> 
> -Scott
Scott Wood Nov. 1, 2011, 10:34 p.m. UTC | #3
On 11/01/2011 05:12 PM, Marek Vasut wrote:
>> On 10/31/2011 08:23 AM, Marek Vasut wrote:
>>> Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
>>> Cc: Albert ARIBAUD <albert.u.boot@aribaud.net>
>>> ---
> [...]
> 
>>
>>> +	for (page = 0; page <= total_pages; page++) {
>>> +		ret = spl_onenand_read_page(0, page, addr, data.pagesize);
>>> +		if (ret)
>>> +			total_pages++;
>>> +		else
>>> +			addr += data.pagesize;
>>> +	}
>>> +}
>>
>> You want to skip to the next block if spl_onenand_read_page() fails
>> (which can occur after you've already read some of the block).
> 
> I want to skip to next page, not next block.

That's not how we normally do things, and is not what the current
OneNAND IPL does.

Bad block markers apply to the entire block -- unless this is a
difference I'm not aware of between NAND and OneNAND.

>> Is it not possible to use a simple memcpy for spl_copy_self()?  If the
>> CPU can run the code, you'd think it could read it.
> 
> Not exactly. The OneNAND only exposes first 1kb of the contents (aka 1 half of 
> the page 0 in my case). That's why I link all of the relevant code there and the 
> rest of the SPL is aligned beyond that. Then I copy the whole SPL to SRAM and 
> execute it again. Then I init DRAM, copy U-Boot there and run it. Simple, isn't 
> it.

Where do you ensure that the stuff used so far is within the 1K?  What
parts are not within the 1K?

I don't see a linker script.

>>> +inline void icache_disable(void) {}
>>> +inline void dcache_disable(void) {}
>>
>> Why are you specifying inline on just about everything, even functions
>> that are not used in this file?
> 
> They are, by dram_init();

There's no point marking something inline if it's not used later on in
the same file -- functions aren't inlined across file boundaries.
You've got inline functions at the very end of the file.

For that matter, there's not much point marking anything inline that
isn't a static inline in a header file (where the compiler must not
generate a non-inline version) -- the compiler has heuristics for
inlining things, and excessive inlining tends to make things bigger
rather than smaller.

>> Why are you not specifying static on things that are not needed outside
>> this file?
> 
> They are actually needed outside.

All of them, including spl_copy_uboot and spl_copy_self?

>>> diff --git a/board/vpac270/vpac270.c b/board/vpac270/vpac270.c
>>> index 43bbdff..f146009 100644
>>> --- a/board/vpac270/vpac270.c
>>> +++ b/board/vpac270/vpac270.c
>>> @@ -56,7 +56,9 @@ struct serial_device *default_serial_console(void)
>>>
>>>  extern void pxa_dram_init(void);
>>>  int dram_init(void)
>>>  {
>>>
>>> +#ifndef	CONFIG_ONENAND
>>>
>>>  	pxa_dram_init();
>>>
>>> +#endif
>>>
>>>  	gd->ram_size = PHYS_SDRAM_1_SIZE;
>>>  	return 0;
>>>  
>>>  }
>>
>> Should this really be about whether OneNAND support is present, or
>> should it be based on whether you're using the OneNAND SPL?
> 
> Basically, on this board this is the same thing.

If you can turn off onenand at all, that suggests there's another boot
source.  Is it not possible to access onenand when using that other boot
source?

In any case, best to use the symbol that most closely matches the reason
you're skipping it, which is something SPL-related.

-Scott
Marek Vasut Nov. 1, 2011, 10:44 p.m. UTC | #4
> On 11/01/2011 05:12 PM, Marek Vasut wrote:
> >> On 10/31/2011 08:23 AM, Marek Vasut wrote:
> >>> Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
> >>> Cc: Albert ARIBAUD <albert.u.boot@aribaud.net>
> >>> ---
> > 
> > [...]
> > 
> >>> +	for (page = 0; page <= total_pages; page++) {
> >>> +		ret = spl_onenand_read_page(0, page, addr, data.pagesize);
> >>> +		if (ret)
> >>> +			total_pages++;
> >>> +		else
> >>> +			addr += data.pagesize;
> >>> +	}
> >>> +}
> >> 
> >> You want to skip to the next block if spl_onenand_read_page() fails
> >> (which can occur after you've already read some of the block).
> > 
> > I want to skip to next page, not next block.
> 
> That's not how we normally do things, and is not what the current
> OneNAND IPL does.
> 
> Bad block markers apply to the entire block -- unless this is a
> difference I'm not aware of between NAND and OneNAND.

Well then it will fail reading the whole block and continue onwards ... it's a 
bit slower like this.

> 
> >> Is it not possible to use a simple memcpy for spl_copy_self()?  If the
> >> CPU can run the code, you'd think it could read it.
> > 
> > Not exactly. The OneNAND only exposes first 1kb of the contents (aka 1
> > half of the page 0 in my case). That's why I link all of the relevant
> > code there and the rest of the SPL is aligned beyond that. Then I copy
> > the whole SPL to SRAM and execute it again. Then I init DRAM, copy
> > U-Boot there and run it. Simple, isn't it.
> 
> Where do you ensure that the stuff used so far is within the 1K?  What
> parts are not within the 1K?
> 
> I don't see a linker script.

Is in V2, missing.

> 
> >>> +inline void icache_disable(void) {}
> >>> +inline void dcache_disable(void) {}
> >> 
> >> Why are you specifying inline on just about everything, even functions
> >> that are not used in this file?
> > 
> > They are, by dram_init();
> 
> There's no point marking something inline if it's not used later on in
> the same file -- functions aren't inlined across file boundaries.
> You've got inline functions at the very end of the file.
> 
> For that matter, there's not much point marking anything inline that
> isn't a static inline in a header file (where the compiler must not
> generate a non-inline version) -- the compiler has heuristics for
> inlining things, and excessive inlining tends to make things bigger
> rather than smaller.
> 
> >> Why are you not specifying static on things that are not needed outside
> >> this file?
> > 
> > They are actually needed outside.
> 
> All of them, including spl_copy_uboot and spl_copy_self?
> 
> >>> diff --git a/board/vpac270/vpac270.c b/board/vpac270/vpac270.c
> >>> index 43bbdff..f146009 100644
> >>> --- a/board/vpac270/vpac270.c
> >>> +++ b/board/vpac270/vpac270.c
> >>> @@ -56,7 +56,9 @@ struct serial_device *default_serial_console(void)
> >>> 
> >>>  extern void pxa_dram_init(void);
> >>>  int dram_init(void)
> >>>  {
> >>> 
> >>> +#ifndef	CONFIG_ONENAND
> >>> 
> >>>  	pxa_dram_init();
> >>> 
> >>> +#endif
> >>> 
> >>>  	gd->ram_size = PHYS_SDRAM_1_SIZE;
> >>>  	return 0;
> >>>  
> >>>  }
> >> 
> >> Should this really be about whether OneNAND support is present, or
> >> should it be based on whether you're using the OneNAND SPL?
> > 
> > Basically, on this board this is the same thing.
> 
> If you can turn off onenand at all, that suggests there's another boot
> source.  Is it not possible to access onenand when using that other boot
> source?

No, they are mutually exclusive.

> 
> In any case, best to use the symbol that most closely matches the reason
> you're skipping it, which is something SPL-related.
> 
> -Scott
Scott Wood Nov. 2, 2011, 10:18 p.m. UTC | #5
On 11/01/2011 05:44 PM, Marek Vasut wrote:
>> On 11/01/2011 05:12 PM, Marek Vasut wrote:
>>>> On 10/31/2011 08:23 AM, Marek Vasut wrote:
>>>>> Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
>>>>> Cc: Albert ARIBAUD <albert.u.boot@aribaud.net>
>>>>> ---
>>>
>>> [...]
>>>
>>>>> +	for (page = 0; page <= total_pages; page++) {
>>>>> +		ret = spl_onenand_read_page(0, page, addr, data.pagesize);
>>>>> +		if (ret)
>>>>> +			total_pages++;
>>>>> +		else
>>>>> +			addr += data.pagesize;
>>>>> +	}
>>>>> +}
>>>>
>>>> You want to skip to the next block if spl_onenand_read_page() fails
>>>> (which can occur after you've already read some of the block).
>>>
>>> I want to skip to next page, not next block.
>>
>> That's not how we normally do things, and is not what the current
>> OneNAND IPL does.
>>
>> Bad block markers apply to the entire block -- unless this is a
>> difference I'm not aware of between NAND and OneNAND.
> 
> Well then it will fail reading the whole block and continue onwards ... it's a 
> bit slower like this.

It doesn't work like that.  The bad block marker is in the first page of
the block only (sometimes the second page can be used).  The bad block
marker is not placed on every page in the block, so if you continue to
subsequent pages it will not fail, but you won't be getting the data
you're expecting.

-Scott
diff mbox

Patch

diff --git a/board/vpac270/Makefile b/board/vpac270/Makefile
index b5c60fd..f25822f 100644
--- a/board/vpac270/Makefile
+++ b/board/vpac270/Makefile
@@ -23,7 +23,13 @@  include $(TOPDIR)/config.mk
 
 LIB	= $(obj)lib$(BOARD).o
 
+ifndef	CONFIG_SPL_BUILD
 COBJS	:= vpac270.o
+endif
+
+ifdef	CONFIG_SPL_BUILD
+COBJS	:= onenand.o
+endif
 
 SRCS	:= $(COBJS:.o=.c)
 OBJS	:= $(addprefix $(obj),$(COBJS))
diff --git a/board/vpac270/onenand.c b/board/vpac270/onenand.c
new file mode 100644
index 0000000..50de2ab
--- /dev/null
+++ b/board/vpac270/onenand.c
@@ -0,0 +1,136 @@ 
+/*
+ * Voipac PXA270 OneNAND SPL
+ *
+ * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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 <config.h>
+#include <asm/io.h>
+#include <onenand_uboot.h>
+
+extern void pxa_dram_init(void);
+
+inline void spl_copy_self(void)
+{
+	extern uint32_t _end;
+	struct spl_onenand_data data;
+	uint32_t page;
+	uint32_t total_bytes = (uint32_t)&_end - CONFIG_SPL_TEXT_BASE;
+	uint32_t total_pages;
+	uint8_t *addr = (uint8_t *)CONFIG_SPL_TEXT_BASE;
+	int ret;
+
+	spl_onenand_get_geometry(&data);
+
+	/* The page can be either 2k or 4k, avoid using DIV_ROUND_UP. */
+	total_pages = total_bytes >> 11;
+	if (data.pagesize == 4096)
+		total_pages >>= 1;
+
+	for (page = 0; page <= total_pages; page++) {
+		ret = spl_onenand_read_page(0, page, addr, data.pagesize);
+		if (ret)
+			total_pages++;
+		else
+			addr += data.pagesize;
+	}
+}
+
+inline void spl_copy_uboot(void)
+{
+	uint8_t *addr = (uint8_t *)CONFIG_SYS_TEXT_BASE;
+	struct spl_onenand_data data;
+	uint32_t total_pages;
+	uint32_t block;
+	uint32_t page, rpage;
+	int ret;
+
+	spl_onenand_get_geometry(&data);
+
+	/* The page can be either 2k or 4k, avoid using DIV_ROUND_UP. */
+	total_pages = CONFIG_SPL_ONENAND_LOAD_SIZE >> 11;
+	page = CONFIG_SPL_ONENAND_LOAD_ADDR >> 11;
+	if (data.pagesize == 4096) {
+		total_pages >>= 1;
+		page >>= 1;
+	}
+
+	for (; page <= total_pages; page++) {
+		block = page >> 6;
+		rpage = page & 0xff;
+		ret = spl_onenand_read_page(block, rpage, addr, data.pagesize);
+		if (ret)
+			total_pages++;
+		else
+			addr += data.pagesize;
+	}
+}
+
+inline void board_init_f(unsigned long unused)
+{
+	uint32_t tmp;
+
+	asm volatile("mov %0, pc" : "=r"(tmp));
+	tmp >>= 24;
+
+	/* The code runs from OneNAND RAM, copy SPL to SRAM and execute it. */
+	if (tmp == 0) {
+		spl_copy_self();
+		asm volatile("mov pc, %0" : : "r"(CONFIG_SPL_TEXT_BASE));
+	}
+
+	/* Hereby, the code runs from (S)RAM, copy U-Boot and execute it. */
+	arch_cpu_init();
+	pxa_dram_init();
+	spl_copy_uboot();
+	asm volatile("mov pc, %0" : : "r"(CONFIG_SYS_TEXT_BASE));
+
+	for (;;)
+		;
+}
+
+inline void board_init_r(gd_t *id, ulong dest_addr)
+{
+	for (;;)
+		;
+}
+
+inline int printf(const char *fmt, ...)
+{
+	return 0;
+}
+
+inline void __coloured_LED_init(void) {}
+inline void __red_LED_on(void) {}
+void coloured_LED_init(void)
+	__attribute__((weak, alias("__coloured_LED_init")));
+void red_LED_on(void)
+	__attribute__((weak, alias("__red_LED_on")));
+void hang(void) __attribute__ ((noreturn));
+void hang(void)
+{
+	for (;;)
+		;
+}
+
+inline void icache_disable(void) {}
+inline void dcache_disable(void) {}
diff --git a/board/vpac270/vpac270.c b/board/vpac270/vpac270.c
index 43bbdff..f146009 100644
--- a/board/vpac270/vpac270.c
+++ b/board/vpac270/vpac270.c
@@ -56,7 +56,9 @@  struct serial_device *default_serial_console(void)
 extern void pxa_dram_init(void);
 int dram_init(void)
 {
+#ifndef	CONFIG_ONENAND
 	pxa_dram_init();
+#endif
 	gd->ram_size = PHYS_SDRAM_1_SIZE;
 	return 0;
 }
diff --git a/include/configs/vpac270.h b/include/configs/vpac270.h
index 9db4d99..d43ff47 100644
--- a/include/configs/vpac270.h
+++ b/include/configs/vpac270.h
@@ -27,7 +27,17 @@ 
  */
 #define	CONFIG_PXA27X		1	/* Marvell PXA270 CPU */
 #define	CONFIG_VPAC270		1	/* Voipac PXA270 board */
-#define	CONFIG_SYS_TEXT_BASE	0x0
+#define	CONFIG_SYS_TEXT_BASE	0xa0000000
+
+#ifdef	CONFIG_ONENAND
+#define	CONFIG_SPL
+#define	CONFIG_SPL_ONENAND_SUPPORT
+#define	CONFIG_SPL_ONENAND_LOAD_ADDR	0x2000
+#define	CONFIG_SPL_ONENAND_LOAD_SIZE	\
+	(512 * 1024 - CONFIG_SPL_ONENAND_LOAD_ADDR)
+#define	CONFIG_SPL_TEXT_BASE	0x5c000000
+#define	CONFIG_SPL_LDSCRIPT	"board/vpac270/u-boot-spl.lds"
+#endif
 
 /*
  * Environment settings
@@ -46,12 +56,19 @@ 
 		"bootm 0xa4000000; "					\
 	"fi; "								\
 	"bootm 0x60000;"
+
+#define	CONFIG_EXTRA_ENV_SETTINGS					\
+	"update_onenand="						\
+		"onenand erase 0x0 0x80000 ; "				\
+		"onenand write 0xa0000000 0x0 0x80000"
+
 #define	CONFIG_BOOTARGS			"console=tty0 console=ttyS0,115200"
 #define	CONFIG_TIMESTAMP
 #define	CONFIG_BOOTDELAY		2	/* Autoboot delay */
 #define	CONFIG_CMDLINE_TAG
 #define	CONFIG_SETUP_MEMORY_TAGS
 #define	CONFIG_LZMA			/* LZMA compression support */
+#define	CONFIG_OF_LIBFDT
 
 /*
  * Serial Console Configuration
@@ -179,16 +196,14 @@ 
 #define	CONFIG_SYS_MEMTEST_END		0xa0800000	/* 4 ... 8 MB in DRAM */
 
 #define	CONFIG_SYS_LOAD_ADDR		PHYS_SDRAM_1
-#define	CONFIG_SYS_IPL_LOAD_ADDR	(0x5c000000)
 #define CONFIG_SYS_SDRAM_BASE		PHYS_SDRAM_1
-#define	CONFIG_SYS_INIT_SP_ADDR		\
-	(PHYS_SDRAM_1 + GENERATED_GBL_DATA_SIZE + 2048)
+#define	CONFIG_SYS_INIT_SP_ADDR		0x5c010000
 
 /*
  * NOR FLASH
  */
 #define	CONFIG_SYS_MONITOR_BASE		0x0
-#define	CONFIG_SYS_MONITOR_LEN		0x40000
+#define	CONFIG_SYS_MONITOR_LEN		0x80000
 #define	CONFIG_ENV_ADDR			\
 			(CONFIG_SYS_MONITOR_BASE + CONFIG_SYS_MONITOR_LEN)
 #define	CONFIG_ENV_SIZE			0x4000