[U-Boot-Users] [PATCH 1/5] OneNAND support

Kyungmin Park kmpark at infradead.org
Fri Sep 7 02:57:23 CEST 2007


[PATCH] OneNAND support

This patch enables the OneNAND at U-boot

Signed-off-by: Kyungmin Park <kyungmin.park at samsung.com>
---
diff --git a/Makefile b/Makefile
index 0477cd3..d42f2ef 100644
--- a/Makefile
+++ b/Makefile
@@ -211,6 +211,7 @@ LIBS += drivers/libdrivers.a
 LIBS += drivers/bios_emulator/libatibiosemu.a
 LIBS += drivers/nand/libnand.a
 LIBS += drivers/nand_legacy/libnand_legacy.a
+LIBS += drivers/onenand/libonenand.a
 LIBS += drivers/net/libnet.a
 ifeq ($(CPU),mpc83xx)
 LIBS += drivers/qe/qe.a
diff --git a/common/Makefile b/common/Makefile
index ef7d097..fde5ad9 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_sata.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 \
 	  fdt_support.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 1db0fc3..6770408 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
@@ -553,7 +554,8 @@ int getenv_r (char *name, char *buf, unsigned len)
 
 #if defined(CFG_ENV_IS_IN_NVRAM) || defined(CFG_ENV_IS_IN_EEPROM) \
     || (defined(CONFIG_CMD_ENV) && defined(CONFIG_CMD_FLASH)) \
-    || (defined(CONFIG_CMD_ENV) && defined(CONFIG_CMD_NAND))
+    || (defined(CONFIG_CMD_ENV) && defined(CONFIG_CMD_NAND)) \
+    || (defined(CONFIG_CMD_ENV) && defined(CONFIG_CMD_ONENAND))
 int do_saveenv (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
 {
 	extern char * env_name_spec;
@@ -608,7 +610,8 @@ U_BOOT_CMD(
 
 #if defined(CFG_ENV_IS_IN_NVRAM) || defined(CFG_ENV_IS_IN_EEPROM) \
     || (defined(CONFIG_CMD_ENV) && defined(CONFIG_CMD_FLASH)) \
-    || (defined(CONFIG_CMD_ENV) && defined(CONFIG_CMD_NAND))
+    || (defined(CONFIG_CMD_ENV) && defined(CONFIG_CMD_NAND)) \
+    || (defined(CONFIG_CMD_ENV) && defined(CONFIG_CMD_ONENAND))
 U_BOOT_CMD(
 	saveenv, 1, 0,	do_saveenv,
 	"saveenv - save environment variables to persistent storage\n",
diff --git a/common/cmd_onenand.c b/common/cmd_onenand.c
new file mode 100644
index 0000000..257a614
--- /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 at 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..2597d1e
--- /dev/null
+++ b/common/env_onenand.c
@@ -0,0 +1,133 @@
+/*
+ * (C) Copyright 2005-2007 Samsung Electronics
+ * Kyungmin Park <kyungmin.park at 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 */




More information about the U-Boot mailing list