diff --git a/Makefile b/Makefile
index 29180f3..01324ba 100644
--- a/Makefile
+++ b/Makefile
@@ -199,6 +199,7 @@ LIBS += dtt/libdtt.a
 LIBS += drivers/libdrivers.a
 LIBS += drivers/nand/libnand.a
 LIBS += drivers/nand_legacy/libnand_legacy.a
+LIBS += drivers/onenand/libonenand.a
 ifeq ($(CPU),mpc83xx)
 LIBS += drivers/qe/qe.a
 endif
diff --git a/common/Makefile b/common/Makefile
index 6f81c4a..f23c960 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -37,13 +37,14 @@ COBJS	= main.o ACEX1K.o altera.o bedbug.o circbuf.o cmd_autoscript.o \
 	  cmd_load.o cmd_log.o \
 	  cmd_mem.o cmd_mii.o cmd_misc.o cmd_mmc.o \
 	  cmd_nand.o cmd_net.o cmd_nvedit.o \
+	  cmd_onenand.o \
 	  cmd_pci.o cmd_pcmcia.o cmd_portio.o \
 	  cmd_reginfo.o cmd_reiser.o cmd_scsi.o cmd_spi.o cmd_universe.o \
 	  cmd_usb.o cmd_vfd.o \
 	  command.o console.o cyclon2.o devices.o dlmalloc.o docecc.o \
 	  environment.o env_common.o \
 	  env_nand.o env_dataflash.o env_flash.o env_eeprom.o \
-	  env_nvram.o env_nowhere.o \
+	  env_onenand.o env_nvram.o env_nowhere.o \
 	  exports.o \
 	  flash.o fpga.o ft_build.o \
 	  hush.o kgdb.o lcd.o lists.o lynxkdi.o \
diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index 9834ba6..e21588e 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -57,8 +57,9 @@ DECLARE_GLOBAL_DATA_PTR;
     !defined(CFG_ENV_IS_IN_FLASH)	&& \
     !defined(CFG_ENV_IS_IN_DATAFLASH)	&& \
     !defined(CFG_ENV_IS_IN_NAND)	&& \
+    !defined(CFG_ENV_IS_IN_ONENAND)	&& \
     !defined(CFG_ENV_IS_NOWHERE)
-# error Define one of CFG_ENV_IS_IN_{NVRAM|EEPROM|FLASH|DATAFLASH|NOWHERE}
+# error Define one of CFG_ENV_IS_IN_{NVRAM|EEPROM|FLASH|DATAFLASH|ONENAND|NOWHERE}
 #endif
 
 #define XMK_STR(x)	#x
@@ -536,6 +537,7 @@ int getenv_r (char *name, char *buf, unsigned len)
 }
 
 #if defined(CFG_ENV_IS_IN_NVRAM) || defined(CFG_ENV_IS_IN_EEPROM) || \
