Re-factoring the legacy NAND code (legacy NAND now only in board-specific
[oweals/u-boot.git] / board / esd / common / auto_update.c
1 /*
2  * (C) Copyright 2003-2004
3  * Gary Jennejohn, DENX Software Engineering, gj@denx.de.
4  * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
5  *
6  * See file CREDITS for list of people who contributed to this
7  * project.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License as
11  * published by the Free Software Foundation; either version 2 of
12  * the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22  * MA 02111-1307 USA
23  */
24
25 #include <common.h>
26
27 #ifndef CFG_NAND_LEGACY
28 #error CFG_NAND_LEGACY not defined in a file using the legacy NAND support!
29 #endif
30
31 #include <command.h>
32 #include <image.h>
33 #include <asm/byteorder.h>
34 #include <linux/mtd/nand_legacy.h>
35 #include <fat.h>
36
37 #include "auto_update.h"
38
39 #ifdef CONFIG_AUTO_UPDATE
40
41 #if !(CONFIG_COMMANDS & CFG_CMD_FAT)
42 #error "must define CFG_CMD_FAT"
43 #endif
44
45
46
47
48 extern au_image_t au_image[];
49 extern int N_AU_IMAGES;
50
51 #define AU_DEBUG
52 #undef AU_DEBUG
53
54 #undef debug
55 #ifdef  AU_DEBUG
56 #define debug(fmt,args...)      printf (fmt ,##args)
57 #else
58 #define debug(fmt,args...)
59 #endif  /* AU_DEBUG */
60
61
62 #define LOAD_ADDR ((unsigned char *)0x100000)   /* where to load files into memory */
63 #define MAX_LOADSZ 0x1e00000
64
65 /* externals */
66 extern int fat_register_device(block_dev_desc_t *, int);
67 extern int file_fat_detectfs(void);
68 extern long file_fat_read(const char *, void *, unsigned long);
69 long do_fat_read (const char *filename, void *buffer, unsigned long maxsize, int dols);
70 #ifdef CONFIG_VFD
71 extern int trab_vfd (ulong);
72 extern int transfer_pic(unsigned char, unsigned char *, int, int);
73 #endif
74 extern int flash_sect_erase(ulong, ulong);
75 extern int flash_sect_protect (int, ulong, ulong);
76 extern int flash_write (char *, ulong, ulong);
77 /* change char* to void* to shutup the compiler */
78 extern block_dev_desc_t *get_dev (char*, int);
79
80 #if (CONFIG_COMMANDS & CFG_CMD_NAND)
81 /* references to names in cmd_nand.c */
82 #define NANDRW_READ     0x01
83 #define NANDRW_WRITE    0x00
84 #define NANDRW_JFFS2    0x02
85 #define NANDRW_JFFS2_SKIP       0x04
86 extern struct nand_chip nand_dev_desc[];
87 extern int nand_legacy_rw(struct nand_chip* nand, int cmd, size_t start, size_t len,
88                    size_t * retlen, u_char * buf);
89 extern int nand_legacy_erase(struct nand_chip* nand, size_t ofs, size_t len, int clean);
90 #endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) */
91
92 extern block_dev_desc_t ide_dev_desc[CFG_IDE_MAXDEVICE];
93
94
95 int au_check_cksum_valid(int i, long nbytes)
96 {
97         image_header_t *hdr;
98         unsigned long checksum;
99
100         hdr = (image_header_t *)LOAD_ADDR;
101
102         if ((au_image[i].type == AU_FIRMWARE) && (au_image[i].size != ntohl(hdr->ih_size))) {
103                 printf ("Image %s has wrong size\n", au_image[i].name);
104                 return -1;
105         }
106
107         if (nbytes != (sizeof(*hdr) + ntohl(hdr->ih_size))) {
108                 printf ("Image %s bad total SIZE\n", au_image[i].name);
109                 return -1;
110         }
111         /* check the data CRC */
112         checksum = ntohl(hdr->ih_dcrc);
113
114         if (crc32 (0, (uchar *)(LOAD_ADDR + sizeof(*hdr)), ntohl(hdr->ih_size))
115                 != checksum) {
116                 printf ("Image %s bad data checksum\n", au_image[i].name);
117                 return -1;
118         }
119         return 0;
120 }
121
122
123 int au_check_header_valid(int i, long nbytes)
124 {
125         image_header_t *hdr;
126         unsigned long checksum;
127
128         hdr = (image_header_t *)LOAD_ADDR;
129         /* check the easy ones first */
130 #undef CHECK_VALID_DEBUG
131 #ifdef CHECK_VALID_DEBUG
132         printf("magic %#x %#x ", ntohl(hdr->ih_magic), IH_MAGIC);
133         printf("arch %#x %#x ", hdr->ih_arch, IH_CPU_PPC);
134         printf("size %#x %#lx ", ntohl(hdr->ih_size), nbytes);
135         printf("type %#x %#x ", hdr->ih_type, IH_TYPE_KERNEL);
136 #endif
137         if (nbytes < sizeof(*hdr))
138         {
139                 printf ("Image %s bad header SIZE\n", au_image[i].name);
140                 return -1;
141         }
142         if (ntohl(hdr->ih_magic) != IH_MAGIC || hdr->ih_arch != IH_CPU_PPC)
143         {
144                 printf ("Image %s bad MAGIC or ARCH\n", au_image[i].name);
145                 return -1;
146         }
147         /* check the hdr CRC */
148         checksum = ntohl(hdr->ih_hcrc);
149         hdr->ih_hcrc = 0;
150
151         if (crc32 (0, (uchar *)hdr, sizeof(*hdr)) != checksum) {
152                 printf ("Image %s bad header checksum\n", au_image[i].name);
153                 return -1;
154         }
155         hdr->ih_hcrc = htonl(checksum);
156
157         /* check the type - could do this all in one gigantic if() */
158         if ((au_image[i].type == AU_FIRMWARE) && (hdr->ih_type != IH_TYPE_FIRMWARE)) {
159                 printf ("Image %s wrong type\n", au_image[i].name);
160                 return -1;
161         }
162         if ((au_image[i].type == AU_SCRIPT) && (hdr->ih_type != IH_TYPE_SCRIPT)) {
163                 printf ("Image %s wrong type\n", au_image[i].name);
164                 return -1;
165         }
166
167         /* recycle checksum */
168         checksum = ntohl(hdr->ih_size);
169
170 #if 0 /* test-only */
171         /* for kernel and app the image header must also fit into flash */
172         if (idx != IDX_DISK)
173                 checksum += sizeof(*hdr);
174         /* check the size does not exceed space in flash. HUSH scripts */
175         /* all have ausize[] set to 0 */
176         if ((ausize[idx] != 0) && (ausize[idx] < checksum)) {
177                 printf ("Image %s is bigger than FLASH\n", au_image[i].name);
178                 return -1;
179         }
180 #endif
181
182         return 0;
183 }
184
185
186 int au_do_update(int i, long sz)
187 {
188         image_header_t *hdr;
189         char *addr;
190         long start, end;
191         int off, rc;
192         uint nbytes;
193         int k;
194 #if (CONFIG_COMMANDS & CFG_CMD_NAND)
195         int total;
196 #endif
197
198         hdr = (image_header_t *)LOAD_ADDR;
199
200         switch (au_image[i].type) {
201         case AU_SCRIPT:
202                 printf("Executing script %s\n", au_image[i].name);
203
204                 /* execute a script */
205                 if (hdr->ih_type == IH_TYPE_SCRIPT) {
206                         addr = (char *)((char *)hdr + sizeof(*hdr));
207                         /* stick a NULL at the end of the script, otherwise */
208                         /* parse_string_outer() runs off the end. */
209                         addr[ntohl(hdr->ih_size)] = 0;
210                         addr += 8;
211
212                         /*
213                          * Replace cr/lf with ;
214                          */
215                         k = 0;
216                         while (addr[k] != 0) {
217                                 if ((addr[k] == 10) || (addr[k] == 13)) {
218                                         addr[k] = ';';
219                                 }
220                                 k++;
221                         }
222
223                         run_command(addr, 0);
224                         return 0;
225                 }
226
227                 break;
228
229         case AU_FIRMWARE:
230         case AU_NOR:
231         case AU_NAND:
232                 start = au_image[i].start;
233                 end = au_image[i].start + au_image[i].size - 1;
234
235                 /*
236                  * do not update firmware when image is already in flash.
237                  */
238                 if (au_image[i].type == AU_FIRMWARE) {
239                         char *orig = (char*)start;
240                         char *new  = (char *)((char *)hdr + sizeof(*hdr));
241                         nbytes = ntohl(hdr->ih_size);
242
243                         while(--nbytes) {
244                                 if (*orig++ != *new++) {
245                                         break;
246                                 }
247                         }
248                         if (!nbytes) {
249                                 printf("Skipping firmware update - images are identical\n");
250                                 break;
251                         }
252                 }
253
254                 /* unprotect the address range */
255                 /* this assumes that ONLY the firmware is protected! */
256                 if (au_image[i].type == AU_FIRMWARE) {
257                         flash_sect_protect(0, start, end);
258                 }
259
260                 /*
261                  * erase the address range.
262                  */
263                 if (au_image[i].type != AU_NAND) {
264                         printf("Updating NOR FLASH with image %s\n", au_image[i].name);
265                         debug ("flash_sect_erase(%lx, %lx);\n", start, end);
266                         flash_sect_erase(start, end);
267                 } else {
268 #if (CONFIG_COMMANDS & CFG_CMD_NAND)
269                         printf("Updating NAND FLASH with image %s\n", au_image[i].name);
270                         debug ("nand_legacy_erase(%lx, %lx);\n", start, end);
271                         rc = nand_legacy_erase (nand_dev_desc, start, end - start + 1, 0);
272                         debug ("nand_legacy_erase returned %x\n", rc);
273 #endif
274                 }
275
276                 udelay(10000);
277
278                 /* strip the header - except for the kernel and ramdisk */
279                 if (au_image[i].type != AU_FIRMWARE) {
280                         addr = (char *)hdr;
281                         off = sizeof(*hdr);
282                         nbytes = sizeof(*hdr) + ntohl(hdr->ih_size);
283                 } else {
284                         addr = (char *)((char *)hdr + sizeof(*hdr));
285                         off = 0;
286                         nbytes = ntohl(hdr->ih_size);
287                 }
288
289                 /*
290                  * copy the data from RAM to FLASH
291                  */
292                 if (au_image[i].type != AU_NAND) {
293                         debug ("flash_write(%p, %lx %x)\n", addr, start, nbytes);
294                         rc = flash_write((char *)addr, start, nbytes);
295                 } else {
296 #if (CONFIG_COMMANDS & CFG_CMD_NAND)
297                         debug ("nand_legacy_rw(%p, %lx %x)\n", addr, start, nbytes);
298                         rc = nand_legacy_rw(nand_dev_desc, NANDRW_WRITE | NANDRW_JFFS2,
299                                      start, nbytes, (size_t *)&total, (uchar *)addr);
300                         debug ("nand_legacy_rw: ret=%x total=%d nbytes=%d\n", rc, total, nbytes);
301 #endif
302                 }
303                 if (rc != 0) {
304                         printf("Flashing failed due to error %d\n", rc);
305                         return -1;
306                 }
307
308                 /*
309                  * check the dcrc of the copy
310                  */
311                 if (au_image[i].type != AU_NAND) {
312                         rc = crc32 (0, (uchar *)(start + off), ntohl(hdr->ih_size));
313                 } else {
314 #if (CONFIG_COMMANDS & CFG_CMD_NAND)
315                         rc = nand_legacy_rw(nand_dev_desc, NANDRW_READ | NANDRW_JFFS2 | NANDRW_JFFS2_SKIP,
316                                      start, nbytes, (size_t *)&total, (uchar *)addr);
317                         rc = crc32 (0, (uchar *)(addr + off), ntohl(hdr->ih_size));
318 #endif
319                 }
320                 if (rc != ntohl(hdr->ih_dcrc)) {
321                         printf ("Image %s Bad Data Checksum After COPY\n", au_image[i].name);
322                         return -1;
323                 }
324
325                 /* protect the address range */
326                 /* this assumes that ONLY the firmware is protected! */
327                 if (au_image[i].type == AU_FIRMWARE) {
328                         flash_sect_protect(1, start, end);
329                 }
330
331                 break;
332
333         default:
334                 printf("Wrong image type selected!\n");
335         }
336
337         return 0;
338 }
339
340
341 static void process_macros (const char *input, char *output)
342 {
343         char c, prev;
344         const char *varname_start = NULL;
345         int inputcnt  = strlen (input);
346         int outputcnt = CFG_CBSIZE;
347         int state = 0;  /* 0 = waiting for '$'  */
348                         /* 1 = waiting for '(' or '{' */
349                         /* 2 = waiting for ')' or '}' */
350                         /* 3 = waiting for '''  */
351 #ifdef DEBUG_PARSER
352         char *output_start = output;
353
354         printf ("[PROCESS_MACROS] INPUT len %d: \"%s\"\n", strlen(input), input);
355 #endif
356
357         prev = '\0';                    /* previous character   */
358
359         while (inputcnt && outputcnt) {
360             c = *input++;
361             inputcnt--;
362
363             if (state!=3) {
364             /* remove one level of escape characters */
365             if ((c == '\\') && (prev != '\\')) {
366                 if (inputcnt-- == 0)
367                         break;
368                 prev = c;
369                 c = *input++;
370             }
371             }
372
373             switch (state) {
374             case 0:                     /* Waiting for (unescaped) $    */
375                 if ((c == '\'') && (prev != '\\')) {
376                         state = 3;
377                         break;
378                 }
379                 if ((c == '$') && (prev != '\\')) {
380                         state++;
381                 } else {
382                         *(output++) = c;
383                         outputcnt--;
384                 }
385                 break;
386             case 1:                     /* Waiting for (        */
387                 if (c == '(' || c == '{') {
388                         state++;
389                         varname_start = input;
390                 } else {
391                         state = 0;
392                         *(output++) = '$';
393                         outputcnt--;
394
395                         if (outputcnt) {
396                                 *(output++) = c;
397                                 outputcnt--;
398                         }
399                 }
400                 break;
401             case 2:                     /* Waiting for )        */
402                 if (c == ')' || c == '}') {
403                         int i;
404                         char envname[CFG_CBSIZE], *envval;
405                         int envcnt = input-varname_start-1; /* Varname # of chars */
406
407                         /* Get the varname */
408                         for (i = 0; i < envcnt; i++) {
409                                 envname[i] = varname_start[i];
410                         }
411                         envname[i] = 0;
412
413                         /* Get its value */
414                         envval = getenv (envname);
415
416                         /* Copy into the line if it exists */
417                         if (envval != NULL)
418                                 while ((*envval) && outputcnt) {
419                                         *(output++) = *(envval++);
420                                         outputcnt--;
421                                 }
422                         /* Look for another '$' */
423                         state = 0;
424                 }
425                 break;
426             case 3:                     /* Waiting for '        */
427                 if ((c == '\'') && (prev != '\\')) {
428                         state = 0;
429                 } else {
430                         *(output++) = c;
431                         outputcnt--;
432                 }
433                 break;
434             }
435             prev = c;
436         }
437
438         if (outputcnt)
439                 *output = 0;
440
441 #ifdef DEBUG_PARSER
442         printf ("[PROCESS_MACROS] OUTPUT len %d: \"%s\"\n",
443                 strlen(output_start), output_start);
444 #endif
445 }
446
447
448 /*
449  * this is called from board_init() after the hardware has been set up
450  * and is usable. That seems like a good time to do this.
451  * Right now the return value is ignored.
452  */
453 int do_auto_update(void)
454 {
455         block_dev_desc_t *stor_dev;
456         long sz;
457         int i, res, cnt, old_ctrlc, got_ctrlc;
458         char buffer[32];
459         char str[80];
460
461         /*
462          * Check whether a CompactFlash is inserted
463          */
464         if (ide_dev_desc[0].type == DEV_TYPE_UNKNOWN) {
465                 return -1;       /* no disk detected! */
466         }
467
468         /* check whether it has a partition table */
469         stor_dev = get_dev("ide", 0);
470         if (stor_dev == NULL) {
471                 debug ("Uknown device type\n");
472                 return -1;
473         }
474         if (fat_register_device(stor_dev, 1) != 0) {
475                 debug ("Unable to register ide disk 0:1 for fatls\n");
476                 return -1;
477         }
478
479         /*
480          * Check if magic file is present
481          */
482         if (do_fat_read(AU_MAGIC_FILE, buffer, sizeof(buffer), LS_NO) <= 0) {
483                 return -1;
484         }
485
486 #ifdef CONFIG_AUTO_UPDATE_SHOW
487         board_auto_update_show(1);
488 #endif
489         puts("\nAutoUpdate Disk detected! Trying to update system...\n");
490
491         /* make sure that we see CTRL-C and save the old state */
492         old_ctrlc = disable_ctrlc(0);
493
494         /* just loop thru all the possible files */
495         for (i = 0; i < N_AU_IMAGES; i++) {
496                 /*
497                  * Try to expand the environment var in the fname
498                  */
499                 process_macros(au_image[i].name, str);
500                 strcpy(au_image[i].name, str);
501
502                 printf("Reading %s ...", au_image[i].name);
503                 /* just read the header */
504                 sz = do_fat_read(au_image[i].name, LOAD_ADDR, sizeof(image_header_t), LS_NO);
505                 debug ("read %s sz %ld hdr %d\n",
506                         au_image[i].name, sz, sizeof(image_header_t));
507                 if (sz <= 0 || sz < sizeof(image_header_t)) {
508                         puts(" not found\n");
509                         continue;
510                 }
511                 if (au_check_header_valid(i, sz) < 0) {
512                         puts(" header not valid\n");
513                         continue;
514                 }
515                 sz = do_fat_read(au_image[i].name, LOAD_ADDR, MAX_LOADSZ, LS_NO);
516                 debug ("read %s sz %ld hdr %d\n",
517                         au_image[i].name, sz, sizeof(image_header_t));
518                 if (sz <= 0 || sz <= sizeof(image_header_t)) {
519                         puts(" not found\n");
520                         continue;
521                 }
522                 if (au_check_cksum_valid(i, sz) < 0) {
523                         puts(" checksum not valid\n");
524                         continue;
525                 }
526                 puts(" done\n");
527
528                 do {
529                         res = au_do_update(i, sz);
530                         /* let the user break out of the loop */
531                         if (ctrlc() || had_ctrlc()) {
532                                 clear_ctrlc();
533                                 if (res < 0)
534                                         got_ctrlc = 1;
535                                 break;
536                         }
537                         cnt++;
538                 } while (res < 0);
539         }
540
541         /* restore the old state */
542         disable_ctrlc(old_ctrlc);
543
544         puts("AutoUpdate finished\n\n");
545 #ifdef CONFIG_AUTO_UPDATE_SHOW
546         board_auto_update_show(0);
547 #endif
548
549         return 0;
550 }
551
552
553 int auto_update(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
554 {
555         do_auto_update();
556
557         return 0;
558 }
559 U_BOOT_CMD(
560         autoupd,        1,      1,      auto_update,
561         "autoupd - Automatically update images\n",
562         NULL
563 );
564 #endif /* CONFIG_AUTO_UPDATE */