Patchwork [U-Boot,v3,3/5] jz4740 nand spl files

login
register
mail settings
Submitter Xiangfu Liu
Date Dec. 6, 2010, 11:53 a.m.
Message ID <1291636436-6535-4-git-send-email-xiangfu@openmobilefree.net>
Download mbox | patch
Permalink /patch/74335/
State Superseded
Headers show

Comments

Xiangfu Liu - Dec. 6, 2010, 11:53 a.m.
From: Xiangfu Liu <xiangfu@openmobilefree.net>

Signed-off-by: Xiangfu Liu <xiangfu@openmobilefree.net>
---
 nand_spl/board/xburst/nanonote/Makefile   |   96 ++++++++
 nand_spl/board/xburst/nanonote/u-boot.lds |   63 ++++++
 nand_spl/nand_boot_jz4740.c               |  344 +++++++++++++++++++++++++++++
 3 files changed, 503 insertions(+), 0 deletions(-)
 create mode 100644 nand_spl/board/xburst/nanonote/Makefile
 create mode 100644 nand_spl/board/xburst/nanonote/u-boot.lds
 create mode 100644 nand_spl/nand_boot_jz4740.c
Scott Wood - Dec. 14, 2010, 12:05 a.m.
On Mon, 6 Dec 2010 19:53:54 +0800
<xiangfu@openmobilefree.net> wrote:

> From: Xiangfu Liu <xiangfu@openmobilefree.net>
> 
> Signed-off-by: Xiangfu Liu <xiangfu@openmobilefree.net>
> ---
>  nand_spl/board/xburst/nanonote/Makefile   |   96 ++++++++
>  nand_spl/board/xburst/nanonote/u-boot.lds |   63 ++++++
>  nand_spl/nand_boot_jz4740.c               |  344 +++++++++++++++++++++++++++++

As I asked last time, is there any reason you can't use the standard
nand_boot.c?  Your non-SPL NAND driver looks like the type that would
work with it.

> +LDSCRIPT= $(TOPDIR)/nand_spl/board/$(BOARDDIR)/u-boot.lds
> +LDFLAGS	= -Bstatic -T $(LDSCRIPT) -Ttext $(TEXT_BASE)
> +AFLAGS	+= -DCONFIG_NAND_SPL
> +CFLAGS	+= -DCONFIG_NAND_SPL -O2

Are you sure you want -O2 and not -Os?  What are the space constraints
for this SPL?

> +$(nandobj)u-boot-spl-16k.bin: $(nandobj)u-boot-spl.bin
> +	dd bs=1024 count=8 if=/dev/zero of=$(nandobj)junk1
> +	cat $< $(nandobj)junk1 > $(nandobj)junk2
> +	dd bs=1024 count=8 if=$(nandobj)junk2 of=$(nandobj)junk3
> +	cat $(nandobj)junk3 $(nandobj)junk3 > $(nandobj)junk4
> +	dd bs=1024 count=256 if=/dev/zero of=$(nandobj)junk5
> +	cat $(nandobj)junk4 $(nandobj)junk5 > $(nandobj)junk6
> +	dd bs=1024 count=256 if=$(nandobj)junk6 of=$@
> +	rm -f $(nandobj)junk*

Again, please explain what's going on here.  Other boards don't do this.

> +static inline void __nand_dev_ready(void)

No underscores.

> +{
> +	unsigned int timeout = 10000;
> +	while ((readl(GPIO_PXPIN(2)) & 0x40000000) && timeout--)
> +		;
> +
> +	while (!(readl(GPIO_PXPIN(2)) & 0x40000000))
> +		;
> +}

From last time:
"Hmm, why a timeout here and not on any of the other spin loops?"

> +static unsigned char oob_buf[128] = {0};

From last time:

"Be careful, this may still go into the BSS even with the assignment.
Is the BSS getting cleared in the SPL boot code on this platform?  Do
you actually rely on it being zero initially?

Either way, the assignment doesn't do much."

> +
> +/*External routines */
> +extern void flush_cache_all(void);
> +extern int serial_init(void);
> +extern void serial_puts(const char *s);
> +extern void sdram_init(void);
> +extern void pll_init(void);
> +extern void usb_boot();

Can't you get these from headers?

