Merge branch 'master' of /home/wd/git/u-boot/master
[platform/kernel/u-boot.git] / tools / updater / 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 #include <flash.h>
30
31 #if defined(CONFIG_CMD_FLASH)
32
33 extern flash_info_t flash_info[];       /* info for FLASH chips */
34
35 /*
36  * The user interface starts numbering for Flash banks with 1
37  * for historical reasons.
38  */
39
40 /*
41  * this routine looks for an abbreviated flash range specification.
42  * the syntax is B:SF[-SL], where B is the bank number, SF is the first
43  * sector to erase, and SL is the last sector to erase (defaults to SF).
44  * bank numbers start at 1 to be consistent with other specs, sector numbers
45  * start at zero.
46  *
47  * returns:     1       - correct spec; *pinfo, *psf and *psl are
48  *                        set appropriately
49  *              0       - doesn't look like an abbreviated spec
50  *              -1      - looks like an abbreviated spec, but got
51  *                        a parsing error, a number out of range,
52  *                        or an invalid flash bank.
53  */
54 static int
55 abbrev_spec(char *str, flash_info_t **pinfo, int *psf, int *psl)
56 {
57     flash_info_t *fp;
58     int bank, first, last;
59     char *p, *ep;
60
61     if ((p = strchr(str, ':')) == NULL)
62         return 0;
63     *p++ = '\0';
64
65     bank = simple_strtoul(str, &ep, 10);
66     if (ep == str || *ep != '\0' ||
67       bank < 1 || bank > CONFIG_SYS_MAX_FLASH_BANKS ||
68       (fp = &flash_info[bank - 1])->flash_id == FLASH_UNKNOWN)
69         return -1;
70
71     str = p;
72     if ((p = strchr(str, '-')) != NULL)
73         *p++ = '\0';
74
75     first = simple_strtoul(str, &ep, 10);
76     if (ep == str || *ep != '\0' || first >= fp->sector_count)
77         return -1;
78
79     if (p != NULL) {
80         last = simple_strtoul(p, &ep, 10);
81         if (ep == p || *ep != '\0' ||
82           last < first || last >= fp->sector_count)
83             return -1;
84     }
85     else
86         last = first;
87
88     *pinfo = fp;
89     *psf = first;
90     *psl = last;
91
92     return 1;
93 }
94 int do_flinfo (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
95 {
96         ulong bank;
97
98         if (argc == 1) {        /* print info for all FLASH banks */
99                 for (bank=0; bank <CONFIG_SYS_MAX_FLASH_BANKS; ++bank) {
100                         printf ("\nBank # %ld: ", bank+1);
101
102                         flash_print_info (&flash_info[bank]);
103                 }
104                 return 0;
105         }
106
107         bank = simple_strtoul(argv[1], NULL, 16);
108         if ((bank < 1) || (bank > CONFIG_SYS_MAX_FLASH_BANKS)) {
109                 printf ("Only FLASH Banks # 1 ... # %d supported\n",
110                         CONFIG_SYS_MAX_FLASH_BANKS);
111                 return 1;
112         }
113         printf ("\nBank # %ld: ", bank);
114         flash_print_info (&flash_info[bank-1]);
115         return 0;
116 }
117 int do_flerase(cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
118 {
119         flash_info_t *info;
120         ulong bank, addr_first, addr_last;
121         int n, sect_first, sect_last;
122         int rcode = 0;
123
124         if (argc < 2)
125                 return cmd_usage(cmdtp);
126
127         if (strcmp(argv[1], "all") == 0) {
128                 for (bank=1; bank<=CONFIG_SYS_MAX_FLASH_BANKS; ++bank) {
129                         printf ("Erase Flash Bank # %ld ", bank);
130                         info = &flash_info[bank-1];
131                         rcode = flash_erase (info, 0, info->sector_count-1);
132                 }
133                 return rcode;
134         }
135
136         if ((n = abbrev_spec(argv[1], &info, &sect_first, &sect_last)) != 0) {
137                 if (n < 0) {
138                         printf("Bad sector specification\n");
139                         return 1;
140                 }
141                 printf ("Erase Flash Sectors %d-%d in Bank # %d ",
142                         sect_first, sect_last, (info-flash_info)+1);
143                 rcode = flash_erase(info, sect_first, sect_last);
144                 return rcode;
145         }
146
147         if (argc != 3)
148                 return cmd_usage(cmdtp);
149
150         if (strcmp(argv[1], "bank") == 0) {
151                 bank = simple_strtoul(argv[2], NULL, 16);
152                 if ((bank < 1) || (bank > CONFIG_SYS_MAX_FLASH_BANKS)) {
153                         printf ("Only FLASH Banks # 1 ... # %d supported\n",
154                                 CONFIG_SYS_MAX_FLASH_BANKS);
155                         return 1;
156                 }
157                 printf ("Erase Flash Bank # %ld ", bank);
158                 info = &flash_info[bank-1];
159                 rcode = flash_erase (info, 0, info->sector_count-1);
160                 return rcode;
161         }
162
163         addr_first = simple_strtoul(argv[1], NULL, 16);
164         addr_last  = simple_strtoul(argv[2], NULL, 16);
165
166         if (addr_first >= addr_last)
167                 return cmd_usage(cmdtp);
168
169         printf ("Erase Flash from 0x%08lx to 0x%08lx ", addr_first, addr_last);
170         rcode = flash_sect_erase(addr_first, addr_last);
171         return rcode;
172 }
173
174 int flash_sect_erase (ulong addr_first, ulong addr_last)
175 {
176         flash_info_t *info;
177         ulong bank;
178         int s_first, s_last;
179         int erased;
180         int rcode = 0;
181
182         erased = 0;
183
184         for (bank=0,info = &flash_info[0]; bank < CONFIG_SYS_MAX_FLASH_BANKS; ++bank, ++info) {
185                 ulong b_end;
186                 int sect;
187
188                 if (info->flash_id == FLASH_UNKNOWN) {
189                         continue;
190                 }
191
192                 b_end = info->start[0] + info->size - 1; /* bank end addr */
193
194                 s_first = -1;           /* first sector to erase        */
195                 s_last  = -1;           /* last  sector to erase        */
196
197                 for (sect=0; sect < info->sector_count; ++sect) {
198                         ulong end;              /* last address in current sect */
199                         short s_end;
200
201                         s_end = info->sector_count - 1;
202
203                         end = (sect == s_end) ? b_end : info->start[sect + 1] - 1;
204
205                         if (addr_first > end)
206                                 continue;
207                         if (addr_last < info->start[sect])
208                                 continue;
209
210                         if (addr_first == info->start[sect]) {
211                                 s_first = sect;
212                         }
213                         if (addr_last  == end) {
214                                 s_last  = sect;
215                         }
216                 }
217                 if (s_first>=0 && s_first<=s_last) {
218                         erased += s_last - s_first + 1;
219                         rcode = flash_erase (info, s_first, s_last);
220                 }
221         }
222         if (erased) {
223             /*  printf ("Erased %d sectors\n", erased); */
224         } else {
225                 printf ("Error: start and/or end address"
226                         " not on sector boundary\n");
227                 rcode = 1;
228         }
229         return rcode;
230 }
231
232
233 int do_protect(cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
234 {
235         flash_info_t *info;
236         ulong bank, addr_first, addr_last;
237         int i, p, n, sect_first, sect_last;
238         int rcode = 0;
239
240         if (argc < 3)
241                 return cmd_usage(cmdtp);
242
243         if (strcmp(argv[1], "off") == 0)
244                 p = 0;
245         else if (strcmp(argv[1], "on") == 0)
246                 p = 1;
247         else
248                 return cmd_usage(cmdtp);
249
250         if (strcmp(argv[2], "all") == 0) {
251                 for (bank=1; bank<=CONFIG_SYS_MAX_FLASH_BANKS; ++bank) {
252                         info = &flash_info[bank-1];
253                         if (info->flash_id == FLASH_UNKNOWN) {
254                                 continue;
255                         }
256                         /*printf ("%sProtect Flash Bank # %ld\n", */
257                         /*      p ? "" : "Un-", bank); */
258
259                         for (i=0; i<info->sector_count; ++i) {
260 #if defined(CONFIG_SYS_FLASH_PROTECTION)
261                                 if (flash_real_protect(info, i, p))
262                                         rcode = 1;
263                                 putc ('.');
264 #else
265                                 info->protect[i] = p;
266 #endif  /* CONFIG_SYS_FLASH_PROTECTION */
267                         }
268                 }
269
270 #if defined(CONFIG_SYS_FLASH_PROTECTION)
271                 if (!rcode) puts (" done\n");
272 #endif  /* CONFIG_SYS_FLASH_PROTECTION */
273
274                 return rcode;
275         }
276
277         if ((n = abbrev_spec(argv[2], &info, &sect_first, &sect_last)) != 0) {
278                 if (n < 0) {
279                         printf("Bad sector specification\n");
280                         return 1;
281                 }
282                 /*printf("%sProtect Flash Sectors %d-%d in Bank # %d\n", */
283                 /*      p ? "" : "Un-", sect_first, sect_last, */
284                 /*      (info-flash_info)+1); */
285                 for (i = sect_first; i <= sect_last; i++) {
286 #if defined(CONFIG_SYS_FLASH_PROTECTION)
287                         if (flash_real_protect(info, i, p))
288                                 rcode =  1;
289                         putc ('.');
290 #else
291                         info->protect[i] = p;
292 #endif  /* CONFIG_SYS_FLASH_PROTECTION */
293                 }
294
295 #if defined(CONFIG_SYS_FLASH_PROTECTION)
296                 if (!rcode) puts (" done\n");
297 #endif  /* CONFIG_SYS_FLASH_PROTECTION */
298
299                 return rcode;
300         }
301
302         if (argc != 4)
303                 return cmd_usage(cmdtp);
304
305         if (strcmp(argv[2], "bank") == 0) {
306                 bank = simple_strtoul(argv[3], NULL, 16);
307                 if ((bank < 1) || (bank > CONFIG_SYS_MAX_FLASH_BANKS)) {
308                         printf ("Only FLASH Banks # 1 ... # %d supported\n",
309                                 CONFIG_SYS_MAX_FLASH_BANKS);
310                         return 1;
311                 }
312                 printf ("%sProtect Flash Bank # %ld\n",
313                         p ? "" : "Un-", bank);
314                 info = &flash_info[bank-1];
315
316                 if (info->flash_id == FLASH_UNKNOWN) {
317                         printf ("missing or unknown FLASH type\n");
318                         return 1;
319                 }
320                 for (i=0; i<info->sector_count; ++i) {
321 #if defined(CONFIG_SYS_FLASH_PROTECTION)
322                         if (flash_real_protect(info, i, p))
323                                 rcode =  1;
324                         putc ('.');
325 #else
326                         info->protect[i] = p;
327 #endif  /* CONFIG_SYS_FLASH_PROTECTION */
328                 }
329
330 #if defined(CONFIG_SYS_FLASH_PROTECTION)
331                 if (!rcode)
332                         puts(" done\n");
333 #endif  /* CONFIG_SYS_FLASH_PROTECTION */
334
335                 return rcode;
336         }
337
338         addr_first = simple_strtoul(argv[2], NULL, 16);
339         addr_last  = simple_strtoul(argv[3], NULL, 16);
340
341         if (addr_first >= addr_last)
342                 return cmd_usage(cmdtp);
343
344         return flash_sect_protect (p, addr_first, addr_last);
345 }
346 int flash_sect_protect (int p, ulong addr_first, ulong addr_last)
347 {
348         flash_info_t *info;
349         ulong bank;
350         int s_first, s_last;
351         int protected, i;
352         int rcode = 0;
353
354         protected = 0;
355
356         for (bank=0,info = &flash_info[0]; bank < CONFIG_SYS_MAX_FLASH_BANKS; ++bank, ++info) {
357                 ulong b_end;
358                 int sect;
359
360                 if (info->flash_id == FLASH_UNKNOWN) {
361                         continue;
362                 }
363
364                 b_end = info->start[0] + info->size - 1; /* bank end addr */
365
366                 s_first = -1;           /* first sector to erase        */
367                 s_last  = -1;           /* last  sector to erase        */
368
369                 for (sect=0; sect < info->sector_count; ++sect) {
370                         ulong end;              /* last address in current sect */
371                         short s_end;
372
373                         s_end = info->sector_count - 1;
374
375                         end = (sect == s_end) ? b_end : info->start[sect + 1] - 1;
376
377                         if (addr_first > end)
378                                 continue;
379                         if (addr_last < info->start[sect])
380                                 continue;
381
382                         if (addr_first == info->start[sect]) {
383                                 s_first = sect;
384                         }
385                         if (addr_last  == end) {
386                                 s_last  = sect;
387                         }
388                 }
389                 if (s_first>=0 && s_first<=s_last) {
390                         protected += s_last - s_first + 1;
391                         for (i=s_first; i<=s_last; ++i) {
392 #if defined(CONFIG_SYS_FLASH_PROTECTION)
393                                 if (flash_real_protect(info, i, p))
394                                         rcode = 1;
395                                 putc ('.');
396 #else
397                                 info->protect[i] = p;
398 #endif  /* CONFIG_SYS_FLASH_PROTECTION */
399                         }
400                 }
401 #if defined(CONFIG_SYS_FLASH_PROTECTION)
402                 if (!rcode) putc ('\n');
403 #endif  /* CONFIG_SYS_FLASH_PROTECTION */
404
405         }
406         if (protected) {
407             /*  printf ("%sProtected %d sectors\n", */
408             /*  p ? "" : "Un-", protected); */
409         } else {
410             printf ("Error: start and/or end address"
411                         " not on sector boundary\n");
412                 rcode = 1;
413         }
414         return rcode;
415 }
416
417 #endif