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