usbd: add support rfs movinand downloading
[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.4.1"
16
17 #ifdef CONFIG_CMD_MTDPARTS
18 #include <jffs2/load_kernel.h>
19 static struct part_info *parts[16];
20 #endif
21
22 static const char pszMe[] = "usbd: ";
23
24 static struct usbd_ops usbd_ops;
25
26 static unsigned int 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)
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\n", name);
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)
144 {
145         return 0;
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 cur_blk_offset;
251 static unsigned int cur_part_size;
252 static unsigned int cur_partition;
253
254 static unsigned int mmc_parts;
255
256 struct partition_info {
257         u32 size;
258         u32 checksum;
259         u32 res;
260 } __attribute__((packed));
261
262 struct partition_header {
263         u8                      fat32head[16];  /* RFSHEAD identifier */
264         struct partition_info   partition[4];
265         u8                      res[448];       /* reserved */
266 } __attribute__((packed));
267
268 struct partition_table {
269         u8      boot_flag;
270         u8      chs_begin[3];
271         u8      type_code;
272         u8      chs_end[3];
273         u32     lba_begin;
274         u32     num_sectors;
275 } __attribute__((packed));
276
277 struct mbr_table {
278         u8                      boot_code[446];
279         struct partition_table  partition[4];
280         u16                     signature;
281 } __attribute__((packed));
282
283 #define MBR_OFFSET      0x10
284
285 struct partition_header part_info;
286 struct mbr_table mbr_info;
287
288 static int write_mmc_partition(struct usbd_ops *usbd, u32 *ram_addr, u32 len)
289 {
290         unsigned int blocks;
291         char offset[12], length[12], ramaddr[12];
292         int i;
293         int loop;
294         u32 cnt;
295         int ret;
296
297         if (cur_part_size > len) {
298                 blocks = len / usbd->mmc_blk;
299                 ret = -1;
300         } else {
301                 blocks = cur_part_size / usbd->mmc_blk;
302                 ret = len - cur_part_size;
303         }
304
305         if (len % usbd->mmc_blk)
306                 blocks++;
307
308         loop = blocks / usbd->mmc_max;
309         if (blocks % usbd->mmc_max)
310                 loop++;
311
312         for (i = 0; i < loop; i++) {
313                 if (i == 0) {
314                         cnt = blocks % usbd->mmc_max;
315                         if (cnt == 0)
316                                 cnt = usbd->mmc_max;
317                 } else {
318                         cnt = usbd->mmc_max;
319                 }
320
321                 sprintf(length, "%x", cnt);
322                 sprintf(offset, "%x", cur_blk_offset);
323                 sprintf(ramaddr, "0x%x", *ram_addr);
324                 mmc_cmd(ramaddr, offset, length);
325
326                 cur_blk_offset += cnt;
327
328                 *ram_addr += (cnt * usbd->mmc_blk);
329         }
330
331         return ret;
332 }
333
334 static void write_file_mmc(struct usbd_ops *usbd, char *ramaddr, u32 len,
335                 char *offset, char *length)
336 {
337         u32 ram_addr;
338         int i;
339         int ret;
340
341         ram_addr = (u32)down_ram_addr;
342
343         if (cur_blk_offset == 0) {
344                 boot_sector *bs;
345                 struct mbr_table *mbr;
346
347                 memcpy(&part_info, (void *)ram_addr,
348                                 sizeof(struct partition_header));
349
350                 ram_addr += sizeof(struct partition_header);
351                 len -= sizeof(struct partition_header);
352                 mbr = (struct mbr_table*)ram_addr;
353
354                 /* modify sectors of p1 */
355                 mbr->partition[0].num_sectors = usbd->mmc_total -
356                                 (MBR_OFFSET +
357                                 mbr->partition[1].num_sectors +
358                                 mbr->partition[2].num_sectors +
359                                 mbr->partition[3].num_sectors);
360
361                 /* modify lba_begin of p2 and p3 */
362                 for (i = 1; i < 4; i++) {
363                         mmc_parts++;
364                         if (part_info.partition[i].size == 0)
365                                 break;
366
367                         mbr->partition[i].lba_begin =
368                                 mbr->partition[i - 1].lba_begin +
369                                 mbr->partition[i - 1].num_sectors;
370                 }
371
372                 /* copy MBR */
373                 memcpy(&mbr_info, mbr, sizeof(struct mbr_table));
374
375                 printf("Total Size: 0x%08x #parts %d\n",
376                                 usbd->mmc_total, mmc_parts);
377                 for (i = 0; i < mmc_parts; i++) {
378                         printf("p%d\t0x%08x\t0x%08x\n", i + 1,
379                                 mbr_info.partition[i].lba_begin,
380                                 mbr_info.partition[i].num_sectors);
381                 }
382
383                 /* write MBR */
384                 sprintf(length, "%x", MBR_OFFSET);
385                 sprintf(offset, "%x", 0);
386                 sprintf(ramaddr, "0x%x", (u32)ram_addr);
387                 ret = mmc_cmd(ramaddr, offset, length);
388
389                 ram_addr += (MBR_OFFSET * usbd->mmc_blk);
390                 len -= (MBR_OFFSET * usbd->mmc_blk);
391
392                 cur_blk_offset = MBR_OFFSET;
393                 cur_partition = 0;
394                 cur_part_size = part_info.partition[0].size;
395
396                 /* modify p1's total sector */
397                 bs = (boot_sector *)ram_addr;
398                 bs->total_sect = mbr_info.partition[0].num_sectors;
399
400                 printf("\nWrite Partition %d.. %d blocks\n",
401                         cur_partition + 1,
402                         part_info.partition[cur_partition].size /
403                         usbd->mmc_blk);
404         }
405
406         for (i = cur_partition; i < mmc_parts; i++) {
407                 ret = write_mmc_partition(usbd, &ram_addr, len);
408
409                 if (ret < 0) {
410                         cur_part_size -= len;
411                         break;
412                 } else {
413                         cur_partition++;
414                         cur_part_size =
415                                 part_info.partition[cur_partition].size;
416                         cur_blk_offset =
417                                 mbr_info.partition[cur_partition].lba_begin;
418
419                         if (ret == 0)
420                                 break;
421                         else
422                                 len = ret;
423
424                         printf("\nWrite Partition %d.. %d blocks\n",
425                                 cur_partition + 1,
426                                 part_info.partition[cur_partition].size /
427                                 usbd->mmc_blk);
428                 }
429         }
430 }
431 #endif
432
433 int write_file_system(char *ramaddr, ulong len, char *offset,
434                 char *length, int part_num, int ubi_update)
435 {
436 #ifdef CONFIG_USE_YAFFS
437         int actual_len = 0;
438         int yaffs_write = 0;
439 #endif
440         int ret = 0;
441
442 #ifdef CONFIG_CMD_UBI
443         /* UBI Update */
444         if (ubi_update) {
445                 sprintf(length, "0x%x", (uint)len);
446                 ret = ubi_cmd(part_id, ramaddr, length, "cont");
447                 return ret;
448         }
449 #endif
450
451         /* Erase entire partition at the first writing */
452         if (write_part == 0 && ubi_update == 0) {
453                 sprintf(offset, "0x%x", (uint)parts[part_num]->offset);
454                 sprintf(length, "0x%x", (uint)parts[part_num]->size);
455                 nand_cmd(0, offset, length, NULL);
456         }
457
458 #ifdef CONFIG_USE_YAFFS
459         /* if using yaffs, wirte size must be 2112*X
460          * so, must have to realloc, and writing */
461         if (!strcmp("yaffs", getenv(parts[part_num]->name))) {
462                 yaffs_write = 1;
463
464                 memcpy((void *)down_ram_addr, yaffs_data, yaffs_len);
465
466                 actual_len = len + yaffs_len;
467                 yaffs_len = actual_len % YAFFS_PAGE;
468                 len = actual_len - yaffs_len;
469
470                 memset(yaffs_data, 0x00, YAFFS_PAGE);
471                 memcpy(yaffs_data, (char *)down_ram_addr + len, yaffs_len);
472         }
473 #endif
474
475         sprintf(offset, "0x%x", (uint)(parts[part_num]->offset + fs_offset));
476         sprintf(length, "0x%x", (uint)len);
477
478 #ifdef CONFIG_USE_YAFFS
479         if (yaffs_write)
480                 ret = nand_cmd(2, ramaddr, offset, length);
481         else
482                 ret = nand_cmd(1, ramaddr, offset, length);
483
484         if (!strcmp("yaffs", getenv(parts[part_num]->name)))
485                 fs_offset += len / YAFFS_PAGE * NAND_PAGE_SIZE;
486         else
487                 fs_offset += len;
488
489 #else
490         fs_offset += len;
491         ret = nand_cmd(1, ramaddr, offset, length);
492 #endif
493
494         return ret;
495 }
496
497 /* Parsing received data packet and Process data */
498 static int process_data(struct usbd_ops *usbd)
499 {
500         ulong cmd = 0, arg = 0, len = 0, flag = 0;
501         char offset[12], length[12], ramaddr[12];
502         int recvlen = 0;
503         unsigned int blocks = 0;
504         int ret = 0;
505         int ubi_update = 0;
506         int ubi_mode = 0;
507         int img_type;
508
509         sprintf(ramaddr, "0x%x", (uint) down_ram_addr);
510
511         /* Parse command */
512         cmd  = *((ulong *) usbd->rx_data + 0);
513         arg  = *((ulong *) usbd->rx_data + 1);
514         len  = *((ulong *) usbd->rx_data + 2);
515         flag = *((ulong *) usbd->rx_data + 3);
516
517         /* Reset tx buffer */
518         memset(usbd->tx_data, 0, sizeof(usbd->tx_data));
519
520         ubi_mode = check_ubi_mode();
521
522         switch (cmd) {
523         case COMMAND_DOWNLOAD_IMAGE:
524                 printf("\nCOMMAND_DOWNLOAD_IMAGE\n");
525
526 #ifdef CONFIG_USE_YAFFS
527                 usbd->recv_setup((char *)down_ram_addr + yaffs_len, (int)len);
528                 printf("Download to 0x%08x, %d bytes\n",
529                                 (uint)down_ram_addr + yaffs_len, (int)len);
530 #else
531                 usbd->recv_setup((char *)down_ram_addr, (int)len);
532                 printf("Download to 0x%08x, %d bytes\n",
533                                 (uint)down_ram_addr, (int)len);
534 #endif
535                 /* response */
536                 usbd->send_data(usbd->tx_data, usbd->tx_len);
537
538                 /* Receive image by using dma */
539                 recvlen = usbd->recv_data();
540                 if (recvlen < len) {
541                         printf("Error: wrong image size -> %d/%d\n",
542                                         (int)recvlen, (int)len);
543
544                         /* Retry this commad */
545                         *((ulong *) usbd->tx_data) = STATUS_RETRY;
546                 } else
547                         *((ulong *) usbd->tx_data) = STATUS_DONE;
548
549                 usbd->send_data(usbd->tx_data, usbd->tx_len);
550                 return 1;
551
552         /* Report partition info */
553         case COMMAND_PARTITION_SYNC:
554                 part_id = arg;
555
556 #ifdef CONFIG_CMD_UBI
557                 if (ubi_mode) {
558                         if (part_id == RAMDISK_PART_ID ||
559                             part_id == FILESYSTEM_PART_ID ||
560                             part_id == FILESYSTEM2_PART_ID) {
561                                 /* change to yaffs style */
562                                 get_part_info();
563                         }
564                 } else {
565                         if (part_id == FILESYSTEM3_PART_ID) {
566                                 /* change ubi style */
567                                 get_part_info();
568                         }
569                 }
570 #endif
571
572                 if (part_id == FILESYSTEM3_PART_ID)
573                         part_id = get_part_id("UBI");
574                 else if (part_id == MODEM_PART_ID)
575                         part_id = get_part_id("modem");
576 #ifdef CONFIG_MIRAGE
577                 if (part_id)
578                         part_id--;
579 #endif
580                 printf("COMMAND_PARTITION_SYNC - Part%d\n", part_id);
581
582                 blocks = parts[part_id]->size / 1024 / 128;
583                 printf("COMMAND_PARTITION_SYNC - Part%d, %d blocks\n",
584                                 part_id, blocks);
585
586                 *((ulong *) usbd->tx_data) = blocks;
587                 usbd->send_data(usbd->tx_data, usbd->tx_len);
588                 return 1;
589
590         case COMMAND_WRITE_PART_0:
591                 /* Do nothing */
592                 printf("COMMAND_WRITE_PART_0\n");
593                 return 1;
594
595         case COMMAND_WRITE_PART_1:
596                 printf("COMMAND_WRITE_PART_BOOT\n");
597                 part_id = get_part_id("bootloader");
598                 img_type = IMG_BOOT;
599                 break;
600
601         case COMMAND_WRITE_PART_2:
602         case COMMAND_ERASE_PARAMETER:
603                 printf("COMMAND_PARAMETER - not support!\n");
604                 break;
605
606         case COMMAND_WRITE_PART_3:
607                 printf("COMMAND_WRITE_KERNEL\n");
608                 part_id = get_part_id("kernel");
609                 img_type = IMG_KERNEL;
610                 break;
611
612         case COMMAND_WRITE_PART_4:
613                 printf("COMMAND_WRITE_ROOTFS\n");
614                 part_id = get_part_id("Root");
615                 img_type = IMG_FILESYSTEM;
616                 ubi_update = arg;
617                 break;
618
619         case COMMAND_WRITE_PART_5:
620                 printf("COMMAND_WRITE_FACTORYFS\n");
621                 part_id = get_part_id("Fact");
622                 img_type = IMG_FILESYSTEM;
623                 ubi_update = arg;
624                 break;
625
626         case COMMAND_WRITE_PART_6:
627                 printf("COMMAND_WRITE_DATAFS\n");
628                 part_id = get_part_id("Data");
629                 img_type = IMG_FILESYSTEM;
630                 ubi_update = arg;
631                 break;
632
633         case COMMAND_WRITE_PART_7:
634                 printf("COMMAND_WRITE_UBI\n");
635                 part_id = get_part_id("UBI");
636                 img_type = IMG_FILESYSTEM;
637                 ubi_update = 0;
638                 /* someday, it will be deleted */
639                 get_part_info();
640                 break;
641
642         case COMMAND_WRITE_PART_8:
643                 printf("COMMAND_WRITE_MODEM\n");
644                 part_id = get_part_id("modem");
645                 img_type = IMG_MODEM;
646                 break;
647
648         case COMMAND_WRITE_PART_9:
649                 printf("COMMAND_WRITE_MMC\n");
650                 img_type = IMG_MMC;
651                 break;
652
653         case COMMAND_WRITE_UBI_INFO:
654                 printf("COMMAND_WRITE_UBI_INFO\n");
655
656                 if (ubi_mode) {
657 #ifdef CONFIG_CMD_UBI
658                         part_id = arg-1;
659                         sprintf(length, "0x%x", (uint)len);
660                         ret = ubi_cmd(part_id, ramaddr, length, "begin");
661                 } else {
662 #endif
663                         printf("Error: Not UBI mode\n");
664                         ret = 1;
665                 }
666
667                 *((ulong *) usbd->tx_data) = ret;
668                 /* Write image success -> Report status */
669                 usbd->send_data(usbd->tx_data, usbd->tx_len);
670
671                 return !ret;
672         /* Download complete -> reset */
673         case COMMAND_RESET_PDA:
674                 printf("\nDownload finished and Auto reset!\nWait........\n");
675
676                 /* Stop USB */
677                 usbd->usb_stop();
678
679                 do_reset();
680                 return 0;
681
682         /* Error */
683         case COMMAND_RESET_USB:
684                 printf("\nError is occured!(maybe previous step)->\
685                                 Turn off and restart!\n");
686
687                 /* Stop USB */
688                 usbd->usb_stop();
689                 return 0;
690
691         case COMMAND_RAM_BOOT:
692                 usbd->usb_stop();
693                 boot_cmd(ramaddr);
694                 return 0;
695
696         case COMMAND_RAMDISK_MODE:
697                 printf("COMMAND_RAMDISK_MODE\n");
698 #ifdef CONFIG_RAMDISK_ADDR
699                 if (arg) {
700                         down_ram_addr = usbd->ram_addr;
701                 } else {
702                         down_ram_addr = CONFIG_RAMDISK_ADDR;
703                         run_cmd("ramboot");
704                 }
705 #endif
706                 return 1;
707
708 #ifdef CONFIG_DOWN_PHONE
709         case COMMAND_DOWN_PHONE:
710                 printf("COMMAND_RESET_PHONE\n");
711
712                 usbd_phone_down();
713
714                 *((ulong *) usbd->tx_data) = STATUS_DONE;
715                 usbd->send_data(usbd->tx_data, usbd->tx_len);
716                 return 1;
717
718         case COMMAND_CHANGE_USB:
719                 printf("COMMAND_CHANGE_USB\n");
720
721                 /* Stop USB */
722                 usbd->usb_stop();
723
724                 usbd_path_change();
725
726                 do_reset();
727                 return 0;
728 #endif
729         case COMMAND_CSA_CLEAR:
730                 printf("COMMAND_CSA_CLEAR\n");
731                 part_id = get_part_id("csa");
732                 img_type = IMG_MODEM;
733                 break;
734
735         case COMMAND_PROGRESS:
736                 if (usbd->set_progress)
737                         usbd->set_progress(arg);
738                 return 1;
739
740         default:
741                 printf("Error: Unknown command -> (%d)\n", (int)cmd);
742                 return 1;
743         }
744
745         /* Erase and Write to NAND */
746         switch (img_type) {
747         case IMG_BOOT:
748 #ifdef CONFIG_S5PC1XX
749                 /* Workaround: for prevent revision mismatch */
750                 if (cpu_is_s5pc110() && (down_mode != MODE_FORCE)) {
751                         int img_rev = 1;
752                         long *img_header = (long *)down_ram_addr;
753
754                         if (*img_header == 0xea000012)
755                                 img_rev = 0;
756
757                         if (img_rev != s5pc1xx_get_cpu_rev()) {
758                                 printf("CPU revision mismatch!\n");
759                                 *((ulong *) usbd->tx_data) = STATUS_ERROR;
760                                 usbd->send_data(usbd->tx_data, usbd->tx_len);
761                                 return 0;
762                         }
763                 }
764 #endif
765 #if defined(CONFIG_ENV_IS_IN_NAND) || defined(CONFIG_ENV_IS_IN_ONENAND)
766                 /* Erase the environment also when write bootloader */
767                 {
768                         int param_id;
769                         param_id = get_part_id("params");
770
771                         if (param_id == -1) {
772                                 sprintf(offset, "%x", CONFIG_ENV_OFFSET);
773                                 sprintf(length, "%x", CONFIG_ENV_SIZE);
774                         } else {
775                                 sprintf(offset, "%x", parts[param_id]->offset);
776                                 sprintf(length, "%x", parts[param_id]->size);
777                         }
778                         nand_cmd(0, offset, length, NULL);
779                 }
780 #endif
781                 /* Fall through for write bootloader */
782         case IMG_KERNEL:
783                 sprintf(offset, "%x", parts[part_id]->offset);
784                 sprintf(length, "%x", parts[part_id]->size);
785
786                 /* Erase */
787                 nand_cmd(0, offset, length, NULL);
788                 /* Write */
789                 sprintf(length, "%x", (unsigned int) len);
790                 ret = nand_cmd(1, ramaddr, offset, length);
791                 break;
792
793         /* File Systems */
794         case IMG_FILESYSTEM:
795                 ret = write_file_system(ramaddr, len, offset, length,
796                                 part_id, ubi_update);
797                 break;
798
799         case IMG_MODEM:
800                 sprintf(offset, "%x", parts[part_id]->offset);
801                 sprintf(length, "%x", parts[part_id]->size);
802
803                 /* Erase */
804                 nand_cmd(0, offset, length, NULL);
805
806                 /* Write : arg (0 Modem) / (1 CSA) */
807                 if (!arg) {
808                         sprintf(length, "%x", (unsigned int) len);
809                         ret = nand_cmd(1, ramaddr, offset, length);
810                 }
811                 break;
812
813 #ifdef CONFIG_CMD_MMC
814         case IMG_MMC:
815                 write_file_mmc(usbd, ramaddr, len, offset, length);
816                 break;
817 #endif
818
819         default:
820                 /* Retry? */
821                 write_part--;
822         }
823
824         if (ret) {
825                 /* Retry this commad */
826                 *((ulong *) usbd->tx_data) = STATUS_RETRY;
827                 usbd->send_data(usbd->tx_data, usbd->tx_len);
828                 return 1;
829         } else
830                 *((ulong *) usbd->tx_data) = STATUS_DONE;
831
832         /* Write image success -> Report status */
833         usbd->send_data(usbd->tx_data, usbd->tx_len);
834
835         write_part++;
836
837         /* Reset write count for another image */
838         if (flag) {
839                 write_part = 0;
840                 fs_offset = 0;
841 #ifdef CONFIG_USE_YAFFS
842                 yaffs_len = 0;
843 #endif
844         }
845
846         return 1;
847 }
848
849 static const char *recv_key = "SAMSUNG";
850 static const char *tx_key = "MPL";
851
852 int do_usbd_down(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
853 {
854         struct usbd_ops *usbd;
855         int err;
856
857         if (argc > 1)
858                 down_mode = simple_strtoul(argv[1], NULL, 10);
859         else
860                 down_mode = MODE_NORMAL;
861
862         printf("USB Downloader v%s (%d)\n", APP_VERSION, down_mode);
863
864         /* get partition info */
865         err = get_part_info();
866         if (err)
867                 return err;
868
869         /* interface setting */
870         usbd = usbd_set_interface(&usbd_ops);
871         down_ram_addr = usbd->ram_addr;
872
873         /* init the usb controller */
874         usbd->usb_init();
875
876         /* receive setting */
877         usbd->recv_setup(usbd->rx_data, usbd->rx_len);
878
879         /* detect the download request from Host PC */
880         if (usbd->recv_data()) {
881                 if (strncmp(usbd->rx_data, recv_key, strlen(recv_key)) == 0) {
882                         printf("Download request from the Host PC\n");
883                         msleep(30);
884
885                         strcpy(usbd->tx_data, tx_key);
886                         usbd->send_data(usbd->tx_data, usbd->tx_len);
887                 } else {
888                         printf("No download request from the Host PC!! 1\n");
889                         return 0;
890                 }
891         } else {
892                 printf("No download request from the Host PC!!\n");
893                 return 0;
894         }
895
896         printf("Receive the packet\n");
897
898         /* receive the data from Host PC */
899         while (1) {
900                 usbd->recv_setup(usbd->rx_data, usbd->rx_len);
901
902                 if (usbd->recv_data()) {
903                         if (process_data(usbd) == 0)
904                                 return 0;
905                 }
906         }
907
908         return 0;
909 }
910
911 U_BOOT_CMD(usbdown, CONFIG_SYS_MAXARGS, 1, do_usbd_down,
912         "Initialize USB device and Run USB Downloader (specific)",
913         "- normal mode\n"
914         "usbdown mode - specific mode (0: NORAML, 1: FORCE)\n"
915 );