]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - common/cmd_onenand.c
Merge branch 'master' of git://git.denx.de/u-boot-ppc4xx
[karo-tx-uboot.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 #include <linux/mtd/compat.h>
16 #include <linux/mtd/mtd.h>
17 #include <linux/mtd/onenand.h>
18
19 #include <asm/io.h>
20
21 extern struct mtd_info onenand_mtd;
22 extern struct onenand_chip onenand_chip;
23
24 int do_onenand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
25 {
26         int ret = 0;
27
28         switch (argc) {
29         case 0:
30         case 1:
31                 printf("Usage:\n%s\n", cmdtp->usage);
32                 return 1;
33
34         case 2:
35                 if (strncmp(argv[1], "open", 4) == 0) {
36                         onenand_init();
37                         return 0;
38                 }
39                 printf("%s\n", onenand_mtd.name);
40                 return 0;
41
42         default:
43                 /* At least 4 args */
44                 if (strncmp(argv[1], "erase", 5) == 0) {
45                         struct erase_info instr = {
46                                 .callback       = NULL,
47                         };
48                         ulong start, end;
49                         ulong block;
50                         char *endtail;
51
52                         if (strncmp(argv[2], "block", 5) == 0) {
53                                 start = simple_strtoul(argv[3], NULL, 10);
54                                 endtail = strchr(argv[3], '-');
55                                 end = simple_strtoul(endtail + 1, NULL, 10);
56                         } else {
57                                 start = simple_strtoul(argv[2], NULL, 10);
58                                 end = simple_strtoul(argv[3], NULL, 10);
59
60                                 start >>= onenand_chip.erase_shift;
61                                 end >>= onenand_chip.erase_shift;
62                                 /* Don't include the end block */
63                                 end--;
64                         }
65
66                         if (!end || end < 0)
67                                 end = start;
68
69                         printf("Erase block from %lu to %lu\n", start, end);
70
71                         for (block = start; block <= end; block++) {
72                                 instr.addr = block << onenand_chip.erase_shift;
73                                 instr.len = 1 << onenand_chip.erase_shift;
74                                 ret = onenand_erase(&onenand_mtd, &instr);
75                                 if (ret) {
76                                         printf("erase failed %lu\n", block);
77                                         break;
78                                 }
79                         }
80
81                         return 0;
82                 }
83
84                 if (strncmp(argv[1], "read", 4) == 0) {
85                         ulong addr = simple_strtoul(argv[2], NULL, 16);
86                         ulong ofs = simple_strtoul(argv[3], NULL, 16);
87                         size_t len = simple_strtoul(argv[4], NULL, 16);
88                         int oob = strncmp(argv[1], "read.oob", 8) ? 0 : 1;
89                         struct mtd_oob_ops ops;
90
91                         ops.mode = MTD_OOB_PLACE;
92
93                         if (oob) {
94                                 ops.len = 0;
95                                 ops.datbuf = NULL;
96                                 ops.ooblen = len;
97                                 ops.oobbuf = (u_char *) addr;
98                         } else {
99                                 ops.len = len;
100                                 ops.datbuf = (u_char *) addr;
101                                 ops.ooblen = 0;
102                                 ops.oobbuf = NULL;
103                         }
104                         ops.retlen = ops.oobretlen = 0;
105
106                         onenand_mtd.read_oob(&onenand_mtd, ofs, &ops);
107                         printf("Done\n");
108
109                         return 0;
110                 }
111
112                 if (strncmp(argv[1], "write", 5) == 0) {
113                         ulong addr = simple_strtoul(argv[2], NULL, 16);
114                         ulong ofs = simple_strtoul(argv[3], NULL, 16);
115                         size_t len = simple_strtoul(argv[4], NULL, 16);
116                         size_t retlen = 0;
117
118                         onenand_write(&onenand_mtd, ofs, len, &retlen,
119                                       (u_char *) addr);
120                         printf("Done\n");
121
122                         return 0;
123                 }
124
125                 if (strncmp(argv[1], "block", 5) == 0) {
126                         ulong addr = simple_strtoul(argv[2], NULL, 16);
127                         ulong block = simple_strtoul(argv[3], NULL, 10);
128                         ulong page = simple_strtoul(argv[4], NULL, 10);
129                         size_t len = simple_strtol(argv[5], NULL, 10);
130                         ulong ofs;
131                         int oob = strncmp(argv[1], "block.oob", 9) ? 0 : 1;
132                         struct mtd_oob_ops ops;
133
134                         ops.mode = MTD_OOB_PLACE;
135
136
137                         ofs = block << onenand_chip.erase_shift;
138                         if (page)
139                                 ofs += page << onenand_chip.page_shift;
140
141                         if (!len) {
142                                 if (oob)
143                                         ops.ooblen = 64;
144                                 else
145                                         ops.len = 512;
146                         }
147
148                         if (oob) {
149                                 ops.datbuf = NULL;
150                                 ops.oobbuf = (u_char *) addr;
151                         } else {
152                                 ops.datbuf = (u_char *) addr;
153                                 ops.oobbuf = NULL;
154                         }
155                         ops.retlen = ops.oobretlen = 0;
156
157                         onenand_read_oob(&onenand_mtd, ofs, &ops);
158                         return 0;
159                 }
160
161                 break;
162         }
163
164         return 0;
165 }
166
167 U_BOOT_CMD(
168         onenand,        6,      1,      do_onenand,
169         "onenand - OneNAND sub-system\n",
170         "info   - show available OneNAND devices\n"
171         "onenand read[.oob] addr ofs len - read data at ofs with len to addr\n"
172         "onenand write addr ofs len - write data at ofs with len from addr\n"
173         "onenand erase saddr eaddr - erase block start addr to end addr\n"
174         "onenand block[.oob] addr block [page] [len] - "
175                 "read data with (block [, page]) to addr"
176 );