recovery: update is modified to support various image
[kernel/u-boot.git] / recovery / usbd.c
1 /*
2  * USB Downloader for SAMSUNG Platform
3  *
4  * Copyright (C) 2007-2010 Samsung Electronics
5  * Minkyu Kang <mk7.kang@samsung.com>
6  *
7  */
8
9 #include <common.h>
10 #include "recovery.h"
11 #include "usbd.h"
12
13 #ifdef RECOVERY_DEBUG
14 #define PUTS(s) serial_puts(DEBUG_MARK"usb: "s)
15 #else
16 #define PUTS(s)
17 #endif
18
19 static struct usbd_ops usbd_ops;
20 static unsigned long down_ram_addr;
21
22 /* Parsing received data packet and Process data */
23 static int process_data(struct usbd_ops *usbd)
24 {
25         ulong cmd = 0, arg = 0, len = 0, flag = 0;
26         int recvlen = 0;
27         int ret = 0;
28         int img_type;
29
30         /* Parse command */
31         cmd  = *((ulong *) usbd->rx_data + 0);
32         arg  = *((ulong *) usbd->rx_data + 1);
33         len  = *((ulong *) usbd->rx_data + 2);
34         flag = *((ulong *) usbd->rx_data + 3);
35
36         /* Reset tx buffer */
37         *((ulong *) usbd->tx_data) = 0;
38
39         switch (cmd) {
40         case COMMAND_DOWNLOAD_IMAGE:
41                 PUTS("COMMAND_DOWNLOAD_IMAGE\n");
42                 usbd->recv_setup((char *)down_ram_addr, (int)len);
43
44                 /* response */
45                 usbd->send_data(usbd->tx_data, usbd->tx_len);
46
47                 /* Receive image */
48                 recvlen = usbd->recv_data();
49
50                 /* Retry this commad */
51                 if (recvlen < len) {
52                         PUTS("Error: wrong image size\n");
53                         *((ulong *) usbd->tx_data) = STATUS_RETRY;
54                 } else
55                         *((ulong *) usbd->tx_data) = STATUS_DONE;
56
57                 usbd->send_data(usbd->tx_data, usbd->tx_len);
58                 return 1;
59
60         case COMMAND_PARTITION_SYNC:
61                 *((ulong *) usbd->tx_data) = CONFIG_RECOVERY_BOOT_BLOCKS - 1;
62                 usbd->send_data(usbd->tx_data, usbd->tx_len);
63                 return 1;
64
65         case COMMAND_WRITE_PART_1:
66                 PUTS("COMMAND_WRITE_PART_BOOT\n");
67                 img_type = IMG_BOOT;
68                 break;
69
70         /* Download complete -> reset */
71         case COMMAND_RESET_PDA:
72                 PUTS("Download finished and Auto reset!\n");
73                 PUTS("Wait........\n");
74                 /* Stop USB */
75                 usbd->usb_stop();
76
77                 if (usbd->cpu_reset)
78                         usbd->cpu_reset();
79
80                 return 0;
81
82         /* Error */
83         case COMMAND_RESET_USB:
84                 PUTS("Error is occured!(maybe previous step)->\
85                                 Turn off and restart!\n");
86                 /* Stop USB */
87                 usbd->usb_stop();
88                 return 0;
89
90         default:
91                 return 1;
92         }
93
94         /* Erase and Write to NAND */
95         switch (img_type) {
96         case IMG_BOOT:
97                 ret = board_update_image((u32 *)down_ram_addr, len);
98                 break;
99
100         default:
101                 /* Retry? */
102                 break;
103         }
104
105         if (ret) {
106                 /* Retry this commad */
107                 *((ulong *) usbd->tx_data) = STATUS_RETRY;
108                 usbd->send_data(usbd->tx_data, usbd->tx_len);
109                 return 1;
110         } else
111                 *((ulong *) usbd->tx_data) = STATUS_DONE;
112
113         /* Write image success -> Report status */
114         usbd->send_data(usbd->tx_data, usbd->tx_len);
115
116         return 1;
117 }
118
119 int do_usbd_down(void)
120 {
121         struct usbd_ops *usbd;
122
123         PUTS("USB Downloader\n");
124         /* interface setting */
125         usbd = usbd_set_interface(&usbd_ops);
126         down_ram_addr = usbd->ram_addr;
127
128         /* init the usb controller */
129         usbd->usb_init();
130
131         /* receive setting */
132         usbd->recv_setup(usbd->rx_data, usbd->rx_len);
133
134         /* detect the download request from Host PC */
135         if (usbd->recv_data())
136                 usbd->send_data(usbd->tx_data, usbd->tx_len);
137         else
138                 return 0;
139
140         PUTS("Receive the packet\n");
141
142         /* receive the data from Host PC */
143         while (1) {
144                 usbd->recv_setup(usbd->rx_data, usbd->rx_len);
145
146                 if (usbd->recv_data()) {
147                         if (process_data(usbd) == 0)
148                                 return 0;
149                 }
150         }
151
152         return 0;
153 }