| /* |
| * 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 */ |