]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/staging/gdm72xx/usb_boot.c
Merge branch 'drm-intel-fixes' of git://people.freedesktop.org/~danvet/drm-intel...
[karo-tx-linux.git] / drivers / staging / gdm72xx / usb_boot.c
1 /*
2  * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
3  *
4  * This software is licensed under the terms of the GNU General Public
5  * License version 2, as published by the Free Software Foundation, and
6  * may be copied, distributed, and modified under those terms.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  */
13
14 #include <linux/uaccess.h>
15 #include <linux/module.h>
16 #include <linux/version.h>
17 #include <linux/kernel.h>
18 #include <linux/mm.h>
19 #include <linux/usb.h>
20 #include <linux/unistd.h>
21 #include <linux/slab.h>
22
23 #include <asm/byteorder.h>
24 #include "gdm_usb.h"
25 #include "usb_boot.h"
26
27 #define DN_KERNEL_MAGIC_NUMBER          0x10760001
28 #define DN_ROOTFS_MAGIC_NUMBER          0x10760002
29
30 #define DOWNLOAD_SIZE   1024
31
32 #define DH2B(x)         __cpu_to_be32(x)
33 #define DL2H(x)         __le32_to_cpu(x)
34
35 #define MIN(a, b)       ((a) > (b) ? (b) : (a))
36
37 #define MAX_IMG_CNT             16
38 #define UIMG_PATH               "/lib/firmware/gdm72xx/gdmuimg.bin"
39 #define KERN_PATH               "/lib/firmware/gdm72xx/zImage"
40 #define FS_PATH                 "/lib/firmware/gdm72xx/ramdisk.jffs2"
41
42 struct dn_header {
43         u32     magic_num;
44         u32     file_size;
45 };
46
47 struct img_header {
48         u32             magic_code;
49         u32             count;
50         u32             len;
51         u32             offset[MAX_IMG_CNT];
52         char    hostname[32];
53         char    date[32];
54 };
55
56 struct fw_info {
57         u32             id;
58         u32             len;
59         u32             kernel_len;
60         u32             rootfs_len;
61         u32             kernel_offset;
62         u32             rootfs_offset;
63         u32             fw_ver;
64         u32             mac_ver;
65         char    hostname[32];
66         char    userid[16];
67         char    date[32];
68         char    user_desc[128];
69 };
70
71 static void array_le32_to_cpu(u32 *arr, int num)
72 {
73         int i;
74         for (i = 0; i < num; i++, arr++)
75                 *arr = DL2H(*arr);
76 }
77
78 static u8 *tx_buf;
79
80 static int gdm_wibro_send(struct usb_device *usbdev, void *data, int len)
81 {
82         int ret;
83         int actual;
84
85         ret = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), data, len,
86                         &actual, 1000);
87
88         if (ret < 0) {
89                 printk(KERN_ERR "Error : usb_bulk_msg ( result = %d )\n", ret);
90                 return ret;
91         }
92         return 0;
93 }
94
95 static int gdm_wibro_recv(struct usb_device *usbdev, void *data, int len)
96 {
97         int ret;
98         int actual;
99
100         ret = usb_bulk_msg(usbdev, usb_rcvbulkpipe(usbdev, 2), data, len,
101                         &actual, 5000);
102
103         if (ret < 0) {
104                 printk(KERN_ERR "Error : usb_bulk_msg(recv) ( result = %d )\n",
105                         ret);
106                 return ret;
107         }
108         return 0;
109 }
110
111 static int download_image(struct usb_device *usbdev, struct file *filp,
112                                 loff_t *pos, u32 img_len, u32 magic_num)
113 {
114         struct dn_header h;
115         int ret = 0;
116         u32 size;
117         int len, readn;
118
119         size = (img_len + DOWNLOAD_SIZE - 1) & ~(DOWNLOAD_SIZE - 1);
120         h.magic_num = DH2B(magic_num);
121         h.file_size = DH2B(size);
122
123         ret = gdm_wibro_send(usbdev, &h, sizeof(h));
124         if (ret < 0)
125                 goto out;
126
127         readn = 0;
128         while ((len = filp->f_op->read(filp, tx_buf, DOWNLOAD_SIZE, pos))) {
129
130                 if (len < 0) {
131                         ret = -1;
132                         goto out;
133                 }
134                 readn += len;
135
136                 ret = gdm_wibro_send(usbdev, tx_buf, DOWNLOAD_SIZE);
137                 if (ret < 0)
138                         goto out;
139                 if (readn >= img_len)
140                         break;
141         }
142
143         if (readn < img_len) {
144                 printk(KERN_ERR "gdmwm: Cannot read to the requested size. "
145                         "Read = %d Requested = %d\n", readn, img_len);
146                 ret = -EIO;
147         }
148 out:
149
150         return ret;
151 }
152
153 int usb_boot(struct usb_device *usbdev, u16 pid)
154 {
155         int i, ret = 0;
156         struct file *filp = NULL;
157         struct inode *inode = NULL;
158         static mm_segment_t fs;
159         struct img_header hdr;
160         struct fw_info fw_info;
161         loff_t pos = 0;
162         char *img_name = UIMG_PATH;
163         int len;
164
165         tx_buf = kmalloc(DOWNLOAD_SIZE, GFP_KERNEL);
166         if (tx_buf == NULL) {
167                 printk(KERN_ERR "Error: kmalloc\n");
168                 return -ENOMEM;
169         }
170
171         fs = get_fs();
172         set_fs(get_ds());
173
174         filp = filp_open(img_name, O_RDONLY | O_LARGEFILE, 0);
175         if (IS_ERR(filp)) {
176                 printk(KERN_ERR "Can't find %s.\n", img_name);
177                 set_fs(fs);
178                 ret = -ENOENT;
179                 goto restore_fs;
180         }
181
182         if (filp->f_dentry)
183                 inode = filp->f_dentry->d_inode;
184         if (!inode || !S_ISREG(inode->i_mode)) {
185                 printk(KERN_ERR "Invalid file type: %s\n", img_name);
186                 ret = -EINVAL;
187                 goto out;
188         }
189
190         len = filp->f_op->read(filp, (u8 *)&hdr, sizeof(hdr), &pos);
191         if (len != sizeof(hdr)) {
192                 printk(KERN_ERR "gdmwm: Cannot read the image info.\n");
193                 ret = -EIO;
194                 goto out;
195         }
196
197         array_le32_to_cpu((u32 *)&hdr, 19);
198 #if 0
199         if (hdr.magic_code != 0x10767fff) {
200                 printk(KERN_ERR "gdmwm: Invalid magic code 0x%08x\n",
201                         hdr.magic_code);
202                 ret = -EINVAL;
203                 goto out;
204         }
205 #endif
206         if (hdr.count > MAX_IMG_CNT) {
207                 printk(KERN_ERR "gdmwm: Too many images. %d\n", hdr.count);
208                 ret = -EINVAL;
209                 goto out;
210         }
211
212         for (i = 0; i < hdr.count; i++) {
213                 if (hdr.offset[i] > hdr.len) {
214                         printk(KERN_ERR "gdmwm: Invalid offset. "
215                                 "Entry = %d Offset = 0x%08x "
216                                 "Image length = 0x%08x\n",
217                                 i, hdr.offset[i], hdr.len);
218                         ret = -EINVAL;
219                         goto out;
220                 }
221
222                 pos = hdr.offset[i];
223                 len = filp->f_op->read(filp, (u8 *)&fw_info, sizeof(fw_info),
224                                         &pos);
225                 if (len != sizeof(fw_info)) {
226                         printk(KERN_ERR "gdmwm: Cannot read the FW info.\n");
227                         ret = -EIO;
228                         goto out;
229                 }
230
231                 array_le32_to_cpu((u32 *)&fw_info, 8);
232 #if 0
233                 if ((fw_info.id & 0xfffff000) != 0x10767000) {
234                         printk(KERN_ERR "gdmwm: Invalid FW id. 0x%08x\n",
235                                 fw_info.id);
236                         ret = -EIO;
237                         goto out;
238                 }
239 #endif
240
241                 if ((fw_info.id & 0xffff) != pid)
242                         continue;
243
244                 pos = hdr.offset[i] + fw_info.kernel_offset;
245                 ret = download_image(usbdev, filp, &pos, fw_info.kernel_len,
246                                 DN_KERNEL_MAGIC_NUMBER);
247                 if (ret < 0)
248                         goto out;
249                 printk(KERN_INFO "GCT: Kernel download success.\n");
250
251                 pos = hdr.offset[i] + fw_info.rootfs_offset;
252                 ret = download_image(usbdev, filp, &pos, fw_info.rootfs_len,
253                                 DN_ROOTFS_MAGIC_NUMBER);
254                 if (ret < 0)
255                         goto out;
256                 printk(KERN_INFO "GCT: Filesystem download success.\n");
257
258                 break;
259         }
260
261         if (i == hdr.count) {
262                 printk(KERN_ERR "Firmware for gsk%x is not installed.\n", pid);
263                 ret = -EINVAL;
264         }
265 out:
266         filp_close(filp, current->files);
267
268 restore_fs:
269         set_fs(fs);
270         kfree(tx_buf);
271         return ret;
272 }
273
274 /*#define GDM7205_PADDING               256 */
275 #define DOWNLOAD_CHUCK                  2048
276 #define KERNEL_TYPE_STRING              "linux"
277 #define FS_TYPE_STRING                  "rootfs"
278
279 static int em_wait_ack(struct usb_device *usbdev, int send_zlp)
280 {
281         int ack;
282         int ret = -1;
283
284         if (send_zlp) {
285                 /*Send ZLP*/
286                 ret = gdm_wibro_send(usbdev, NULL, 0);
287                 if (ret < 0)
288                         goto out;
289         }
290
291         /*Wait for ACK*/
292         ret = gdm_wibro_recv(usbdev, &ack, sizeof(ack));
293         if (ret < 0)
294                 goto out;
295 out:
296         return ret;
297 }
298
299 static int em_download_image(struct usb_device *usbdev, char *path,
300                                 char *type_string)
301 {
302         struct file *filp;
303         struct inode *inode;
304         static mm_segment_t fs;
305         char *buf = NULL;
306         loff_t pos = 0;
307         int ret = 0;
308         int len, readn = 0;
309         #if defined(GDM7205_PADDING)
310         const int pad_size = GDM7205_PADDING;
311         #else
312         const int pad_size = 0;
313         #endif
314
315         fs = get_fs();
316         set_fs(get_ds());
317
318         filp = filp_open(path, O_RDONLY | O_LARGEFILE, 0);
319         if (IS_ERR(filp)) {
320                 printk(KERN_ERR "Can't find %s.\n", path);
321                 set_fs(fs);
322                 ret = -ENOENT;
323                 goto restore_fs;
324         }
325
326         if (filp->f_dentry) {
327                 inode = filp->f_dentry->d_inode;
328                 if (!inode || !S_ISREG(inode->i_mode)) {
329                         printk(KERN_ERR "Invalid file type: %s\n", path);
330                         ret = -EINVAL;
331                         goto out;
332                 }
333         }
334
335         buf = kmalloc(DOWNLOAD_CHUCK + pad_size, GFP_KERNEL);
336         if (buf == NULL) {
337                 printk(KERN_ERR "Error: kmalloc\n");
338                 return -ENOMEM;
339         }
340
341         strcpy(buf+pad_size, type_string);
342         ret = gdm_wibro_send(usbdev, buf, strlen(type_string)+pad_size);
343         if (ret < 0)
344                 goto out;
345
346         while ((len = filp->f_op->read(filp, buf+pad_size, DOWNLOAD_CHUCK,
347                                         &pos))) {
348                 if (len < 0) {
349                         ret = -1;
350                         goto out;
351                 }
352                 readn += len;
353
354                 ret = gdm_wibro_send(usbdev, buf, len+pad_size);
355                 if (ret < 0)
356                         goto out;
357
358                 ret = em_wait_ack(usbdev, ((len+pad_size) % 512 == 0));
359                 if (ret < 0)
360                         goto out;
361         }
362
363         ret = em_wait_ack(usbdev, 1);
364         if (ret < 0)
365                 goto out;
366
367 out:
368         filp_close(filp, current->files);
369
370 restore_fs:
371         set_fs(fs);
372
373         kfree(buf);
374
375         return ret;
376 }
377
378 static int em_fw_reset(struct usb_device *usbdev)
379 {
380         int ret;
381
382         /*Send ZLP*/
383         ret = gdm_wibro_send(usbdev, NULL, 0);
384         return ret;
385 }
386
387 int usb_emergency(struct usb_device *usbdev)
388 {
389         int ret;
390
391         ret = em_download_image(usbdev, KERN_PATH, KERNEL_TYPE_STRING);
392         if (ret < 0)
393                 goto out;
394         printk(KERN_INFO "GCT Emergency: Kernel download success.\n");
395
396         ret = em_download_image(usbdev, FS_PATH, FS_TYPE_STRING);
397         if (ret < 0)
398                 goto out;
399         printk(KERN_INFO "GCT Emergency: Filesystem download success.\n");
400
401         ret = em_fw_reset(usbdev);
402 out:
403         return ret;
404 }