usbd: add download mode
[kernel/u-boot.git] / common / cmd_usbd.c
1 /*
2  * USB Downloader for SAMSUNG Platform
3  *
4  * Copyright (C) 2007-2008 Samsung Electronics
5  * Minkyu Kang <mk7.kang@samsung.com>
6  *
7  */
8
9 #include <common.h>
10 #include <usbd.h>
11 #include <asm/errno.h>
12 #include <malloc.h>
13
14 /* version of USB Downloader Application */
15 #define APP_VERSION     "1.3.5"
16
17 #ifdef CONFIG_CMD_MTDPARTS
18 #include <jffs2/load_kernel.h>
19 static struct part_info *parts[8];
20 #endif
21
22 static const char pszMe[] = "usbd: ";
23
24 static struct usbd_ops usbd_ops;
25
26 static unsigned int part_id = BOOT_PART_ID;
27 static unsigned int write_part = 0;
28 static unsigned long fs_offset = 0x0;
29
30 #ifdef CONFIG_USE_YAFFS
31 static unsigned int yaffs_len = 0;
32 static unsigned char yaffs_data[2112];
33 #define YAFFS_PAGE 2112
34 #endif
35
36 #define NAND_PAGE_SIZE 2048
37
38 static unsigned long down_ram_addr;
39
40 static int down_mode;
41
42 /* cpu/${CPU} dependent */
43 extern void do_reset(void);
44
45 /* common commands */
46 extern int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
47 extern int do_run(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]);
48
49 int mtdparts_init(void);
50 int find_dev_and_part(const char*, struct mtd_device**, u8*, struct part_info**);
51
52 /* common/cmd_jffs2.c */
53 extern struct list_head devices;
54
55 static u8 count_mtdparts(void)
56 {
57         struct list_head *dentry, *pentry;
58         struct mtd_device *dev;
59         u8 part_num = 0;
60
61         list_for_each(dentry, &devices) {
62                 dev = list_entry(dentry, struct mtd_device, link);
63
64                 /* list partitions for given device */
65                 list_for_each(pentry, &dev->parts)
66                         part_num++;
67         }
68
69         return part_num;
70 }
71
72 #ifdef CONFIG_CMD_UBI
73 static int check_ubi_mode(void)
74 {
75         char *env_ubifs;
76         int ubi_mode;
77
78         env_ubifs = getenv("ubi");
79         ubi_mode = !strcmp(env_ubifs, "enabled");
80
81         return ubi_mode;
82 }
83 #else
84 #define check_ubi_mode()                0
85 #endif
86
87 #ifdef CONFIG_MTD_PARTITIONS
88 static int get_part_info(void)
89 {
90         struct mtd_device *dev;
91         u8 out_partnum;
92         char part_name[12];
93         char nand_name[12];
94         int i;
95         int part_num;
96         int ubi_mode = 0;
97
98 #if defined(CONFIG_CMD_NAND)
99         sprintf(nand_name, "nand0");
100 #elif defined(CONFIG_CMD_ONENAND)
101         sprintf(nand_name, "onenand0");
102 #else
103         printf("Configure your NAND sub-system\n");
104         return 0;
105 #endif
106
107         if (mtdparts_init())
108                 return 0;
109
110         ubi_mode = check_ubi_mode();
111
112         part_num = count_mtdparts();
113         for (i = 0; i < part_num; i++) {
114                 sprintf(part_name, "%s,%d", nand_name, i);
115
116                 if (find_dev_and_part(part_name, &dev, &out_partnum, &parts[i]))
117                         return -EINVAL;
118         }
119
120         return 0;
121 }
122
123 static int get_part_id(char *name, int id)
124 {
125         int nparts = count_mtdparts();
126         int i;
127
128         for (i = 0; i < nparts; i++) {
129                 if (strcmp(parts[i]->name, name) == 0)
130                         return i;
131         }
132
133         printf("Error: Unknown partition -> %s(%d)\n", name, id);
134         return -1;
135 }
136 #else
137 static int get_part_info(void)
138 {
139         printf("Error: Can't get patition information\n");
140         return -EINVAL;
141 }
142
143 static int get_part_id(char *name, int id)
144 {
145         return id;
146 }
147 #endif
148
149 static void boot_cmd(char *addr)
150 {
151         char *argv[] = { "bootm", addr };
152         do_bootm(NULL, 0, 2, argv);
153 }
154
155 static void run_cmd(char *cmd)
156 {
157         char *argv[] = { "run", cmd };
158         do_run(NULL, 0, 2, argv);
159 }
160
161 #if defined(CONFIG_CMD_NAND)
162 extern int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
163 #elif defined(CONFIG_CMD_ONENAND)
164 extern int do_onenand(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
165 #endif
166
167 /* NAND erase and write using nand command */
168 static int nand_cmd(int type, char *p1, char *p2, char *p3)
169 {
170         int ret = 1;
171         char nand_name[12];
172         int (*nand_func) (cmd_tbl_t *, int, int, char **);
173
174 #if defined(CONFIG_CMD_NAND)
175         sprintf(nand_name, "nand");
176         nand_func = do_nand;
177 #elif defined(CONFIG_CMD_ONENAND)
178         sprintf(nand_name, "onenand");
179         nand_func = do_onenand;
180 #else
181         printf("Configure your NAND sub-system\n");
182         return 0;
183 #endif
184
185         if (type == 0) {
186                 char *argv[] = {nand_name, "erase", p1, p2};
187                 printf("%s %s %s %s\n", argv[0], argv[1], argv[2], argv[3]);
188                 ret = nand_func(NULL, 0, 4, argv);
189         } else if (type == 1) {
190                 char *argv[] = {nand_name, "write", p1, p2, p3};
191                 printf("%s %s %s %s %s\n", argv[0], argv[1], argv[2],
192                                 argv[3], argv[4]);
193                 ret = nand_func(NULL, 0, 5, argv);
194         } else if (type == 2) {
195                 char *argv[] = {nand_name, "write.yaffs", p1, p2, p3};
196                 printf("%s %s %s %s %s\n", argv[0], argv[1], argv[2],
197                                 argv[3], argv[4]);
198                 ret = nand_func(NULL, 0, 5, argv);
199         }
200
201         if (ret)
202                 printf("Error: NAND Command\n");
203
204         return ret;
205 }
206
207 #ifdef CONFIG_CMD_UBI
208 int do_ubi(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
209
210 int ubi_cmd(int part, char *p1, char *p2, char *p3)
211 {
212         int ret = 1;
213
214         if (part == RAMDISK_PART_ID) {
215                 char *argv[] = {"ubi", "write", p1, "rootfs.cramfs", p2, p3};
216                 printf("%s %s %s %s %s %s\n", argv[0], argv[1], argv[2],
217                                 argv[3], argv[4], argv[5]);
218                 ret = do_ubi(NULL, 0, 6, argv);
219         } else if (part == FILESYSTEM_PART_ID) {
220                 char *argv[] = {"ubi", "write", p1, "factoryfs.cramfs", p2, p3};
221                 printf("%s %s %s %s %s %s\n", argv[0], argv[1], argv[2],
222                                 argv[3], argv[4], argv[5]);
223                 ret = do_ubi(NULL, 0, 6, argv);
224         } else if (part == FILESYSTEM2_PART_ID) {
225                 char *argv[] = {"ubi", "write", p1, "datafs.ubifs", p2, p3};
226                 printf("%s %s %s %s %s %s\n", argv[0], argv[1], argv[2],
227                                 argv[3], argv[4], argv[5]);
228                 ret = do_ubi(NULL, 0, 6, argv);
229         }
230
231         return ret;
232 }
233 #endif
234
235 #ifdef CONFIG_CMD_MMC
236 #include <fat.h>
237
238 extern int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
239
240 static int mmc_cmd(char *p1, char *p2, char *p3)
241 {
242         char *argv[] = {"mmc", "write", "0", p1, p2, p3};
243         int ret;
244
245         ret = do_mmcops(NULL, 0, 6, argv);
246
247         return ret;
248 }
249
250 static unsigned int org_blk_offset;
251 static unsigned int org_root_blk;
252 static unsigned int org_data_blk;
253
254 static unsigned int cur_blk_offset;
255 static unsigned int cur_root_blk;
256 static unsigned int cur_data_blk;
257
258 static int erase_mmc_block(struct usbd_ops *usbd,
259                 unsigned int blocks, unsigned int start)
260 {
261         char *data;
262         char offset[12], length[12], ramaddr[12];
263         int i;
264         int loop;
265         u32 cnt;
266         int ret = 0;
267
268         loop = blocks / usbd->mmc_max;
269         if (blocks % usbd->mmc_max)
270                 loop++;
271
272         data = malloc(usbd->mmc_max);
273         memset(data, 0, usbd->mmc_max);
274
275         for (i = 0; i < loop; i++) {
276                 if (i == 0) {
277                         cnt = blocks % usbd->mmc_max;
278                         if (cnt == 0)
279                                 cnt = usbd->mmc_max;
280                 } else {
281                         cnt = usbd->mmc_max;
282                 }
283
284                 sprintf(length, "%x", cnt);
285                 sprintf(offset, "%x", start);
286                 sprintf(ramaddr, "0x%x", (u32)data);
287                 ret = mmc_cmd(ramaddr, offset, length);
288
289                 start += cnt;
290         }
291
292         free(data);
293
294         return ret;
295 }
296
297 static int write_file_mmc(struct usbd_ops *usbd, char *ramaddr, u32 len,
298                 char *offset, char *length)
299 {
300         uint blocks;
301         uint cnt;
302         uint ram_addr;
303         int i;
304         int loop;
305         int ret;
306
307         if (cur_blk_offset == 0) {
308                 boot_sector *bs;
309                 u16 cluster_size;
310                 u32 fat32_length;
311                 u32 total_sect;
312
313                 /* boot block */
314                 bs = (boot_sector *)down_ram_addr;
315
316                 org_root_blk = bs->fat32_length + bs->reserved;
317                 org_data_blk = bs->fat32_length * 2 + bs->reserved;
318
319                 cluster_size = bs->cluster_size;
320                 fat32_length = bs->fat32_length;
321                 total_sect = bs->total_sect;
322
323                 if (cluster_size != 0x8) {
324                         printf("Cluster size must be 0x8\n");
325                         return 1;
326                 }
327
328                 bs->total_sect = usbd->mmc_total;
329                 bs->fat32_length = usbd->mmc_total / usbd->mmc_blk / 2;
330
331                 cur_root_blk = bs->fat32_length + bs->reserved;
332                 cur_data_blk = (bs->fat32_length + 0x10) * 2;
333
334                 /* backup boot block */
335                 bs = (boot_sector *)(down_ram_addr +
336                                 usbd->mmc_blk * bs->backup_boot);
337                 bs->total_sect = usbd->mmc_total;
338                 bs->fat32_length = usbd->mmc_total / usbd->mmc_blk / 2;
339
340                 /* write reserved blocks */
341                 sprintf(length, "%x", bs->reserved);
342                 sprintf(offset, "%x", cur_blk_offset);
343                 sprintf(ramaddr, "0x%x", (uint)down_ram_addr);
344                 ret = mmc_cmd(ramaddr, offset, length);
345
346                 cur_blk_offset = bs->reserved;
347
348                 /* write root blocks */
349                 erase_mmc_block(usbd, bs->fat32_length, cur_blk_offset);
350                 sprintf(length, "%x", fat32_length);
351                 sprintf(offset, "%x", cur_blk_offset);
352                 sprintf(ramaddr, "0x%x", (uint)(down_ram_addr +
353                                 cur_blk_offset * usbd->mmc_blk));
354                 ret = mmc_cmd(ramaddr, offset, length);
355
356                 org_blk_offset = org_root_blk;
357                 cur_blk_offset = cur_root_blk;
358
359                 erase_mmc_block(usbd, bs->fat32_length, cur_blk_offset);
360                 sprintf(length, "%x", fat32_length);
361                 sprintf(offset, "%x", cur_blk_offset);
362                 sprintf(ramaddr, "0x%x", (uint)(down_ram_addr +
363                                 org_blk_offset * usbd->mmc_blk));
364                 ret = mmc_cmd(ramaddr, offset, length);
365
366                 org_blk_offset = org_data_blk;
367                 cur_blk_offset = cur_data_blk;
368
369                 /* write file list */
370                 sprintf(length, "%x", cluster_size);
371                 sprintf(offset, "%x", cur_blk_offset);
372                 sprintf(ramaddr, "0x%x", (uint)(down_ram_addr +
373                                 org_blk_offset * usbd->mmc_blk));
374                 ret = mmc_cmd(ramaddr, offset, length);
375
376                 org_blk_offset += cluster_size;
377                 cur_blk_offset += cluster_size;
378
379                 ram_addr = down_ram_addr + org_blk_offset * usbd->mmc_blk;
380                 blocks = len / usbd->mmc_blk - org_blk_offset;
381
382                 if (len % usbd->mmc_blk)
383                         blocks++;
384
385                 loop = blocks / usbd->mmc_max;
386                 if (blocks % usbd->mmc_max)
387                         loop++;
388         } else {
389                 blocks = len / usbd->mmc_blk;
390                 if (len % usbd->mmc_blk)
391                         blocks++;
392
393                 loop = blocks / usbd->mmc_max;
394                 if (blocks % usbd->mmc_max)
395                         loop++;
396
397                 ram_addr = down_ram_addr;
398         }
399
400         for (i = 0; i < loop; i++) {
401                 if (i == 0) {
402                         cnt = blocks % usbd->mmc_max;
403                         if (cnt == 0)
404                                 cnt = usbd->mmc_max;
405                 } else {
406                         cnt = usbd->mmc_max;
407                 }
408
409                 sprintf(length, "%x", cnt);
410                 sprintf(offset, "%x", cur_blk_offset);
411                 sprintf(ramaddr, "0x%x", ram_addr);
412                 ret = mmc_cmd(ramaddr, offset, length);
413
414                 org_blk_offset += cnt;
415                 cur_blk_offset += cnt;
416
417                 ram_addr += cnt * usbd->mmc_blk;
418         }
419
420         return ret;
421 }
422 #endif
423
424 int write_file_system(char *ramaddr, ulong len, char *offset,
425                 char *length, int part_num, int ubi_update)
426 {
427 #ifdef CONFIG_USE_YAFFS
428         int actual_len = 0;
429         int yaffs_write = 0;
430 #endif
431         int ret = 0;
432
433 #ifdef CONFIG_CMD_UBI
434         /* UBI Update */
435         if (ubi_update) {
436                 sprintf(length, "0x%x", (uint)len);
437                 ret = ubi_cmd(part_id, ramaddr, length, "cont");
438                 return ret;
439         }
440 #endif
441
442         /* Erase entire partition at the first writing */
443         if (write_part == 0 && ubi_update == 0) {
444                 sprintf(offset, "0x%x", (uint)parts[part_num]->offset);
445                 sprintf(length, "0x%x", (uint)parts[part_num]->size);
446                 nand_cmd(0, offset, length, NULL);
447         }
448
449 #ifdef CONFIG_USE_YAFFS
450         /* if using yaffs, wirte size must be 2112*X
451          * so, must have to realloc, and writing */
452         if (!strcmp("yaffs", getenv(parts[part_num]->name))) {
453                 yaffs_write = 1;
454
455                 memcpy((void *)down_ram_addr, yaffs_data, yaffs_len);
456
457                 actual_len = len + yaffs_len;
458                 yaffs_len = actual_len % YAFFS_PAGE;
459                 len = actual_len - yaffs_len;
460
461                 memset(yaffs_data, 0x00, YAFFS_PAGE);
462                 memcpy(yaffs_data, (char *)down_ram_addr + len, yaffs_len);
463         }
464 #endif
465
466         sprintf(offset, "0x%x", (uint)(parts[part_num]->offset + fs_offset));
467         sprintf(length, "0x%x", (uint)len);
468
469 #ifdef CONFIG_USE_YAFFS
470         if (yaffs_write)
471                 ret = nand_cmd(2, ramaddr, offset, length);
472         else
473                 ret = nand_cmd(1, ramaddr, offset, length);
474
475         if (!strcmp("yaffs", getenv(parts[part_num]->name)))
476                 fs_offset += len / YAFFS_PAGE * NAND_PAGE_SIZE;
477         else
478                 fs_offset += len;
479
480 #else
481         fs_offset += len;
482         ret = nand_cmd(1, ramaddr, offset, length);
483 #endif
484
485         return ret;
486 }
487
488 /* Parsing received data packet and Process data */
489 static int process_data(struct usbd_ops *usbd)
490 {
491         ulong cmd = 0, arg = 0, len = 0, flag = 0;
492         char offset[12], length[12], ramaddr[12];
493         int recvlen = 0;
494         unsigned int blocks = 0;
495         int ret = 0;
496         int ubi_update = 0;
497         int ubi_mode = 0;
498
499         sprintf(ramaddr, "0x%x", (uint) down_ram_addr);
500
501         /* Parse command */
502         cmd  = *((ulong *) usbd->rx_data + 0);
503         arg  = *((ulong *) usbd->rx_data + 1);
504         len  = *((ulong *) usbd->rx_data + 2);
505         flag = *((ulong *) usbd->rx_data + 3);
506
507         /* Reset tx buffer */
508         memset(usbd->tx_data, 0, sizeof(usbd->tx_data));
509
510         ubi_mode = check_ubi_mode();
511
512         switch (cmd) {
513         case COMMAND_DOWNLOAD_IMAGE:
514                 printf("\nCOMMAND_DOWNLOAD_IMAGE\n");
515
516 #ifdef CONFIG_USE_YAFFS
517                 usbd->recv_setup((char *)down_ram_addr + yaffs_len, (int)len);
518                 printf("Download to 0x%08x, %d bytes\n",
519                                 (uint)down_ram_addr + yaffs_len, (int)len);
520 #else
521                 usbd->recv_setup((char *)down_ram_addr, (int)len);
522                 printf("Download to 0x%08x, %d bytes\n",
523                                 (uint)down_ram_addr, (int)len);
524 #endif
525                 /* response */
526                 usbd->send_data(usbd->tx_data, usbd->tx_len);
527
528                 /* Receive image by using dma */
529                 recvlen = usbd->recv_data();
530                 if (recvlen < len) {
531                         printf("Error: wrong image size -> %d/%d\n",
532                                         (int)recvlen, (int)len);
533
534                         /* Retry this commad */
535                         *((ulong *) usbd->tx_data) = STATUS_RETRY;
536                 } else
537                         *((ulong *) usbd->tx_data) = STATUS_DONE;
538
539                 usbd->send_data(usbd->tx_data, usbd->tx_len);
540                 return 1;
541
542         /* Report partition info */
543         case COMMAND_PARTITION_SYNC:
544                 part_id = arg;
545
546 #ifdef CONFIG_CMD_UBI
547                 if (ubi_mode) {
548                         if (part_id == RAMDISK_PART_ID ||
549                             part_id == FILESYSTEM_PART_ID ||
550                             part_id == FILESYSTEM2_PART_ID) {
551                                 /* change to yaffs style */
552                                 get_part_info();
553                         }
554                 } else {
555                         if (part_id == FILESYSTEM3_PART_ID) {
556                                 /* change ubi style */
557                                 get_part_info();
558                         }
559                 }
560 #endif
561
562                 if (part_id == FILESYSTEM3_PART_ID)
563                         part_id = get_part_id("UBI", FILESYSTEM_PART_ID);
564                 else if (part_id == MODEM_PART_ID)
565                         part_id = get_part_id("modem", MODEM_PART_ID);
566 #ifdef CONFIG_MIRAGE
567                 if (part_id)
568                         part_id--;
569 #endif
570                 printf("COMMAND_PARTITION_SYNC - Part%d\n", part_id);
571
572                 blocks = parts[part_id]->size / 1024 / 128;
573                 printf("COMMAND_PARTITION_SYNC - Part%d, %d blocks\n",
574                                 part_id, blocks);
575
576                 *((ulong *) usbd->tx_data) = blocks;
577                 usbd->send_data(usbd->tx_data, usbd->tx_len);
578                 return 1;
579
580         case COMMAND_WRITE_PART_0:
581                 /* Do nothing */
582                 printf("COMMAND_WRITE_PART_0\n");
583                 return 1;
584
585         case COMMAND_WRITE_PART_1:
586                 printf("COMMAND_WRITE_PART_BOOT\n");
587                 part_id = get_part_id("bootloader", BOOT_PART_ID);
588                 break;
589
590         case COMMAND_WRITE_PART_2:
591         case COMMAND_ERASE_PARAMETER:
592                 printf("COMMAND_PARAMETER - not support!\n");
593                 break;
594
595         case COMMAND_WRITE_PART_3:
596                 printf("COMMAND_WRITE_KERNEL\n");
597                 part_id = get_part_id("kernel", KERNEL_PART_ID);
598                 break;
599
600         case COMMAND_WRITE_PART_4:
601                 printf("COMMAND_WRITE_ROOTFS\n");
602                 part_id = get_part_id("Root", RAMDISK_PART_ID);
603                 ubi_update = arg;
604                 break;
605
606         case COMMAND_WRITE_PART_5:
607                 printf("COMMAND_WRITE_FACTORYFS\n");
608                 part_id = get_part_id("Fact", FILESYSTEM_PART_ID);
609                 ubi_update = arg;
610                 break;
611
612         case COMMAND_WRITE_PART_6:
613                 printf("COMMAND_WRITE_DATAFS\n");
614                 part_id = get_part_id("Data", FILESYSTEM2_PART_ID);
615                 ubi_update = arg;
616                 break;
617
618         case COMMAND_WRITE_PART_7:
619                 printf("COMMAND_WRITE_UBI\n");
620                 part_id = get_part_id("UBI", FILESYSTEM3_PART_ID);
621                 ubi_update = 0;
622                 /* someday, it will be deleted */
623                 get_part_info();
624                 break;
625
626         case COMMAND_WRITE_PART_8:
627                 printf("COMMAND_WRITE_MODEM\n");
628                 part_id = MODEM_PART_ID;
629                 break;
630
631         case COMMAND_WRITE_PART_9:
632                 printf("COMMAND_WRITE_MMC\n");
633                 part_id = MMC_PART_ID;
634                 break;
635
636         case COMMAND_WRITE_UBI_INFO:
637                 printf("COMMAND_WRITE_UBI_INFO\n");
638
639                 if (ubi_mode) {
640 #ifdef CONFIG_CMD_UBI
641                         part_id = arg-1;
642                         sprintf(length, "0x%x", (uint)len);
643                         ret = ubi_cmd(part_id, ramaddr, length, "begin");
644                 } else {
645 #endif
646                         printf("Error: Not UBI mode\n");
647                         ret = 1;
648                 }
649
650                 *((ulong *) usbd->tx_data) = ret;
651                 /* Write image success -> Report status */
652                 usbd->send_data(usbd->tx_data, usbd->tx_len);
653
654                 return !ret;
655         /* Download complete -> reset */
656         case COMMAND_RESET_PDA:
657                 printf("\nDownload finished and Auto reset!\nWait........\n");
658
659                 /* Stop USB */
660                 usbd->usb_stop();
661
662                 do_reset();
663                 return 0;
664
665         /* Error */
666         case COMMAND_RESET_USB:
667                 printf("\nError is occured!(maybe previous step)->\
668                                 Turn off and restart!\n");
669
670                 /* Stop USB */
671                 usbd->usb_stop();
672                 return 0;
673
674         case COMMAND_RAM_BOOT:
675                 usbd->usb_stop();
676                 boot_cmd(ramaddr);
677                 return 0;
678
679         case COMMAND_RAMDISK_MODE:
680                 printf("COMMAND_RAMDISK_MODE\n");
681 #ifdef CONFIG_RAMDISK_ADDR
682                 if (arg) {
683                         down_ram_addr = usbd->ram_addr;
684                 } else {
685                         down_ram_addr = CONFIG_RAMDISK_ADDR;
686                         run_cmd("ramboot");
687                 }
688 #endif
689                 return 1;
690
691 #ifdef CONFIG_DOWN_PHONE
692         case COMMAND_DOWN_PHONE:
693                 printf("COMMAND_RESET_PHONE\n");
694
695                 usbd_phone_down();
696
697                 *((ulong *) usbd->tx_data) = STATUS_DONE;
698                 usbd->send_data(usbd->tx_data, usbd->tx_len);
699                 return 1;
700
701         case COMMAND_CHANGE_USB:
702                 printf("COMMAND_CHANGE_USB\n");
703
704                 /* Stop USB */
705                 usbd->usb_stop();
706
707                 usbd_path_change();
708
709                 do_reset();
710                 return 0;
711 #endif
712         case COMMAND_PROGRESS:
713                 if (usbd->set_progress)
714                         usbd->set_progress(arg);
715                 return 1;
716
717         default:
718                 printf("Error: Unknown command -> (%d)\n", (int)cmd);
719                 return 1;
720         }
721
722         /* Erase and Write to NAND */
723         switch (part_id) {
724         case BOOT_PART_ID:
725 #ifdef CONFIG_S5PC1XX
726                 /* Workaround: for prevent revision mismatch */
727                 if (cpu_is_s5pc110() && (down_mode != MODE_FORCE)) {
728                         int img_rev = 1;
729                         long *img_header = (long *)down_ram_addr;
730
731                         if (*img_header == 0xea000012)
732                                 img_rev = 0;
733
734                         if (img_rev != s5pc1xx_get_cpu_rev()) {
735                                 printf("CPU revision mismatch!\n");
736                                 *((ulong *) usbd->tx_data) = STATUS_ERROR;
737                                 usbd->send_data(usbd->tx_data, usbd->tx_len);
738                                 return 0;
739                         }
740                 }
741 #endif
742 #if defined(CONFIG_ENV_IS_IN_NAND) || defined(CONFIG_ENV_IS_IN_ONENAND)
743                 /* Erase the environment also when write bootloader */
744                 {
745                         int param_id;
746                         param_id = get_part_id("params", 1);
747
748                         if (param_id == -1) {
749                                 sprintf(offset, "%x", CONFIG_ENV_OFFSET);
750                                 sprintf(length, "%x", CONFIG_ENV_SIZE);
751                         } else {
752                                 sprintf(offset, "%x", parts[param_id]->offset);
753                                 sprintf(length, "%x", parts[param_id]->size);
754                         }
755                         nand_cmd(0, offset, length, NULL);
756                 }
757 #endif
758                 /* Fall through for write bootloader */
759         case KERNEL_PART_ID:
760                 sprintf(offset, "%x", parts[part_id]->offset);
761                 sprintf(length, "%x", parts[part_id]->size);
762
763                 /* Erase */
764                 nand_cmd(0, offset, length, NULL);
765                 /* Write */
766                 sprintf(length, "%x", (unsigned int) len);
767                 ret = nand_cmd(1, ramaddr, offset, length);
768                 break;
769
770         /* File System */
771         case RAMDISK_PART_ID:           /* rootfs */
772         case FILESYSTEM_PART_ID:        /* factoryfs */
773         case FILESYSTEM2_PART_ID:       /* datafs */
774         case FILESYSTEM3_PART_ID:       /* ubifs */
775                 ret = write_file_system(ramaddr, len, offset, length,
776                                 part_id, ubi_update);
777                 break;
778
779         case MODEM_PART_ID:
780                 part_id = get_part_id("modem", MODEM_PART_ID);
781
782                 sprintf(offset, "%x", parts[part_id]->offset);
783                 sprintf(length, "%x", parts[part_id]->size);
784
785                 /* Erase */
786                 nand_cmd(0, offset, length, NULL);
787                 /* Write */
788                 sprintf(length, "%x", (unsigned int) len);
789                 ret = nand_cmd(1, ramaddr, offset, length);
790                 break;
791
792 #ifdef CONFIG_CMD_MMC
793         case MMC_PART_ID:
794                 write_file_mmc(usbd, ramaddr, len, offset, length);
795                 break;
796 #endif
797
798         default:
799                 /* Retry? */
800                 write_part--;
801         }
802
803         if (ret) {
804                 /* Retry this commad */
805                 *((ulong *) usbd->tx_data) = STATUS_RETRY;
806                 usbd->send_data(usbd->tx_data, usbd->tx_len);
807                 return 1;
808         } else
809                 *((ulong *) usbd->tx_data) = STATUS_DONE;
810
811         /* Write image success -> Report status */
812         usbd->send_data(usbd->tx_data, usbd->tx_len);
813
814         write_part++;
815
816         /* Reset write count for another image */
817         if (flag) {
818                 write_part = 0;
819                 fs_offset = 0;
820 #ifdef CONFIG_USE_YAFFS
821                 yaffs_len = 0;
822 #endif
823         }
824
825         return 1;
826 }
827
828 static const char *recv_key = "SAMSUNG";
829 static const char *tx_key = "MPL";
830
831 int do_usbd_down(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
832 {
833         struct usbd_ops *usbd;
834         int err;
835
836         if (argc > 1)
837                 down_mode = simple_strtoul(argv[1], NULL, 10);
838         else
839                 down_mode = MODE_NORMAL;
840
841         printf("USB Downloader v%s (%d)\n", APP_VERSION, down_mode);
842
843         /* get partition info */
844         err = get_part_info();
845         if (err)
846                 return err;
847
848         /* interface setting */
849         usbd = usbd_set_interface(&usbd_ops);
850         down_ram_addr = usbd->ram_addr;
851
852         /* init the usb controller */
853         usbd->usb_init();
854
855         /* receive setting */
856         usbd->recv_setup(usbd->rx_data, usbd->rx_len);
857
858         /* detect the download request from Host PC */
859         if (usbd->recv_data()) {
860                 if (strncmp(usbd->rx_data, recv_key, strlen(recv_key)) == 0) {
861                         printf("Download request from the Host PC\n");
862                         msleep(30);
863
864                         strcpy(usbd->tx_data, tx_key);
865                         usbd->send_data(usbd->tx_data, usbd->tx_len);
866                 } else {
867                         printf("No download request from the Host PC!! 1\n");
868                         return 0;
869                 }
870         } else {
871                 printf("No download request from the Host PC!!\n");
872                 return 0;
873         }
874
875         printf("Receive the packet\n");
876
877         /* receive the data from Host PC */
878         while (1) {
879                 usbd->recv_setup(usbd->rx_data, usbd->rx_len);
880
881                 if (usbd->recv_data()) {
882                         if (process_data(usbd) == 0)
883                                 return 0;
884                 }
885         }
886
887         return 0;
888 }
889
890 U_BOOT_CMD(usbdown, CONFIG_SYS_MAXARGS, 1, do_usbd_down,
891         "Initialize USB device and Run USB Downloader (specific)",
892         "- normal mode\n"
893         "usbdown mode - specific mode (0: NORAML, 1: FORCE)\n"
894 );