fs: ubifs: code cleanup
[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 #ifdef CONFIG_UBIFS_MK
26 #include <mkfs.ubifs.h>
27 #endif
28
29 #ifdef CONFIG_UBINIZE
30 #include <ubinize.h>
31 #endif
32
33 static const char pszMe[] = "usbd: ";
34
35 static struct usbd_ops usbd_ops;
36
37 static unsigned int part_id;
38 static unsigned int write_part = 0;
39 static unsigned long fs_offset = 0x0;
40
41 #ifdef CONFIG_USE_YAFFS
42 static unsigned int yaffs_len = 0;
43 static unsigned char yaffs_data[2112];
44 #define YAFFS_PAGE 2112
45 #endif
46
47 #define NAND_PAGE_SIZE 2048
48
49 static unsigned long down_ram_addr;
50
51 static int down_mode;
52
53 /* cpu/${CPU} dependent */
54 extern void do_reset(void);
55
56 /* common commands */
57 extern int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
58 extern int do_run(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]);
59
60 int mtdparts_init(void);
61 int find_dev_and_part(const char*, struct mtd_device**, u8*, struct part_info**);
62
63 /* common/cmd_jffs2.c */
64 extern struct list_head devices;
65
66 static u8 count_mtdparts(void)
67 {
68         struct list_head *dentry, *pentry;
69         struct mtd_device *dev;
70         u8 part_num = 0;
71
72         list_for_each(dentry, &devices) {
73                 dev = list_entry(dentry, struct mtd_device, link);
74
75                 /* list partitions for given device */
76                 list_for_each(pentry, &dev->parts)
77                         part_num++;
78         }
79
80         return part_num;
81 }
82
83 #ifdef CONFIG_CMD_UBI
84 static int check_ubi_mode(void)
85 {
86         char *env_ubifs;
87         int ubi_mode;
88
89         env_ubifs = getenv("ubi");
90         ubi_mode = !strcmp(env_ubifs, "enabled");
91
92         return ubi_mode;
93 }
94 #else
95 #define check_ubi_mode()                0
96 #endif
97
98 #ifdef CONFIG_MTD_PARTITIONS
99 static int get_part_info(void)
100 {
101         struct mtd_device *dev;
102         u8 out_partnum;
103         char part_name[12];
104         char nand_name[12];
105         int i;
106         int part_num;
107         int ubi_mode = 0;
108
109 #if defined(CONFIG_CMD_NAND)
110         sprintf(nand_name, "nand0");
111 #elif defined(CONFIG_CMD_ONENAND)
112         sprintf(nand_name, "onenand0");
113 #else
114         printf("Configure your NAND sub-system\n");
115         return 0;
116 #endif
117
118         if (mtdparts_init())
119                 return 0;
120
121         ubi_mode = check_ubi_mode();
122
123         part_num = count_mtdparts();
124         for (i = 0; i < part_num; i++) {
125                 sprintf(part_name, "%s,%d", nand_name, i);
126
127                 if (find_dev_and_part(part_name, &dev, &out_partnum, &parts[i]))
128                         return -EINVAL;
129         }
130
131         return 0;
132 }
133
134 static int get_part_id(char *name)
135 {
136         int nparts = count_mtdparts();
137         int i;
138
139         for (i = 0; i < nparts; i++) {
140                 if (strcmp(parts[i]->name, name) == 0)
141                         return i;
142         }
143
144         printf("Error: Unknown partition -> %s\n", name);
145         return -1;
146 }
147 #else
148 static int get_part_info(void)
149 {
150         printf("Error: Can't get patition information\n");
151         return -EINVAL;
152 }
153
154 static int get_part_id(char *name)
155 {
156         return 0;
157 }
158 #endif
159
160 static void boot_cmd(char *addr)
161 {
162         char *argv[] = { "bootm", addr };
163         do_bootm(NULL, 0, 2, argv);
164 }
165
166 static void run_cmd(char *cmd)
167 {
168         char *argv[] = { "run", cmd };
169         do_run(NULL, 0, 2, argv);
170 }
171
172 #if defined(CONFIG_CMD_NAND)
173 extern int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
174 #elif defined(CONFIG_CMD_ONENAND)
175 extern int do_onenand(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
176 #endif
177
178 /* NAND erase and write using nand command */
179 static int nand_cmd(int type, char *p1, char *p2, char *p3)
180 {
181         int ret = 1;
182         char nand_name[12];
183         int (*nand_func) (cmd_tbl_t *, int, int, char **);
184
185 #if defined(CONFIG_CMD_NAND)
186         sprintf(nand_name, "nand");
187         nand_func = do_nand;
188 #elif defined(CONFIG_CMD_ONENAND)
189         sprintf(nand_name, "onenand");
190         nand_func = do_onenand;
191 #else
192         printf("Configure your NAND sub-system\n");
193         return 0;
194 #endif
195
196         if (type == 0) {
197                 char *argv[] = {nand_name, "erase", p1, p2};
198                 printf("%s %s %s %s\n", argv[0], argv[1], argv[2], argv[3]);
199                 ret = nand_func(NULL, 0, 4, argv);
200         } else if (type == 1) {
201                 char *argv[] = {nand_name, "write", p1, p2, p3};
202                 printf("%s %s %s %s %s\n", argv[0], argv[1], argv[2],
203                                 argv[3], argv[4]);
204                 ret = nand_func(NULL, 0, 5, argv);
205         } else if (type == 2) {
206                 char *argv[] = {nand_name, "write.yaffs", p1, p2, p3};
207                 printf("%s %s %s %s %s\n", argv[0], argv[1], argv[2],
208                                 argv[3], argv[4]);
209                 ret = nand_func(NULL, 0, 5, argv);
210         } else if (type == 3) {
211                 char *argv[] = {nand_name, "lock", p1, p2};
212                 printf("%s %s %s %s\n", argv[0], argv[1], argv[2], argv[3]);
213                 ret = nand_func(NULL, 0, 4, argv);
214         }
215
216         if (ret)
217                 printf("Error: NAND Command\n");
218
219         return ret;
220 }
221
222 #ifdef CONFIG_CMD_UBI
223 int do_ubi(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
224
225 int ubi_cmd(int part, char *p1, char *p2, char *p3)
226 {
227         int ret = 1;
228
229         if (part == RAMDISK_PART_ID) {
230                 char *argv[] = {"ubi", "write", p1, "rootfs.cramfs", p2, p3};
231                 printf("%s %s %s %s %s %s\n", argv[0], argv[1], argv[2],
232                                 argv[3], argv[4], argv[5]);
233                 ret = do_ubi(NULL, 0, 6, argv);
234         } else if (part == FILESYSTEM_PART_ID) {
235                 char *argv[] = {"ubi", "write", p1, "factoryfs.cramfs", p2, p3};
236                 printf("%s %s %s %s %s %s\n", argv[0], argv[1], argv[2],
237                                 argv[3], argv[4], argv[5]);
238                 ret = do_ubi(NULL, 0, 6, argv);
239         } else if (part == FILESYSTEM2_PART_ID) {
240                 char *argv[] = {"ubi", "write", p1, "datafs.ubifs", p2, p3};
241                 printf("%s %s %s %s %s %s\n", argv[0], argv[1], argv[2],
242                                 argv[3], argv[4], argv[5]);
243                 ret = do_ubi(NULL, 0, 6, argv);
244         }
245
246         return ret;
247 }
248 #endif
249
250 #ifdef CONFIG_CMD_MMC
251 #include <fat.h>
252
253 extern int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
254
255 static int mmc_cmd(int ops, char *p1, char *p2, char *p3)
256 {
257         int ret;
258
259         if (ops) {
260                 char *argv[] = {"mmc", "write", "0", p1, p2, p3};
261                 ret = do_mmcops(NULL, 0, 6, argv);
262         } else {
263                 char *argv[] = {"mmc", "read", "0", p1, p2, p3};
264                 ret = do_mmcops(NULL, 0, 6, argv);
265         }
266
267         return ret;
268 }
269
270 #define NORMAL_PARTITION        0
271 #define EXTEND_PARTITION        1
272
273 #define EXTEND_PART_TYPE        5
274
275 #define EXTEND_MAX_PART         32
276
277 static unsigned int cur_blk_offset;
278 static unsigned int cur_part_size;
279 static unsigned int cur_part;
280
281 static unsigned int mmc_parts;
282 static unsigned int mmc_part_write;
283
284 static u8 part_mode = 0;
285
286 struct partition_info {
287         u32 size;
288         u32 checksum;
289         u32 res;
290 } __attribute__((packed));
291
292 struct partition_header {
293         u8                      fat32head[16];  /* RFSHEAD identifier */
294         struct partition_info   partition[EXTEND_MAX_PART];
295         u8                      res[112];       /* reserved */
296 } __attribute__((packed));
297
298 struct partition_table {
299         u8      boot_flag;
300         u8      chs_begin[3];
301         u8      type_code;
302         u8      chs_end[3];
303         u32     lba_begin;
304         u32     num_sectors;
305 } __attribute__((packed));
306
307 struct mbr_table {
308         u8                      boot_code[446];
309         struct partition_table  partition[4];
310         u16                     signature;
311 } __attribute__((packed));
312
313 struct mul_partition_info {
314         u32 lba_begin;
315         u32 num_sectors;
316 } __attribute__((packed));
317
318 #define MBR_OFFSET      0x10
319
320 struct partition_header part_info;
321 struct mbr_table mbr_info;
322 struct mul_partition_info mul_info[EXTEND_MAX_PART];
323
324 static int write_mmc_partition(struct usbd_ops *usbd, u32 *ram_addr, u32 len)
325 {
326         unsigned int blocks;
327         char offset[12], length[12], ramaddr[12];
328         int i;
329         int loop;
330         u32 cnt;
331         int ret;
332
333         if (cur_part_size > len) {
334                 blocks = len / usbd->mmc_blk;
335                 ret = -1;
336         } else {
337                 blocks = cur_part_size / usbd->mmc_blk;
338                 ret = len - cur_part_size;
339         }
340
341         if (len % usbd->mmc_blk)
342                 blocks++;
343
344         loop = blocks / usbd->mmc_max;
345         if (blocks % usbd->mmc_max)
346                 loop++;
347
348         for (i = 0; i < loop; i++) {
349                 if (i == 0) {
350                         cnt = blocks % usbd->mmc_max;
351                         if (cnt == 0)
352                                 cnt = usbd->mmc_max;
353                 } else {
354                         cnt = usbd->mmc_max;
355                 }
356
357                 sprintf(length, "%x", cnt);
358                 sprintf(offset, "%x", cur_blk_offset);
359                 sprintf(ramaddr, "0x%x", *ram_addr);
360                 mmc_cmd(OPS_WRITE, ramaddr, offset, length);
361
362                 cur_blk_offset += cnt;
363
364                 *ram_addr += (cnt * usbd->mmc_blk);
365         }
366
367         return ret;
368 }
369
370 static int write_file_mmc(struct usbd_ops *usbd, char *ramaddr, u32 len,
371                 char *offset, char *length)
372 {
373         u32 ram_addr;
374         int i;
375         int ret;
376         struct mbr_table *mbr;
377
378         if (!usbd->mmc_total) {
379                 printf("MMC is not supported!\n");
380                 return 0;
381         }
382
383         ram_addr = (u32)down_ram_addr;
384
385         if (cur_blk_offset == 0) {
386                 boot_sector *bs;
387                 u32 mbr_blk_size;
388
389                 memcpy(&part_info, (void *)ram_addr,
390                                 sizeof(struct partition_header));
391
392                 ram_addr += sizeof(struct partition_header);
393                 len -= sizeof(struct partition_header);
394                 mbr = (struct mbr_table*)ram_addr;
395                 mbr_blk_size = mbr->partition[0].lba_begin;
396
397                 if (mbr->partition[0].type_code != EXTEND_PART_TYPE) {
398                         part_mode = NORMAL_PARTITION;
399
400                         /* modify sectors of p1 */
401                         mbr->partition[0].num_sectors = usbd->mmc_total -
402                                         (mbr_blk_size +
403                                         mbr->partition[1].num_sectors +
404                                         mbr->partition[2].num_sectors +
405                                         mbr->partition[3].num_sectors);
406
407                         mmc_parts++;
408
409                         /* modify lba_begin of p2 and p3 and p4 */
410                         for (i = 1; i < 4; i++) {
411                                 if (part_info.partition[i].size == 0)
412                                         break;
413
414                                 mmc_parts++;
415                                 mbr->partition[i].lba_begin =
416                                         mbr->partition[i - 1].lba_begin +
417                                         mbr->partition[i - 1].num_sectors;
418                         }
419
420                         /* copy MBR */
421                         memcpy(&mbr_info, mbr, sizeof(struct mbr_table));
422
423                         printf("Total Size: 0x%08x #parts %d\n",
424                                         (unsigned int)usbd->mmc_total,
425                                         mmc_parts);
426                         for (i = 0; i < mmc_parts; i++) {
427                                 printf("p%d\t0x%08x\t0x%08x\n", i + 1,
428                                         mbr_info.partition[i].lba_begin,
429                                         mbr_info.partition[i].num_sectors);
430                         }
431
432                         /* write MBR */
433                         sprintf(length, "%x", mbr_blk_size);
434                         sprintf(offset, "%x", 0);
435                         sprintf(ramaddr, "0x%x", (u32)ram_addr);
436                         ret = mmc_cmd(OPS_WRITE, ramaddr, offset, length);
437
438                         ram_addr += mbr_blk_size * usbd->mmc_blk;
439                         len -= mbr_blk_size * usbd->mmc_blk;
440
441                         cur_blk_offset = mbr_blk_size;
442                         cur_part = 0;
443                         cur_part_size = part_info.partition[0].size;
444
445                         /* modify p1's total sector */
446                         bs = (boot_sector *)ram_addr;
447                         bs->total_sect = mbr_info.partition[0].num_sectors;
448
449                         printf("\nWrite Partition %d.. %d blocks\n",
450                                 cur_part + 1,
451                                 part_info.partition[cur_part].size /
452                                 (int)usbd->mmc_blk);
453                 } else {
454                         part_mode = EXTEND_PARTITION;
455
456                         for (i = 0; i < EXTEND_MAX_PART; i++) {
457                                 if (part_info.partition[i].size == 0)
458                                         break;
459                                 mmc_parts++;
460                         }
461
462                         if (mmc_parts == 0)
463                                 return -1;
464                         else
465                                 printf("found %d partitions\n", mmc_parts);
466
467                         /* build partition table */
468
469                         mul_info[0].num_sectors =
470                                 usbd->mmc_total - mbr_blk_size * 2;
471                         for (i = 1; i < mmc_parts; i++) {
472                                 mul_info[i].num_sectors =
473                                         part_info.partition[i].res;
474                         }
475
476                         for (i = 1; i < mmc_parts; i++) {
477                                 mul_info[0].num_sectors -=
478                                         mul_info[i].num_sectors;
479                         }
480
481                         mul_info[0].lba_begin = mbr->partition[0].lba_begin;
482                         for (i = 1; i < mmc_parts; i++) {
483                                 mul_info[i].lba_begin =
484                                         mul_info[i-1].lba_begin +
485                                         mul_info[i-1].num_sectors;
486                         }
487
488                         /* modify main MBR */
489                         mbr->partition[0].num_sectors =
490                                 usbd->mmc_total - mbr_blk_size;
491
492                         /* modify MBR data of p1 */
493                         mbr = (struct mbr_table *)
494                                 (ram_addr + mbr_blk_size * usbd->mmc_blk);
495
496                         mbr->partition[0].num_sectors =
497                                 mul_info[0].num_sectors - mbr_blk_size;
498                         mbr->partition[1].lba_begin =
499                                 mul_info[1].lba_begin - mbr_blk_size;
500
501                         /* modify BPB data of p1 */
502                         bs = (boot_sector *)
503                                 ((u32)mbr + mbr_blk_size * usbd->mmc_blk);
504                         memset(&bs->sectors, 0, 2);
505                         bs->total_sect = mbr->partition[0].num_sectors;
506
507                         printf("Total Size: 0x%08x #parts %d\n",
508                                         (unsigned int)usbd->mmc_total,
509                                         mmc_parts);
510                         for (i = 0; i < mmc_parts; i++) {
511                                 printf("p%d\t0x%08x\t0x%08x\n", i + 1,
512                                         mul_info[i].lba_begin,
513                                         mul_info[i].num_sectors);
514                         }
515
516                         cur_blk_offset = 0;
517                         cur_part = 0;
518                         cur_part_size = part_info.partition[0].size;
519
520                         printf("\nWrite Partition %d.. %d blocks\n",
521                                 cur_part + 1,
522                                 part_info.partition[cur_part].size /
523                                 (int)usbd->mmc_blk);
524                 }
525         }
526
527         for (i = cur_part; i < mmc_parts; i++) {
528                 ret = write_mmc_partition(usbd, &ram_addr, len);
529
530                 if (ret < 0) {
531                         cur_part_size -= len;
532                         break;
533                 } else {
534                         cur_part++;
535                         cur_part_size =
536                                 part_info.partition[cur_part].size;
537
538                         if (part_mode == NORMAL_PARTITION) {
539                                 cur_blk_offset =
540                                         mbr_info.partition[cur_part].lba_begin;
541                         } else {
542                                 cur_blk_offset =
543                                         mul_info[cur_part].lba_begin;
544                                 /* modify MBR */
545                                 if (cur_part <= mmc_parts) {
546                                         mbr = (struct mbr_table *)ram_addr;
547                                         mbr->partition[1].lba_begin =
548                                                 mul_info[cur_part+1].lba_begin -
549                                                 mbr->partition[0].lba_begin;
550                                 }
551                         }
552
553                         if (ret == 0)
554                                 break;
555                         else
556                                 len = ret;
557
558                         printf("\nWrite Partition %d.. %d blocks\n",
559                                 cur_part + 1,
560                                 part_info.partition[cur_part].size /
561                                 (int)usbd->mmc_blk);
562                 }
563         }
564
565         return 0;
566 }
567
568 static int write_file_mmc_part(struct usbd_ops *usbd, char *ramaddr, u32 len,
569                 char *offset, char *length)
570 {
571         u32 ram_addr;
572         u32 ofs;
573         int i;
574         struct mbr_table *mbr;
575         u32 mbr_blk_size;
576
577         ram_addr = (u32)down_ram_addr;
578         mbr = &mbr_info;
579
580         if (cur_blk_offset == 0) {
581                 /* read MBR */
582                 sprintf(length, "%x", (unsigned int)
583                         (sizeof(struct mbr_table)/usbd->mmc_blk));
584                 sprintf(offset, "%x", 0);
585                 sprintf(ramaddr, "0x%x", (u32)mbr);
586                 mmc_cmd(OPS_READ, ramaddr, offset, length);
587
588                 mbr_blk_size = mbr->partition[0].lba_begin;
589
590                 if (mbr->partition[0].type_code != EXTEND_PART_TYPE) {
591                         part_mode = NORMAL_PARTITION;
592
593                         for (i = 0; i < 4; i++) {
594                                 printf("p%d\t0x%08x\t0x%08x\n", i + 1,
595                                         mbr_info.partition[i].lba_begin,
596                                         mbr_info.partition[i].num_sectors);
597                         }
598
599                         cur_blk_offset =
600                                 mbr->partition[mmc_part_write - 1].lba_begin;
601                         cur_part = mmc_part_write - 1;
602                         cur_part_size = len;
603
604                         if (mmc_part_write == 1) {
605                                 ram_addr += sizeof(struct mbr_table);
606                                 cur_blk_offset += sizeof(struct mbr_table) /
607                                         usbd->mmc_blk;
608                                 len -= sizeof(struct mbr_table);
609                         }
610                 } else {
611                         part_mode = EXTEND_PARTITION;
612
613                         mbr_blk_size = mbr->partition[0].lba_begin;
614
615                         for (i = 1; i < mmc_part_write; i++) {
616                                 ofs = mbr->partition[0].lba_begin +
617                                         mbr->partition[1].lba_begin;
618                                 printf("P%d start blk: 0x%x, size: 0x%x\n", i,
619                                         ofs, mbr->partition[0].num_sectors);
620                                 sprintf(length, "%x", (unsigned int)
621                                         (sizeof(struct mbr_table) /
622                                         usbd->mmc_blk));
623                                 sprintf(offset, "%x", ofs);
624                                 sprintf(ramaddr, "0x%x", (u32)mbr);
625                                 mmc_cmd(OPS_READ, ramaddr, offset, length);
626                         }
627
628                         ofs = mbr->partition[0].lba_begin +
629                                 mbr->partition[1].lba_begin;
630
631                         ofs += mbr_blk_size; /* skip MBR */
632                         cur_blk_offset = ofs;
633                         cur_part = mmc_part_write - 1;
634                         cur_part_size = len;
635
636                         if (mmc_part_write == 1) {
637                                 boot_sector *bs;
638                                 u32 total_sect;
639                                 u8 *tmp;
640                                 /* modify BPB data of p1 */
641                                 sprintf(length, "%x", (unsigned int)
642                                         (sizeof(struct mbr_table) /
643                                         usbd->mmc_blk));
644                                 sprintf(offset, "%x", cur_blk_offset);
645                                 sprintf(ramaddr, "0x%x", (u32)mbr);
646                                 mmc_cmd(OPS_READ, ramaddr, offset, length);
647
648                                 bs = (boot_sector *)mbr;
649                                 total_sect = bs->total_sect;
650
651                                 bs = (boot_sector *)ram_addr;
652                                 memset(&bs->sectors, 0, 2);
653                                 bs->total_sect = total_sect;
654                         }
655                 }
656         }
657
658         printf("\nWrite Partition %d.. %d blocks\n",
659                 cur_part + 1,
660                 len / (int)usbd->mmc_blk);
661
662         write_mmc_partition(usbd, &ram_addr, len);
663
664         return 0;
665 }
666 #endif
667
668 static int write_file_system(char *ramaddr, ulong len, char *offset,
669                 char *length, int part_num, int ubi_update)
670 {
671 #ifdef CONFIG_USE_YAFFS
672         int actual_len = 0;
673         int yaffs_write = 0;
674 #endif
675         int ret = 0;
676
677 #ifdef CONFIG_CMD_UBI
678         /* UBI Update */
679         if (ubi_update) {
680                 sprintf(length, "0x%x", (uint)len);
681                 ret = ubi_cmd(part_id, ramaddr, length, "cont");
682                 return ret;
683         }
684 #endif
685
686         /* Erase entire partition at the first writing */
687         if (write_part == 0 && ubi_update == 0) {
688                 sprintf(offset, "0x%x", (uint)parts[part_num]->offset);
689                 sprintf(length, "0x%x", (uint)parts[part_num]->size);
690                 nand_cmd(0, offset, length, NULL);
691         }
692
693 #ifdef CONFIG_USE_YAFFS
694         /* if using yaffs, wirte size must be 2112*X
695          * so, must have to realloc, and writing */
696         if (!strcmp("yaffs", getenv(parts[part_num]->name))) {
697                 yaffs_write = 1;
698
699                 memcpy((void *)down_ram_addr, yaffs_data, yaffs_len);
700
701                 actual_len = len + yaffs_len;
702                 yaffs_len = actual_len % YAFFS_PAGE;
703                 len = actual_len - yaffs_len;
704
705                 memset(yaffs_data, 0x00, YAFFS_PAGE);
706                 memcpy(yaffs_data, (char *)down_ram_addr + len, yaffs_len);
707         }
708 #endif
709
710         sprintf(offset, "0x%x", (uint)(parts[part_num]->offset + fs_offset));
711         sprintf(length, "0x%x", (uint)len);
712
713 #ifdef CONFIG_USE_YAFFS
714         if (yaffs_write)
715                 ret = nand_cmd(2, ramaddr, offset, length);
716         else
717                 ret = nand_cmd(1, ramaddr, offset, length);
718
719         if (!strcmp("yaffs", getenv(parts[part_num]->name)))
720                 fs_offset += len / YAFFS_PAGE * NAND_PAGE_SIZE;
721         else
722                 fs_offset += len;
723
724 #else
725         fs_offset += len;
726         ret = nand_cmd(1, ramaddr, offset, length);
727 #endif
728
729         return ret;
730 }
731
732 static int qboot_erase = 0;
733
734 /* Erase the qboot */
735 static void erase_qboot_area(void)
736 {
737         char offset[12], length[12];
738         int qboot_id;
739
740         if (qboot_erase)
741                 return;
742
743         qboot_id = get_part_id("qboot");
744
745         if (qboot_id != -1) {
746                 printf("\nCOMMAND_ERASE_QBOOT\n");
747                 sprintf(offset, "%x", parts[qboot_id]->offset);
748                 sprintf(length, "%x", parts[qboot_id]->size);
749                 nand_cmd(0, offset, length, NULL);
750                 qboot_erase = 1;
751         }
752 }
753
754 /* Parsing received data packet and Process data */
755 static int process_data(struct usbd_ops *usbd)
756 {
757         ulong cmd = 0, arg = 0, ofs = 0, len = 0, flag = 0;
758         char offset[12], length[12], ramaddr[12];
759         int recvlen = 0;
760         unsigned int blocks = 0;
761         int ret = 0;
762         int ubi_update = 0;
763         int ubi_mode = 0;
764         int img_type;
765
766         sprintf(ramaddr, "0x%x", (uint) down_ram_addr);
767
768         /* Parse command */
769         cmd  = *((ulong *) usbd->rx_data + 0);
770         arg  = *((ulong *) usbd->rx_data + 1);
771         len  = *((ulong *) usbd->rx_data + 2);
772         flag = *((ulong *) usbd->rx_data + 3);
773
774         /* Reset tx buffer */
775         memset(usbd->tx_data, 0, sizeof(usbd->tx_data));
776
777         ubi_mode = check_ubi_mode();
778
779         switch (cmd) {
780         case COMMAND_DOWNLOAD_IMAGE:
781                 printf("\nCOMMAND_DOWNLOAD_IMAGE\n");
782
783 #ifdef CONFIG_USE_YAFFS
784                 usbd->recv_setup((char *)down_ram_addr + yaffs_len, (int)len);
785                 printf("Download to 0x%08x, %d bytes\n",
786                                 (uint)down_ram_addr + yaffs_len, (int)len);
787 #else
788                 usbd->recv_setup((char *)down_ram_addr, (int)len);
789                 printf("Download to 0x%08x, %d bytes\n",
790                                 (uint)down_ram_addr, (int)len);
791 #endif
792                 /* response */
793                 usbd->send_data(usbd->tx_data, usbd->tx_len);
794
795                 /* Receive image by using dma */
796                 recvlen = usbd->recv_data();
797                 if (recvlen < len) {
798                         printf("Error: wrong image size -> %d/%d\n",
799                                         (int)recvlen, (int)len);
800
801                         /* Retry this commad */
802                         *((ulong *) usbd->tx_data) = STATUS_RETRY;
803                 } else
804                         *((ulong *) usbd->tx_data) = STATUS_DONE;
805
806                 usbd->send_data(usbd->tx_data, usbd->tx_len);
807                 return 1;
808
809         /* Report partition info */
810         case COMMAND_PARTITION_SYNC:
811                 part_id = arg;
812
813 #ifdef CONFIG_CMD_UBI
814                 if (ubi_mode) {
815                         if (part_id == RAMDISK_PART_ID ||
816                             part_id == FILESYSTEM_PART_ID ||
817                             part_id == FILESYSTEM2_PART_ID) {
818                                 /* change to yaffs style */
819                                 get_part_info();
820                         }
821                 } else {
822                         if (part_id == FILESYSTEM3_PART_ID) {
823                                 /* change ubi style */
824                                 get_part_info();
825                         }
826                 }
827 #endif
828
829                 if (part_id == FILESYSTEM3_PART_ID)
830                         part_id = get_part_id("UBI");
831                 else if (part_id == MODEM_PART_ID)
832                         part_id = get_part_id("modem");
833                 else if (part_id == KERNEL_PART_ID)
834                         part_id = get_part_id("kernel");
835 #ifdef CONFIG_MIRAGE
836                 if (part_id)
837                         part_id--;
838 #endif
839                 printf("COMMAND_PARTITION_SYNC - Part%d\n", part_id);
840
841                 blocks = parts[part_id]->size / 1024 / 128;
842                 printf("COMMAND_PARTITION_SYNC - Part%d, %d blocks\n",
843                                 part_id, blocks);
844
845                 *((ulong *) usbd->tx_data) = blocks;
846                 usbd->send_data(usbd->tx_data, usbd->tx_len);
847                 return 1;
848
849         case COMMAND_WRITE_PART_0:
850                 /* Do nothing */
851                 printf("COMMAND_WRITE_PART_0\n");
852                 return 1;
853
854         case COMMAND_WRITE_PART_1:
855                 printf("COMMAND_WRITE_PART_BOOT\n");
856                 part_id = get_part_id("bootloader");
857                 img_type = IMG_BOOT;
858                 break;
859
860         case COMMAND_WRITE_PART_2:
861         case COMMAND_ERASE_PARAMETER:
862                 printf("COMMAND_PARAMETER - not support!\n");
863                 break;
864
865         case COMMAND_WRITE_PART_3:
866                 printf("COMMAND_WRITE_KERNEL\n");
867                 part_id = get_part_id("kernel");
868                 img_type = IMG_KERNEL;
869                 break;
870
871         case COMMAND_WRITE_PART_4:
872                 printf("COMMAND_WRITE_ROOTFS\n");
873                 part_id = get_part_id("Root");
874                 img_type = IMG_FILESYSTEM;
875                 ubi_update = arg;
876                 break;
877
878         case COMMAND_WRITE_PART_5:
879                 printf("COMMAND_WRITE_FACTORYFS\n");
880                 part_id = get_part_id("Fact");
881                 img_type = IMG_FILESYSTEM;
882                 ubi_update = arg;
883                 break;
884
885         case COMMAND_WRITE_PART_6:
886                 printf("COMMAND_WRITE_DATAFS\n");
887                 part_id = get_part_id("Data");
888                 img_type = IMG_FILESYSTEM;
889                 ubi_update = arg;
890                 break;
891
892         case COMMAND_WRITE_PART_7:
893                 printf("COMMAND_WRITE_UBI\n");
894                 part_id = get_part_id("UBI");
895                 img_type = IMG_FILESYSTEM;
896                 ubi_update = 0;
897                 /* someday, it will be deleted */
898                 get_part_info();
899                 break;
900
901         case COMMAND_WRITE_PART_8:
902                 printf("COMMAND_WRITE_MODEM\n");
903                 part_id = get_part_id("modem");
904                 img_type = IMG_MODEM;
905                 break;
906
907 #ifdef CONFIG_CMD_MMC
908         case COMMAND_WRITE_PART_9:
909                 printf("COMMAND_WRITE_MMC\n");
910                 img_type = IMG_MMC;
911                 mmc_part_write = arg;
912                 break;
913 #endif
914
915         case COMMAND_WRITE_UBI_INFO:
916                 printf("COMMAND_WRITE_UBI_INFO\n");
917
918                 if (ubi_mode) {
919 #ifdef CONFIG_CMD_UBI
920                         part_id = arg-1;
921                         sprintf(length, "0x%x", (uint)len);
922                         ret = ubi_cmd(part_id, ramaddr, length, "begin");
923                 } else {
924 #endif
925                         printf("Error: Not UBI mode\n");
926                         ret = 1;
927                 }
928
929                 *((ulong *) usbd->tx_data) = ret;
930                 /* Write image success -> Report status */
931                 usbd->send_data(usbd->tx_data, usbd->tx_len);
932
933                 return !ret;
934         /* Download complete -> reset */
935         case COMMAND_RESET_PDA:
936                 printf("\nDownload finished and Auto reset!\nWait........\n");
937
938                 /* Stop USB */
939                 usbd->usb_stop();
940
941                 if (usbd->cpu_reset)
942                         usbd->cpu_reset();
943                 else
944                         do_reset();
945
946                 return 0;
947
948         /* Error */
949         case COMMAND_RESET_USB:
950                 printf("\nError is occured!(maybe previous step)->\
951                                 Turn off and restart!\n");
952
953                 /* Stop USB */
954                 usbd->usb_stop();
955                 return 0;
956
957         case COMMAND_RAM_BOOT:
958                 usbd->usb_stop();
959                 boot_cmd(ramaddr);
960                 return 0;
961
962         case COMMAND_RAMDISK_MODE:
963                 printf("COMMAND_RAMDISK_MODE\n");
964 #ifdef CONFIG_RAMDISK_ADDR
965                 if (arg) {
966                         down_ram_addr = usbd->ram_addr;
967                 } else {
968                         down_ram_addr = CONFIG_RAMDISK_ADDR;
969                         run_cmd("ramboot");
970                 }
971 #endif
972                 return 1;
973
974 #ifdef CONFIG_DOWN_PHONE
975         case COMMAND_DOWN_PHONE:
976                 printf("COMMAND_RESET_PHONE\n");
977
978                 usbd_phone_down();
979
980                 *((ulong *) usbd->tx_data) = STATUS_DONE;
981                 usbd->send_data(usbd->tx_data, usbd->tx_len);
982                 return 1;
983
984         case COMMAND_CHANGE_USB:
985                 printf("COMMAND_CHANGE_USB\n");
986
987                 /* Stop USB */
988                 usbd->usb_stop();
989
990                 usbd_path_change();
991
992                 do_reset();
993                 return 0;
994 #endif
995         case COMMAND_CSA_CLEAR:
996                 printf("COMMAND_CSA_CLEAR\n");
997                 part_id = get_part_id("csa");
998                 img_type = IMG_MODEM;
999                 break;
1000
1001         case COMMAND_PROGRESS:
1002                 if (usbd->set_progress)
1003                         usbd->set_progress(arg);
1004                 return 1;
1005
1006         default:
1007                 printf("Error: Unknown command -> (%d)\n", (int)cmd);
1008                 return 1;
1009         }
1010
1011         /* Erase and Write to NAND */
1012         switch (img_type) {
1013         case IMG_BOOT:
1014                 ofs = parts[part_id]->offset;
1015 #ifdef CONFIG_RECOVERY
1016         {
1017                 /* block is fixed:
1018                         1m = ipl(16k)+recovery(240k)+bootloader(768k)*/
1019                 long *buf = (long *)down_ram_addr;
1020                 u32 ofst;
1021                 u32 bootloader_edge = parts[part_id]->size;
1022                 u32 bootloader_addr = bootloader_edge >> 2;
1023                 u32 recovery_edge = bootloader_addr;
1024                 u32 recovery_addr = recovery_edge >> 4;
1025                 u32 ipl_addr = 0;
1026
1027                 if (len > bootloader_addr) {
1028                         ofst = bootloader_addr / sizeof(buf);
1029                         if (*(buf + ofst) == 0xea000012) {
1030                                 /* case: ipl + recovery + bootloader */
1031                                 printf("target: ipl + recovery + loader\n");
1032                                 ofs = ipl_addr;
1033                         } else {
1034                                 /* case: unknown format */
1035                                 printf("target: unknown\n");
1036                                 *((ulong *) usbd->tx_data) = STATUS_ERROR;
1037                                 usbd->send_data(usbd->tx_data, usbd->tx_len);
1038                                 return 0;
1039                         }
1040                 } else {
1041                         ofst = recovery_addr/sizeof(buf);
1042                         if (*(buf + ofst) == 0xea000012 &&
1043                                 *(buf + ofst - 1) == 0x00000000) {
1044                                 /* case: ipl + bootloader (old type) */
1045                                 printf("target: ipl + bootloader\n");
1046                                 ofs = ipl_addr;
1047                         } else {
1048                                 /* case: bootloader only */
1049                                 printf("target: bootloader\n");
1050                                 ofs = bootloader_addr;
1051
1052                                 /* skip revision check */
1053                                 down_mode = MODE_FORCE;
1054                         }
1055                 }
1056
1057                 sprintf(offset, "%x", (uint)ofs);
1058                 sprintf(length, "%x", parts[part_id]->size);
1059
1060                 /* check block is locked/locked-tight */
1061                 ret = nand_cmd(3, offset, length, NULL);
1062                 if (ret) {
1063                         printf("target is locked%s\n",
1064                                 (ret == 1) ? "-tight" : "");
1065                         printf("-> try at recovery mode "
1066                                 "to update 'system'.\n");
1067                         printf("   how-to: reset "
1068                                 "while pressing volume up and down.\n");
1069                         *((ulong *) usbd->tx_data) = STATUS_ERROR;
1070                         usbd->send_data(usbd->tx_data, usbd->tx_len);
1071                         return 0;
1072                 }
1073         }
1074 #endif
1075 #ifdef CONFIG_S5PC1XX
1076                 /* Workaround: for prevent revision mismatch */
1077                 if (cpu_is_s5pc110() && (down_mode != MODE_FORCE)) {
1078                         int img_rev = 1;
1079                         long *img_header = (long *)down_ram_addr;
1080
1081                         if (*img_header == 0xea000012)
1082                                 img_rev = 0;
1083                         else if (*(img_header + 0x400) == 0xea000012)
1084                                 img_rev = 2;
1085
1086                         if (img_rev != s5p_get_cpu_rev()) {
1087                                 printf("CPU revision mismatch!\n"
1088                                         "bootloader is %s%s\n"
1089                                         "download image is %s%s\n",
1090                                         s5p_get_cpu_rev() ? "EVT1" : "EVT0",
1091                                         s5p_get_cpu_rev() == 2 ? "-Fused" : "",
1092                                         img_rev ? "EVT1" : "EVT0",
1093                                         img_rev == 2 ? "-Fused" : "");
1094                                 *((ulong *) usbd->tx_data) = STATUS_ERROR;
1095                                 usbd->send_data(usbd->tx_data, usbd->tx_len);
1096                                 return 0;
1097                         }
1098                 }
1099 #endif
1100 #if defined(CONFIG_ENV_IS_IN_NAND) || defined(CONFIG_ENV_IS_IN_ONENAND)
1101                 /* Erase the environment also when write bootloader */
1102                 {
1103                         int param_id;
1104                         param_id = get_part_id("params");
1105
1106                         if (param_id == -1) {
1107                                 sprintf(offset, "%x", CONFIG_ENV_ADDR);
1108                                 sprintf(length, "%x", CONFIG_ENV_SIZE);
1109                         } else {
1110                                 sprintf(offset, "%x", parts[param_id]->offset);
1111                                 sprintf(length, "%x", parts[param_id]->size);
1112                         }
1113                         nand_cmd(0, offset, length, NULL);
1114                 }
1115 #endif
1116                 sprintf(offset, "%x", (uint)ofs);
1117                 if (ofs != 0)
1118                         sprintf(length, "%x", parts[part_id]->size - (uint)ofs);
1119                 else
1120                         sprintf(length, "%x", parts[part_id]->size);
1121
1122                 /* Erase */
1123                 nand_cmd(0, offset, length, NULL);
1124                 /* Write */
1125                 sprintf(length, "%x", (unsigned int) len);
1126                 ret = nand_cmd(1, ramaddr, offset, length);
1127                 break;
1128
1129         case IMG_KERNEL:
1130                 sprintf(offset, "%x", parts[part_id]->offset);
1131                 sprintf(length, "%x", parts[part_id]->size);
1132
1133                 /* Erase */
1134                 nand_cmd(0, offset, length, NULL);
1135                 /* Write */
1136                 sprintf(length, "%x", (unsigned int) len);
1137                 ret = nand_cmd(1, ramaddr, offset, length);
1138
1139                 erase_qboot_area();
1140                 break;
1141
1142         /* File Systems */
1143         case IMG_FILESYSTEM:
1144                 ret = write_file_system(ramaddr, len, offset, length,
1145                                 part_id, ubi_update);
1146
1147                 erase_qboot_area();
1148                 break;
1149
1150         case IMG_MODEM:
1151                 sprintf(offset, "%x", parts[part_id]->offset);
1152                 sprintf(length, "%x", parts[part_id]->size);
1153
1154                 /* Erase */
1155                 if (!arg)
1156                         nand_cmd(0, offset, length, NULL);
1157                 else
1158                         printf("CSA Clear will be skipped temporary\n");
1159
1160 #ifdef CONFIG_UBIFS_MK
1161                 void *dest_addr;
1162                 void *src_addr = (void *) down_ram_addr;
1163                 int leb_size, max_leb_cnt, mkfs_min_io_size;
1164                 unsigned long ubifs_dest_size, ubi_dest_size;
1165 #ifdef CONFIG_S5PC110
1166                 mkfs_min_io_size = 4096;
1167                 leb_size = 248 * 1024;
1168                 max_leb_cnt = 4096;
1169 #elif CONFIG_S5PC210
1170                 mkfs_min_io_size = 2048;
1171                 leb_size = 126 * 1024;
1172                 max_leb_cnt = 4096;
1173 #endif
1174                 printf("Start making ubifs\n");
1175                 ret = mkfs(src_addr, len, &dest_addr, &ubifs_dest_size,
1176                            mkfs_min_io_size, leb_size, max_leb_cnt);
1177                 if (ret) {
1178                         printf("Error : making ubifs failed\n");
1179                         goto out;
1180                 }
1181                 printf("Complete making ubifs\n");
1182 #endif
1183
1184 #ifdef CONFIG_UBINIZE
1185                 int peb_size, ubi_min_io_size, subpage_size, vid_hdr_offs;
1186 #ifdef CONFIG_S5PC110
1187                 ubi_min_io_size = 4096;
1188                 peb_size = 256 * 1024;
1189                 subpage_size = 4096;
1190                 vid_hdr_offs = 0;
1191 #elif CONFIG_S5PC210
1192                 ubi_min_io_size = 2048;
1193                 peb_size = 128 * 1024;
1194                 subpage_size = 512;
1195                 vid_hdr_offs = 512;
1196 #endif
1197                 printf("Start ubinizing\n");
1198                 ret = ubinize(dest_addr, ubifs_dest_size,
1199                               src_addr, &ubi_dest_size,
1200                               peb_size, ubi_min_io_size,
1201                               subpage_size, vid_hdr_offs);
1202                 if (ret) {
1203                         printf("Error : ubinizing failed\n");
1204                         goto out;
1205                 }
1206                 printf("Complete ubinizing\n");
1207
1208                 len = (unsigned int) ubi_dest_size;
1209
1210                 free(dest_addr);
1211 #endif
1212                 /* Write : arg (0 Modem) / (1 CSA) */
1213                 if (!arg) {
1214                         sprintf(length, "%x", (unsigned int) len);
1215                         ret = nand_cmd(1, ramaddr, offset, length);
1216                 }
1217 out:
1218                 break;
1219
1220 #ifdef CONFIG_CMD_MMC
1221         case IMG_MMC:
1222
1223                 if (mmc_part_write)
1224                         ret = write_file_mmc_part(usbd, ramaddr,
1225                                                 len, offset, length);
1226                 else
1227                         ret = write_file_mmc(usbd, ramaddr,
1228                                                 len, offset, length);
1229
1230                 erase_qboot_area();
1231                 break;
1232 #endif
1233
1234         default:
1235                 /* Retry? */
1236                 write_part--;
1237         }
1238
1239         if (ret) {
1240                 /* Retry this commad */
1241                 *((ulong *) usbd->tx_data) = STATUS_RETRY;
1242                 usbd->send_data(usbd->tx_data, usbd->tx_len);
1243                 return 1;
1244         } else
1245                 *((ulong *) usbd->tx_data) = STATUS_DONE;
1246
1247         /* Write image success -> Report status */
1248         usbd->send_data(usbd->tx_data, usbd->tx_len);
1249
1250         write_part++;
1251
1252         /* Reset write count for another image */
1253         if (flag) {
1254                 write_part = 0;
1255                 fs_offset = 0;
1256 #ifdef CONFIG_USE_YAFFS
1257                 yaffs_len = 0;
1258 #endif
1259         }
1260
1261         return 1;
1262 }
1263
1264 static const char *recv_key = "SAMSUNG";
1265 static const char *tx_key = "MPL";
1266
1267 int do_usbd_down(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
1268 {
1269         struct usbd_ops *usbd;
1270         int err;
1271
1272         if (argc > 1)
1273                 down_mode = simple_strtoul(argv[1], NULL, 10);
1274         else
1275                 down_mode = MODE_NORMAL;
1276
1277         printf("USB Downloader v%s\n", APP_VERSION);
1278
1279         /* get partition info */
1280         err = get_part_info();
1281         if (err)
1282                 return err;
1283
1284         /* interface setting */
1285         usbd = usbd_set_interface(&usbd_ops);
1286         down_ram_addr = usbd->ram_addr;
1287
1288         /* init the usb controller */
1289         usbd->usb_init();
1290
1291         /* receive setting */
1292         usbd->recv_setup(usbd->rx_data, usbd->rx_len);
1293
1294         /* detect the download request from Host PC */
1295         if (usbd->recv_data()) {
1296                 if (strncmp(usbd->rx_data, recv_key, strlen(recv_key)) == 0) {
1297                         printf("Download request from the Host PC\n");
1298                         msleep(30);
1299
1300                         strcpy(usbd->tx_data, tx_key);
1301                         usbd->send_data(usbd->tx_data, usbd->tx_len);
1302                 } else {
1303                         printf("No download request from the Host PC!! 1\n");
1304                         return 0;
1305                 }
1306         } else {
1307                 printf("No download request from the Host PC!!\n");
1308                 return 0;
1309         }
1310
1311         printf("Receive the packet\n");
1312
1313         /* receive the data from Host PC */
1314         while (1) {
1315                 usbd->recv_setup(usbd->rx_data, usbd->rx_len);
1316
1317                 if (usbd->recv_data()) {
1318                         if (process_data(usbd) == 0)
1319                                 return 0;
1320                 }
1321         }
1322
1323         return 0;
1324 }
1325
1326 U_BOOT_CMD(usbdown, CONFIG_SYS_MAXARGS, 1, do_usbd_down,
1327         "Initialize USB device and Run USB Downloader (specific)",
1328         "- normal mode\n"
1329         "usbdown mode - specific mode (0: NORAML, 1: FORCE)"
1330 );