diff --git a/arch/arm/cpu/arm1176/start.S b/arch/arm/cpu/arm1176/start.S
index 848144a..26a3533 100644
--- a/arch/arm/cpu/arm1176/start.S
+++ b/arch/arm/cpu/arm1176/start.S
@@ -51,7 +51,7 @@
 
 .globl _start
 _start: b	reset
-#ifndef CONFIG_NAND_SPL
+#ifndef CONFIG_SPL_BUILD
 	ldr	pc, _undefined_instruction
 	ldr	pc, _software_interrupt
 	ldr	pc, _prefetch_abort
@@ -164,7 +164,7 @@ cpu_init_crit:
 	 * When booting from NAND - it has definitely been a reset, so, no need
 	 * to flush caches and disable the MMU
 	 */
-#ifndef CONFIG_NAND_SPL
+#ifndef CONFIG_SPL_BUILD
 	/*
 	 * flush v4 I/D caches
 	 */
@@ -356,21 +356,14 @@ clbss_l:str	r2, [r0]		/* clear loop...		    */
 	cmp	r0, r1
 	bne	clbss_l
 
-#ifndef CONFIG_NAND_SPL
 	bl coloured_LED_init
 	bl red_led_on
 #endif
-#endif
 
 /*
  * We are done. Do not return, instead branch to second part of board
  * initialization, now running from RAM.
  */
-#ifdef CONFIG_NAND_SPL
-	ldr     pc, _nand_boot
-
-_nand_boot: .word nand_boot
-#else
 	ldr	r0, _board_init_r_ofs
 	adr	r1, _start
 	add	lr, r0, r1
@@ -383,7 +376,6 @@ _nand_boot: .word nand_boot
 
 _board_init_r_ofs:
 	.word board_init_r - _start
-#endif
 
 _rel_dyn_start_ofs:
 	.word __rel_dyn_start - _start
@@ -397,7 +389,7 @@ _mmu_table_base:
 	.word mmu_table
 #endif
 
-#ifndef CONFIG_NAND_SPL
+#ifndef CONFIG_SPL_BUILD
 /*
  * we assume that cache operation is done before. (eg. cleanup_before_linux())
  * actually, we don't need to do anything about cache if not use d-cache in
@@ -575,4 +567,4 @@ fiq:
 	get_bad_stack
 	bad_save_user_regs
 	bl	do_fiq
-#endif /* CONFIG_NAND_SPL */
+#endif /* CONFIG_SPL_BUILD */
diff --git a/board/samsung/smdk6400/Makefile b/board/samsung/smdk6400/Makefile
index 645c8e2..f7fa667 100644
--- a/board/samsung/smdk6400/Makefile
+++ b/board/samsung/smdk6400/Makefile
@@ -28,15 +28,34 @@ include $(TOPDIR)/config.mk
 
 LIB	= $(obj)lib$(BOARD).o
 
+ifndef CONFIG_SPL_BUILD
 COBJS-y	:= smdk6400.o
+endif
+
 SOBJS	:= lowlevel_init.o mem_init.o
 
-SRCS    := $(SOBJS:.o=.S) $(COBJS-y:.o=.c)
-OBJS	:= $(addprefix $(obj),$(COBJS-y))
-SOBJS	:= $(addprefix $(obj),$(SOBJS))
+ifdef CONFIG_SPL_BUILD
+COBJS-y += smdk6400_nand_spl.o
+endif
+
+SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS-y) $(SOBJS))
+
+ALL	:=	 $(obj).depend $(LIB)
+
+ifdef CONFIG_SPL_BUILD
+ALL	+= $(OBJTREE)/tools/mk$(BOARD)spl
+endif
+
+all:	$(ALL)
+
+$(LIB):	$(OBJS)
+	$(call cmd_link_o_target, $(OBJS))
 
-$(LIB):	$(obj).depend $(SOBJS) $(OBJS)
-	$(call cmd_link_o_target, $(SOBJS) $(OBJS))
+ifdef CONFIG_SPL_BUILD
+$(OBJTREE)/tools/mk$(BOARD)spl:	tools/mksmdk6400_image.c
+	$(HOSTCC) tools/mksmdk6400_image.c -o $(OBJTREE)/tools/mk$(BOARD)spl
+endif
 
 #########################################################################
 
