usbd: add CSA Clear
[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 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         int img_type;
499
500         sprintf(ramaddr, "0x%x", (uint) down_ram_addr);
501
502         /* Parse command */
503         cmd  = *((ulong *) usbd->rx_data + 0);
504         arg  = *((ulong *) usbd->rx_data + 1);
505         len  = *((ulong *) usbd->rx_data + 2);
506         flag = *((ulong *) usbd->rx_data + 3);
507
508         /* Reset tx buffer */
509         memset(usbd->tx_data, 0, sizeof(usbd->tx_data));
510
511         ubi_mode = check_ubi_mode();
512
513         switch (cmd) {
514         case COMMAND_DOWNLOAD_IMAGE:
515                 printf("\nCOMMAND_DOWNLOAD_IMAGE\n");
516
517 #ifdef CONFIG_USE_YAFFS
518                 usbd->recv_setup((char *)down_ram_addr + yaffs_len, (int)len);
519                 printf("Download to 0x%08x, %d bytes\n",
520                                 (uint)down_ram_addr + yaffs_len, (int)len);
521 #else
522                 usbd->recv_setup((char *)down_ram_addr, (int)len);
523                 printf("Download to 0x%08x, %d bytes\n",
524                                 (uint)down_ram_addr, (int)len);
525 #endif
526                 /* response */
527                 usbd->send_data(usbd->tx_data, usbd->tx_len);
528
529                 /* Receive image by using dma */
530                 recvlen = usbd->recv_data();
531                 if (recvlen < len) {
532                         printf("Error: wrong image size -> %d/%d\n",
533                                         (int)recvlen, (int)len);
534
535                         /* Retry this commad */
536                         *((ulong *) usbd->tx_data) = STATUS_RETRY;
537                 } else
538                         *((ulong *) usbd->tx_data) = STATUS_DONE;
539
540                 usbd->send_data(usbd->tx_data, usbd->tx_len);
541                 return 1;
542
543         /* Report partition info */
544         case COMMAND_PARTITION_SYNC:
545                 part_id = arg;
546
547 #ifdef CONFIG_CMD_UBI
548                 if (ubi_mode) {
549                         if (part_id == RAMDISK_PART_ID ||
550                             part_id == FILESYSTEM_PART_ID ||
551                             part_id == FILESYSTEM2_PART_ID) {
552                                 /* change to yaffs style */
553                                 get_part_info();
554                         }
555                 } else {
556                         if (part_id == FILESYSTEM3_PART_ID) {
557                                 /* change ubi style */
558                                 get_part_info();
559                         }
560                 }
561 #endif
562
563                 if (part_id == FILESYSTEM3_PART_ID)
564                         part_id = get_part_id("UBI");
565                 else if (part_id == MODEM_PART_ID)
566                         part_id = get_part_id("modem");
567 #ifdef CONFIG_MIRAGE
568                 if (part_id)
569                         part_id--;
570 #endif
571                 printf("COMMAND_PARTITION_SYNC - Part%d\n", part_id);
572
573                 blocks = parts[part_id]->size / 1024 / 128;
574                 printf("COMMAND_PARTITION_SYNC - Part%d, %d blocks\n",
575                                 part_id, blocks);
576
577                 *((ulong *) usbd->tx_data) = blocks;
578                 usbd->send_data(usbd->tx_data, usbd->tx_len);
579                 return 1;
580
581         case COMMAND_WRITE_PART_0:
582                 /* Do nothing */
583                 printf("COMMAND_WRITE_PART_0\n");
584                 return 1;
585
586         case COMMAND_WRITE_PART_1:
587                 printf("COMMAND_WRITE_PART_BOOT\n");
588                 part_id = get_part_id("bootloader");
589                 img_type = IMG_BOOT;
590                 break;
591
592         case COMMAND_WRITE_PART_2:
593         case COMMAND_ERASE_PARAMETER:
594                 printf("COMMAND_PARAMETER - not support!\n");
595                 break;
596
597         case COMMAND_WRITE_PART_3:
598                 printf("COMMAND_WRITE_KERNEL\n");
599                 part_id = get_part_id("kernel");
600                 img_type = IMG_KERNEL;
601                 break;
602
603         case COMMAND_WRITE_PART_4:
604                 printf("COMMAND_WRITE_ROOTFS\n");
605                 part_id = get_part_id("Root");
606                 img_type = IMG_FILESYSTEM;
607                 ubi_update = arg;
608                 break;
609
610         case COMMAND_WRITE_PART_5:
611                 printf("COMMAND_WRITE_FACTORYFS\n");
612                 part_id = get_part_id("Fact");
613                 img_type = IMG_FILESYSTEM;
614                 ubi_update = arg;
615                 break;
616
617         case COMMAND_WRITE_PART_6:
618                 printf("COMMAND_WRITE_DATAFS\n");
619                 part_id = get_part_id("Data");
620                 img_type = IMG_FILESYSTEM;
621                 ubi_update = arg;
622                 break;
623
624         case COMMAND_WRITE_PART_7:
625                 printf("COMMAND_WRITE_UBI\n");
626                 part_id = get_part_id("UBI");
627                 img_type = IMG_FILESYSTEM;
628                 ubi_update = 0;
629                 /* someday, it will be deleted */
630                 get_part_info();
631                 break;
632
633         case COMMAND_WRITE_PART_8:
634                 printf("COMMAND_WRITE_MODEM\n");
635                 part_id = get_part_id("modem");
636                 img_type = IMG_MODEM;
637                 break;
638
639         case COMMAND_WRITE_PART_9:
640                 printf("COMMAND_WRITE_MMC\n");
641                 img_type = IMG_MMC;
642                 break;
643
644         case COMMAND_WRITE_UBI_INFO:
645                 printf("COMMAND_WRITE_UBI_INFO\n");
646
647                 if (ubi_mode) {
648 #ifdef CONFIG_CMD_UBI
649                         part_id = arg-1;
650                         sprintf(length, "0x%x", (uint)len);
651                         ret = ubi_cmd(part_id, ramaddr, length, "begin");
652                 } else {
653 #endif
654                         printf("Error: Not UBI mode\n");
655                         ret = 1;
656                 }
657
658                 *((ulong *) usbd->tx_data) = ret;
659                 /* Write image success -> Report status */
660                 usbd->send_data(usbd->tx_data, usbd->tx_len);
661
662                 return !ret;
663         /* Download complete -> reset */
664         case COMMAND_RESET_PDA:
665                 printf("\nDownload finished and Auto reset!\nWait........\n");
666
667                 /* Stop USB */
668                 usbd->usb_stop();
669
670                 do_reset();
671                 return 0;
672
673         /* Error */
674         case COMMAND_RESET_USB:
675                 printf("\nError is occured!(maybe previous step)->\
676                                 Turn off and restart!\n");
677
678                 /* Stop USB */
679                 usbd->usb_stop();
680                 return 0;
681
682         case COMMAND_RAM_BOOT:
683                 usbd->usb_stop();
684                 boot_cmd(ramaddr);
685                 return 0;
686
687         case COMMAND_RAMDISK_MODE:
688                 printf("COMMAND_RAMDISK_MODE\n");
689 #ifdef CONFIG_RAMDISK_ADDR
690                 if (arg) {
691                         down_ram_addr = usbd->ram_addr;
692                 } else {
693                         down_ram_addr = CONFIG_RAMDISK_ADDR;
694                         run_cmd("ramboot");
695                 }
696 #endif
697                 return 1;
698
699 #ifdef CONFIG_DOWN_PHONE
700         case COMMAND_DOWN_PHONE:
701                 printf("COMMAND_RESET_PHONE\n");
702
703                 usbd_phone_down();
704
705                 *((ulong *) usbd->tx_data) = STATUS_DONE;
706                 usbd->send_data(usbd->tx_data, usbd->tx_len);
707                 return 1;
708
709         case COMMAND_CHANGE_USB:
710                 printf("COMMAND_CHANGE_USB\n");
711
712                 /* Stop USB */
713                 usbd->usb_stop();
714
715                 usbd_path_change();
716
717                 do_reset();
718                 return 0;
719 #endif
720         case COMMAND_CSA_CLEAR:
721                 printf("COMMAND_CSA_CLEAR\n");
722                 part_id = get_part_id("csa");
723                 img_type = IMG_MODEM;
724                 break;
725
726         case COMMAND_PROGRESS:
727                 if (usbd->set_progress)
728                         usbd->set_progress(arg);
729                 return 1;
730
731         default:
732                 printf("Error: Unknown command -> (%d)\n", (int)cmd);
733                 return 1;
734         }
735
736         /* Erase and Write to NAND */
737         switch (img_type) {
738         case IMG_BOOT:
739 #ifdef CONFIG_S5PC1XX
740                 /* Workaround: for prevent revision mismatch */
741                 if (cpu_is_s5pc110() && (down_mode != MODE_FORCE)) {
742                         int img_rev = 1;
743                         long *img_header = (long *)down_ram_addr;
744
745                         if (*img_header == 0xea000012)
746                                 img_rev = 0;
747
748                         if (img_rev != s5pc1xx_get_cpu_rev()) {
749                                 printf("CPU revision mismatch!\n");
750                                 *((ulong *) usbd->tx_data) = STATUS_ERROR;
751                                 usbd->send_data(usbd->tx_data, usbd->tx_len);
752                                 return 0;
753                         }
754                 }
755 #endif
756 #if defined(CONFIG_ENV_IS_IN_NAND) || defined(CONFIG_ENV_IS_IN_ONENAND)
757                 /* Erase the environment also when write bootloader */
758                 {
759                         int param_id;
760                         param_id = get_part_id("params");
761
762                         if (param_id == -1) {
763                                 sprintf(offset, "%x", CONFIG_ENV_OFFSET);
764                                 sprintf(length, "%x", CONFIG_ENV_SIZE);
765                         } else {
766                                 sprintf(offset, "%x", parts[param_id]->offset);
767                                 sprintf(length, "%x", parts[param_id]->size);
768                         }
769                         nand_cmd(0, offset, length, NULL);
770                 }
771 #endif
772                 /* Fall through for write bootloader */
773         case IMG_KERNEL:
774                 sprintf(offset, "%x", parts[part_id]->offset);
775                 sprintf(length, "%x", parts[part_id]->size);
776
777                 /* Erase */
778                 nand_cmd(0, offset, length, NULL);
779                 /* Write */
780                 sprintf(length, "%x", (unsigned int) len);
781                 ret = nand_cmd(1, ramaddr, offset, length);
782                 break;
783
784         /* File Systems */
785         case IMG_FILESYSTEM:
786                 ret = write_file_system(ramaddr, len, offset, length,
787                                 part_id, ubi_update);
788                 break;
789
790         case IMG_MODEM:
791                 sprintf(offset, "%x", parts[part_id]->offset);
792                 sprintf(length, "%x", parts[part_id]->size);
793
794                 /* Erase */
795                 nand_cmd(0, offset, length, NULL);
796
797                 /* Write : arg (0 Modem) / (1 CSA) */
798                 if (!arg) {
799                         sprintf(length, "%x", (unsigned int) len);
800                         ret = nand_cmd(1, ramaddr, offset, length);
801                 }
802                 break;
803
804 #ifdef CONFIG_CMD_MMC
805         case IMG_MMC:
806                 write_file_mmc(usbd, ramaddr, len, offset, length);
807                 break;
808 #endif
809
810         default:
811                 /* Retry? */
812                 write_part--;
813         }
814
815         if (ret) {
816                 /* Retry this commad */
817                 *((ulong *) usbd->tx_data) = STATUS_RETRY;
818                 usbd->send_data(usbd->tx_data, usbd->tx_len);
819                 return 1;
820         } else
821                 *((ulong *) usbd->tx_data) = STATUS_DONE;
822
823         /* Write image success -> Report status */
824         usbd->send_data(usbd->tx_data, usbd->tx_len);
825
826         write_part++;
827
828         /* Reset write count for another image */
829         if (flag) {
830                 write_part = 0;
831                 fs_offset = 0;
832 #ifdef CONFIG_USE_YAFFS
833                 yaffs_len = 0;
834 #endif
835         }
836
837         return 1;
838 }
839
840 static const char *recv_key = "SAMSUNG";
841 static const char *tx_key = "MPL";
842
843 int do_usbd_down(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
844 {
845         struct usbd_ops *usbd;
846         int err;
847
848         if (argc > 1)
849                 down_mode = simple_strtoul(argv[1], NULL, 10);
850         else
851                 down_mode = MODE_NORMAL;
852
853         printf("USB Downloader v%s (%d)\n", APP_VERSION, down_mode);
854
855         /* get partition info */
856         err = get_part_info();
857         if (err)
858                 return err;
859
860         /* interface setting */
861         usbd = usbd_set_interface(&usbd_ops);
862         down_ram_addr = usbd->ram_addr;
863
864         /* init the usb controller */
865         usbd->usb_init();
866
867         /* receive setting */
868         usbd->recv_setup(usbd->rx_data, usbd->rx_len);
869
870         /* detect the download request from Host PC */
871         if (usbd->recv_data()) {
872                 if (strncmp(usbd->rx_data, recv_key, strlen(recv_key)) == 0) {
873                         printf("Download request from the Host PC\n");
874                         msleep(30);
875
876                         strcpy(usbd->tx_data, tx_key);
877                         usbd->send_data(usbd->tx_data, usbd->tx_len);
878                 } else {
879                         printf("No download request from the Host PC!! 1\n");
880                         return 0;
881                 }
882         } else {
883                 printf("No download request from the Host PC!!\n");
884                 return 0;
885         }
886
887         printf("Receive the packet\n");
888
889         /* receive the data from Host PC */
890         while (1) {
891                 usbd->recv_setup(usbd->rx_data, usbd->rx_len);
892
893                 if (usbd->recv_data()) {
894                         if (process_data(usbd) == 0)
895                                 return 0;
896                 }
897         }
898
899         return 0;
900 }
901
902 U_BOOT_CMD(usbdown, CONFIG_SYS_MAXARGS, 1, do_usbd_down,
903         "Initialize USB device and Run USB Downloader (specific)",
904         "- normal mode\n"
905         "usbdown mode - specific mode (0: NORAML, 1: FORCE)\n"
906 );