merge with master
[kernel/u-boot.git] / common / cmd_usbd.c
1 /*
2  * USB Downloader
3  *
4  * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
5  * PROPRIETARY/CONFIDENTIAL
6  * This software is the confidential and proprietary information of
7  * SAMSUNG ELECTRONICS ("Confidential Information").
8  * You shall not disclose such Confidential Information and shall
9  * use it only in accordance with the terms of the license agreement
10  * you entered into with SAMSUNG ELECTRONICS.  SAMSUNG make no
11  * representations or warranties about the suitability
12  * of the software, either express or implied, including but not
13  * limited to the implied warranties of merchantability, fitness for
14  * a particular purpose, or non-infringement.
15  * SAMSUNG shall not be liable for any damages suffered by licensee as
16  * a result of using, modifying or distributing this software or its derivatives.
17  *
18  */
19
20 #include <common.h>
21 #include <usbd.h>
22 #include <asm/errno.h>
23 #include <asm/arch/power.h>
24 #include <malloc.h>
25 #include <mbr.h>
26 #include <mmc.h>
27 #include <fat.h>
28 #include <part.h>
29 #include <fbutils.h>
30 #include <mobile/header.h>
31 #include <mobile/pit.h>
32 #include <mobile/fota.h>
33 #include <mobile/misc.h>
34 #include <mobile/fs_type_check.h>
35 #include <mobile/stopwatch.h>
36 #ifndef CONFIG_CMD_PIT
37 #error "USB Downloader need to define the CONFIG_CMD_PIT"
38 #endif
39 #ifndef CONFIG_GENERIC_MMC
40 #error "USB Downloader need to define the CONFIG_GENERIC_MMC"
41 #endif
42
43 #define DEBUG(level, fmt, args...) \
44         if (level < debug_level) printf(fmt, ##args);
45 #define ERROR(fmt, args...) \
46         printf("error: " fmt, ##args);
47
48 #ifdef CONFIG_MMC_ASYNC_WRITE
49 #define mmc_async_on(d, c)      mmc_async_on(d, c)
50 #else
51 #define mmc_async_on(d, c)      do { } while(0)
52 #endif
53
54 /* version of USB Downloader Application */
55 #define APP_VERSION             "1.0"
56
57 /* download/upload packet size */
58 #define PKT_DOWNLOAD_SIZE       (1 << 20)
59 #define PKT_DOWNLOAD_CHUNK_SIZE (32 << 20)
60 #define PKT_UPLOAD_SIZE         (512 << 10)
61
62 enum {
63         OPS_READ,
64         OPS_WRITE,
65         OPS_ERASE,
66 };
67
68 enum {
69         FILE_TYPE_NORMAL,
70         FILE_TYPE_PIT,
71 };
72
73 static struct usbd_ops usbd_ops;
74 static struct mmc *mmc;
75
76 static int down_mode = MODE_NORMAL;
77 static int debug_level = 2;
78 static int check_speed = 0;
79
80 static u32 download_addr;
81 static u32 download_addr_ofs;
82
83 static u32 download_total_size;
84 static u32 download_packet_size;
85 static u32 download_unit;
86 static u32 download_prog;
87 static u32 download_prog_check;
88
89 static int dump_start;
90
91 static int file_size;
92 static int file_type;
93 static int file_offset;
94
95 extern struct pitpart_data pitparts[];
96
97 static int pkt_download(void *dest, const int size);
98 static void send_data_rsp(s32 ack, s32 count);
99
100 #ifdef CONFIG_ENV_UPDATE_WITH_DL
101 static unsigned char update_flag = 0;
102 #endif
103
104
105 static void set_update_state(int on)
106 {
107         static int state = 0;
108
109         if (state == on)
110                 return;
111         else
112                 state = on;
113
114         if (on)
115                 setenv("updatestate", "going");
116         else
117                 setenv("updatestate", NULL);
118
119         saveenv();
120 }
121
122 static void set_update_flag(void)
123 {
124         int i;
125 #ifdef CONFIG_ENV_UPDATE_WITH_DL
126         int count = 0;
127         char buf[512] = {0, };
128         char *paramlist[] = { "SLP_KERNEL_NEW", "SLP_ROOTFS_NEW" };
129 #endif
130         if (update_flag & (1 << SLP_KERNEL_NEW))
131                 setenv("SLP_KERNEL_NEW","1");
132         if (update_flag & (1 << SLP_ROOTFS_NEW))
133                 setenv("SLP_ROOTFS_NEW","1");
134 #ifdef CONFIG_ENV_UPDATE_WITH_DL
135         for (i = 0; i < ARRAY_SIZE(paramlist); i++) {
136                 count += sprintf(buf + count, "%s=%s;",
137                                 paramlist[i], getenv(paramlist[i]));
138                 DEBUG(3, "buf: %s\n", buf);
139         }
140
141         setenv("updated", "1");
142         setenv("updateparam", buf);
143
144         DEBUG(1, "update env: %s(%d)\n", buf, strlen(buf));
145 #endif
146         saveenv();
147 }
148
149 static int mmc_cmd(int ops, int dev_num, ulong start, lbaint_t cnt, void *addr)
150 {
151         int ret = 0;
152
153         DEBUG(1, "mmc %s 0 0x%x 0x%x 0x%x\n", ops ? "write" : "read",
154                         (u32)addr, (u32)start, (u32)cnt);
155
156         if (ops == OPS_WRITE)
157                 ret = mmc->block_dev.block_write(dev_num, start, cnt, addr);
158         else if (ops == OPS_READ)
159                 ret = mmc->block_dev.block_read(dev_num, start, cnt, addr);
160
161         if (ret > 0)
162                 ret = 1;
163         else
164                 ret = 0;
165
166         return ret;
167 }
168
169 static int mmc_write(struct usbd_ops *usbd, unsigned int len, int part_num)
170 {
171         int ret = 0;
172         int pit_idx;
173         int blk_len = len / usbd->mmc_blk;
174         int fstype;
175         int ums_id;
176
177         if (gpt_parts <= part_num) {
178                 ERROR("Partition table have %d partitions (request %d)\n",
179                                 gpt_parts, part_num);
180                 return 0;
181         }
182
183         /* check partition overwrite */
184         if ((gpt_offset[part_num] + file_offset + blk_len) > gpt_offset[part_num + 1]
185                 && (part_num + 1) < gpt_parts) {
186                 ERROR("download img is too large (blk size: 0x%x)\n",
187                         gpt_offset[part_num + 1] - gpt_offset[part_num]);
188 #ifdef CONFIG_LCD
189                 set_font_color(FONT_YELLOW);
190                 if (!board_no_lcd_support()) {
191                         fb_printf("\nError: download img is too large\n");
192                 }
193 #endif
194                 return -1;
195         }
196
197         ret = mmc_cmd(OPS_WRITE, usbd->mmc_dev,
198                         gpt_offset[part_num] + file_offset,
199                         blk_len,
200                         (void *)download_addr);
201
202         file_offset += blk_len;
203
204         return ret;
205 }
206
207 static int fs_write(struct usbd_ops *usbd, char *file_name, int part_id, int len)
208 {
209         int ret;
210         char cmd[12], arg1[12], arg2[128], arg3[128], arg4[12];
211         char * const argv[] = {cmd, "mmc", arg1, arg2, arg3, arg4};
212         int fstype;
213
214         ret = fstype_register_device(&mmc->block_dev, part_id);
215         if (ret < 0) {
216                 ERROR("fstype_register_divce\n");
217                 return 0;
218         }
219
220         sprintf(arg1, "%d:%d", usbd->mmc_dev, part_id);
221         fstype = fstype_check(&mmc->block_dev);
222
223         /* detect filesystem */
224         if (fstype == FS_TYPE_EXT4) {
225 #if defined(CONFIG_CMD_EXT4)
226                 sprintf(cmd, "ext4write");
227                 sprintf(arg2, "/%s", file_name);
228                 sprintf(arg3, "0x%x", (u32)download_addr);
229                 sprintf(arg4, "%d", len);
230
231                 if (do_ext4_write(NULL, 0, 6, argv)) {
232                         ERROR("writing %s\n", file_name);
233                         return 0;
234                 }
235                 return 1;
236 #endif
237         } else if (fstype == FS_TYPE_VFAT) {
238 #if defined(CONFIG_FAT_WRITE)
239                 sprintf(cmd, "fatwrite");
240                 sprintf(arg2, "0x%x", (u32)download_addr);
241                 sprintf(arg3, "%s", file_name);
242                 sprintf(arg4, "%d", len);
243
244                 if (do_fat_fswrite(NULL, 0, 6, argv)) {
245                         ERROR("writing %s\n", file_name);
246                         return 0;
247                 }
248                 return 1;
249 #endif
250         }
251
252         /* change filesystem by CONFIG define
253            fs priority: ext4 -> vfat */
254 #if defined(CONFIG_CMD_EXT4)
255         if (fstype != FS_TYPE_EXT4) {
256                 sprintf(cmd, "ext4format");
257                 if (do_ext4_format(NULL, 0, 3, argv)) {
258                         ERROR("format with ext4\n");
259                         return 0;
260                 }
261         }
262
263         sprintf(cmd, "ext4write");
264         sprintf(arg2, "/%s", file_name);
265         sprintf(arg3, "0x%x", (u32)download_addr);
266         sprintf(arg4, "%d", len);
267
268         ret = do_ext4_write(NULL, 0, 6, argv);
269 #elif defined(CONFIG_FAT_WRITE)
270         if (fstype != FS_TYPE_VFAT) {
271                 sprintf(cmd, "fatformat");
272                 if (do_fat_format(NULL, 0, 3, argv)) {
273                         ERROR("format with vfat\n");
274                         return 0;
275                 }
276         }
277
278         sprintf(cmd, "fatwrite");
279         sprintf(arg2, "0x%x", (u32)download_addr);
280         sprintf(arg3, "%s", file_name);
281         sprintf(arg4, "%d", len);
282
283         ret = do_fat_fswrite(NULL, 0, 6, argv);
284 #else
285         ERROR("doesn't support filesystem\n");
286         return 0;
287 #endif
288
289         if (ret) {
290                 ERROR("writing %s\n", file_name);
291                 return 0;
292         }
293
294         return 1;
295 }
296
297 static int fusing_mmc(u32 pit_idx, u32 addr, u32 len, u32 is_last)
298 {
299         int ret = -1;
300         char buf[64];
301         char *name = pitparts[pit_idx].name;
302         int part_id = pitparts[pit_idx].id;
303         int part_type = pitparts[pit_idx].part_type;
304         int part_fstype = pitparts[pit_idx].filesys;
305
306         name = pitparts[pit_idx].name;
307
308         if (name == NULL)
309                 name = "?";
310
311         DEBUG(3, "mmc (%d, %s) len(0x%x)\n", part_id, name, len);
312
313         if (part_id >= PIT_BOOTPART0_ID) {
314                 sprintf(buf, "mmc boot 0 1 1 %d", PIT_BOOTPARTn_GET(part_id));
315                 if (run_command(buf, 0) > 0) {
316                         sprintf(buf, "mmc write 0 0x%x 0 0x%x", addr,
317                                 (u32)pitparts[pit_idx].size / usbd_ops.mmc_blk);
318                         ret = run_command(buf, 0);
319                 } else
320                         ERROR("s-boot update failed\n");
321
322                 run_command("mmc boot 0 1 1 0", 0);
323
324                 goto fusing_mmc_end;
325         }
326
327         if (part_type != PART_TYPE_DATA) {
328                 ERROR("not supported type: %d\n", part_type);
329                 return ret;
330         }
331
332         if (part_fstype == PART_FS_TYPE_BASIC) {
333                 DEBUG(3, "at hidden partition\n");
334                 ret = mmc_cmd(OPS_WRITE, usbd_ops.mmc_dev,
335                                 pitparts[pit_idx].offset / usbd_ops.mmc_blk,
336                                 pitparts[pit_idx].size / usbd_ops.mmc_blk,
337                                 (void *)addr);
338         } else {
339                 DEBUG(3, "at normal partition as image\n");
340                 int part_base = pit_get_partition_base();
341                 ret = mmc_write(&usbd_ops, len, (pit_idx - part_base));
342         }
343
344 fusing_mmc_end:
345         DEBUG(3, "mmc done\n");
346
347         return ret;
348 }
349
350 static int fusing_fs(u32 pit_idx, u32 addr, u32 len, u32 is_last)
351 {
352         int ret = 0;
353         int part_id;
354         int tmp_id;
355         char *name = pitparts[pit_idx].name;
356         static u32 offset = 0; /* At last, offset is file size */
357
358         DEBUG(3, "file (%d, %s) len(0x%x)\n", pitparts[pit_idx].id, name, len);
359
360         memcpy(CONFIG_SYS_BACKUP_ADDR + offset, download_addr, len);
361         offset += len;
362
363         if (!is_last)
364                 return 1;
365
366         download_addr = CONFIG_SYS_BACKUP_ADDR;
367
368         if (!strncmp(name, "install-", 8) ||
369             !strncmp(name, "fota-delta", 10)) {
370                 /* need to erase for hibernation */
371                 erase_given_area(PARTS_QBOOT, QBOOT_ERASE_SIZE);
372
373                 tmp_id = get_pitpart_id(PARTS_UMS);
374         } else
375                 tmp_id = get_pitpart_id(PARTS_BOOT);
376
377         part_id = pit_adjust_id_on_mmc(tmp_id);
378         ret = fs_write(&usbd_ops, pitparts[pit_idx].file_name, part_id, offset);
379         offset = 0;
380
381 #ifdef CONFIG_FOTA_DELTA_DOWNLOAD
382         if (!ret && !strncmp(name, "fota-delta", 10)) {
383                 DEBUG(3, "set FOTA flag\n");
384                 board_inform_set(REBOOT_FOTA);
385         }
386 #endif
387         DEBUG(3, "file done\n");
388
389         return ret;
390 }
391
392 static int update_pit(void)
393 {
394         char arg1[12], arg2[12];
395         char *argv[] = {"pit", arg1, arg2};
396         u32 boot_idx;
397         u32 boot_offset = 0;
398         u32 boot_size = 0;
399
400         boot_idx = get_pitpart_id(PARTS_BOOT);
401         if (boot_idx >= 0) {
402                 boot_offset = pitparts[boot_idx].offset;
403                 boot_size = pitparts[boot_idx].size;
404         }
405
406         sprintf(arg1, "update");
407         sprintf(arg2, "%x", (u32)download_addr);
408         do_pit(NULL, 0, 3, argv);
409
410         sprintf(arg1, "write");
411         sprintf(arg2, "%x", (u32)download_addr);
412         do_pit(NULL, 0, 3, argv);
413
414         if (!pit_no_partition_support()) {
415                 char *mbr = getenv("mbrparts");
416                 int len = strlen(mbr) + 1;
417                 int mbr_idx = pit_get_partition_base();
418                 memcpy((void *)download_addr, (void *)mbr, len);
419                 set_gpt_info(&mmc->block_dev, (char *)download_addr, len,
420                                 pitparts[mbr_idx].offset / usbd_ops.mmc_blk);
421         }
422
423         /*
424          * boot partition format, that is only formatted at bootloader.
425          * format conditions are,
426          * - can't detect filesystem (e.g., not formatted, broken)
427          * - boot partition size or location is changed.
428          */
429         boot_idx = get_pitpart_id(PARTS_BOOT);
430         if ((boot_offset != pitparts[boot_idx].offset) ||
431                         (boot_size != pitparts[boot_idx].size)) {
432                 char cmd[32];
433                 /* just erase partition head to format at writing */
434                 DEBUG(1, "erase /boot partition to format");
435                 sprintf(cmd, "mmc erase 0 0x%x 4",
436                         pitparts[boot_idx].offset / usbd_ops.mmc_blk);
437                 run_command(cmd, 0);
438         }
439
440         printf("Update pit is done!\n");
441
442         return 1;
443 }
444
445 static int fusing_recv_data(u32 addr, int pit_idx, s32 size, int final)
446 {
447         int ret = 1;
448         char *name;
449         int uboot_index = -1;
450
451         if (file_type == FILE_TYPE_PIT)
452                 return update_pit();
453
454         name = pitparts[pit_idx].name;
455
456
457         switch (pitparts[pit_idx].dev_type) {
458         case PIT_DEVTYPE_MMC:
459                 ret = fusing_mmc(pit_idx, addr, size, final);
460                 break;
461         case PIT_DEVTYPE_FILE:
462                 ret = fusing_fs(pit_idx, addr, size, final);
463                 break;
464         default:
465                 DEBUG(1, "unknown device type(%d). plz check PIT\n", pitparts[pit_idx].dev_type);
466                 ret = -1;
467         }
468
469         return ret;
470 }
471
472 static inline void set_async_buffer(void)
473 {
474         if (download_addr_ofs)
475                 download_addr_ofs = 0;
476         else
477                 download_addr_ofs = PKT_DOWNLOAD_CHUNK_SIZE + (5 << 20);
478
479         download_addr = usbd_ops.ram_addr + download_addr_ofs;
480         DEBUG(3, "download addr: 0x%8x\n", download_addr);
481 }
482
483 static void recv_data_end(int pit_idx)
484 {
485         char *name;
486
487         if (pit_idx < 0) {
488                 ERROR("invalid pit index\n");
489                 return;
490         }
491
492         name = pitparts[pit_idx].name;
493
494 #ifndef CONFIG_ENV_UPDATE_WITH_DL
495         if (!strncmp(name, PARTS_BOOTLOADER, 6)) {
496                 erase_given_area(PARTS_PARAMS, 0);
497         }
498 #endif
499         if (!strncmp(name, PARTS_QBOOT, 5)) {
500                 qboot_erase = 1;
501         } else if (!strncmp(name, PARTS_KERNEL, 6)) {
502                 update_flag |= 1 << SLP_KERNEL_NEW;
503                 erase_given_area(PARTS_QBOOT, QBOOT_ERASE_SIZE);
504         } else if (!strncmp(name, PARTS_ROOT, 8) ||
505                 !strncmp(name, PARTS_DATA,4)) {
506                 update_flag |= 1 << SLP_ROOTFS_NEW;
507                 erase_given_area(PARTS_QBOOT, QBOOT_ERASE_SIZE);
508         } else if (!strncmp(name, PARTS_CSC,3)) {
509                 update_flag |= 1 << SLP_ROOTFS_NEW;
510         } else if (!strncmp(name, PARTS_UBI, 3)) {
511                 erase_given_area(PARTS_QBOOT, QBOOT_ERASE_SIZE);
512         }
513 }
514
515 static int recv_data(int pit_idx)
516 {
517         u32 dn_addr;
518         u32 buffered = 0;
519         u32 progressed = 0;
520         s32 remained = file_size;
521         int ret = 1;
522         int count = 1;
523         int final = 0;
524         unsigned long long sw_size;
525         u32 sw_check = 0;
526         u32 sw_bak = 0;
527         u32 sw_time = 0;
528
529         if ((pit_idx < 0) && (file_type != FILE_TYPE_PIT)) {
530                 ERROR("invalid pit index because of wrong file name\n");
531                 return -ENOENT;
532         }
533
534         if (check_speed)
535                 sw_size = (unsigned long long) download_packet_size *
536                                 stopwatch_tick_clock() / 1024; /* KB */
537
538         while(!final) {
539                 if (check_speed) {
540                         sw_bak = sw_check;
541                         sw_check = stopwatch_tick_count();
542
543                         if (!sw_time && sw_bak)
544                                 sw_time = sw_check - sw_bak;
545                         else
546                                 sw_time = (sw_time + (sw_check - sw_bak)) / 2;
547                 }
548
549                 dn_addr = download_addr + buffered;
550                 ret = pkt_download((void *)dn_addr, download_packet_size);
551                 if (ret <= 0)
552                         return ret;
553
554                 buffered += download_packet_size;
555                 progressed += download_packet_size;
556
557                 /* check last packet */
558                 if (progressed >= file_size)
559                         final = 1;
560
561                 /* fusing per chunk */
562                 if ((buffered >= PKT_DOWNLOAD_CHUNK_SIZE) || final) {
563                         if (check_speed)
564                                 printf("[%d MB/s]\n", (u32)(sw_size / sw_time / 1024));
565
566                         set_update_state(1);
567                         ret = fusing_recv_data(download_addr, pit_idx, MIN(buffered, remained), final);
568                         if (ret <= 0)
569                                 return ret;
570
571                         set_async_buffer();
572                         remained -= buffered;
573                         buffered = 0;
574                 }
575
576                 if (final)
577                         recv_data_end(pit_idx);
578
579                 send_data_rsp(0, count++);
580
581                 /* progress bar */
582                 download_prog += download_packet_size;
583                 if (download_prog > download_prog_check) {
584                         if (usbd_ops.set_progress)
585                                 usbd_ops.set_progress(download_prog / download_unit);
586                         download_prog_check += max(download_unit, download_packet_size);
587                 }
588         }
589
590         return ret;
591 }
592
593 /*
594  * DOWNLOAD
595  */
596
597 #define VER_PROTOCOL_MAJOR      4
598 #define VER_PROTOCOL_MINOR      0
599
600 enum rqt {
601         RQT_INFO = 200,
602         RQT_CMD,
603         RQT_DL,
604         RQT_UL,
605 };
606
607 enum rqt_data {
608         /* RQT_INFO */
609         RQT_INFO_VER_PROTOCOL = 1,
610         RQT_INIT_VER_HW,
611         RQT_INIT_VER_BOOT,
612         RQT_INIT_VER_KERNEL,
613         RQT_INIT_VER_PLATFORM,
614         RQT_INIT_VER_CSC,
615
616         /* RQT_CMD */
617         RQT_CMD_REBOOT = 1,
618         RQT_CMD_POWEROFF,
619         RQT_CMD_EFSCLEAR,
620
621         /* RQT_DL */
622         RQT_DL_INIT = 1,
623         RQT_DL_FILE_INFO,
624         RQT_DL_FILE_START,
625         RQT_DL_FILE_END,
626         RQT_DL_EXIT,
627
628         /* RQT_UL */
629         RQT_UL_INIT = 1,
630         RQT_UL_START,
631         RQT_UL_END,
632         RQT_UL_EXIT,
633 };
634
635 typedef struct _rqt_box {       /* total: 256B */
636         s32 rqt;                /* request id */
637         s32 rqt_data;           /* request data id */
638         s32 int_data[14];       /* int data */
639         char str_data[5][32];   /* string data */
640         char md5[32];           /* md5 checksum */
641 } __attribute__((packed)) rqt_box;
642
643 typedef struct _rsp_box {       /* total: 128B */
644         s32 rsp;                /* response id (= request id) */
645         s32 rsp_data;           /* response data id */
646         s32 ack;                /* ack */
647         s32 int_data[5];        /* int data */
648         char str_data[3][32];   /* string data */
649 } __attribute__((packed)) rsp_box;
650
651 typedef struct _data_rsp_box {  /* total: 8B */
652         s32 ack;                /* response id (= request id) */
653         s32 count;              /* response data id */
654 } __attribute__((packed)) data_rsp_box;
655
656
657 static const char dl_key[] = "THOR";
658 static const char dl_ack[] = "ROHT";
659
660 static inline int pkt_download(void *dest, const int size)
661 {
662         usbd_ops.recv_setup((char *)dest, size);
663         return usbd_ops.recv_data();
664 }
665
666 static inline void pkt_upload(void *src, const int size)
667 {
668         usbd_ops.send_data((char *)src, size);
669 }
670
671 static void send_rsp(const rsp_box *rsp)
672 {
673         /* should be copy on dma duffer */
674         memcpy(usbd_ops.tx_data, rsp, sizeof(rsp_box));
675         pkt_upload(usbd_ops.tx_data, sizeof(rsp_box));
676
677         DEBUG(1, "-RSP: %d, %d\n", rsp->rsp, rsp->rsp_data);
678 }
679
680 static void send_data_rsp(s32 ack, s32 count)
681 {
682         data_rsp_box rsp;
683
684         rsp.ack = ack;
685         rsp.count = count;
686
687         /* should be copy on dma duffer */
688         memcpy(usbd_ops.tx_data, &rsp, sizeof(data_rsp_box));
689         pkt_upload(usbd_ops.tx_data, sizeof(data_rsp_box));
690
691         DEBUG(3, "-DATA RSP: %d, %d\n", ack, count);
692 }
693
694 static int process_rqt_info(const rqt_box *rqt)
695 {
696         rsp_box rsp = {0, };
697
698         rsp.rsp = rqt->rqt;
699         rsp.rsp_data = rqt->rqt_data;
700
701         switch (rqt->rqt_data) {
702         case RQT_INFO_VER_PROTOCOL:
703                 rsp.int_data[0] = VER_PROTOCOL_MAJOR;
704                 rsp.int_data[1] = VER_PROTOCOL_MINOR;
705                 break;
706         case RQT_INIT_VER_HW:
707                 sprintf(rsp.str_data[0], "%x", get_board_rev());
708                 break;
709         case RQT_INIT_VER_BOOT:
710                 sprintf(rsp.str_data[0], "%s", getenv("ver"));
711                 break;
712         case RQT_INIT_VER_KERNEL:
713                 sprintf(rsp.str_data[0], "%s", "k unknown");
714                 break;
715         case RQT_INIT_VER_PLATFORM:
716                 sprintf(rsp.str_data[0], "%s", "p unknown");
717                 break;
718         case RQT_INIT_VER_CSC:
719                 sprintf(rsp.str_data[0], "%s", "c unknown");
720                 break;
721         default:
722                 return 0;
723         }
724
725         send_rsp(&rsp);
726         return 1;
727 }
728
729 static int process_rqt_cmd(const rqt_box *rqt)
730 {
731         rsp_box rsp = {0, };
732
733         rsp.rsp = rqt->rqt;
734         rsp.rsp_data = rqt->rqt_data;
735
736         switch (rqt->rqt_data) {
737         case RQT_CMD_REBOOT:
738                 DEBUG(1, "TARGET RESET\n");
739                 send_rsp(&rsp);
740
741                 board_inform_clear(0);
742                 board_inform_set(0);
743
744                 run_command("reset", 0);
745                 break;
746         case RQT_CMD_POWEROFF:
747                 DEBUG(1, "TARGET POWEROFF\n");
748                 send_rsp(&rsp);
749
750                 power_off();
751                 break;
752         case RQT_CMD_EFSCLEAR:
753                 /* DEBUG(1, "EFS CLEAR\n"); */
754                 /* erase /csa/nv/nvdata.bin */
755                 fs_write(&usbd_ops, "nv/nvdata.bin", 1, 0);
756                 send_rsp(&rsp);
757                 break;
758         default:
759                 return 0;
760         }
761
762         return 1;
763 }
764
765 static int process_rqt_download(const rqt_box *rqt)
766 {
767         rsp_box rsp = {0, };
768         int ret;
769         char *file_name;
770         static int pit_idx;
771
772         rsp.rsp = rqt->rqt;
773         rsp.rsp_data = rqt->rqt_data;
774
775         switch (rqt->rqt_data) {
776         case RQT_DL_INIT:
777                 download_total_size = rqt->int_data[0];
778                 download_unit = download_total_size / 100;
779                 download_prog = 0;
780                 download_prog_check = 0 + download_unit;
781
782                 DEBUG(1, "INIT: total %d bytes\n", download_total_size);
783
784                 download_addr_ofs = 0;
785                 mmc_async_on(mmc, 1);
786                 break;
787         case RQT_DL_FILE_INFO:
788                 file_type = rqt->int_data[0];
789                 file_size = rqt->int_data[1];
790                 file_name = rqt->str_data[0];
791                 file_offset = 0;
792                 if (file_type == FILE_TYPE_PIT) {
793                         int pit_is_up = pit_check_version(file_name);
794                         /*
795                          * Partition policy is changed from 08 version.
796                          * When 08 version is installed, we will block migrating
797                          * to previous version by pit.
798                          */
799                         if ((pit_get_version() == 8) && (pit_is_up < 0)) {
800                                 lcd_display_clear();
801                                 init_font();
802                                 set_font_color(FONT_RED);
803                                 fb_printf("[Error]\n\n");
804                                 set_font_color(FONT_WHITE);
805                                 fb_printf("Must download pit version larger than 8.\n");
806                                 fb_printf("Press power key retry to download again.\n");
807                                 while(!check_exit_key());
808                                 return -1;
809                         }
810                         pit_idx = get_pitpart_id_for_pit(file_name);
811                 } else
812                         pit_idx = get_pitpart_id_by_filename(file_name);
813
814                 DEBUG(1, "INFO: name(%s, %d), size(%d), type(%d)\n", file_name, pit_idx, file_size, file_type);
815
816                 rsp.int_data[0] = PKT_DOWNLOAD_SIZE;
817                 download_packet_size = PKT_DOWNLOAD_SIZE;
818                 break;
819         case RQT_DL_FILE_START:
820                 send_rsp(&rsp);
821                 return recv_data(pit_idx);
822         case RQT_DL_FILE_END:
823                 break;
824         case RQT_DL_EXIT:
825                 mmc_async_on(mmc, 0);
826                 set_update_state(0);
827                 set_update_flag();
828                 break;
829         default:
830                 return 0;
831         }
832
833         send_rsp(&rsp);
834         return 1;
835 }
836
837 static int process_rqt_upload(const rqt_box *rqt)
838 {
839         rsp_box rsp = {0, };
840
841         rsp.rsp = rqt->rqt;
842         rsp.rsp_data = rqt->rqt_data;
843
844         switch (rqt->rqt_data) {
845         case RQT_UL_INIT:
846                 break;
847         case RQT_UL_START:
848                 break;
849         case RQT_UL_END:
850                 break;
851         case RQT_UL_EXIT:
852                 break;
853         default:
854                 return 0;
855         }
856
857         send_rsp(&rsp);
858         return 1;
859 }
860
861 static int process_download_data(struct usbd_ops *usbd)
862 {
863         rqt_box rqt;
864         int ret = 1;
865
866         memset(&rqt, 0, sizeof(rqt));
867         memcpy(&rqt, usbd->rx_data, sizeof(rqt));
868
869         DEBUG(1, "+RQT: %d, %d\n", rqt.rqt, rqt.rqt_data);
870
871         switch (rqt.rqt) {
872         case RQT_INFO:
873                 ret = process_rqt_info(&rqt);
874                 break;
875         case RQT_CMD:
876                 ret = process_rqt_cmd(&rqt);
877                 break;
878         case RQT_DL:
879                 ret = process_rqt_download(&rqt);
880                 break;
881         case RQT_UL:
882                 ret = process_rqt_upload(&rqt);
883                 break;
884         default:
885                 ERROR("unknown request (%d)\n", rqt.rqt);
886                 ret = 0;
887         }
888
889         /*
890          * > 0 : success
891          * = 0 : error -> exit
892          * < 0 : error -> retry
893          */
894         return ret;
895 }
896
897 /*
898  * UPLOAD for RDX
899  */
900
901 static const char rdx_preamble[] = "PrEaMbLe";
902 static const char rdx_postamble[] = "PoStAmBlE";
903 static const char rdx_ack[] = "AcKnOwLeDgMeNt";
904
905 static const char rdx_probe[] = "PrObE";
906 static const char rdx_xfer[] = "DaTaXfEr";
907
908 extern int rdx_info_get(void **info_buf, int *info_size);
909
910 static int process_upload_data(struct usbd_ops *usbd)
911 {
912         static u32 dump_start, dump_end, upstate = 0;
913         char *rx = usbd->rx_data;
914         char *tx = usbd->tx_data;
915         u32 chunk_size;
916         void *buf;
917         int size;
918
919         if (!strncmp(rx, rdx_probe, strlen(rdx_probe))) {
920                 DEBUG(1, "up: information upload\n");
921
922                 rdx_info_get(&buf, &size);
923                 memcpy(tx, buf , size);
924                 usbd->send_data(usbd_ops.tx_data, size);
925                 return 1;
926         } else if (!strncmp(rx, rdx_preamble, strlen(rdx_preamble))) {
927                 DEBUG(1, "up: preamble\n");
928                 upstate = 1;
929
930                 strcpy(tx, rdx_ack);
931                 usbd->send_data(tx, sizeof(rdx_ack));
932                 return 1;
933         }
934
935         /* get dump start, end address */
936         if ((upstate == 1 || upstate == 2) && (strlen(rx) == 8)) {
937                 if (upstate == 1)
938                         dump_start = simple_strtoul(rx, NULL, 16);
939                 else if (upstate == 2)
940                         dump_end = simple_strtoul(rx, NULL, 16);
941                 else
942                         DEBUG(1, "up: oops!\n");
943                 upstate++;
944
945                 if (upstate == 3)
946                         DEBUG(1, "up: start(0x%08x), end(0x%08x)\n",
947                                 dump_start, dump_end);
948
949                 strcpy(tx, rdx_ack);
950                 usbd->send_data(tx, sizeof(rdx_ack));
951                 return 1;
952         }
953
954         if ((upstate == 3)
955             && (!strncmp(rx, rdx_xfer, strlen(rdx_xfer))
956                 || !strncmp(rx, rdx_ack, strlen(rdx_ack)))) {
957                 if (dump_start > dump_end) {
958                         upstate = 0;
959                         strcpy(tx, rdx_postamble);
960                         usbd->send_data(tx, sizeof(rdx_postamble));
961                         return 1;
962                 }
963
964                 /* dummy command for system reset */
965                 if ((dump_start == 0xfffffffc) && (dump_end == 0xffffffff))
966                         usbd->cancel(END_BOOT);
967
968                 chunk_size = min(PKT_UPLOAD_SIZE, (dump_end - dump_start + 1));
969                 usbd->send_data(dump_start, chunk_size);
970                 dump_start += chunk_size;
971
972                 if (!(dump_start % 0x1000000))
973                         DEBUG(1, "up: uploaded 0x%08x / 0x%08x\n",
974                                 dump_start, dump_end);
975                 return 1;
976         }
977
978         upstate = 0;
979         return 1;
980 }
981
982 int do_usbd_down(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
983 {
984         struct usbd_ops *usbd;
985         int (*process_data) (struct usbd_ops *);
986         int recv_size;
987         char *p;
988         int ret;
989         int update_fail = 0;
990
991         /* check debug level */
992         if (p = getenv("usbdebug")) {
993                 debug_level = simple_strtoul(p, NULL, 10);
994                 DEBUG(0, "debug level %d\n", debug_level);
995         }
996
997         /* download speed check option */
998         if (debug_level >= 2)
999                 check_speed = 1;
1000
1001         /* check option */
1002         if (argc > 1) {
1003                 p = argv[1];
1004                 if (!strncmp(p, "fail", 4)) {
1005                         DEBUG(1, "opt: fail\n");
1006                         update_fail = 1;
1007                 } else if (!strncmp(p, "force", 5)) {
1008                         DEBUG(1, "opt: force\n");
1009                         down_mode = MODE_FORCE;
1010                 } else if (!strncmp(p, "upload", 6)) {
1011                         DEBUG(1, "opt: upload\n");
1012                         down_mode = MODE_UPLOAD;
1013                 }
1014         }
1015
1016         usbd = usbd_set_interface(&usbd_ops, down_mode);
1017         usbd->rx_len = 256;
1018
1019         if (down_mode == MODE_UPLOAD)
1020                 goto setup_usb;
1021
1022         download_addr = (u32)usbd->ram_addr;
1023
1024         if (usbd->set_logo)
1025                 usbd->set_logo(APP_VERSION, usbd->mmc_info, update_fail);
1026
1027         mmc = find_mmc_device(usbd->mmc_dev);
1028         mmc_init(mmc);
1029
1030         /* get gpt info */
1031         set_gpt_dev(usbd->mmc_dev);
1032         gpt_parts = get_gpt_table(&mmc->block_dev, gpt_offset);
1033         if (!gpt_parts) {
1034                 char buf[32];
1035                 sprintf(buf, "gpt default %d", usbd->mmc_dev);
1036                 run_command(buf, 0);
1037         }
1038
1039         DEBUG(1, "Downloader v%s %s\n",
1040                 APP_VERSION,
1041                 down_mode == MODE_FORCE ? "- Force" : "");
1042
1043 setup_usb:
1044         /* init the usb controller */
1045         if (!usbd->usb_init()) {
1046                 usbd->cancel(END_BOOT);
1047                 return 0;
1048         }
1049
1050         /* refresh download logo since downloading fail */
1051         if (update_fail) {
1052                 if (usbd->set_logo)
1053                         usbd->set_logo(APP_VERSION, usbd->mmc_info, 0);
1054
1055         }
1056
1057 setup_retry:
1058         usbd->recv_setup(usbd->rx_data, strlen(dl_key));
1059         /* detect the download request from Host PC */
1060         ret = usbd->recv_data();
1061         if (ret > 0) {
1062                 if (!strncmp(usbd->rx_data, dl_key, strlen(dl_key))) {
1063                         DEBUG(1, "Download request from the Host PC\n");
1064                         msleep(30);
1065
1066                         strcpy(usbd->tx_data, dl_ack);
1067                         usbd->send_data(usbd->tx_data, strlen(dl_ack));
1068                 } else if (!strncmp(usbd->rx_data, rdx_preamble, strlen(rdx_preamble))) {
1069                         DEBUG(1, "Upload request from the Host\n");
1070                         msleep(30);
1071
1072                         strcpy(usbd->tx_data, rdx_ack);
1073                         usbd->send_data(usbd->tx_data, sizeof(rdx_ack));
1074                 } else if (strncmp(usbd->rx_data, "AT", 2) == 0) {
1075                         int i;
1076                         char atcmd_rev[10];
1077                         const char aterr_key[13] = {
1078                                 0x0d, 0x0a,
1079                                 'C' , 'M' , 'E' , ' ' ,'E', 'R', 'R', 'O', 'R',
1080                                 0x0d, 0x0a
1081                         };
1082
1083                         strncpy(atcmd_rev, usbd->rx_data, sizeof(atcmd_rev));
1084                         for (i = 2; i < sizeof(atcmd_rev); i++) {
1085                                 if (atcmd_rev[i] == 0x0d) {
1086                                         atcmd_rev[i] = '\0';
1087                                         DEBUG(1, "Received AT cmd from the Host PC:%s , length:%d\n",atcmd_rev, i);
1088                                         break;
1089                                 }
1090                         }
1091
1092                         strncpy(usbd->tx_data, aterr_key, sizeof(aterr_key));
1093                         usbd->send_data(usbd->tx_data, sizeof(aterr_key));
1094
1095 #ifdef CONFIG_S5P_USB_DMA
1096                         msleep(30);
1097                         /*BULK_IN/OUT_RESET_DATA_PID to 0*/
1098                         usbd->prepare_dma(NULL, 0, 0);
1099 #endif
1100                         DEBUG(1, "Retry waiting key from the Host PC\n");
1101                         goto setup_retry;
1102                 } else {
1103                         DEBUG(1, "Invalid request from the Host PC!! (len=%lu)\n", usbd->rx_len);
1104                         usbd->cancel(END_RETRY);
1105                         return 0;
1106                 }
1107         } else if (ret < 0) {
1108                 usbd->cancel(END_RETRY);
1109                 return 0;
1110         } else {
1111                 usbd->cancel(END_BOOT);
1112                 return 0;
1113         }
1114
1115         usbd->start();
1116         file_offset = 0;
1117
1118         if (down_mode == MODE_UPLOAD) {
1119                 process_data = process_upload_data;
1120                 usbd->rx_len = sizeof(rdx_probe);
1121         } else {
1122                 process_data = process_download_data;
1123         }
1124
1125         /* receive the data from Host PC */
1126         while (1) {
1127                 usbd->recv_setup(usbd->rx_data, usbd->rx_len);
1128
1129                 ret = usbd->recv_data();
1130                 if (ret > 0) {
1131                         ret = process_data(usbd);
1132                         if (ret < 0) {
1133                                 usbd->cancel(END_RETRY);
1134                                 return 0;
1135                         } else if (ret == 0) {
1136                                 usbd->cancel(END_NORMAL);
1137                                 return 0;
1138                         }
1139                 } else if (ret < 0) {
1140                         usbd->cancel(END_FAIL);
1141                         return 0;
1142                 } else {
1143                         usbd->cancel(END_BOOT);
1144                         return 0;
1145                 }
1146         }
1147
1148         return 0;
1149 }
1150
1151 U_BOOT_CMD(usbdown, CONFIG_SYS_MAXARGS, 1, do_usbd_down,
1152         "USB Downloader for SLP",
1153         "usbdown <force> - download binary images (force - don't check target)\n"
1154         "usbdown upload - upload debug info"
1155 );