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