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