usb_boot.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  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. #include <linux/uaccess.h>
  14. #include <linux/module.h>
  15. #include <linux/kernel.h>
  16. #include <linux/mm.h>
  17. #include <linux/usb.h>
  18. #include <linux/unistd.h>
  19. #include <linux/slab.h>
  20. #include <linux/firmware.h>
  21. #include <asm/byteorder.h>
  22. #include "gdm_usb.h"
  23. #include "usb_boot.h"
  24. #define DN_KERNEL_MAGIC_NUMBER 0x10760001
  25. #define DN_ROOTFS_MAGIC_NUMBER 0x10760002
  26. #define DOWNLOAD_SIZE 1024
  27. #define MAX_IMG_CNT 16
  28. #define FW_DIR "gdm72xx/"
  29. #define FW_UIMG "gdmuimg.bin"
  30. #define FW_KERN "zImage"
  31. #define FW_FS "ramdisk.jffs2"
  32. struct dn_header {
  33. __be32 magic_num;
  34. __be32 file_size;
  35. };
  36. struct img_header {
  37. u32 magic_code;
  38. u32 count;
  39. u32 len;
  40. u32 offset[MAX_IMG_CNT];
  41. char hostname[32];
  42. char date[32];
  43. };
  44. struct fw_info {
  45. u32 id;
  46. u32 len;
  47. u32 kernel_len;
  48. u32 rootfs_len;
  49. u32 kernel_offset;
  50. u32 rootfs_offset;
  51. u32 fw_ver;
  52. u32 mac_ver;
  53. char hostname[32];
  54. char userid[16];
  55. char date[32];
  56. char user_desc[128];
  57. };
  58. static void array_le32_to_cpu(u32 *arr, int num)
  59. {
  60. int i;
  61. for (i = 0; i < num; i++, arr++)
  62. le32_to_cpus(arr);
  63. }
  64. static u8 *tx_buf;
  65. static int gdm_wibro_send(struct usb_device *usbdev, void *data, int len)
  66. {
  67. int ret;
  68. int actual;
  69. ret = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), data, len,
  70. &actual, 1000);
  71. if (ret < 0) {
  72. dev_err(&usbdev->dev, "Error : usb_bulk_msg ( result = %d )\n",
  73. ret);
  74. return ret;
  75. }
  76. return 0;
  77. }
  78. static int gdm_wibro_recv(struct usb_device *usbdev, void *data, int len)
  79. {
  80. int ret;
  81. int actual;
  82. ret = usb_bulk_msg(usbdev, usb_rcvbulkpipe(usbdev, 2), data, len,
  83. &actual, 5000);
  84. if (ret < 0) {
  85. dev_err(&usbdev->dev,
  86. "Error : usb_bulk_msg(recv) ( result = %d )\n", ret);
  87. return ret;
  88. }
  89. return 0;
  90. }
  91. static int download_image(struct usb_device *usbdev,
  92. const struct firmware *firm,
  93. loff_t pos, u32 img_len, u32 magic_num)
  94. {
  95. struct dn_header h;
  96. int ret = 0;
  97. u32 size;
  98. size = ALIGN(img_len, DOWNLOAD_SIZE);
  99. h.magic_num = cpu_to_be32(magic_num);
  100. h.file_size = cpu_to_be32(size);
  101. ret = gdm_wibro_send(usbdev, &h, sizeof(h));
  102. if (ret < 0)
  103. return ret;
  104. while (img_len > 0) {
  105. if (img_len > DOWNLOAD_SIZE)
  106. size = DOWNLOAD_SIZE;
  107. else
  108. size = img_len; /* the last chunk of data */
  109. memcpy(tx_buf, firm->data + pos, size);
  110. ret = gdm_wibro_send(usbdev, tx_buf, size);
  111. if (ret < 0)
  112. return ret;
  113. img_len -= size;
  114. pos += size;
  115. }
  116. return ret;
  117. }
  118. int usb_boot(struct usb_device *usbdev, u16 pid)
  119. {
  120. int i, ret = 0;
  121. struct img_header hdr;
  122. struct fw_info fw_info;
  123. loff_t pos = 0;
  124. char *img_name = FW_DIR FW_UIMG;
  125. const struct firmware *firm;
  126. ret = request_firmware(&firm, img_name, &usbdev->dev);
  127. if (ret < 0) {
  128. dev_err(&usbdev->dev,
  129. "requesting firmware %s failed with error %d\n",
  130. img_name, ret);
  131. return ret;
  132. }
  133. tx_buf = kmalloc(DOWNLOAD_SIZE, GFP_KERNEL);
  134. if (!tx_buf) {
  135. release_firmware(firm);
  136. return -ENOMEM;
  137. }
  138. if (firm->size < sizeof(hdr)) {
  139. dev_err(&usbdev->dev, "Cannot read the image info.\n");
  140. ret = -EIO;
  141. goto out;
  142. }
  143. memcpy(&hdr, firm->data, sizeof(hdr));
  144. array_le32_to_cpu((u32 *)&hdr, 19);
  145. if (hdr.count > MAX_IMG_CNT) {
  146. dev_err(&usbdev->dev, "Too many images. %d\n", hdr.count);
  147. ret = -EINVAL;
  148. goto out;
  149. }
  150. for (i = 0; i < hdr.count; i++) {
  151. if (hdr.offset[i] > hdr.len) {
  152. dev_err(&usbdev->dev,
  153. "Invalid offset. Entry = %d Offset = 0x%08x Image length = 0x%08x\n",
  154. i, hdr.offset[i], hdr.len);
  155. ret = -EINVAL;
  156. goto out;
  157. }
  158. pos = hdr.offset[i];
  159. if (firm->size < sizeof(fw_info) + pos) {
  160. dev_err(&usbdev->dev, "Cannot read the FW info.\n");
  161. ret = -EIO;
  162. goto out;
  163. }
  164. memcpy(&fw_info, firm->data + pos, sizeof(fw_info));
  165. array_le32_to_cpu((u32 *)&fw_info, 8);
  166. if ((fw_info.id & 0xffff) != pid)
  167. continue;
  168. pos = hdr.offset[i] + fw_info.kernel_offset;
  169. if (firm->size < fw_info.kernel_len + pos) {
  170. dev_err(&usbdev->dev, "Kernel FW is too small.\n");
  171. goto out;
  172. }
  173. ret = download_image(usbdev, firm, pos, fw_info.kernel_len,
  174. DN_KERNEL_MAGIC_NUMBER);
  175. if (ret < 0)
  176. goto out;
  177. dev_info(&usbdev->dev, "GCT: Kernel download success.\n");
  178. pos = hdr.offset[i] + fw_info.rootfs_offset;
  179. if (firm->size < fw_info.rootfs_len + pos) {
  180. dev_err(&usbdev->dev, "Filesystem FW is too small.\n");
  181. goto out;
  182. }
  183. ret = download_image(usbdev, firm, pos, fw_info.rootfs_len,
  184. DN_ROOTFS_MAGIC_NUMBER);
  185. if (ret < 0)
  186. goto out;
  187. dev_info(&usbdev->dev, "GCT: Filesystem download success.\n");
  188. break;
  189. }
  190. if (i == hdr.count) {
  191. dev_err(&usbdev->dev, "Firmware for gsk%x is not installed.\n",
  192. pid);
  193. ret = -EINVAL;
  194. }
  195. out:
  196. release_firmware(firm);
  197. kfree(tx_buf);
  198. return ret;
  199. }
  200. /*#define GDM7205_PADDING 256 */
  201. #define DOWNLOAD_CHUCK 2048
  202. #define KERNEL_TYPE_STRING "linux"
  203. #define FS_TYPE_STRING "rootfs"
  204. static int em_wait_ack(struct usb_device *usbdev, int send_zlp)
  205. {
  206. int ack;
  207. int ret = -1;
  208. if (send_zlp) {
  209. /*Send ZLP*/
  210. ret = gdm_wibro_send(usbdev, NULL, 0);
  211. if (ret < 0)
  212. goto out;
  213. }
  214. /*Wait for ACK*/
  215. ret = gdm_wibro_recv(usbdev, &ack, sizeof(ack));
  216. if (ret < 0)
  217. goto out;
  218. out:
  219. return ret;
  220. }
  221. static int em_download_image(struct usb_device *usbdev, const char *img_name,
  222. char *type_string)
  223. {
  224. char *buf = NULL;
  225. loff_t pos = 0;
  226. int ret = 0;
  227. int len;
  228. int img_len;
  229. const struct firmware *firm;
  230. #if defined(GDM7205_PADDING)
  231. const int pad_size = GDM7205_PADDING;
  232. #else
  233. const int pad_size = 0;
  234. #endif
  235. ret = request_firmware(&firm, img_name, &usbdev->dev);
  236. if (ret < 0) {
  237. dev_err(&usbdev->dev,
  238. "requesting firmware %s failed with error %d\n",
  239. img_name, ret);
  240. return ret;
  241. }
  242. buf = kmalloc(DOWNLOAD_CHUCK + pad_size, GFP_KERNEL);
  243. if (!buf) {
  244. release_firmware(firm);
  245. return -ENOMEM;
  246. }
  247. strcpy(buf+pad_size, type_string);
  248. ret = gdm_wibro_send(usbdev, buf, strlen(type_string)+pad_size);
  249. if (ret < 0)
  250. goto out;
  251. img_len = firm->size;
  252. if (img_len <= 0) {
  253. ret = -1;
  254. goto out;
  255. }
  256. while (img_len > 0) {
  257. if (img_len > DOWNLOAD_CHUCK)
  258. len = DOWNLOAD_CHUCK;
  259. else
  260. len = img_len; /* the last chunk of data */
  261. memcpy(buf+pad_size, firm->data + pos, len);
  262. ret = gdm_wibro_send(usbdev, buf, len+pad_size);
  263. if (ret < 0)
  264. goto out;
  265. img_len -= DOWNLOAD_CHUCK;
  266. pos += DOWNLOAD_CHUCK;
  267. ret = em_wait_ack(usbdev, ((len+pad_size) % 512 == 0));
  268. if (ret < 0)
  269. goto out;
  270. }
  271. ret = em_wait_ack(usbdev, 1);
  272. if (ret < 0)
  273. goto out;
  274. out:
  275. release_firmware(firm);
  276. kfree(buf);
  277. return ret;
  278. }
  279. static int em_fw_reset(struct usb_device *usbdev)
  280. {
  281. /*Send ZLP*/
  282. return gdm_wibro_send(usbdev, NULL, 0);
  283. }
  284. int usb_emergency(struct usb_device *usbdev)
  285. {
  286. int ret;
  287. const char *kern_name = FW_DIR FW_KERN;
  288. const char *fs_name = FW_DIR FW_FS;
  289. ret = em_download_image(usbdev, kern_name, KERNEL_TYPE_STRING);
  290. if (ret < 0)
  291. return ret;
  292. dev_err(&usbdev->dev, "GCT Emergency: Kernel download success.\n");
  293. ret = em_download_image(usbdev, fs_name, FS_TYPE_STRING);
  294. if (ret < 0)
  295. return ret;
  296. dev_info(&usbdev->dev, "GCT Emergency: Filesystem download success.\n");
  297. ret = em_fw_reset(usbdev);
  298. return ret;
  299. }