| /* | 
 |  *  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> | 
 |  | 
 | #ifdef CONFIG_CMD_ONENAND | 
 |  | 
 | #include <linux/mtd/compat.h> | 
 | #include <linux/mtd/mtd.h> | 
 | #include <linux/mtd/onenand.h> | 
 |  | 
 | #include <asm/io.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; | 
 | 			ulong block; | 
 |  | 
 | 			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; | 
 | 		} | 
 |  | 
 | 		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 saddr eaddr - erase block start addr to end addr\n" | 
 | 	"onenand block[.oob] addr block [page] [len] - " | 
 | 		"read data with (block [, page]) to addr" | 
 | ); | 
 |  | 
 | #endif /* CONFIG_CMD_ONENAND */ |