recovery: universal: support the usb downloader
[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 <usbd.h>
11
12 #define OPS_READ        0
13 #define OPS_WRITE       1
14
15 static struct usbd_ops usbd_ops;
16 static unsigned long down_ram_addr;
17
18 /* Parsing received data packet and Process data */
19 static int process_data(struct usbd_ops *usbd)
20 {
21         ulong cmd = 0, arg = 0, len = 0, flag = 0;
22         int recvlen = 0;
23         int ret = 0;
24         int img_type;
25
26         /* Parse command */
27         cmd  = *((ulong *) usbd->rx_data + 0);
28         arg  = *((ulong *) usbd->rx_data + 1);
29         len  = *((ulong *) usbd->rx_data + 2);
30         flag = *((ulong *) usbd->rx_data + 3);
31
32         /* Reset tx buffer */
33         *((ulong *) usbd->tx_data) = 0;
34
35         switch (cmd) {
36         case COMMAND_DOWNLOAD_IMAGE:
37                 usbd->recv_setup((char *)down_ram_addr, (int)len);
38
39                 /* response */
40                 usbd->send_data(usbd->tx_data, usbd->tx_len);
41
42                 /* Receive image */
43                 recvlen = usbd->recv_data();
44
45                 /* Retry this commad */
46                 if (recvlen < len)
47                         *((ulong *) usbd->tx_data) = STATUS_RETRY;
48                 else
49                         *((ulong *) usbd->tx_data) = STATUS_DONE;
50
51                 usbd->send_data(usbd->tx_data, usbd->tx_len);
52                 return 1;
53
54         case COMMAND_PARTITION_SYNC:
55                 *((ulong *) usbd->tx_data) = CONFIG_RECOVERY_BOOT_BLOCKS - 1;
56                 usbd->send_data(usbd->tx_data, usbd->tx_len);
57                 return 1;
58
59         case COMMAND_WRITE_PART_1:
60                 img_type = IMG_BOOT;
61                 break;
62
63         /* Download complete -> reset */
64         case COMMAND_RESET_PDA:
65                 /* Stop USB */
66                 usbd->usb_stop();
67
68                 if (usbd->cpu_reset)
69                         usbd->cpu_reset();
70
71                 return 0;
72
73         /* Error */
74         case COMMAND_RESET_USB:
75                 /* Stop USB */
76                 usbd->usb_stop();
77                 return 0;
78
79         default:
80                 return 1;
81         }
82
83         /* Erase and Write to NAND */
84         switch (img_type) {
85         case IMG_BOOT:
86                 /* TO DO */
87                 /* Erase */
88                 /* Write */
89                 /* offset: CONFIG_RECOVERY_ADDR */
90                 /* size: CONFIG_RECOVERY_SIZE */
91                 break;
92
93         default:
94                 /* Retry? */
95                 break;
96         }
97
98         if (ret) {
99                 /* Retry this commad */
100                 *((ulong *) usbd->tx_data) = STATUS_RETRY;
101                 usbd->send_data(usbd->tx_data, usbd->tx_len);
102                 return 1;
103         } else
104                 *((ulong *) usbd->tx_data) = STATUS_DONE;
105
106         /* Write image success -> Report status */
107         usbd->send_data(usbd->tx_data, usbd->tx_len);
108
109         return 1;
110 }
111
112 int do_usbd_down(void)
113 {
114         struct usbd_ops *usbd;
115
116         /* interface setting */
117         usbd = usbd_set_interface(&usbd_ops);
118         down_ram_addr = usbd->ram_addr;
119
120         /* init the usb controller */
121         usbd->usb_init();
122
123         /* receive setting */
124         usbd->recv_setup(usbd->rx_data, usbd->rx_len);
125
126         /* detect the download request from Host PC */
127         if (usbd->recv_data())
128                 usbd->send_data(usbd->tx_data, usbd->tx_len);
129         else
130                 return 0;
131
132         /* receive the data from Host PC */
133         while (1) {
134                 usbd->recv_setup(usbd->rx_data, usbd->rx_len);
135
136                 if (usbd->recv_data()) {
137                         if (process_data(usbd) == 0)
138                                 return 0;
139                 }
140         }
141
142         return 0;
143 }