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