Merge branch 'master' of git://git.denx.de/u-boot
[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.5.3"
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         } else if (type == 3) {
203                 char *argv[] = {nand_name, "lock", p1, p2};
204                 printf("%s %s %s %s\n", argv[0], argv[1], argv[2], argv[3]);
205                 ret = nand_func(NULL, 0, 4, argv);
206         }
207
208         if (ret)
209                 printf("Error: NAND Command\n");
210
211         return ret;
212 }
213
214 #ifdef CONFIG_CMD_UBI
215 int do_ubi(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
216
217 int ubi_cmd(int part, char *p1, char *p2, char *p3)
218 {
219         int ret = 1;
220
221         if (part == RAMDISK_PART_ID) {
222                 char *argv[] = {"ubi", "write", p1, "rootfs.cramfs", p2, p3};
223                 printf("%s %s %s %s %s %s\n", argv[0], argv[1], argv[2],
224                                 argv[3], argv[4], argv[5]);
225                 ret = do_ubi(NULL, 0, 6, argv);
226         } else if (part == FILESYSTEM_PART_ID) {
227                 char *argv[] = {"ubi", "write", p1, "factoryfs.cramfs", p2, p3};
228                 printf("%s %s %s %s %s %s\n", argv[0], argv[1], argv[2],
229                                 argv[3], argv[4], argv[5]);
230                 ret = do_ubi(NULL, 0, 6, argv);
231         } else if (part == FILESYSTEM2_PART_ID) {
232                 char *argv[] = {"ubi", "write", p1, "datafs.ubifs", p2, p3};
233                 printf("%s %s %s %s %s %s\n", argv[0], argv[1], argv[2],
234                                 argv[3], argv[4], argv[5]);
235                 ret = do_ubi(NULL, 0, 6, argv);
236         }
237
238         return ret;
239 }
240 #endif
241
242 #ifdef CONFIG_CMD_MMC
243 #include <fat.h>
244
245 extern int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
246
247 static int mmc_cmd(int ops, char *p1, char *p2, char *p3)
248 {
249         int ret;
250
251         if (ops) {
252                 char *argv[] = {"mmc", "write", "0", p1, p2, p3};
253                 ret = do_mmcops(NULL, 0, 6, argv);
254         } else {
255                 char *argv[] = {"mmc", "read", "0", p1, p2, p3};
256                 ret = do_mmcops(NULL, 0, 6, argv);
257         }
258
259         return ret;
260 }
261
262 static unsigned int cur_blk_offset;
263 static unsigned int cur_part_size;
264 static unsigned int cur_partition;
265
266 static unsigned int mmc_parts;
267 static unsigned int mmc_part_write;
268
269 struct partition_info {
270         u32 size;
271         u32 checksum;
272         u32 res;
273 } __attribute__((packed));
274
275 struct partition_header {
276         u8                      fat32head[16];  /* RFSHEAD identifier */
277         struct partition_info   partition[4];
278         u8                      res[448];       /* reserved */
279 } __attribute__((packed));
280
281 struct partition_table {
282         u8      boot_flag;
283         u8      chs_begin[3];
284         u8      type_code;
285         u8      chs_end[3];
286         u32     lba_begin;
287         u32     num_sectors;
288 } __attribute__((packed));
289
290 struct mbr_table {
291         u8                      boot_code[446];
292         struct partition_table  partition[4];
293         u16                     signature;
294 } __attribute__((packed));
295
296 #define MBR_OFFSET      0x10
297
298 struct partition_header part_info;
299 struct mbr_table mbr_info;
300
301 static int write_mmc_partition(struct usbd_ops *usbd, u32 *ram_addr, u32 len)
302 {
303         unsigned int blocks;
304         char offset[12], length[12], ramaddr[12];
305         int i;
306         int loop;
307         u32 cnt;
308         int ret;
309
310         if (cur_part_size > len) {
311                 blocks = len / usbd->mmc_blk;
312                 ret = -1;
313         } else {
314                 blocks = cur_part_size / usbd->mmc_blk;
315                 ret = len - cur_part_size;
316         }
317
318         if (len % usbd->mmc_blk)
319                 blocks++;
320
321         loop = blocks / usbd->mmc_max;
322         if (blocks % usbd->mmc_max)
323                 loop++;
324
325         for (i = 0; i < loop; i++) {
326                 if (i == 0) {
327                         cnt = blocks % usbd->mmc_max;
328                         if (cnt == 0)
329                                 cnt = usbd->mmc_max;
330                 } else {
331                         cnt = usbd->mmc_max;
332                 }
333
334                 sprintf(length, "%x", cnt);
335                 sprintf(offset, "%x", cur_blk_offset);
336                 sprintf(ramaddr, "0x%x", *ram_addr);
337                 mmc_cmd(OPS_WRITE, ramaddr, offset, length);
338
339                 cur_blk_offset += cnt;
340
341                 *ram_addr += (cnt * usbd->mmc_blk);
342         }
343
344         return ret;
345 }
346
347 static int write_file_mmc(struct usbd_ops *usbd, char *ramaddr, u32 len,
348                 char *offset, char *length)
349 {
350         u32 ram_addr;
351         int i;
352         int ret;
353
354         if (!usbd->mmc_total) {
355                 printf("MMC is not supported!\n");
356                 return 0;
357         }
358
359         ram_addr = (u32)down_ram_addr;
360
361         if (cur_blk_offset == 0) {
362                 boot_sector *bs;
363                 struct mbr_table *mbr;
364
365                 memcpy(&part_info, (void *)ram_addr,
366                                 sizeof(struct partition_header));
367
368                 ram_addr += sizeof(struct partition_header);
369                 len -= sizeof(struct partition_header);
370                 mbr = (struct mbr_table*)ram_addr;
371
372                 /* modify sectors of p1 */
373                 mbr->partition[0].num_sectors = usbd->mmc_total -
374                                 (MBR_OFFSET +
375                                 mbr->partition[1].num_sectors +
376                                 mbr->partition[2].num_sectors +
377                                 mbr->partition[3].num_sectors);
378
379                 mmc_parts++;
380
381                 /* modify lba_begin of p2 and p3 and p4 */
382                 for (i = 1; i < 4; i++) {
383                         if (part_info.partition[i].size == 0)
384                                 break;
385
386                         mmc_parts++;
387                         mbr->partition[i].lba_begin =
388                                 mbr->partition[i - 1].lba_begin +
389                                 mbr->partition[i - 1].num_sectors;
390                 }
391
392                 /* copy MBR */
393                 memcpy(&mbr_info, mbr, sizeof(struct mbr_table));
394
395                 printf("Total Size: 0x%08x #parts %d\n",
396                                 (unsigned int)usbd->mmc_total, mmc_parts);
397                 for (i = 0; i < mmc_parts; i++) {
398                         printf("p%d\t0x%08x\t0x%08x\n", i + 1,
399                                 mbr_info.partition[i].lba_begin,
400                                 mbr_info.partition[i].num_sectors);
401                 }
402
403                 /* write MBR */
404                 sprintf(length, "%x", MBR_OFFSET);
405                 sprintf(offset, "%x", 0);
406                 sprintf(ramaddr, "0x%x", (u32)ram_addr);
407                 ret = mmc_cmd(OPS_WRITE, ramaddr, offset, length);
408
409                 ram_addr += (MBR_OFFSET * usbd->mmc_blk);
410                 len -= (MBR_OFFSET * usbd->mmc_blk);
411
412                 cur_blk_offset = MBR_OFFSET;
413                 cur_partition = 0;
414                 cur_part_size = part_info.partition[0].size;
415
416                 /* modify p1's total sector */
417                 bs = (boot_sector *)ram_addr;
418                 bs->total_sect = mbr_info.partition[0].num_sectors;
419
420                 printf("\nWrite Partition %d.. %d blocks\n",
421                         cur_partition + 1,
422                         part_info.partition[cur_partition].size /
423                         (int)usbd->mmc_blk);
424         }
425
426         for (i = cur_partition; i < mmc_parts; i++) {
427                 ret = write_mmc_partition(usbd, &ram_addr, len);
428
429                 if (ret < 0) {
430                         cur_part_size -= len;
431                         break;
432                 } else {
433                         cur_partition++;
434                         cur_part_size =
435                                 part_info.partition[cur_partition].size;
436                         cur_blk_offset =
437                                 mbr_info.partition[cur_partition].lba_begin;
438
439                         if (ret == 0)
440                                 break;
441                         else
442                                 len = ret;
443
444                         printf("\nWrite Partition %d.. %d blocks\n",
445                                 cur_partition + 1,
446                                 part_info.partition[cur_partition].size /
447                                 (int)usbd->mmc_blk);
448                 }
449         }
450
451         return 0;
452 }
453
454 static int write_file_mmc_part(struct usbd_ops *usbd, char *ramaddr, u32 len,
455                 char *offset, char *length)
456 {
457         u32 ram_addr;
458         int ret;
459         int i;
460
461         ram_addr = (u32)down_ram_addr;
462
463         if (cur_blk_offset == 0) {
464                 /* read MBR */
465                 sprintf(length, "%x", MBR_OFFSET);
466                 sprintf(offset, "%x", 0);
467                 sprintf(ramaddr, "0x%x", (u32)&mbr_info);
468                 ret = mmc_cmd(OPS_READ, ramaddr, offset, length);
469
470                 for (i = 0; i < 4; i++) {
471                         printf("p%d\t0x%08x\t0x%08x\n", i + 1,
472                                 mbr_info.partition[i].lba_begin,
473                                 mbr_info.partition[i].num_sectors);
474                 }
475
476                 cur_blk_offset = (unsigned int)
477                         mbr_info.partition[mmc_part_write - 1].lba_begin;
478                 cur_partition = mmc_part_write - 1;
479                 cur_part_size = (unsigned int)len;
480
481                 if (mmc_part_write == 1) {
482                         ram_addr += sizeof(boot_sector);
483                         cur_blk_offset += sizeof(boot_sector) / usbd->mmc_blk;
484                         len -= sizeof(boot_sector);
485                 }
486         }
487
488         printf("\nWrite Partition %d.. %d blocks\n",
489                 cur_partition + 1,
490                 len / (int)usbd->mmc_blk);
491
492         write_mmc_partition(usbd, &ram_addr, len);
493
494         return 0;
495 }
496 #endif
497
498 static int write_file_system(char *ramaddr, ulong len, char *offset,
499                 char *length, int part_num, int ubi_update)
500 {
501 #ifdef CONFIG_USE_YAFFS
502         int actual_len = 0;
503         int yaffs_write = 0;
504 #endif
505         int ret = 0;
506
507 #ifdef CONFIG_CMD_UBI
508         /* UBI Update */
509         if (ubi_update) {
510                 sprintf(length, "0x%x", (uint)len);
511                 ret = ubi_cmd(part_id, ramaddr, length, "cont");
512                 return ret;
513         }
514 #endif
515
516         /* Erase entire partition at the first writing */
517         if (write_part == 0 && ubi_update == 0) {
518                 sprintf(offset, "0x%x", (uint)parts[part_num]->offset);
519                 sprintf(length, "0x%x", (uint)parts[part_num]->size);
520                 nand_cmd(0, offset, length, NULL);
521         }
522
523 #ifdef CONFIG_USE_YAFFS
524         /* if using yaffs, wirte size must be 2112*X
525          * so, must have to realloc, and writing */
526         if (!strcmp("yaffs", getenv(parts[part_num]->name))) {
527                 yaffs_write = 1;
528
529                 memcpy((void *)down_ram_addr, yaffs_data, yaffs_len);
530
531                 actual_len = len + yaffs_len;
532                 yaffs_len = actual_len % YAFFS_PAGE;
533                 len = actual_len - yaffs_len;
534
535                 memset(yaffs_data, 0x00, YAFFS_PAGE);
536                 memcpy(yaffs_data, (char *)down_ram_addr + len, yaffs_len);
537         }
538 #endif
539
540         sprintf(offset, "0x%x", (uint)(parts[part_num]->offset + fs_offset));
541         sprintf(length, "0x%x", (uint)len);
542
543 #ifdef CONFIG_USE_YAFFS
544         if (yaffs_write)
545                 ret = nand_cmd(2, ramaddr, offset, length);
546         else
547                 ret = nand_cmd(1, ramaddr, offset, length);
548
549         if (!strcmp("yaffs", getenv(parts[part_num]->name)))
550                 fs_offset += len / YAFFS_PAGE * NAND_PAGE_SIZE;
551         else
552                 fs_offset += len;
553
554 #else
555         fs_offset += len;
556         ret = nand_cmd(1, ramaddr, offset, length);
557 #endif
558
559         return ret;
560 }
561
562 /* Parsing received data packet and Process data */
563 static int process_data(struct usbd_ops *usbd)
564 {
565         ulong cmd = 0, arg = 0, ofs = 0, len = 0, flag = 0;
566         char offset[12], length[12], ramaddr[12];
567         int recvlen = 0;
568         unsigned int blocks = 0;
569         int ret = 0;
570         int ubi_update = 0;
571         int ubi_mode = 0;
572         int img_type;
573
574         sprintf(ramaddr, "0x%x", (uint) down_ram_addr);
575
576         /* Parse command */
577         cmd  = *((ulong *) usbd->rx_data + 0);
578         arg  = *((ulong *) usbd->rx_data + 1);
579         len  = *((ulong *) usbd->rx_data + 2);
580         flag = *((ulong *) usbd->rx_data + 3);
581
582         /* Reset tx buffer */
583         memset(usbd->tx_data, 0, sizeof(usbd->tx_data));
584
585         ubi_mode = check_ubi_mode();
586
587         switch (cmd) {
588         case COMMAND_DOWNLOAD_IMAGE:
589                 printf("\nCOMMAND_DOWNLOAD_IMAGE\n");
590
591 #ifdef CONFIG_USE_YAFFS
592                 usbd->recv_setup((char *)down_ram_addr + yaffs_len, (int)len);
593                 printf("Download to 0x%08x, %d bytes\n",
594                                 (uint)down_ram_addr + yaffs_len, (int)len);
595 #else
596                 usbd->recv_setup((char *)down_ram_addr, (int)len);
597                 printf("Download to 0x%08x, %d bytes\n",
598                                 (uint)down_ram_addr, (int)len);
599 #endif
600                 /* response */
601                 usbd->send_data(usbd->tx_data, usbd->tx_len);
602
603                 /* Receive image by using dma */
604                 recvlen = usbd->recv_data();
605                 if (recvlen < len) {
606                         printf("Error: wrong image size -> %d/%d\n",
607                                         (int)recvlen, (int)len);
608
609                         /* Retry this commad */
610                         *((ulong *) usbd->tx_data) = STATUS_RETRY;
611                 } else
612                         *((ulong *) usbd->tx_data) = STATUS_DONE;
613
614                 usbd->send_data(usbd->tx_data, usbd->tx_len);
615                 return 1;
616
617         /* Report partition info */
618         case COMMAND_PARTITION_SYNC:
619                 part_id = arg;
620
621 #ifdef CONFIG_CMD_UBI
622                 if (ubi_mode) {
623                         if (part_id == RAMDISK_PART_ID ||
624                             part_id == FILESYSTEM_PART_ID ||
625                             part_id == FILESYSTEM2_PART_ID) {
626                                 /* change to yaffs style */
627                                 get_part_info();
628                         }
629                 } else {
630                         if (part_id == FILESYSTEM3_PART_ID) {
631                                 /* change ubi style */
632                                 get_part_info();
633                         }
634                 }
635 #endif
636
637                 if (part_id == FILESYSTEM3_PART_ID)
638                         part_id = get_part_id("UBI");
639                 else if (part_id == MODEM_PART_ID)
640                         part_id = get_part_id("modem");
641                 else if (part_id == KERNEL_PART_ID)
642                         part_id = get_part_id("kernel");
643 #ifdef CONFIG_MIRAGE
644                 if (part_id)
645                         part_id--;
646 #endif
647                 printf("COMMAND_PARTITION_SYNC - Part%d\n", part_id);
648
649                 blocks = parts[part_id]->size / 1024 / 128;
650                 printf("COMMAND_PARTITION_SYNC - Part%d, %d blocks\n",
651                                 part_id, blocks);
652
653                 *((ulong *) usbd->tx_data) = blocks;
654                 usbd->send_data(usbd->tx_data, usbd->tx_len);
655                 return 1;
656
657         case COMMAND_WRITE_PART_0:
658                 /* Do nothing */
659                 printf("COMMAND_WRITE_PART_0\n");
660                 return 1;
661
662         case COMMAND_WRITE_PART_1:
663                 printf("COMMAND_WRITE_PART_BOOT\n");
664                 part_id = get_part_id("bootloader");
665                 img_type = IMG_BOOT;
666                 break;
667
668         case COMMAND_WRITE_PART_2:
669         case COMMAND_ERASE_PARAMETER:
670                 printf("COMMAND_PARAMETER - not support!\n");
671                 break;
672
673         case COMMAND_WRITE_PART_3:
674                 printf("COMMAND_WRITE_KERNEL\n");
675                 part_id = get_part_id("kernel");
676                 img_type = IMG_KERNEL;
677                 break;
678
679         case COMMAND_WRITE_PART_4:
680                 printf("COMMAND_WRITE_ROOTFS\n");
681                 part_id = get_part_id("Root");
682                 img_type = IMG_FILESYSTEM;
683                 ubi_update = arg;
684                 break;
685
686         case COMMAND_WRITE_PART_5:
687                 printf("COMMAND_WRITE_FACTORYFS\n");
688                 part_id = get_part_id("Fact");
689                 img_type = IMG_FILESYSTEM;
690                 ubi_update = arg;
691                 break;
692
693         case COMMAND_WRITE_PART_6:
694                 printf("COMMAND_WRITE_DATAFS\n");
695                 part_id = get_part_id("Data");
696                 img_type = IMG_FILESYSTEM;
697                 ubi_update = arg;
698                 break;
699
700         case COMMAND_WRITE_PART_7:
701                 printf("COMMAND_WRITE_UBI\n");
702                 part_id = get_part_id("UBI");
703                 img_type = IMG_FILESYSTEM;
704                 ubi_update = 0;
705                 /* someday, it will be deleted */
706                 get_part_info();
707                 break;
708
709         case COMMAND_WRITE_PART_8:
710                 printf("COMMAND_WRITE_MODEM\n");
711                 part_id = get_part_id("modem");
712                 img_type = IMG_MODEM;
713                 break;
714
715 #ifdef CONFIG_CMD_MMC
716         case COMMAND_WRITE_PART_9:
717                 printf("COMMAND_WRITE_MMC\n");
718                 img_type = IMG_MMC;
719                 mmc_part_write = arg;
720                 break;
721 #endif
722
723         case COMMAND_WRITE_UBI_INFO:
724                 printf("COMMAND_WRITE_UBI_INFO\n");
725
726                 if (ubi_mode) {
727 #ifdef CONFIG_CMD_UBI
728                         part_id = arg-1;
729                         sprintf(length, "0x%x", (uint)len);
730                         ret = ubi_cmd(part_id, ramaddr, length, "begin");
731                 } else {
732 #endif
733                         printf("Error: Not UBI mode\n");
734                         ret = 1;
735                 }
736
737                 *((ulong *) usbd->tx_data) = ret;
738                 /* Write image success -> Report status */
739                 usbd->send_data(usbd->tx_data, usbd->tx_len);
740
741                 return !ret;
742         /* Download complete -> reset */
743         case COMMAND_RESET_PDA:
744                 printf("\nDownload finished and Auto reset!\nWait........\n");
745
746                 /* Stop USB */
747                 usbd->usb_stop();
748
749                 if (usbd->cpu_reset)
750                         usbd->cpu_reset();
751                 else
752                         do_reset();
753
754                 return 0;
755
756         /* Error */
757         case COMMAND_RESET_USB:
758                 printf("\nError is occured!(maybe previous step)->\
759                                 Turn off and restart!\n");
760
761                 /* Stop USB */
762                 usbd->usb_stop();
763                 return 0;
764
765         case COMMAND_RAM_BOOT:
766                 usbd->usb_stop();
767                 boot_cmd(ramaddr);
768                 return 0;
769
770         case COMMAND_RAMDISK_MODE:
771                 printf("COMMAND_RAMDISK_MODE\n");
772 #ifdef CONFIG_RAMDISK_ADDR
773                 if (arg) {
774                         down_ram_addr = usbd->ram_addr;
775                 } else {
776                         down_ram_addr = CONFIG_RAMDISK_ADDR;
777                         run_cmd("ramboot");
778                 }
779 #endif
780                 return 1;
781
782 #ifdef CONFIG_DOWN_PHONE
783         case COMMAND_DOWN_PHONE:
784                 printf("COMMAND_RESET_PHONE\n");
785
786                 usbd_phone_down();
787
788                 *((ulong *) usbd->tx_data) = STATUS_DONE;
789                 usbd->send_data(usbd->tx_data, usbd->tx_len);
790                 return 1;
791
792         case COMMAND_CHANGE_USB:
793                 printf("COMMAND_CHANGE_USB\n");
794
795                 /* Stop USB */
796                 usbd->usb_stop();
797
798                 usbd_path_change();
799
800                 do_reset();
801                 return 0;
802 #endif
803         case COMMAND_CSA_CLEAR:
804                 printf("COMMAND_CSA_CLEAR\n");
805                 part_id = get_part_id("csa");
806                 img_type = IMG_MODEM;
807                 break;
808
809         case COMMAND_PROGRESS:
810                 if (usbd->set_progress)
811                         usbd->set_progress(arg);
812                 return 1;
813
814         default:
815                 printf("Error: Unknown command -> (%d)\n", (int)cmd);
816                 return 1;
817         }
818
819         /* Erase and Write to NAND */
820         switch (img_type) {
821         case IMG_BOOT:
822                 ofs = parts[part_id]->offset;
823 #ifdef CONFIG_RECOVERY
824         {
825                 /* block is fixed:
826                         1m = ipl(16k)+recovery(240k)+bootloader(768k)*/
827                 long *buf = (long *)down_ram_addr;
828                 u32 ofst;
829                 u32 bootloader_edge = parts[part_id]->size;
830                 u32 bootloader_addr = bootloader_edge >> 2;
831                 u32 recovery_edge = bootloader_addr;
832                 u32 recovery_addr = recovery_edge >> 4;
833                 u32 ipl_addr = 0;
834
835                 if (len > bootloader_addr) {
836                         ofst = bootloader_addr / sizeof(buf);
837                         if (*(buf + ofst) == 0xea000012) {
838                                 /* case: ipl + recovery + bootloader */
839                                 printf("target: ipl + recovery + loader\n");
840                                 ofs = ipl_addr;
841                         } else {
842                                 /* case: unknown format */
843                                 printf("target: unknown\n");
844                                 *((ulong *) usbd->tx_data) = STATUS_ERROR;
845                                 usbd->send_data(usbd->tx_data, usbd->tx_len);
846                                 return 0;
847                         }
848                 } else {
849                         ofst = recovery_addr/sizeof(buf);
850                         if (*(buf + ofst) == 0xea000012 &&
851                                 *(buf + ofst - 1) == 0x00000000) {
852                                 /* case: ipl + bootloader (old type) */
853                                 printf("target: ipl + bootloader\n");
854                                 ofs = ipl_addr;
855                         } else {
856                                 /* case: bootloader only */
857                                 printf("target: bootloader\n");
858                                 ofs = bootloader_addr;
859
860                                 /* skip revision check */
861                                 down_mode = MODE_FORCE;
862                         }
863                 }
864
865                 sprintf(offset, "%x", (uint)ofs);
866                 sprintf(length, "%x", parts[part_id]->size);
867
868                 /* check block is locked/locked-tight */
869                 ret = nand_cmd(3, offset, length, NULL);
870                 if (ret) {
871                         printf("target is locked%s\n",
872                                 (ret == 1) ? "-tight" : "");
873                         printf("-> try at recovery mode "
874                                 "to update 'system'.\n");
875                         printf("   how-to: reset "
876                                 "while pressing volume up and down.\n");
877                         *((ulong *) usbd->tx_data) = STATUS_ERROR;
878                         usbd->send_data(usbd->tx_data, usbd->tx_len);
879                         return 0;
880                 }
881         }
882 #endif
883 #ifdef CONFIG_S5PC1XX
884                 /* Workaround: for prevent revision mismatch */
885                 if (cpu_is_s5pc110() && (down_mode != MODE_FORCE)) {
886                         int img_rev = 1;
887                         long *img_header = (long *)down_ram_addr;
888
889                         if (*img_header == 0xea000012)
890                                 img_rev = 0;
891                         else if (*(img_header + 0x400) == 0xea000012)
892                                 img_rev = 2;
893
894                         if (img_rev != s5pc1xx_get_cpu_rev()) {
895                                 printf("CPU revision mismatch!\n"
896                                         "bootloader is %s%s\n"
897                                         "download image is %s%s\n",
898                                         s5pc1xx_get_cpu_rev() ? "EVT1" : "EVT0",
899                                         s5pc1xx_get_cpu_rev() == 2 ? "-Fused" : "",
900                                         img_rev ? "EVT1" : "EVT0",
901                                         img_rev == 2 ? "-Fused" : "");
902                                 *((ulong *) usbd->tx_data) = STATUS_ERROR;
903                                 usbd->send_data(usbd->tx_data, usbd->tx_len);
904                                 return 0;
905                         }
906                 }
907 #endif
908 #if defined(CONFIG_ENV_IS_IN_NAND) || defined(CONFIG_ENV_IS_IN_ONENAND)
909                 /* Erase the environment also when write bootloader */
910                 {
911                         int param_id;
912                         param_id = get_part_id("params");
913
914                         if (param_id == -1) {
915                                 sprintf(offset, "%x", CONFIG_ENV_ADDR);
916                                 sprintf(length, "%x", CONFIG_ENV_SIZE);
917                         } else {
918                                 sprintf(offset, "%x", parts[param_id]->offset);
919                                 sprintf(length, "%x", parts[param_id]->size);
920                         }
921                         nand_cmd(0, offset, length, NULL);
922                 }
923 #endif
924                 sprintf(offset, "%x", (uint)ofs);
925                 if (ofs != 0)
926                         sprintf(length, "%x", parts[part_id]->size - (uint)ofs);
927                 else
928                         sprintf(length, "%x", parts[part_id]->size);
929
930                 /* Erase */
931                 nand_cmd(0, offset, length, NULL);
932                 /* Write */
933                 sprintf(length, "%x", (unsigned int) len);
934                 ret = nand_cmd(1, ramaddr, offset, length);
935                 break;
936
937         case IMG_KERNEL:
938                 sprintf(offset, "%x", parts[part_id]->offset);
939                 sprintf(length, "%x", parts[part_id]->size);
940
941                 /* Erase */
942                 nand_cmd(0, offset, length, NULL);
943                 /* Write */
944                 sprintf(length, "%x", (unsigned int) len);
945                 ret = nand_cmd(1, ramaddr, offset, length);
946                 break;
947
948         /* File Systems */
949         case IMG_FILESYSTEM:
950                 /* Erase the qboot also when write ubi image */
951                 {
952                         int qboot_id;
953                         qboot_id = get_part_id("qboot");
954
955                         if (qboot_id != -1) {
956                                 sprintf(offset, "%x", parts[qboot_id]->offset);
957                                 sprintf(length, "%x", parts[qboot_id]->size);
958                                 nand_cmd(0, offset, length, NULL);
959                         }
960                 }
961                 ret = write_file_system(ramaddr, len, offset, length,
962                                 part_id, ubi_update);
963                 break;
964
965         case IMG_MODEM:
966                 sprintf(offset, "%x", parts[part_id]->offset);
967                 sprintf(length, "%x", parts[part_id]->size);
968
969                 /* Erase */
970                 if (!arg)
971                         nand_cmd(0, offset, length, NULL);
972                 else
973                         printf("CSA Clear will be skipped temporary\n");
974
975                 /* Write : arg (0 Modem) / (1 CSA) */
976                 if (!arg) {
977                         sprintf(length, "%x", (unsigned int) len);
978                         ret = nand_cmd(1, ramaddr, offset, length);
979                 }
980                 break;
981
982 #ifdef CONFIG_CMD_MMC
983         case IMG_MMC:
984                 if (mmc_part_write)
985                         ret = write_file_mmc_part(usbd, ramaddr,
986                                                 len, offset, length);
987                 else
988                         ret = write_file_mmc(usbd, ramaddr,
989                                                 len, offset, length);
990                 break;
991 #endif
992
993         default:
994                 /* Retry? */
995                 write_part--;
996         }
997
998         if (ret) {
999                 /* Retry this commad */
1000                 *((ulong *) usbd->tx_data) = STATUS_RETRY;
1001                 usbd->send_data(usbd->tx_data, usbd->tx_len);
1002                 return 1;
1003         } else
1004                 *((ulong *) usbd->tx_data) = STATUS_DONE;
1005
1006         /* Write image success -> Report status */
1007         usbd->send_data(usbd->tx_data, usbd->tx_len);
1008
1009         write_part++;
1010
1011         /* Reset write count for another image */
1012         if (flag) {
1013                 write_part = 0;
1014                 fs_offset = 0;
1015 #ifdef CONFIG_USE_YAFFS
1016                 yaffs_len = 0;
1017 #endif
1018         }
1019
1020         return 1;
1021 }
1022
1023 static const char *recv_key = "SAMSUNG";
1024 static const char *tx_key = "MPL";
1025
1026 int do_usbd_down(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
1027 {
1028         struct usbd_ops *usbd;
1029         int err;
1030
1031         if (argc > 1)
1032                 down_mode = simple_strtoul(argv[1], NULL, 10);
1033         else
1034                 down_mode = MODE_NORMAL;
1035
1036         printf("USB Downloader v%s\n", APP_VERSION);
1037
1038         /* get partition info */
1039         err = get_part_info();
1040         if (err)
1041                 return err;
1042
1043         /* interface setting */
1044         usbd = usbd_set_interface(&usbd_ops);
1045         down_ram_addr = usbd->ram_addr;
1046
1047         /* init the usb controller */
1048         usbd->usb_init();
1049
1050         /* receive setting */
1051         usbd->recv_setup(usbd->rx_data, usbd->rx_len);
1052
1053         /* detect the download request from Host PC */
1054         if (usbd->recv_data()) {
1055                 if (strncmp(usbd->rx_data, recv_key, strlen(recv_key)) == 0) {
1056                         printf("Download request from the Host PC\n");
1057                         msleep(30);
1058
1059                         strcpy(usbd->tx_data, tx_key);
1060                         usbd->send_data(usbd->tx_data, usbd->tx_len);
1061                 } else {
1062                         printf("No download request from the Host PC!! 1\n");
1063                         return 0;
1064                 }
1065         } else {
1066                 printf("No download request from the Host PC!!\n");
1067                 return 0;
1068         }
1069
1070         printf("Receive the packet\n");
1071
1072         /* receive the data from Host PC */
1073         while (1) {
1074                 usbd->recv_setup(usbd->rx_data, usbd->rx_len);
1075
1076                 if (usbd->recv_data()) {
1077                         if (process_data(usbd) == 0)
1078                                 return 0;
1079                 }
1080         }
1081
1082         return 0;
1083 }
1084
1085 U_BOOT_CMD(usbdown, CONFIG_SYS_MAXARGS, 1, do_usbd_down,
1086         "Initialize USB device and Run USB Downloader (specific)",
1087         "- normal mode\n"
1088         "usbdown mode - specific mode (0: NORAML, 1: FORCE)\n"
1089 );