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