+    defined(CFG_ENV_IS_IN_ONENAND) || \
     ((CONFIG_COMMANDS & (CFG_CMD_ENV|CFG_CMD_FLASH)) == \
       (CFG_CMD_ENV|CFG_CMD_FLASH)) || \
     ((CONFIG_COMMANDS & (CFG_CMD_ENV|CFG_CMD_NAND)) == \
@@ -594,6 +596,7 @@ U_BOOT_CMD(
 );
 
 #if defined(CFG_ENV_IS_IN_NVRAM) || defined(CFG_ENV_IS_IN_EEPROM) || \
+    defined(CFG_ENV_IS_IN_ONENAND) || \
     ((CONFIG_COMMANDS & (CFG_CMD_ENV|CFG_CMD_FLASH)) == \
       (CFG_CMD_ENV|CFG_CMD_FLASH)) || \
     ((CONFIG_COMMANDS & (CFG_CMD_ENV|CFG_CMD_NAND)) == \
diff --git a/common/cmd_onenand.c b/common/cmd_onenand.c
new file mode 100644
index 0000000..473cedb
--- /dev/null
+++ b/common/cmd_onenand.c
@@ -0,0 +1,201 @@
+/*
+ *  U-Boot command for OneNAND support
+ *
+ *  Copyright (C) 2005-2007 Samsung Electronics
+ *  Kyungmin Park <kyungmin.park@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <command.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_ONENAND)
+
+#include <linux/mtd/onenand.h>
+
+extern struct mtd_info onenand_mtd;
+extern struct onenand_chip onenand_chip;
+
+int do_onenand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+	int ret = 0;
+
+	switch (argc) {
+	case 0:
+	case 1:
+		printf("Usage:\n%s\n", cmdtp->usage);
+		return 1;
+
+	case 2:
+		if (strncmp(argv[1], "open", 4) == 0) {
+			onenand_init();
+			return 0;
+		}
+		onenand_print_device_info(onenand_chip.device_id, 1);
+		return 0;
+
+	default:
+		/* At least 4 args */
+		if (strncmp(argv[1], "erase", 5) == 0) {
+			struct erase_info instr;
+			ulong start, end;
+			char *endtail;
+			ulong block;
+
+			if (strncmp(argv[2], "block", 5) == 0) {
+				start = simple_strtoul(argv[3], NULL, 10);
+				endtail = strchr(argv[3], '-');
+				end = simple_strtoul(endtail + 1, NULL, 10);
+			} else {
+				start = simple_strtoul(argv[2], NULL, 10);
+				end = simple_strtoul(argv[3], NULL, 10);
+				start -= (unsigned long) onenand_chip.base;
+				end -= (unsigned long) onenand_chip.base;
+			}
+
+			if (!end || end < 0)
+				end = start;
+
+			printf("Erase block from %d to %d\n", start, end);
+
+			for (block = start; block <= end; block++) {
+				instr.addr = block << onenand_chip.erase_shift;
+				instr.len = 1 << onenand_chip.erase_shift;
+				ret = onenand_erase(&onenand_mtd, &instr);
+				if (ret) {
+					printf("erase failed %d\n", block);
+					break;
+				}
+			}
+
+			return 0;
+		}
+
+		if (strncmp(argv[1], "read", 4) == 0) {
+			ulong addr = simple_strtoul(argv[2], NULL, 16);
+			ulong ofs = simple_strtoul(argv[3], NULL, 16);
+			size_t len = simple_strtoul(argv[4], NULL, 16);
+			size_t retlen = 0;
+			int oob = strncmp(argv[1], "read.oob", 8) ? 0 : 1;
+
+			ofs -= (unsigned long) onenand_chip.base;
+
+			if (oob)
+				onenand_read_oob(&onenand_mtd, ofs, len,
+						 &retlen, (u_char *) addr);
+			else
+				onenand_read(&onenand_mtd, ofs, len, &retlen,
+					     (u_char *) addr);
+			printf("Done\n");
+
+			return 0;
+		}
+
+		if (strncmp(argv[1], "write", 5) == 0) {
+			ulong addr = simple_strtoul(argv[2], NULL, 16);
+			ulong ofs = simple_strtoul(argv[3], NULL, 16);
+			size_t len = simple_strtoul(argv[4], NULL, 16);
+			size_t retlen = 0;
+
+			ofs -= (unsigned long) onenand_chip.base;
+
+			onenand_write(&onenand_mtd, ofs, len, &retlen,
+				      (u_char *) addr);
+			printf("Done\n");
+
+			return 0;
+		}
+
+		if (strncmp(argv[1], "block", 5) == 0) {
+			ulong addr = simple_strtoul(argv[2], NULL, 16);
+			ulong block = simple_strtoul(argv[3], NULL, 10);
+			ulong page = simple_strtoul(argv[4], NULL, 10);
+			size_t len = simple_strtol(argv[5], NULL, 10);
+			size_t retlen = 0;
+			ulong ofs;
+			int oob = strncmp(argv[1], "block.oob", 9) ? 0 : 1;
+
+			ofs = block << onenand_chip.erase_shift;
+			if (page)
+				ofs += page << onenand_chip.page_shift;
+
+			if (!len) {
+				if (oob)
+					len = 64;
+				else
+					len = 512;
+			}
+
+			if (oob)
+				onenand_read_oob(&onenand_mtd, ofs, len,
+						 &retlen, (u_char *) addr);
+			else
+				onenand_read(&onenand_mtd, ofs, len, &retlen,
+					     (u_char *) addr);
+			return 0;
+		}
+
+		if (strncmp(argv[1], "unlock", 6) == 0) {
+			ulong start = simple_strtoul(argv[2], NULL, 10);
+			ulong ofs = simple_strtoul(argv[3], NULL, 10);
+
+			if (!ofs)
+				ofs = (1 << onenand_chip.erase_shift);
+
+			start = start << onenand_chip.erase_shift;
+#if 0
+			printk("start = 0x%08x, ofs = 0x%08x\n", start, ofs);
+#endif
+			onenand_unlock(&onenand_mtd, start, start + ofs);
+
+			return 0;
+		}
+
+		if (strncmp(argv[1], "save", 4) == 0 &&
+		    strncmp(argv[2], "bootloader", 10) == 0) {
+			ulong addr = simple_strtoul(argv[3], NULL, 16);
+			struct erase_info instr;
+			int ofs = 0;
+			int len = 0x20000;
+			int retlen;
+
+			printf("save bootloader...\n");
+
+			if (!addr)
+				break;
+
+			onenand_unlock(&onenand_mtd, ofs, len);
+
+			instr.addr = 0 << onenand_chip.erase_shift;
+			instr.len = 1 << onenand_chip.erase_shift;
+			onenand_erase(&onenand_mtd, &instr);
+
+			onenand_write(&onenand_mtd, ofs, len, &retlen,
+				      (u_char *) addr);
+			onenand_unlock(&onenand_mtd, CFG_ENV_ADDR,
+				       onenand_mtd.size - CFG_ENV_ADDR);
+			return 0;
+		}
+
+		break;
+	}
+
+	return 0;
+}
+
+U_BOOT_CMD(onenand, 6, 1, do_onenand,
+	   "onenand - OneNAND sub-system\n",
+	   "info   - show available OneNAND devices\n"
+	   "onenand read[.oob] addr ofs len - read data at ofs with len to addr\n"
+	   "onenand write addr ofs len - write data at ofs with len from addr\n"
+	   "onenand erase block start-end - erase block from start to end\n"
+	   "onenand erase saddr eaddr - erase block start addr to end addr\n"
+	   "onenand block[.oob] addr block [page] [len] - "
+	   "read data with (block [, page]) to addr\n"
+	   "onenand unlock start-end - unlock block from start to end\n"
+	   "onenand save bootloader addr - save bootloader at addr\n");
+
+#endif				/* (CONFIG_COMMANDS & CFG_CMD_ONENAND) */
diff --git a/common/env_onenand.c b/common/env_onenand.c
new file mode 100644
index 0000000..9450a61
--- /dev/null
+++ b/common/env_onenand.c
@@ -0,0 +1,133 @@
+/*
+ * (C) Copyright 2005-2007 Samsung Electronics
+ * Kyungmin Park <kyungmin.park@samsung.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>
+
+#if defined(CFG_ENV_IS_IN_ONENAND)	/* Environment is in OneNAND */
+
+#include <command.h>
+#include <environment.h>
+#include <linux/stddef.h>
+#include <malloc.h>
+
+#include <linux/mtd/onenand.h>
+
+extern struct mtd_info onenand_mtd;
+extern struct onenand_chip onenand_chip;
+
+/* References to names in env_common.c */
+extern uchar default_environment[];
+
+#define ONENAND_ENV_SIZE(mtd)	(mtd.oobblock - ENV_HEADER_SIZE)
+
+char *env_name_spec = "OneNAND";
+
+#ifdef ENV_IS_EMBEDDED
+extern uchar environment[];
+env_t *env_ptr = (env_t *) (&environment[0]);
+#else				/* ! ENV_IS_EMBEDDED */
+static unsigned char onenand_env[MAX_ONENAND_PAGESIZE];
+env_t *env_ptr = (env_t *) onenand_env;
+#endif				/* ENV_IS_EMBEDDED */
+
+uchar env_get_char_spec(int index)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	return (*((uchar *) (gd->env_addr + index)));
+}
+
+void env_relocate_spec(void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+	unsigned long env_addr;
+	int use_default = 0;
+	int retlen;
+
+	env_addr = CFG_ENV_ADDR;
+	env_addr -= (unsigned long) onenand_chip.base;
+
+	/* Check OneNAND exist */
+	if (onenand_mtd.oobblock)
+		/* Ignore read fail */
+		onenand_read(&onenand_mtd, env_addr, onenand_mtd.oobblock,
+			     &retlen, (u_char *) env_ptr);
+	else
+		onenand_mtd.oobblock = MAX_ONENAND_PAGESIZE;
+
+	if (crc32(0, env_ptr->data, ONENAND_ENV_SIZE(onenand_mtd)) !=
+	    env_ptr->crc)
+		use_default = 1;
+
+	if (use_default) {
+		memcpy(env_ptr->data, default_environment,
+		       ONENAND_ENV_SIZE(onenand_mtd));
+		env_ptr->crc =
+		    crc32(0, env_ptr->data, ONENAND_ENV_SIZE(onenand_mtd));
+	}
+
+	gd->env_addr = (ulong) & env_ptr->data;
+	gd->env_valid = 1;
+}
+
+int saveenv(void)
+{
+	unsigned long env_addr = CFG_ENV_ADDR;
+	struct erase_info instr;
+	int retlen;
+
+	instr.len = CFG_ENV_SIZE;
+	instr.addr = env_addr;
+	instr.addr -= (unsigned long) onenand_chip.base;
+	if (onenand_erase(&onenand_mtd, &instr)) {
+		printf("OneNAND: erase failed at 0x%08x\n", env_addr);
+		return 1;
+	}
+
+	/* update crc */
+	env_ptr->crc =
+	    crc32(0, env_ptr->data, onenand_mtd.oobblock - ENV_HEADER_SIZE);
+
+	env_addr -= (unsigned long) onenand_chip.base;
+	if (onenand_write
+	    (&onenand_mtd, env_addr, onenand_mtd.oobblock, &retlen,
+	     (u_char *) env_ptr)) {
+		printf("OneNAND: write failed at 0x%08x\n", instr.addr);
+		return 2;
+	}
+
+	return 0;
+}
+
+int env_init(void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	/* use default */
+	gd->env_addr = (ulong) & default_environment[0];
+	gd->env_valid = 1;
+
+	return 0;
+}
+
+#endif				/* CFG_ENV_IS_IN_ONENAND */
diff --git a/drivers/onenand/Makefile b/drivers/onenand/Makefile
new file mode 100644
index 0000000..246ebc7
--- /dev/null
+++ b/drivers/onenand/Makefile
@@ -0,0 +1,42 @@
+#
+# Copyright (C) 2005-2007 Samsung Electronics. 
+# Kyungmin Park <kyungmin.park@samsung.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 $(TOPDIR)/config.mk
+
+LIB	= libonenand.a
+
+OBJS	= onenand_base.o onenand_bbt.o
+
+all:	$(LIB)
+
+$(LIB): $(OBJS)
+	$(AR) crv $@ $(OBJS)
+
+#########################################################################
+
+.depend:	Makefile $(OBJS:.o=.c)
+		$(CC) -M $(CFLAGS) $(OBJS:.o=.c) > $@
+
+sinclude .depend
+
+#########################################################################