diff --git a/board/samsung/smdk6400/lowlevel_init.S b/board/samsung/smdk6400/lowlevel_init.S
index 1142be1..6cc7567 100644
--- a/board/samsung/smdk6400/lowlevel_init.S
+++ b/board/samsung/smdk6400/lowlevel_init.S
@@ -83,18 +83,12 @@ lowlevel_init:
 	str	r3, [r0, #oVECTADDR]
 	str	r3, [r1, #oVECTADDR]
 
+#ifdef CONFIG_SPL_BUILD
 	/* init system clock */
 	bl system_clock_init
 
-#ifndef CONFIG_NAND_SPL
-	/* for UART */
-	bl uart_asm_init
-#endif
-
-#ifdef CONFIG_BOOT_NAND
 	/* simple init for NAND */
 	bl nand_asm_init
-#endif
 
 	/* Memory subsystem address 0x7e00f120 */
 	ldr	r0, =ELFIN_MEM_SYS_CFG
@@ -104,6 +98,12 @@ lowlevel_init:
 	str	r1, [r0]
 
 	bl	mem_ctrl_asm_init
+#endif
+
+#ifndef CONFIG_SPL_BUILD
+	/* for UART */
+	bl uart_asm_init
+#endif
 
 /* Wakeup support. Don't know if it's going to be used, untested. */
 	ldr	r0, =(ELFIN_CLOCK_POWER_BASE + RST_STAT_OFFSET)
@@ -243,7 +243,7 @@ wait_for_async:
 	mov	pc, lr
 
 
-#ifndef CONFIG_NAND_SPL
+#ifndef CONFIG_SPL_BUILD
 /*
  * uart_asm_init: Initialize UART's pins
  */
@@ -255,7 +255,7 @@ uart_asm_init:
 	mov	pc, lr
 #endif
 
-#ifdef CONFIG_BOOT_NAND
+#ifdef CONFIG_SPL_BUILD
 /*
  * NAND Interface init for SMDK6400
  */
diff --git a/board/samsung/smdk6400/smdk6400_nand_spl.c b/board/samsung/smdk6400/smdk6400_nand_spl.c
index a023284..34649a2 100644
--- a/board/samsung/smdk6400/smdk6400_nand_spl.c
+++ b/board/samsung/smdk6400/smdk6400_nand_spl.c
@@ -1,13 +1,6 @@
 /*
- * (C) Copyright 2002
- * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
- * Marius Groeger <mgroeger@sysgo.de>
- *
- * (C) Copyright 2002
- * David Mueller, ELSOFT AG, <d.mueller@elsoft.ch>
- *
- * (C) Copyright 2008
- * Guennadi Liakhovetki, DENX Software Engineering, <lg@denx.de>
+ * Copyright (C) 2012
+ * Zhong Hongbo <bocui107@gmail.com>
  *
  * See file CREDITS for list of people who contributed to this
  * project.
@@ -29,9 +22,55 @@
  */
 
 #include <common.h>
+#include <config.h>
+#include <nand.h>
 
 void board_init_f(unsigned long bootflag)
 {
-	relocate_code(CONFIG_SYS_TEXT_BASE - TOTAL_MALLOC_LEN, NULL,
-			CONFIG_SYS_TEXT_BASE);
+	/*
+	 * We call relocate_code() with relocation target same as the
+	 * CONFIG_SYS_SPL_TEXT_BASE. This will result in relocation getting
+	 * skipped. Instead, only .bss initialization will happen. That's
+	 * all we need
+	 */
+	relocate_code(CONFIG_SPL_STACK, NULL, CONFIG_SPL_TEXT_BASE);
+}
+
+void board_init_r(gd_t *id, ulong dest_addr)
+{
+	__attribute__((noreturn)) void (*uboot)(void);
+
+	spl_nand_copy();
+	/*
+	 * Jump to U-Boot image
+	 */
+	uboot = (void *)CONFIG_SYS_UBOOT_BASE;
+	(*uboot)();
+	/* Never returns Here */
+}
+
+void spl_nand_copy(void)
+{
+	/*
+	 * Init board specific nand support
+	 */
+	nand_init();
+	/*
+	 * Load U-Boot image from NAND into RAM
+	 */
+	nand_spl_load_image(CONFIG_SYS_NAND_U_BOOT_OFFS,
+			CONFIG_SYS_NAND_U_BOOT_SIZE,
+			(void *)CONFIG_SYS_UBOOT_BASE);
+
+#ifdef CONFIG_NAND_ENV_DST
+	nand_spl_load_image(CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE,
+			(void *)CONFIG_NAND_ENV_DST);
+
+#ifdef CONFIG_ENV_OFFSET_REDUND
+	nand_spl_load_image(CONFIG_ENV_OFFSET_REDUND, CONFIG_ENV_SIZE,
+			(void *)CONFIG_NAND_ENV_DST + CONFIG_ENV_SIZE);
+#endif
+#endif
+
+	nand_deselect();
 }
diff --git a/board/samsung/smdk6400/tools/mksmdk6400_image.c b/board/samsung/smdk6400/tools/mksmdk6400_image.c
new file mode 100644
index 0000000..1a51913
--- /dev/null
+++ b/board/samsung/smdk6400/tools/mksmdk6400_image.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2011 Samsung Electronics
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#define CHECKSUM_OFFSET		(14*1024-4)
+#define BUFSIZE			(16*1024)
+#define FILE_PERM		(S_IRUSR | S_IWUSR | S_IRGRP \
+				| S_IWGRP | S_IROTH | S_IWOTH)
+/*
+* Requirement:
+* IROM code reads first 14K bytes from boot device.
+* It then calculates the checksum of 14K-4 bytes and compare with data at
+* 14K-4 offset.
+*
+* This function takes two filenames:
+* IN  "u-boot-spl.bin" and
+* OUT "u-boot-mmc-spl.bin" as filenames.
+* It reads the "u-boot-spl.bin" in 16K buffer.
+* It calculates checksum of 14K-4 Bytes and stores at 14K-4 offset in buffer.
+* It writes the buffer to "u-boot-mmc-spl.bin" file.
+*/
+
+int main(int argc, char **argv)
+{
+	int i, len;
+	unsigned char buffer[BUFSIZE] = {0};
+	int ifd, ofd;
+	unsigned int checksum = 0, count;
+
+	if (argc != 3) {
+		printf(" %d Wrong number of arguments\n", argc);
+		exit(EXIT_FAILURE);
+	}
+
+	ifd = open(argv[1], O_RDONLY);
+	if (ifd < 0) {
+		fprintf(stderr, "%s: Can't open %s: %s\n",
+			argv[0], argv[1], strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	ofd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, FILE_PERM);
+	if (ifd < 0) {
+		fprintf(stderr, "%s: Can't open %s: %s\n",
+			argv[0], argv[2], strerror(errno));
+		if (ifd)
+			close(ifd);
+		exit(EXIT_FAILURE);
+	}
+
+	len = lseek(ifd, 0, SEEK_END);
+	lseek(ifd, 0, SEEK_SET);
+
+	count = (len < CHECKSUM_OFFSET) ? len : CHECKSUM_OFFSET;
+
+	if (read(ifd, buffer, count) != count) {
+		fprintf(stderr, "%s: Can't read %s: %s\n",
+			argv[0], argv[1], strerror(errno));
+
+		if (ifd)
+			close(ifd);
+		if (ofd)
+			close(ofd);
+
+		exit(EXIT_FAILURE);
+	}
+
+	for (i = 0, checksum = 0; i < CHECKSUM_OFFSET; i++)
+		checksum += buffer[i];
+
+	memcpy(&buffer[CHECKSUM_OFFSET], &checksum, sizeof(checksum));
+
+	if (write(ofd, buffer, BUFSIZE) != BUFSIZE) {
+		fprintf(stderr, "%s: Can't write %s: %s\n",
+			argv[0], argv[2], strerror(errno));
+
+		if (ifd)
+			close(ifd);
+		if (ofd)
+			close(ofd);
+
+		exit(EXIT_FAILURE);
+	}
+
+	if (ifd)
+		close(ifd);
+	if (ofd)
+		close(ofd);
+
+	return EXIT_SUCCESS;
+}
diff --git a/drivers/mtd/nand/s3c64xx.c b/drivers/mtd/nand/s3c64xx.c
index 3199bf1..b85b641 100644
--- a/drivers/mtd/nand/s3c64xx.c
+++ b/drivers/mtd/nand/s3c64xx.c
@@ -39,7 +39,7 @@
 #define MAX_CHIPS	2
 static int nand_cs[MAX_CHIPS] = {0, 1};
 
-#ifdef CONFIG_NAND_SPL
+#ifdef CONFIG_SPL_BUILD
 #define printf(arg...) do {} while (0)
 #endif
 
@@ -285,7 +285,7 @@ int board_nand_init(struct nand_chip *nand)
 	nand->dev_ready		= s3c_nand_device_ready;
 	nand->select_chip	= s3c_nand_select_chip;
 	nand->options		= 0;
-#ifdef CONFIG_NAND_SPL
+#ifdef CONFIG_SPL_BUILD
 	nand->read_byte		= nand_read_byte;
 	nand->write_buf		= nand_write_buf;
 	nand->read_buf		= nand_read_buf;
diff --git a/include/configs/smdk6400.h b/include/configs/smdk6400.h
index 06b85bf..632ecb7 100644
--- a/include/configs/smdk6400.h
+++ b/include/configs/smdk6400.h
@@ -238,11 +238,10 @@
 #define CONFIG_SYS_NAND_YAFFS_WRITE	1  /* support yaffs write		      */
 #define CONFIG_SYS_NAND_BBT_2NDPAGE	1  /* bad-block markers in 1st and 2nd pages  */
 
-#define CONFIG_SYS_NAND_U_BOOT_DST	CONFIG_SYS_PHY_UBOOT_BASE	/* NUB load-addr      */
-#define CONFIG_SYS_NAND_U_BOOT_START	CONFIG_SYS_NAND_U_BOOT_DST	/* NUB start-addr     */
-
-#define CONFIG_SYS_NAND_U_BOOT_OFFS	(4 * 1024)	/* Offset to RAM U-Boot image */
-#define CONFIG_SYS_NAND_U_BOOT_SIZE	(252 * 1024)	/* Size of RAM U-Boot image   */
+/* Offset to RAM U-Boot image */
+#define CONFIG_SYS_NAND_U_BOOT_OFFS	(16 * 1024)
+/* Size of RAM U-Boot image   */
+#define CONFIG_SYS_NAND_U_BOOT_SIZE	(252 * 1024)
 
 /* NAND chip page size		*/
 #define CONFIG_SYS_NAND_PAGE_SIZE	2048
@@ -266,8 +265,6 @@
 				 48, 49, 50, 51, 52, 53, 54, 55, \
 				 56, 57, 58, 59, 60, 61, 62, 63}
 
-/* Boot configuration (define only one of next 3) */
-#define CONFIG_BOOT_NAND
 /* None of these are currently implemented. Left from the original Samsung
  * version for reference
 #define CONFIG_BOOT_NOR
@@ -275,7 +272,15 @@
 #define CONFIG_BOOT_ONENAND
 */
 
-#define CONFIG_NAND
+#define CONFIG_SPL
+#define CONFIG_SPL_NAND
+#define CONFIG_SPL_NAND_SIMPLE
+#define CONFIG_SPL_NAND_SUPPORT
+
+#define CONFIG_SPL_TEXT_BASE	0xd0020000
+#define CONFIG_SPL_STACK  CONFIG_SYS_PHY_UBOOT_BASE - CONFIG_SYS_MALLOC_LEN
+#define CONFIG_SPL_LIBGENERIC_SUPPORT
+
 #define CONFIG_NAND_S3C64XX
 /* Unimplemented or unsupported. See comment above.
 #define CONFIG_ONENAND
