Merge branch 'master' of git://www.denx.de/git/u-boot-at91
[platform/kernel/u-boot.git] / common / cmd_onenand.c
1 /*
2  *  U-Boot command for OneNAND support
3  *
4  *  Copyright (C) 2005-2007 Samsung Electronics
5  *  Kyungmin Park <kyungmin.park@samsung.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  */
11
12 #include <common.h>
13 #include <command.h>
14
15 #ifdef CONFIG_CMD_ONENAND
16
17 #include <linux/mtd/compat.h>
18 #include <linux/mtd/mtd.h>
19 #include <linux/mtd/onenand.h>
20
21 #include <asm/io.h>
22
23 extern struct mtd_info onenand_mtd;
24 extern struct onenand_chip onenand_chip;
25
26 int do_onenand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
27 {
28         int ret = 0;
29
30         switch (argc) {
31         case 0:
32         case 1:
33                 printf("Usage:\n%s\n", cmdtp->usage);
34                 return 1;
35
36         case 2:
37                 if (strncmp(argv[1], "open", 4) == 0) {
38                         onenand_init();
39                         return 0;
40                 }
41                 printf("%s\n", onenand_mtd.name);
42                 return 0;
43
44         default:
45                 /* At least 4 args */
46                 if (strncmp(argv[1], "erase", 5) == 0) {
47                         struct erase_info instr = {
48                                 .callback       = NULL,
49                         };
50                         ulong start, end;
51                         ulong block;
52                         char *endtail;
53
54                         if (strncmp(argv[2], "block", 5) == 0) {
55                                 start = simple_strtoul(argv[3], NULL, 10);
56                                 endtail = strchr(argv[3], '-');
57                                 end = simple_strtoul(endtail + 1, NULL, 10);
58                         } else {
59                                 start = simple_strtoul(argv[2], NULL, 10);
60                                 end = simple_strtoul(argv[3], NULL, 10);
61
62                                 start >>= onenand_chip.erase_shift;
63                                 end >>= onenand_chip.erase_shift;
64                                 /* Don't include the end block */
65                                 end--;
66                         }
67
68                         if (!end || end < 0)
69                                 end = start;
70
71                         printf("Erase block from %lu to %lu\n", start, end);
72
73                         for (block = start; block <= end; block++) {
74                                 instr.addr = block << onenand_chip.erase_shift;
75                                 instr.len = 1 << onenand_chip.erase_shift;
76                                 ret = onenand_erase(&onenand_mtd, &instr);
77                                 if (ret) {
78                                         printf("erase failed %lu\n", block);
79                                         break;
80                                 }
81                         }
82
83                         return 0;
84                 }
85
86                 if (strncmp(argv[1], "read", 4) == 0) {
87                         ulong addr = simple_strtoul(argv[2], NULL, 16);
88                         ulong ofs = simple_strtoul(argv[3], NULL, 16);
89                         size_t len = simple_strtoul(argv[4], NULL, 16);
90                         size_t retlen = 0;
91                         int oob = strncmp(argv[1], "read.oob", 8) ? 0 : 1;
92
93                         if (oob)
94                                 onenand_read_oob(&onenand_mtd, ofs, len,
95                                                  &retlen, (u_char *) addr);
96                         else
97                                 onenand_read(&onenand_mtd, ofs, len, &retlen,
98                                              (u_char *) addr);
99                         printf("Done\n");
100
101                         return 0;
102                 }
103
104                 if (strncmp(argv[1], "write", 5) == 0) {
105                         ulong addr = simple_strtoul(argv[2], NULL, 16);
106                         ulong ofs = simple_strtoul(argv[3], NULL, 16);
107                         size_t len = simple_strtoul(argv[4], NULL, 16);
108                         size_t retlen = 0;
109
110                         onenand_write(&onenand_mtd, ofs, len, &retlen,
111                                       (u_char *) addr);
112                         printf("Done\n");
113
114                         return 0;
115                 }
116
117                 if (strncmp(argv[1], "block", 5) == 0) {
118                         ulong addr = simple_strtoul(argv[2], NULL, 16);
119                         ulong block = simple_strtoul(argv[3], NULL, 10);
120                         ulong page = simple_strtoul(argv[4], NULL, 10);
121                         size_t len = simple_strtol(argv[5], NULL, 10);
122                         size_t retlen = 0;
123                         ulong ofs;
124                         int oob = strncmp(argv[1], "block.oob", 9) ? 0 : 1;
125
126                         ofs = block << onenand_chip.erase_shift;
127                         if (page)
128                                 ofs += page << onenand_chip.page_shift;
129
130                         if (!len) {
131                                 if (oob)
132                                         len = 64;
133                                 else
134                                         len = 512;
135                         }
136
137                         if (oob)
138                                 onenand_read_oob(&onenand_mtd, ofs, len,
139                                                  &retlen, (u_char *) addr);
140                         else
141                                 onenand_read(&onenand_mtd, ofs, len, &retlen,
142                                              (u_char *) addr);
143                         return 0;
144                 }
145
146                 break;
147         }
148
149         return 0;
150 }
151
152 U_BOOT_CMD(
153         onenand,        6,      1,      do_onenand,
154         "onenand - OneNAND sub-system\n",
155         "info   - show available OneNAND devices\n"
156         "onenand read[.oob] addr ofs len - read data at ofs with len to addr\n"
157         "onenand write addr ofs len - write data at ofs with len from addr\n"
158         "onenand erase saddr eaddr - erase block start addr to end addr\n"
159         "onenand block[.oob] addr block [page] [len] - "
160                 "read data with (block [, page]) to addr"
161 );
162
163 #endif /* CONFIG_CMD_ONENAND */