> +static void gpio_init(void)
> +{
> +	__gpio_as_sdram_16bit_4720();
> +	__gpio_as_uart0();
> +	__gpio_jtag_to_uart0();
> +}
> +
> +static int is_usb_boot()
> +{
> +	__gpio_as_input(KEY_U_IN);
> +	__gpio_enable_pull(KEY_U_IN);
> +	__gpio_as_output(KEY_U_OUT);
> +	__gpio_clear_pin(KEY_U_OUT);
> +
> +	if (__gpio_get_pin(KEY_U_IN) == 0)
> +		return 1;
> +
> +	return 0;
> +}
> +
> +void nand_boot(void)
> +{
> +	void (*uboot)(void);
> +
> +	gpio_init();
> +	pll_init();
> +	serial_init();
> +	sdram_init();
> +	writel(0x094c4400, EMC_SMCR1);	 	/* Optimize the timing of nand */
> +
> +	serial_puts("\nNAND Boot\n");
> +
> +#if defined(CONFIG_NANONOTE)
> +	if (is_usb_boot()) {
> +		serial_puts("[U] pressed, goto USBBOOT mode\n");
> +		usb_boot();
> +	}
> +#endif

Again, this should go in a board file, which is separate from the NAND
implementation.  Especially if this is the only thing keeping you from
using the generic nand_boot.c.

-Scott
Xiangfu Liu - Jan. 9, 2011, 3:48 p.m.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi Scott

> 
> I don't see any of my comments on v3 addressed or responded to:
> http://lists.denx.de/pipermail/u-boot/2010-December/083601.html


On 12/14/2010 08:05 AM, Scott Wood wrote:
>>  nand_spl/nand_boot_jz4740.c               |  344 +++++++++++++++++++++++++++++
> 
> As I asked last time, is there any reason you can't use the standard
> nand_boot.c?  Your non-SPL NAND driver looks like the type that would
> work with it.

thanks for point out, in next version patches, I will remove the nand_boot_jz4740.c

> 
>> +LDSCRIPT= $(TOPDIR)/nand_spl/board/$(BOARDDIR)/u-boot.lds
>> +LDFLAGS	= -Bstatic -T $(LDSCRIPT) -Ttext $(TEXT_BASE)
>> +AFLAGS	+= -DCONFIG_NAND_SPL
>> +CFLAGS	+= -DCONFIG_NAND_SPL -O2
> 
> Are you sure you want -O2 and not -Os?  What are the space constraints
> for this SPL?
> 

the nand_spl must less then 8kb. 
~~~
#The boot program can load two areas of data from NAND flash to internal SRAM, one is the normal
#area up to 8KB starting from NAND flash address 0, the other is the backup area up to 8KB starting
#from NAND flash address 0x2000. After reset, the boot program will first read the normal area data
#from NAND flash using hardware Reed-Solomon ECC. If no ECC error is detected or ECC error is
#correctable, the boot program then branches to internal SRAM at 4 bytes offset. If it detects an
#uncorrectable ECC error, it will continue to read the backup area of data from NAND flash using
#hardware Reed-Solomon ECC. 
~~~

I try to add "-Os", then I got some compile error:
~~~
mipsel-openwrt-linux-gcc -g  -Os   -D__KERNEL__ -DCONFIG_SYS_TEXT_BASE=0x80100000 -I/home/xiangfu/workspace/PanGu/u-boot.upstream/include -fno-builtin -ffreestanding -nostdinc -isystem /home/xiangfu/workspace/PanGu/openwrt-xburst/staging_dir/toolchain-mipsel_gcc-4.3.3+cs_uClibc-0.9.30.1/usr/lib/gcc/mipsel-openwrt-linux-uclibc/4.3.3/include -pipe  -DCONFIG_MIPS -D__MIPS__ -G 0 -mabicalls -fpic -msoft-float -march=4kc -mtune=4kc -mabicalls -mips32 -Wall -Wstrict-prototypes -fno-stack-protector -DCONFIG_NAND_SPL -Os -c -o jz4740_nand.o jz4740_nand.c
jz4740_nand.c: In function 'board_nand_init':
jz4740_nand.c:298: warning: implicit declaration of function 'usb_boot'
cd /home/xiangfu/workspace/PanGu/u-boot.upstream/nand_spl/board/xburst/nanonote && mipsel-openwrt-linux-ld -Bstatic -T /home/xiangfu/workspace/PanGu/u-boot.upstream/nand_spl/board/xburst/nanonote/u-boot.lds -Ttext 0x80000000 $UNDEF_SYM start.o usbboot.o nand_boot.o cpu.o jz4740.o jz_serial.o jz4740_nand.o \
		-Map /home/xiangfu/workspace/PanGu/u-boot.upstream/nand_spl/u-boot-spl.map \
		-o /home/xiangfu/workspace/PanGu/u-boot.upstream/nand_spl/u-boot-spl
jz4740.o: In function `sdram_init':
jz4740.c:(.text+0x60): undefined reference to `memcpy'
~~~


>> +$(nandobj)u-boot-spl-16k.bin: $(nandobj)u-boot-spl.bin
>> +	dd bs=1024 count=8 if=/dev/zero of=$(nandobj)junk1
>> +	cat $< $(nandobj)junk1 > $(nandobj)junk2
>> +	dd bs=1024 count=8 if=$(nandobj)junk2 of=$(nandobj)junk3
>> +	cat $(nandobj)junk3 $(nandobj)junk3 > $(nandobj)junk4
>> +	dd bs=1024 count=256 if=/dev/zero of=$(nandobj)junk5
>> +	cat $(nandobj)junk4 $(nandobj)junk5 > $(nandobj)junk6
>> +	dd bs=1024 count=256 if=$(nandobj)junk6 of=$@
>> +	rm -f $(nandobj)junk*
> 
> Again, please explain what's going on here.  Other boards don't do this.
> 

add comments in "Makefile" in next patches.


- -- 
Best Regards
Xiangfu Liu
http://www.openmobilefree.net
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk0p2LEACgkQRRAEFRxkgLSVCwCeIQ3AC86hiUy98sBLoG8Zq1EE
WP8An3a8aIyzzwDJ46I/wBNytwGyJTyK
=YvtK
-----END PGP SIGNATURE-----
Scott Wood - Jan. 10, 2011, 6:43 p.m.
On Sun, 9 Jan 2011 23:48:01 +0800
Xiangfu Liu <xiangfu@openmobilefree.net> wrote:

> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
> 
> Hi Scott
> 
> > 
> > I don't see any of my comments on v3 addressed or responded to:
> > http://lists.denx.de/pipermail/u-boot/2010-December/083601.html
> 
> 
> On 12/14/2010 08:05 AM, Scott Wood wrote:
> >>  nand_spl/nand_boot_jz4740.c               |  344 +++++++++++++++++++++++++++++
> > 
> > As I asked last time, is there any reason you can't use the standard
> > nand_boot.c?  Your non-SPL NAND driver looks like the type that would
> > work with it.
> 
> thanks for point out, in next version patches, I will remove the nand_boot_jz4740.c
> 
> > 
> >> +LDSCRIPT= $(TOPDIR)/nand_spl/board/$(BOARDDIR)/u-boot.lds
> >> +LDFLAGS	= -Bstatic -T $(LDSCRIPT) -Ttext $(TEXT_BASE)
> >> +AFLAGS	+= -DCONFIG_NAND_SPL
> >> +CFLAGS	+= -DCONFIG_NAND_SPL -O2
> > 
> > Are you sure you want -O2 and not -Os?  What are the space constraints
> > for this SPL?
> > 
> 
> the nand_spl must less then 8kb. 
> ~~~
> #The boot program can load two areas of data from NAND flash to internal SRAM, one is the normal
> #area up to 8KB starting from NAND flash address 0, the other is the backup area up to 8KB starting
> #from NAND flash address 0x2000. After reset, the boot program will first read the normal area data
> #from NAND flash using hardware Reed-Solomon ECC. If no ECC error is detected or ECC error is
> #correctable, the boot program then branches to internal SRAM at 4 bytes offset. If it detects an
> #uncorrectable ECC error, it will continue to read the backup area of data from NAND flash using
> #hardware Reed-Solomon ECC. 
> ~~~
> 
> I try to add "-Os", then I got some compile error:
> ~~~
> mipsel-openwrt-linux-gcc -g  -Os   -D__KERNEL__ -DCONFIG_SYS_TEXT_BASE=0x80100000 -I/home/xiangfu/workspace/PanGu/u-boot.upstream/include -fno-builtin -ffreestanding -nostdinc -isystem /home/xiangfu/workspace/PanGu/openwrt-xburst/staging_dir/toolchain-mipsel_gcc-4.3.3+cs_uClibc-0.9.30.1/usr/lib/gcc/mipsel-openwrt-linux-uclibc/4.3.3/include -pipe  -DCONFIG_MIPS -D__MIPS__ -G 0 -mabicalls -fpic -msoft-float -march=4kc -mtune=4kc -mabicalls -mips32 -Wall -Wstrict-prototypes -fno-stack-protector -DCONFIG_NAND_SPL -Os -c -o jz4740_nand.o jz4740_nand.c
> jz4740_nand.c: In function 'board_nand_init':
> jz4740_nand.c:298: warning: implicit declaration of function 'usb_boot'
> cd /home/xiangfu/workspace/PanGu/u-boot.upstream/nand_spl/board/xburst/nanonote && mipsel-openwrt-linux-ld -Bstatic -T /home/xiangfu/workspace/PanGu/u-boot.upstream/nand_spl/board/xburst/nanonote/u-boot.lds -Ttext 0x80000000 $UNDEF_SYM start.o usbboot.o nand_boot.o cpu.o jz4740.o jz_serial.o jz4740_nand.o \
> 		-Map /home/xiangfu/workspace/PanGu/u-boot.upstream/nand_spl/u-boot-spl.map \
> 		-o /home/xiangfu/workspace/PanGu/u-boot.upstream/nand_spl/u-boot-spl
> jz4740.o: In function `sdram_init':
> jz4740.c:(.text+0x60): undefined reference to `memcpy'
> ~~~

Try -fno-builtin

> >> +$(nandobj)u-boot-spl-16k.bin: $(nandobj)u-boot-spl.bin
> >> +	dd bs=1024 count=8 if=/dev/zero of=$(nandobj)junk1
> >> +	cat $< $(nandobj)junk1 > $(nandobj)junk2
> >> +	dd bs=1024 count=8 if=$(nandobj)junk2 of=$(nandobj)junk3
> >> +	cat $(nandobj)junk3 $(nandobj)junk3 > $(nandobj)junk4
> >> +	dd bs=1024 count=256 if=/dev/zero of=$(nandobj)junk5
> >> +	cat $(nandobj)junk4 $(nandobj)junk5 > $(nandobj)junk6
> >> +	dd bs=1024 count=256 if=$(nandobj)junk6 of=$@
> >> +	rm -f $(nandobj)junk*
> > 
> > Again, please explain what's going on here.  Other boards don't do this.
> > 
> 
> add comments in "Makefile" in next patches.

Is there no way that can be simplified?  It looks like a very elaborate
and obfuscated means of getting some zero padding between the SPL and
the payload.  Other boards do this in a much more straightforward
manner.

-Scott

Patch

diff --git a/nand_spl/board/xburst/nanonote/Makefile b/nand_spl/board/xburst/nanonote/Makefile
new file mode 100644
index 0000000..f5d1eb5
--- /dev/null
+++ b/nand_spl/board/xburst/nanonote/Makefile
@@ -0,0 +1,96 @@ 
+#
+# (C) Copyright 2006
+# Stefan Roese, DENX Software Engineering, sr@denx.de.
+#
+# 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 $(TOPDIR)/config.mk
+TEXT_BASE = 0x80000000
+
+LDSCRIPT= $(TOPDIR)/nand_spl/board/$(BOARDDIR)/u-boot.lds
+LDFLAGS	= -Bstatic -T $(LDSCRIPT) -Ttext $(TEXT_BASE)
+AFLAGS	+= -DCONFIG_NAND_SPL
+CFLAGS	+= -DCONFIG_NAND_SPL -O2
+
+SOBJS	= start.o usbboot.o
+COBJS	= nand_boot_jz4740.o cpu.o jz4740.o jz_serial.o
+
+SRCS	:= $(addprefix $(obj),$(SOBJS:.o=.S) $(COBJS:.o=.c))
+OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS))
+__OBJS	:= $(SOBJS) $(COBJS)
+LNDIR	:= $(OBJTREE)/nand_spl/board/$(BOARDDIR)
+
+nandobj	:= $(OBJTREE)/nand_spl/
+
+ALL	= $(nandobj)u-boot-spl $(nandobj)u-boot-spl.bin $(nandobj)u-boot-spl-16k.bin
+all:	$(obj).depend $(ALL)
+
+$(nandobj)u-boot-spl-16k.bin: $(nandobj)u-boot-spl.bin
+	dd bs=1024 count=8 if=/dev/zero of=$(nandobj)junk1
+	cat $< $(nandobj)junk1 > $(nandobj)junk2
+	dd bs=1024 count=8 if=$(nandobj)junk2 of=$(nandobj)junk3
+	cat $(nandobj)junk3 $(nandobj)junk3 > $(nandobj)junk4
+	dd bs=1024 count=256 if=/dev/zero of=$(nandobj)junk5
+	cat $(nandobj)junk4 $(nandobj)junk5 > $(nandobj)junk6
+	dd bs=1024 count=256 if=$(nandobj)junk6 of=$@
+	rm -f $(nandobj)junk*
+
+$(nandobj)u-boot-spl.bin:	$(nandobj)u-boot-spl
+	$(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
+
+$(nandobj)u-boot-spl:	$(OBJS)
+	cd $(LNDIR) && $(LD) $(LDFLAGS) $$UNDEF_SYM $(__OBJS) \
+		-Map $(nandobj)u-boot-spl.map \
+		-o $(nandobj)u-boot-spl
+
+# create symbolic links for common files
+$(obj)start.S:
+	@rm -f $(obj)start.S
+	ln -s $(SRCTREE)/arch/mips/cpu/xburst/start_spl.S $(obj)start.S
+
+$(obj)usbboot.S:
+	@rm -f $(obj)usbboot.S
+	ln -s $(SRCTREE)/arch/mips/cpu/xburst/usbboot.S $(obj)usbboot.S
+
+$(obj)cpu.c:
+	@rm -f $(obj)cpu.c
+	ln -s $(SRCTREE)/arch/mips/cpu/xburst/cpu.c $(obj)cpu.c
+
+$(obj)jz4740.c:
+	@rm -f $(obj)jz4740.c
+	ln -s $(SRCTREE)/arch/mips/cpu/xburst/jz4740.c $(obj)jz4740.c
+
+$(obj)jz_serial.c:
+	@rm -f $(obj)jz_serial.c
+	ln -s $(SRCTREE)/arch/mips/cpu/xburst/jz_serial.c $(obj)jz_serial.c
+
+$(obj)nand_boot_jz4740.c:
+	@rm -f $(obj)nand_boot_jz4740.c
+	ln -s $(SRCTREE)/nand_spl/nand_boot_jz4740.c $(obj)nand_boot_jz4740.c
+
+$(obj)%.o:	$(obj)%.S
+	$(CC) $(AFLAGS) -c -o $@ $<
+
+$(obj)%.o:	$(obj)%.c
+	$(CC) $(CFLAGS) -c -o $@ $<
+
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
diff --git a/nand_spl/board/xburst/nanonote/u-boot.lds b/nand_spl/board/xburst/nanonote/u-boot.lds
new file mode 100644
index 0000000..7042388
--- /dev/null
+++ b/nand_spl/board/xburst/nanonote/u-boot.lds
@@ -0,0 +1,63 @@ 
+/*
+ * (C) Copyright 2005
+ * Ingenic Semiconductor, <jlwei@ingenic.cn>
+ *
+ * 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
+ */
+
+OUTPUT_FORMAT("elf32-tradlittlemips", "elf32-tradlittlemips", "elf32-tradlittlemips")
+
+OUTPUT_ARCH(mips)
+ENTRY(_start)
+SECTIONS
+{
+	. = 0x00000000;
+
+	. = ALIGN(4);
+	.text       :
+	{
+	  *(.text)
+	}
+
+	. = ALIGN(4);
+	.rodata  : { *(.rodata) }
+
+	. = ALIGN(4);
+	.data  : { *(.data) }
+
+	. = ALIGN(4);
+	.sdata  : { *(.sdata) }
+
+	_gp = ALIGN(16);
+
+	__got_start = .;
+	.got  : { *(.got) }
+	__got_end = .;
+
+	.sdata  : { *(.sdata) }
+
+	__u_boot_cmd_start = .;
+	.u_boot_cmd : { *(.u_boot_cmd) }
+	__u_boot_cmd_end = .;
+
+	uboot_end_data = .;
+	num_got_entries = (__got_end - __got_start) >> 2;
+
+	. = ALIGN(4);
+	.sbss  : { *(.sbss) }
+	.bss  : { *(.bss) }
+	uboot_end = .;
+}
diff --git a/nand_spl/nand_boot_jz4740.c b/nand_spl/nand_boot_jz4740.c
new file mode 100644
index 0000000..aa911a2
--- /dev/null
+++ b/nand_spl/nand_boot_jz4740.c
@@ -0,0 +1,344 @@ 
+/*
+ * Copyright (C) 2007 Ingenic Semiconductor Inc.
+ * Author: Peter <jlwei@ingenic.cn>
+ *
+ * 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>
+#include <asm/jz4740.h>
+
+#define KEY_U_OUT       (32 * 2 + 16)
+#define KEY_U_IN        (32 * 3 + 19)
+
+/* NAND flash definitions */
+#define NAND_DATAPORT	0xb8000000
+#define NAND_ADDRPORT	0xb8010000
+#define NAND_COMMPORT	0xb8008000
+
+#if (JZ4740_NANDBOOT_CFG == JZ4740_NANDBOOT_B8R3)
+	#define NAND_BUS_WIDTH 8
+	#define NAND_ROW_CYCLE 3
+#elif (JZ4740_NANDBOOT_CFG == JZ4740_NANDBOOT_B8R2)
+	#define NAND_BUS_WIDTH 8
+	#define NAND_ROW_CYCLE 2
+#elif (JZ4740_NANDBOOT_CFG == JZ4740_NANDBOOT_B16R3)
+	#define NAND_BUS_WIDTH 16
+	#define NAND_ROW_CYCLE 3
+#elif (JZ4740_NANDBOOT_CFG == JZ4740_NANDBOOT_B16R2)
+	#define NAND_BUS_WIDTH 16
+	#define NAND_ROW_CYCLE 2
+#endif
+
+static inline void __nand_dev_ready(void)
+{
+	unsigned int timeout = 10000;
+	while ((readl(GPIO_PXPIN(2)) & 0x40000000) && timeout--)
+		;
+
+	while (!(readl(GPIO_PXPIN(2)) & 0x40000000))
+		;
+}
+
+/* NAND flash parameters */
+static int page_size;
+static int oob_size;
+static int ecc_count;
+static int page_per_block;
+static int bad_block_pos;
+static int block_size;
+static unsigned char oob_buf[128] = {0};
+
+/*External routines */
+extern void flush_cache_all(void);
+extern int serial_init(void);
+extern void serial_puts(const char *s);
+extern void sdram_init(void);
+extern void pll_init(void);
+extern void usb_boot();
+
+/* NAND flash routines */
+static inline void nand_read_buf(void *buf, int count)
+{
+#if NAND_BUS_WIDTH == 16
+	int i;
+	u16 *p = (u16 *)buf;
+
+	for (i = 0; i < count; i += 2)
+		*p++ = readw(NAND_DATAPORT);
+
+#elif NAND_BUS_WIDTH == 8
+	int i;
+	u8 *p = (u8 *)buf;
+
+	for (i = 0; i < count; i++)
+		*p++ = readb(NAND_DATAPORT);
+
+#endif
+}
+
+/* Correct 1~9-bit errors in 512-bytes data */
+static void rs_correct(unsigned char *dat, int idx, int mask)
+{
+	int i;
+
+	idx--;
+
+	i = idx + (idx >> 3);
+	if (i >= 512)
+		return;
+
+	mask <<= (idx & 0x7);
+
+	dat[i] ^= mask & 0xff;
+	if (i < 511)
+		dat[i+1] ^= (mask >> 8) & 0xff;
+}
+
+static int nand_read_oob(int page_addr, uchar *buf, int size)
+{
+	int col_addr;
+	if (page_size != 512)
+		col_addr = page_size;
+	else {
+		col_addr = 0;
+		__nand_dev_ready();
+	}
+
+	if (page_size != 512)	/* Send READ0 command */
+		writeb(NAND_CMD_READ0, NAND_COMMPORT);
+	else	/* Send READOOB command */
+		writeb(NAND_CMD_READOOB, NAND_COMMPORT);
+
+	/* Send column address */
+	writeb((col_addr & 0xff), NAND_ADDRPORT);
+	if (page_size != 512)
+		writeb((col_addr >> 8) & 0xff, NAND_ADDRPORT);
+
+	/* Send page address */
+	writeb((page_addr & 0xff), NAND_ADDRPORT);
+	writeb((page_addr >> 8) & 0xff, NAND_ADDRPORT);
+#if defined NAND_ROW_CYCLE && NAND_ROW_CYCLE == 3
+	writeb((page_addr >> 16) & 0xff, NAND_ADDRPORT);
+#endif
+
+	/* Send READSTART command for 2048 or 4096 ps NAND */
+	if (page_size != 512)
+		writeb(NAND_CMD_READSTART, NAND_COMMPORT);
+
+	__nand_dev_ready();	/* Wait for device ready */
+
+	nand_read_buf(buf, size);	/* Read oob data */
+
+	if (page_size == 512)
+		__nand_dev_ready();
+
+	return 0;
+}
+
+static int nand_read_page(int page_addr, uchar *dst, uchar *oobbuf)
+{
+	uchar *databuf = dst, *tmpbuf;
+	int i, j;
+
+	nand_read_oob(page_addr, oobbuf, oob_size);	/* Read oob data */
+
+	writeb(NAND_CMD_READ0, NAND_COMMPORT);	/* Send READ0 command */
+
+	writeb(0, NAND_ADDRPORT);	/* Send column address */
+	if (page_size != 512)
+		writeb(0, NAND_ADDRPORT);
+
+	/* Send page address */
+	writeb((page_addr & 0xff), NAND_ADDRPORT);
+	writeb((page_addr >> 8) & 0xff, NAND_ADDRPORT);
+#if defined NAND_ROW_CYCLE && NAND_ROW_CYCLE == 3
+	writeb((page_addr >> 16) & 0xff, NAND_ADDRPORT);
+#endif
+
+	/* Send READSTART command for 2048 or 4096 ps NAND */
+	if (page_size != 512)
+		writeb(NAND_CMD_READSTART, NAND_COMMPORT);
+
+	/* Wait for device ready */
+	__nand_dev_ready();
+
+	/* Read page data */
+	tmpbuf = databuf;
+
+	for (i = 0; i < ecc_count; i++) {
+		volatile unsigned char *paraddr = (volatile unsigned char *)EMC_NFPAR0;
+		unsigned int stat;
+
+		/* Enable RS decoding */
+		writel(0x0, EMC_NFINTS);
+		writel(EMC_NFECR_ECCE | EMC_NFECR_ERST | EMC_NFECR_RS | 
+		       EMC_NFECR_RS_DECODING, EMC_NFECR);
+
+		/* Read data */
+		nand_read_buf((void *)tmpbuf, CONFIG_SYS_NAND_ECCSIZE);
+
+		/* Set PAR values */
+		for (j = 0; j < CONFIG_SYS_NAND_ECCBYTES; j++)
+			*paraddr++ = oobbuf[CONFIG_SYS_NAND_ECC_POS + i*CONFIG_SYS_NAND_ECCBYTES + j];
+
+		/* Set PRDY */
+		writel(readl(EMC_NFECR) |= EMC_NFECR_PRDY, EMC_NFECR);
+
+		/* Wait for completion */
+		while (!(readl(EMC_NFINTS) & EMC_NFINTS_DECF))
+			;
+
+		/* Disable decoding */
+		writel(readl(EMC_NFECR) & ~EMC_NFECR_ECCE, EMC_NFECR);
+
+		/* Check result of decoding */
+		stat = readl(EMC_NFINTS);
+		if (stat & EMC_NFINTS_ERR) {
+			/* Error occurred */
+			/* serial_puts("Error occurred\n"); */
+			if (stat & EMC_NFINTS_UNCOR) {
+				/* Uncorrectable error occurred */
+				/* serial_puts("Uncorrectable error occurred\n"); */
+			} else {
+				unsigned int errcnt, index, mask;
+
+				errcnt = (stat & EMC_NFINTS_ERRCNT_MASK) >> EMC_NFINTS_ERRCNT_BIT;
+				switch (errcnt) {
+				case 4:
+					index = (readl(EMC_NFERR3) & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT;
+					mask = (readl(EMC_NFERR3) & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT;
+				case 3:
+					index = (readl(EMC_NFERR2) & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT;
+					mask = (readl(EMC_NFERR2) & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT;
+					rs_correct(tmpbuf, index, mask);
+				case 2:
+					index = (readl(EMC_NFERR1) & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT;
+					mask = (readl(EMC_NFERR1) & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT;
+					rs_correct(tmpbuf, index, mask);
+				case 1:
+					index = (readl(EMC_NFERR0) & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT;
+					mask = (readl(EMC_NFERR0) & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT;
+					rs_correct(tmpbuf, index, mask);
+					break;
+				default:
+					break;
+				}
+			}
+		}
+		tmpbuf += CONFIG_SYS_NAND_ECCSIZE;
+	}
+
+	return 0;
+}
+
+#ifndef CONFIG_SYS_NAND_BADBLOCK_PAGE
+/* NAND bad block was marked at this page in a block, starting from 0 */
+#define CONFIG_SYS_NAND_BADBLOCK_PAGE 0 
+#endif
+
+static void nand_load(int offs, int uboot_size, uchar *dst)
+{
+	int page;
+	int pagecopy_count;
+
+	/* enable nand */
+	writel(readl(EMC_NFCSR) | (EMC_NFCSR_NFE1 | EMC_NFCSR_NFCE1), EMC_NFCSR);
+
+	page = offs / page_size;
+	pagecopy_count = 0;
+	while (pagecopy_count < (uboot_size / page_size)) {
+		if (page % page_per_block == 0) {
+			nand_read_oob(page + CONFIG_SYS_NAND_BADBLOCK_PAGE, 
+				      oob_buf, oob_size);
+			if (oob_buf[bad_block_pos] != 0xff) {
+				page += page_per_block;
+				continue;	/* Skip bad block */
+			}
+		}
+		/* Load this page to dst, do the ECC */
+		nand_read_page(page, dst, oob_buf);
+
+		dst += page_size;
+		page++;
+		pagecopy_count++;
+	}
+
+	/* disable nand */
+	writel(readl(EMC_NFCSR) & ~(EMC_NFCSR_NFCE1), EMC_NFCSR);
+}
+
+static void gpio_init(void)
+{
+	__gpio_as_sdram_16bit_4720();
+	__gpio_as_uart0();
+	__gpio_jtag_to_uart0();
+}
+
+static int is_usb_boot()
+{
+	__gpio_as_input(KEY_U_IN);
+	__gpio_enable_pull(KEY_U_IN);
+	__gpio_as_output(KEY_U_OUT);
+	__gpio_clear_pin(KEY_U_OUT);
+
+	if (__gpio_get_pin(KEY_U_IN) == 0)
+		return 1;
+
+	return 0;
+}
+
+void nand_boot(void)
+{
+	void (*uboot)(void);
+
+	gpio_init();
+	pll_init();
+	serial_init();
+	sdram_init();
+	writel(0x094c4400, EMC_SMCR1);	 	/* Optimize the timing of nand */
+
+	serial_puts("\nNAND Boot\n");
+
+#if defined(CONFIG_NANONOTE)
+	if (is_usb_boot()) {
+		serial_puts("[U] pressed, goto USBBOOT mode\n");
+		usb_boot();
+	}
+#endif
+	page_size = CONFIG_SYS_NAND_PAGE_SIZE;
+	block_size = CONFIG_SYS_NAND_BLOCK_SIZE;
+	page_per_block = CONFIG_SYS_NAND_BLOCK_SIZE / CONFIG_SYS_NAND_PAGE_SIZE;
+	bad_block_pos = (page_size == 512) ? 5 : 0;
+	oob_size = page_size / 32;
+	ecc_count = page_size / CONFIG_SYS_NAND_ECCSIZE;
+
+	/* Load U-Boot image from NAND into RAM */
+	nand_load(CONFIG_SYS_NAND_U_BOOT_OFFS, CONFIG_SYS_NAND_U_BOOT_SIZE,
+		  (uchar *)CONFIG_SYS_NAND_U_BOOT_DST);
+
+	uboot = (void (*)(void))CONFIG_SYS_NAND_U_BOOT_START;
+
+	serial_puts("Starting U-Boot ...\n");
+
+	/* Flush caches */
+	flush_cache_all();
+
+	/* Jump to U-Boot image */
+	(*uboot)();
+}