]> git.karo-electronics.de Git - karo-tx-uboot.git/blob - common/cmd_flash.c
* Code cleanup:
[karo-tx-uboot.git] / common / cmd_flash.c
1 /*
2  * (C) Copyright 2000
3  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23
24 /*
25  * FLASH support
26  */
27 #include <common.h>
28 #include <command.h>
29
30
31 #ifdef CONFIG_HAS_DATAFLASH
32 #include <dataflash.h>
33 #endif
34
35 #if (CONFIG_COMMANDS & CFG_CMD_FLASH)
36
37 extern flash_info_t flash_info[];       /* info for FLASH chips */
38
39 /*
40  * The user interface starts numbering for Flash banks with 1
41  * for historical reasons.
42  */
43
44 /*
45  * this routine looks for an abbreviated flash range specification.
46  * the syntax is B:SF[-SL], where B is the bank number, SF is the first
47  * sector to erase, and SL is the last sector to erase (defaults to SF).
48  * bank numbers start at 1 to be consistent with other specs, sector numbers
49  * start at zero.
50  *
51  * returns:     1       - correct spec; *pinfo, *psf and *psl are
52  *                        set appropriately
53  *              0       - doesn't look like an abbreviated spec
54  *              -1      - looks like an abbreviated spec, but got
55  *                        a parsing error, a number out of range,
56  *                        or an invalid flash bank.
57  */
58 static int
59 abbrev_spec(char *str, flash_info_t **pinfo, int *psf, int *psl)
60 {
61     flash_info_t *fp;
62     int bank, first, last;
63     char *p, *ep;
64
65     if ((p = strchr(str, ':')) == NULL)
66         return 0;
67     *p++ = '\0';
68
69     bank = simple_strtoul(str, &ep, 10);
70     if (ep == str || *ep != '\0' ||
71       bank < 1 || bank > CFG_MAX_FLASH_BANKS ||
72       (fp = &flash_info[bank - 1])->flash_id == FLASH_UNKNOWN)
73         return -1;
74
75     str = p;
76     if ((p = strchr(str, '-')) != NULL)
77         *p++ = '\0';
78
79     first = simple_strtoul(str, &ep, 10);
80     if (ep == str || *ep != '\0' || first >= fp->sector_count)
81         return -1;
82
83     if (p != NULL) {
84         last = simple_strtoul(p, &ep, 10);
85         if (ep == p || *ep != '\0' ||
86           last < first || last >= fp->sector_count)
87             return -1;
88     }
89     else
90         last = first;
91
92     *pinfo = fp;
93     *psf = first;
94     *psl = last;
95
96     return 1;
97 }
98 int do_flinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
99 {
100         ulong bank;
101
102 #ifdef CONFIG_HAS_DATAFLASH
103         dataflash_print_info();
104 #endif
105
106         if (argc == 1) {        /* print info for all FLASH banks */
107                 for (bank=0; bank <CFG_MAX_FLASH_BANKS; ++bank) {
108                         printf ("\nBank # %ld: ", bank+1);
109
110                         flash_print_info (&flash_info[bank]);
111                 }
112                 return 0;
113         }
114
115         bank = simple_strtoul(argv[1], NULL, 16);
116         if ((bank < 1) || (bank > CFG_MAX_FLASH_BANKS)) {
117                 printf ("Only FLASH Banks # 1 ... # %d supported\n",
118                         CFG_MAX_FLASH_BANKS);
119                 return 1;
120         }
121         printf ("\nBank # %ld: ", bank);
122         flash_print_info (&flash_info[bank-1]);
123         return 0;
124 }
125 int do_flerase (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
126 {
127         flash_info_t *info;
128         ulong bank, addr_first, addr_last;
129         int n, sect_first, sect_last;
130         int rcode = 0;
131
132         if (argc < 2) {
133                 printf ("Usage:\n%s\n", cmdtp->usage);
134                 return 1;
135         }
136
137         if (strcmp(argv[1], "all") == 0) {
138                 for (bank=1; bank<=CFG_MAX_FLASH_BANKS; ++bank) {
139                         printf ("Erase Flash Bank # %ld ", bank);
140                         info = &flash_info[bank-1];
141                         rcode = flash_erase (info, 0, info->sector_count-1);
142                 }
143                 return rcode;
144         }
145
146         if ((n = abbrev_spec(argv[1], &info, &sect_first, &sect_last)) != 0) {
147                 if (n < 0) {
148                         printf("Bad sector specification\n");
149                         return 1;
150                 }
151                 printf ("Erase Flash Sectors %d-%d in Bank # %d ",
152                         sect_first, sect_last, (info-flash_info)+1);
153                 rcode = flash_erase(info, sect_first, sect_last);
154                 return rcode;
155         }
156
157         if (argc != 3) {
158                 printf ("Usage:\n%s\n", cmdtp->usage);
159                 return 1;
160         }
161
162         if (strcmp(argv[1], "bank") == 0) {
163                 bank = simple_strtoul(argv[2], NULL, 16);
164                 if ((bank < 1) || (bank > CFG_MAX_FLASH_BANKS)) {
165                         printf ("Only FLASH Banks # 1 ... # %d supported\n",
166                                 CFG_MAX_FLASH_BANKS);
167                         return 1;
168                 }
169                 printf ("Erase Flash Bank # %ld ", bank);
170                 info = &flash_info[bank-1];
171                 rcode = flash_erase (info, 0, info->sector_count-1);
172                 return rcode;
173         }
174
175         addr_first = simple_strtoul(argv[1], NULL, 16);
176         addr_last  = simple_strtoul(argv[2], NULL, 16);
177
178         if (addr_first >= addr_last) {
179                 printf ("Usage:\n%s\n", cmdtp->usage);
180                 return 1;
181         }
182
183         printf ("Erase Flash from 0x%08lx to 0x%08lx ", addr_first, addr_last);
184         rcode = flash_sect_erase(addr_first, addr_last);
185         return rcode;
186 }
187
188 int flash_sect_erase (ulong addr_first, ulong addr_last)
189 {
190         flash_info_t *info;
191         ulong bank;
192         int s_first, s_last;
193         int erased;
194         int rcode = 0;
195
196         erased = 0;
197
198         for (bank=0,info=&flash_info[0]; bank < CFG_MAX_FLASH_BANKS; ++bank, ++info) {
199                 ulong b_end;
200                 int sect;
201
202                 if (info->flash_id == FLASH_UNKNOWN) {
203                         continue;
204                 }
205
206                 b_end = info->start[0] + info->size - 1; /* bank end addr */
207
208                 s_first = -1;           /* first sector to erase        */
209                 s_last  = -1;           /* last  sector to erase        */
210
211                 for (sect=0; sect < info->sector_count; ++sect) {
212                         ulong end;              /* last address in current sect */
213                         short s_end;
214
215                         s_end = info->sector_count - 1;
216
217                         end = (sect == s_end) ? b_end : info->start[sect + 1] - 1;
218
219                         if (addr_first > end)
220                                 continue;
221                         if (addr_last < info->start[sect])
222                                 continue;
223
224                         if (addr_first == info->start[sect]) {
225                                 s_first = sect;
226                         }
227                         if (addr_last  == end) {
228                                 s_last  = sect;
229                         }
230                 }
231                 if (s_first>=0 && s_first<=s_last) {
232                         erased += s_last - s_first + 1;
233                         rcode = flash_erase (info, s_first, s_last);
234                 }
235         }
236         if (erased) {
237                 printf ("Erased %d sectors\n", erased);
238         } else {
239                 printf ("Error: start and/or end address"
240                         " not on sector boundary\n");
241                 rcode = 1;
242         }
243         return rcode;
244 }
245
246
247 int do_protect (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
248 {
249         flash_info_t *info;
250         ulong bank, addr_first, addr_last;
251         int i, p, n, sect_first, sect_last;
252         int rcode = 0;
253
254         if (argc < 3) {
255                 printf ("Usage:\n%s\n", cmdtp->usage);
256                 return 1;
257         }
258
259         if (strcmp(argv[1], "off") == 0)
260                 p = 0;
261         else if (strcmp(argv[1], "on") == 0)
262                 p = 1;
263         else {
264                 printf ("Usage:\n%s\n", cmdtp->usage);
265                 return 1;
266         }
267
268         if (strcmp(argv[2], "all") == 0) {
269                 for (bank=1; bank<=CFG_MAX_FLASH_BANKS; ++bank) {
270                         info = &flash_info[bank-1];
271                         if (info->flash_id == FLASH_UNKNOWN) {
272                                 continue;
273                         }
274                         printf ("%sProtect Flash Bank # %ld\n",
275                                 p ? "" : "Un-", bank);
276
277                         for (i=0; i<info->sector_count; ++i) {
278 #if defined(CFG_FLASH_PROTECTION)
279                                 if (flash_real_protect(info, i, p))
280                                         rcode = 1;
281                                 putc ('.');
282 #else
283                                 info->protect[i] = p;
284 #endif  /* CFG_FLASH_PROTECTION */
285                         }
286                 }
287
288 #if defined(CFG_FLASH_PROTECTION)
289                 if (!rcode) puts (" done\n");
290 #endif  /* CFG_FLASH_PROTECTION */
291
292                 return rcode;
293         }
294
295         if ((n = abbrev_spec(argv[2], &info, &sect_first, &sect_last)) != 0) {
296                 if (n < 0) {
297                         printf("Bad sector specification\n");
298                         return 1;
299                 }
300                 printf("%sProtect Flash Sectors %d-%d in Bank # %d\n",
301                         p ? "" : "Un-", sect_first, sect_last,
302                         (info-flash_info)+1);
303                 for (i = sect_first; i <= sect_last; i++) {
304 #if defined(CFG_FLASH_PROTECTION)
305                         if (flash_real_protect(info, i, p))
306                                 rcode =  1;
307                         putc ('.');
308 #else
309                         info->protect[i] = p;
310 #endif  /* CFG_FLASH_PROTECTION */
311                 }
312
313 #if defined(CFG_FLASH_PROTECTION)
314                 if (!rcode) puts (" done\n");
315 #endif  /* CFG_FLASH_PROTECTION */
316
317                 return rcode;
318         }
319
320         if (argc != 4) {
321                 printf ("Usage:\n%s\n", cmdtp->usage);
322                 return 1;
323         }
324
325         if (strcmp(argv[2], "bank") == 0) {
326                 bank = simple_strtoul(argv[3], NULL, 16);
327                 if ((bank < 1) || (bank > CFG_MAX_FLASH_BANKS)) {
328                         printf ("Only FLASH Banks # 1 ... # %d supported\n",
329                                 CFG_MAX_FLASH_BANKS);
330                         return 1;
331                 }
332                 printf ("%sProtect Flash Bank # %ld\n",
333                         p ? "" : "Un-", bank);
334                 info = &flash_info[bank-1];
335
336                 if (info->flash_id == FLASH_UNKNOWN) {
337                         printf ("missing or unknown FLASH type\n");
338                         return 1;
339                 }
340                 for (i=0; i<info->sector_count; ++i) {
341 #if defined(CFG_FLASH_PROTECTION)
342                         if (flash_real_protect(info, i, p))
343                                 rcode =  1;
344                         putc ('.');
345 #else
346                         info->protect[i] = p;
347 #endif  /* CFG_FLASH_PROTECTION */
348                 }
349
350 #if defined(CFG_FLASH_PROTECTION)
351                 if (!rcode) puts (" done\n");
352 #endif  /* CFG_FLASH_PROTECTION */
353
354                 return rcode;
355         }
356
357         addr_first = simple_strtoul(argv[2], NULL, 16);
358         addr_last  = simple_strtoul(argv[3], NULL, 16);
359
360         if (addr_first >= addr_last) {
361                 printf ("Usage:\n%s\n", cmdtp->usage);
362                 return 1;
363         }
364         rcode = flash_sect_protect (p, addr_first, addr_last);
365         return rcode;
366 }
367
368
369 int flash_sect_protect (int p, ulong addr_first, ulong addr_last)
370 {
371         flash_info_t *info;
372         ulong bank;
373         int s_first, s_last;
374         int protected, i;
375         int rcode = 0;
376
377         protected = 0;
378
379         for (bank=0,info=&flash_info[0]; bank < CFG_MAX_FLASH_BANKS; ++bank, ++info) {
380                 ulong b_end;
381                 int sect;
382
383                 if (info->flash_id == FLASH_UNKNOWN) {
384                         continue;
385                 }
386
387                 b_end = info->start[0] + info->size - 1; /* bank end addr */
388
389                 s_first = -1;           /* first sector to erase        */
390                 s_last  = -1;           /* last  sector to erase        */
391
392                 for (sect=0; sect < info->sector_count; ++sect) {
393                         ulong end;              /* last address in current sect */
394                         short s_end;
395
396                         s_end = info->sector_count - 1;
397
398                         end = (sect == s_end) ? b_end : info->start[sect + 1] - 1;
399
400                         if (addr_first > end)
401                                 continue;
402                         if (addr_last < info->start[sect])
403                                 continue;
404
405                         if (addr_first == info->start[sect]) {
406                                 s_first = sect;
407                         }
408                         if (addr_last  == end) {
409                                 s_last  = sect;
410                         }
411                 }
412                 if (s_first>=0 && s_first<=s_last) {
413                         protected += s_last - s_first + 1;
414                         for (i=s_first; i<=s_last; ++i) {
415 #if defined(CFG_FLASH_PROTECTION)
416                                 if (flash_real_protect(info, i, p))
417                                         rcode = 1;
418                                 putc ('.');
419 #else
420                                 info->protect[i] = p;
421 #endif  /* CFG_FLASH_PROTECTION */
422                         }
423                 }
424 #if defined(CFG_FLASH_PROTECTION)
425                 if (!rcode) putc ('\n');
426 #endif  /* CFG_FLASH_PROTECTION */
427
428         }
429         if (protected) {
430                 printf ("%sProtected %d sectors\n",
431                         p ? "" : "Un-", protected);
432         } else {
433                 printf ("Error: start and/or end address"
434                         " not on sector boundary\n");
435                 rcode = 1;
436         }
437         return rcode;
438 }
439
440
441 /**************************************************/
442
443 cmd_tbl_t U_BOOT_CMD(FLINFO) = MK_CMD_ENTRY(
444         "flinfo",    2,    1,    do_flinfo,
445         "flinfo  - print FLASH memory information\n",
446         "\n    - print information for all FLASH memory banks\n"
447         "flinfo N\n    - print information for FLASH memory bank # N\n"
448 );
449
450 cmd_tbl_t U_BOOT_CMD(ERASE) = MK_CMD_ENTRY(
451         "erase",   3,   1,  do_flerase,
452         "erase   - erase FLASH memory\n",
453         "start end\n"
454         "    - erase FLASH from addr 'start' to addr 'end'\n"
455         "erase N:SF[-SL]\n    - erase sectors SF-SL in FLASH bank # N\n"
456         "erase bank N\n    - erase FLASH bank # N\n"
457         "erase all\n    - erase all FLASH banks\n"
458 );
459
460 cmd_tbl_t U_BOOT_CMD(PROTECT) = MK_CMD_ENTRY(
461         "protect",  4,  1,   do_protect,
462         "protect - enable or disable FLASH write protection\n",
463         "on  start end\n"
464         "    - protect FLASH from addr 'start' to addr 'end'\n"
465         "protect on  N:SF[-SL]\n"
466         "    - protect sectors SF-SL in FLASH bank # N\n"
467         "protect on  bank N\n    - protect FLASH bank # N\n"
468         "protect on  all\n    - protect all FLASH banks\n"
469         "protect off start end\n"
470         "    - make FLASH from addr 'start' to addr 'end' writable\n"
471         "protect off N:SF[-SL]\n"
472         "    - make sectors SF-SL writable in FLASH bank # N\n"
473         "protect off bank N\n    - make FLASH bank # N writable\n"
474         "protect off all\n    - make all FLASH banks writable\n"
475 );
476
477 #endif  /* CFG_CMD_FLASH */