2 * USB Downloader for SAMSUNG Platform
4 * Copyright (C) 2007-2008 Samsung Electronics
5 * Minkyu Kang <mk7.kang@samsung.com>
11 #include <asm/errno.h>
14 /* version of USB Downloader Application */
15 #define APP_VERSION "1.5.0"
20 #ifdef CONFIG_CMD_MTDPARTS
21 #include <jffs2/load_kernel.h>
22 static struct part_info *parts[16];
25 static const char pszMe[] = "usbd: ";
27 static struct usbd_ops usbd_ops;
29 static unsigned int part_id;
30 static unsigned int write_part = 0;
31 static unsigned long fs_offset = 0x0;
33 #ifdef CONFIG_USE_YAFFS
34 static unsigned int yaffs_len = 0;
35 static unsigned char yaffs_data[2112];
36 #define YAFFS_PAGE 2112
39 #define NAND_PAGE_SIZE 2048
41 static unsigned long down_ram_addr;
45 /* cpu/${CPU} dependent */
46 extern void do_reset(void);
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[]);
52 int mtdparts_init(void);
53 int find_dev_and_part(const char*, struct mtd_device**, u8*, struct part_info**);
55 /* common/cmd_jffs2.c */
56 extern struct list_head devices;
58 static u8 count_mtdparts(void)
60 struct list_head *dentry, *pentry;
61 struct mtd_device *dev;
64 list_for_each(dentry, &devices) {
65 dev = list_entry(dentry, struct mtd_device, link);
67 /* list partitions for given device */
68 list_for_each(pentry, &dev->parts)
76 static int check_ubi_mode(void)
81 env_ubifs = getenv("ubi");
82 ubi_mode = !strcmp(env_ubifs, "enabled");
87 #define check_ubi_mode() 0
90 #ifdef CONFIG_MTD_PARTITIONS
91 static int get_part_info(void)
93 struct mtd_device *dev;
101 #if defined(CONFIG_CMD_NAND)
102 sprintf(nand_name, "nand0");
103 #elif defined(CONFIG_CMD_ONENAND)
104 sprintf(nand_name, "onenand0");
106 printf("Configure your NAND sub-system\n");
113 ubi_mode = check_ubi_mode();
115 part_num = count_mtdparts();
116 for (i = 0; i < part_num; i++) {
117 sprintf(part_name, "%s,%d", nand_name, i);
119 if (find_dev_and_part(part_name, &dev, &out_partnum, &parts[i]))
126 static int get_part_id(char *name)
128 int nparts = count_mtdparts();
131 for (i = 0; i < nparts; i++) {
132 if (strcmp(parts[i]->name, name) == 0)
136 printf("Error: Unknown partition -> %s\n", name);
140 static int get_part_info(void)
142 printf("Error: Can't get patition information\n");
146 static int get_part_id(char *name)
152 static void boot_cmd(char *addr)
154 char *argv[] = { "bootm", addr };
155 do_bootm(NULL, 0, 2, argv);
158 static void run_cmd(char *cmd)
160 char *argv[] = { "run", cmd };
161 do_run(NULL, 0, 2, argv);
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[]);
170 /* NAND erase and write using nand command */
171 static int nand_cmd(int type, char *p1, char *p2, char *p3)
175 int (*nand_func) (cmd_tbl_t *, int, int, char **);
177 #if defined(CONFIG_CMD_NAND)
178 sprintf(nand_name, "nand");
180 #elif defined(CONFIG_CMD_ONENAND)
181 sprintf(nand_name, "onenand");
182 nand_func = do_onenand;
184 printf("Configure your NAND sub-system\n");
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],
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],
201 ret = nand_func(NULL, 0, 5, argv);
205 printf("Error: NAND Command\n");
210 #ifdef CONFIG_CMD_UBI
211 int do_ubi(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
213 int ubi_cmd(int part, char *p1, char *p2, char *p3)
217 if (part == RAMDISK_PART_ID) {
218 char *argv[] = {"ubi", "write", p1, "rootfs.cramfs", p2, p3};
219 printf("%s %s %s %s %s %s\n", argv[0], argv[1], argv[2],
220 argv[3], argv[4], argv[5]);
221 ret = do_ubi(NULL, 0, 6, argv);
222 } else if (part == FILESYSTEM_PART_ID) {
223 char *argv[] = {"ubi", "write", p1, "factoryfs.cramfs", p2, p3};
224 printf("%s %s %s %s %s %s\n", argv[0], argv[1], argv[2],
225 argv[3], argv[4], argv[5]);
226 ret = do_ubi(NULL, 0, 6, argv);
227 } else if (part == FILESYSTEM2_PART_ID) {
228 char *argv[] = {"ubi", "write", p1, "datafs.ubifs", p2, p3};
229 printf("%s %s %s %s %s %s\n", argv[0], argv[1], argv[2],
230 argv[3], argv[4], argv[5]);
231 ret = do_ubi(NULL, 0, 6, argv);
238 #ifdef CONFIG_CMD_MMC
241 extern int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
243 static int mmc_cmd(int ops, char *p1, char *p2, char *p3)
248 char *argv[] = {"mmc", "write", "0", p1, p2, p3};
249 ret = do_mmcops(NULL, 0, 6, argv);
251 char *argv[] = {"mmc", "read", "0", p1, p2, p3};
252 ret = do_mmcops(NULL, 0, 6, argv);
258 static unsigned int cur_blk_offset;
259 static unsigned int cur_part_size;
260 static unsigned int cur_partition;
262 static unsigned int mmc_parts;
263 static unsigned int mmc_part_write;
265 struct partition_info {
269 } __attribute__((packed));
271 struct partition_header {
272 u8 fat32head[16]; /* RFSHEAD identifier */
273 struct partition_info partition[4];
274 u8 res[448]; /* reserved */
275 } __attribute__((packed));
277 struct partition_table {
284 } __attribute__((packed));
288 struct partition_table partition[4];
290 } __attribute__((packed));
292 #define MBR_OFFSET 0x10
294 struct partition_header part_info;
295 struct mbr_table mbr_info;
297 static int write_mmc_partition(struct usbd_ops *usbd, u32 *ram_addr, u32 len)
300 char offset[12], length[12], ramaddr[12];
306 if (cur_part_size > len) {
307 blocks = len / usbd->mmc_blk;
310 blocks = cur_part_size / usbd->mmc_blk;
311 ret = len - cur_part_size;
314 if (len % usbd->mmc_blk)
317 loop = blocks / usbd->mmc_max;
318 if (blocks % usbd->mmc_max)
321 for (i = 0; i < loop; i++) {
323 cnt = blocks % usbd->mmc_max;
330 sprintf(length, "%x", cnt);
331 sprintf(offset, "%x", cur_blk_offset);
332 sprintf(ramaddr, "0x%x", *ram_addr);
333 mmc_cmd(OPS_WRITE, ramaddr, offset, length);
335 cur_blk_offset += cnt;
337 *ram_addr += (cnt * usbd->mmc_blk);
343 static int write_file_mmc(struct usbd_ops *usbd, char *ramaddr, u32 len,
344 char *offset, char *length)
350 if (!usbd->mmc_total) {
351 printf("MMC is not supported!\n");
355 ram_addr = (u32)down_ram_addr;
357 if (cur_blk_offset == 0) {
359 struct mbr_table *mbr;
361 memcpy(&part_info, (void *)ram_addr,
362 sizeof(struct partition_header));
364 ram_addr += sizeof(struct partition_header);
365 len -= sizeof(struct partition_header);
366 mbr = (struct mbr_table*)ram_addr;
368 /* modify sectors of p1 */
369 mbr->partition[0].num_sectors = usbd->mmc_total -
371 mbr->partition[1].num_sectors +
372 mbr->partition[2].num_sectors +
373 mbr->partition[3].num_sectors);
377 /* modify lba_begin of p2 and p3 and p4 */
378 for (i = 1; i < 4; i++) {
379 if (part_info.partition[i].size == 0)
383 mbr->partition[i].lba_begin =
384 mbr->partition[i - 1].lba_begin +
385 mbr->partition[i - 1].num_sectors;
389 memcpy(&mbr_info, mbr, sizeof(struct mbr_table));
391 printf("Total Size: 0x%08x #parts %d\n",
392 (unsigned int)usbd->mmc_total, mmc_parts);
393 for (i = 0; i < mmc_parts; i++) {
394 printf("p%d\t0x%08x\t0x%08x\n", i + 1,
395 mbr_info.partition[i].lba_begin,
396 mbr_info.partition[i].num_sectors);
400 sprintf(length, "%x", MBR_OFFSET);
401 sprintf(offset, "%x", 0);
402 sprintf(ramaddr, "0x%x", (u32)ram_addr);
403 ret = mmc_cmd(OPS_WRITE, ramaddr, offset, length);
405 ram_addr += (MBR_OFFSET * usbd->mmc_blk);
406 len -= (MBR_OFFSET * usbd->mmc_blk);
408 cur_blk_offset = MBR_OFFSET;
410 cur_part_size = part_info.partition[0].size;
412 /* modify p1's total sector */
413 bs = (boot_sector *)ram_addr;
414 bs->total_sect = mbr_info.partition[0].num_sectors;
416 printf("\nWrite Partition %d.. %d blocks\n",
418 part_info.partition[cur_partition].size /
422 for (i = cur_partition; i < mmc_parts; i++) {
423 ret = write_mmc_partition(usbd, &ram_addr, len);
426 cur_part_size -= len;
431 part_info.partition[cur_partition].size;
433 mbr_info.partition[cur_partition].lba_begin;
440 printf("\nWrite Partition %d.. %d blocks\n",
442 part_info.partition[cur_partition].size /
450 static int write_file_mmc_part(struct usbd_ops *usbd, char *ramaddr, u32 len,
451 char *offset, char *length)
457 ram_addr = (u32)down_ram_addr;
459 if (cur_blk_offset == 0) {
461 sprintf(length, "%x", MBR_OFFSET);
462 sprintf(offset, "%x", 0);
463 sprintf(ramaddr, "0x%x", (u32)&mbr_info);
464 ret = mmc_cmd(OPS_READ, ramaddr, offset, length);
466 for (i = 0; i < 4; i++) {
467 printf("p%d\t0x%08x\t0x%08x\n", i + 1,
468 mbr_info.partition[i].lba_begin,
469 mbr_info.partition[i].num_sectors);
472 cur_blk_offset = (unsigned int)
473 mbr_info.partition[mmc_part_write - 1].lba_begin;
474 cur_partition = mmc_part_write - 1;
475 cur_part_size = (unsigned int)len;
477 if (mmc_part_write == 1) {
478 ram_addr += sizeof(boot_sector);
479 cur_blk_offset += sizeof(boot_sector) / usbd->mmc_blk;
480 len -= sizeof(boot_sector);
484 printf("\nWrite Partition %d.. %d blocks\n",
486 len / (int)usbd->mmc_blk);
488 write_mmc_partition(usbd, &ram_addr, len);
494 static int write_file_system(char *ramaddr, ulong len, char *offset,
495 char *length, int part_num, int ubi_update)
497 #ifdef CONFIG_USE_YAFFS
503 #ifdef CONFIG_CMD_UBI
506 sprintf(length, "0x%x", (uint)len);
507 ret = ubi_cmd(part_id, ramaddr, length, "cont");
512 /* Erase entire partition at the first writing */
513 if (write_part == 0 && ubi_update == 0) {
514 sprintf(offset, "0x%x", (uint)parts[part_num]->offset);
515 sprintf(length, "0x%x", (uint)parts[part_num]->size);
516 nand_cmd(0, offset, length, NULL);
519 #ifdef CONFIG_USE_YAFFS
520 /* if using yaffs, wirte size must be 2112*X
521 * so, must have to realloc, and writing */
522 if (!strcmp("yaffs", getenv(parts[part_num]->name))) {
525 memcpy((void *)down_ram_addr, yaffs_data, yaffs_len);
527 actual_len = len + yaffs_len;
528 yaffs_len = actual_len % YAFFS_PAGE;
529 len = actual_len - yaffs_len;
531 memset(yaffs_data, 0x00, YAFFS_PAGE);
532 memcpy(yaffs_data, (char *)down_ram_addr + len, yaffs_len);
536 sprintf(offset, "0x%x", (uint)(parts[part_num]->offset + fs_offset));
537 sprintf(length, "0x%x", (uint)len);
539 #ifdef CONFIG_USE_YAFFS
541 ret = nand_cmd(2, ramaddr, offset, length);
543 ret = nand_cmd(1, ramaddr, offset, length);
545 if (!strcmp("yaffs", getenv(parts[part_num]->name)))
546 fs_offset += len / YAFFS_PAGE * NAND_PAGE_SIZE;
552 ret = nand_cmd(1, ramaddr, offset, length);
558 /* Parsing received data packet and Process data */
559 static int process_data(struct usbd_ops *usbd)
561 ulong cmd = 0, arg = 0, len = 0, flag = 0;
562 char offset[12], length[12], ramaddr[12];
564 unsigned int blocks = 0;
570 sprintf(ramaddr, "0x%x", (uint) down_ram_addr);
573 cmd = *((ulong *) usbd->rx_data + 0);
574 arg = *((ulong *) usbd->rx_data + 1);
575 len = *((ulong *) usbd->rx_data + 2);
576 flag = *((ulong *) usbd->rx_data + 3);
578 /* Reset tx buffer */
579 memset(usbd->tx_data, 0, sizeof(usbd->tx_data));
581 ubi_mode = check_ubi_mode();
584 case COMMAND_DOWNLOAD_IMAGE:
585 printf("\nCOMMAND_DOWNLOAD_IMAGE\n");
587 #ifdef CONFIG_USE_YAFFS
588 usbd->recv_setup((char *)down_ram_addr + yaffs_len, (int)len);
589 printf("Download to 0x%08x, %d bytes\n",
590 (uint)down_ram_addr + yaffs_len, (int)len);
592 usbd->recv_setup((char *)down_ram_addr, (int)len);
593 printf("Download to 0x%08x, %d bytes\n",
594 (uint)down_ram_addr, (int)len);
597 usbd->send_data(usbd->tx_data, usbd->tx_len);
599 /* Receive image by using dma */
600 recvlen = usbd->recv_data();
602 printf("Error: wrong image size -> %d/%d\n",
603 (int)recvlen, (int)len);
605 /* Retry this commad */
606 *((ulong *) usbd->tx_data) = STATUS_RETRY;
608 *((ulong *) usbd->tx_data) = STATUS_DONE;
610 usbd->send_data(usbd->tx_data, usbd->tx_len);
613 /* Report partition info */
614 case COMMAND_PARTITION_SYNC:
617 #ifdef CONFIG_CMD_UBI
619 if (part_id == RAMDISK_PART_ID ||
620 part_id == FILESYSTEM_PART_ID ||
621 part_id == FILESYSTEM2_PART_ID) {
622 /* change to yaffs style */
626 if (part_id == FILESYSTEM3_PART_ID) {
627 /* change ubi style */
633 if (part_id == FILESYSTEM3_PART_ID)
634 part_id = get_part_id("UBI");
635 else if (part_id == MODEM_PART_ID)
636 part_id = get_part_id("modem");
637 else if (part_id == KERNEL_PART_ID)
638 part_id = get_part_id("kernel");
643 printf("COMMAND_PARTITION_SYNC - Part%d\n", part_id);
645 blocks = parts[part_id]->size / 1024 / 128;
646 printf("COMMAND_PARTITION_SYNC - Part%d, %d blocks\n",
649 *((ulong *) usbd->tx_data) = blocks;
650 usbd->send_data(usbd->tx_data, usbd->tx_len);
653 case COMMAND_WRITE_PART_0:
655 printf("COMMAND_WRITE_PART_0\n");
658 case COMMAND_WRITE_PART_1:
659 printf("COMMAND_WRITE_PART_BOOT\n");
660 part_id = get_part_id("bootloader");
664 case COMMAND_WRITE_PART_2:
665 case COMMAND_ERASE_PARAMETER:
666 printf("COMMAND_PARAMETER - not support!\n");
669 case COMMAND_WRITE_PART_3:
670 printf("COMMAND_WRITE_KERNEL\n");
671 part_id = get_part_id("kernel");
672 img_type = IMG_KERNEL;
675 case COMMAND_WRITE_PART_4:
676 printf("COMMAND_WRITE_ROOTFS\n");
677 part_id = get_part_id("Root");
678 img_type = IMG_FILESYSTEM;
682 case COMMAND_WRITE_PART_5:
683 printf("COMMAND_WRITE_FACTORYFS\n");
684 part_id = get_part_id("Fact");
685 img_type = IMG_FILESYSTEM;
689 case COMMAND_WRITE_PART_6:
690 printf("COMMAND_WRITE_DATAFS\n");
691 part_id = get_part_id("Data");
692 img_type = IMG_FILESYSTEM;
696 case COMMAND_WRITE_PART_7:
697 printf("COMMAND_WRITE_UBI\n");
698 part_id = get_part_id("UBI");
699 img_type = IMG_FILESYSTEM;
701 /* someday, it will be deleted */
705 case COMMAND_WRITE_PART_8:
706 printf("COMMAND_WRITE_MODEM\n");
707 part_id = get_part_id("modem");
708 img_type = IMG_MODEM;
711 case COMMAND_WRITE_PART_9:
712 printf("COMMAND_WRITE_MMC\n");
714 mmc_part_write = arg;
717 case COMMAND_WRITE_UBI_INFO:
718 printf("COMMAND_WRITE_UBI_INFO\n");
721 #ifdef CONFIG_CMD_UBI
723 sprintf(length, "0x%x", (uint)len);
724 ret = ubi_cmd(part_id, ramaddr, length, "begin");
727 printf("Error: Not UBI mode\n");
731 *((ulong *) usbd->tx_data) = ret;
732 /* Write image success -> Report status */
733 usbd->send_data(usbd->tx_data, usbd->tx_len);
736 /* Download complete -> reset */
737 case COMMAND_RESET_PDA:
738 printf("\nDownload finished and Auto reset!\nWait........\n");
747 case COMMAND_RESET_USB:
748 printf("\nError is occured!(maybe previous step)->\
749 Turn off and restart!\n");
755 case COMMAND_RAM_BOOT:
760 case COMMAND_RAMDISK_MODE:
761 printf("COMMAND_RAMDISK_MODE\n");
762 #ifdef CONFIG_RAMDISK_ADDR
764 down_ram_addr = usbd->ram_addr;
766 down_ram_addr = CONFIG_RAMDISK_ADDR;
772 #ifdef CONFIG_DOWN_PHONE
773 case COMMAND_DOWN_PHONE:
774 printf("COMMAND_RESET_PHONE\n");
778 *((ulong *) usbd->tx_data) = STATUS_DONE;
779 usbd->send_data(usbd->tx_data, usbd->tx_len);
782 case COMMAND_CHANGE_USB:
783 printf("COMMAND_CHANGE_USB\n");
793 case COMMAND_CSA_CLEAR:
794 printf("COMMAND_CSA_CLEAR\n");
795 part_id = get_part_id("csa");
796 img_type = IMG_MODEM;
799 case COMMAND_PROGRESS:
800 if (usbd->set_progress)
801 usbd->set_progress(arg);
805 printf("Error: Unknown command -> (%d)\n", (int)cmd);
809 /* Erase and Write to NAND */
812 #ifdef CONFIG_S5PC1XX
813 /* Workaround: for prevent revision mismatch */
814 if (cpu_is_s5pc110() && (down_mode != MODE_FORCE)) {
816 long *img_header = (long *)down_ram_addr;
818 if (*img_header == 0xea000012)
821 if (img_rev != s5pc1xx_get_cpu_rev()) {
822 printf("CPU revision mismatch!\n");
823 *((ulong *) usbd->tx_data) = STATUS_ERROR;
824 usbd->send_data(usbd->tx_data, usbd->tx_len);
829 #if defined(CONFIG_ENV_IS_IN_NAND) || defined(CONFIG_ENV_IS_IN_ONENAND)
830 /* Erase the environment also when write bootloader */
833 param_id = get_part_id("params");
835 if (param_id == -1) {
836 sprintf(offset, "%x", CONFIG_ENV_OFFSET);
837 sprintf(length, "%x", CONFIG_ENV_SIZE);
839 sprintf(offset, "%x", parts[param_id]->offset);
840 sprintf(length, "%x", parts[param_id]->size);
842 nand_cmd(0, offset, length, NULL);
845 /* Fall through for write bootloader */
847 sprintf(offset, "%x", parts[part_id]->offset);
848 sprintf(length, "%x", parts[part_id]->size);
851 nand_cmd(0, offset, length, NULL);
853 sprintf(length, "%x", (unsigned int) len);
854 ret = nand_cmd(1, ramaddr, offset, length);
859 ret = write_file_system(ramaddr, len, offset, length,
860 part_id, ubi_update);
864 sprintf(offset, "%x", parts[part_id]->offset);
865 sprintf(length, "%x", parts[part_id]->size);
869 nand_cmd(0, offset, length, NULL);
871 printf("CSA Clear will be skipped temporary\n");
873 /* Write : arg (0 Modem) / (1 CSA) */
875 sprintf(length, "%x", (unsigned int) len);
876 ret = nand_cmd(1, ramaddr, offset, length);
880 #ifdef CONFIG_CMD_MMC
883 ret = write_file_mmc_part(usbd, ramaddr,
884 len, offset, length);
886 ret = write_file_mmc(usbd, ramaddr,
887 len, offset, length);
897 /* Retry this commad */
898 *((ulong *) usbd->tx_data) = STATUS_RETRY;
899 usbd->send_data(usbd->tx_data, usbd->tx_len);
902 *((ulong *) usbd->tx_data) = STATUS_DONE;
904 /* Write image success -> Report status */
905 usbd->send_data(usbd->tx_data, usbd->tx_len);
909 /* Reset write count for another image */
913 #ifdef CONFIG_USE_YAFFS
921 static const char *recv_key = "SAMSUNG";
922 static const char *tx_key = "MPL";
924 int do_usbd_down(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
926 struct usbd_ops *usbd;
930 down_mode = simple_strtoul(argv[1], NULL, 10);
932 down_mode = MODE_NORMAL;
934 printf("USB Downloader v%s\n", APP_VERSION);
936 /* get partition info */
937 err = get_part_info();
941 /* interface setting */
942 usbd = usbd_set_interface(&usbd_ops);
943 down_ram_addr = usbd->ram_addr;
945 /* init the usb controller */
948 /* receive setting */
949 usbd->recv_setup(usbd->rx_data, usbd->rx_len);
951 /* detect the download request from Host PC */
952 if (usbd->recv_data()) {
953 if (strncmp(usbd->rx_data, recv_key, strlen(recv_key)) == 0) {
954 printf("Download request from the Host PC\n");
957 strcpy(usbd->tx_data, tx_key);
958 usbd->send_data(usbd->tx_data, usbd->tx_len);
960 printf("No download request from the Host PC!! 1\n");
964 printf("No download request from the Host PC!!\n");
968 printf("Receive the packet\n");
970 /* receive the data from Host PC */
972 usbd->recv_setup(usbd->rx_data, usbd->rx_len);
974 if (usbd->recv_data()) {
975 if (process_data(usbd) == 0)
983 U_BOOT_CMD(usbdown, CONFIG_SYS_MAXARGS, 1, do_usbd_down,
984 "Initialize USB device and Run USB Downloader (specific)",
986 "usbdown mode - specific mode (0: NORAML, 1: FORCE)\n"