usb_dfu.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. /*
  2. * usb_dfu.c
  3. *
  4. * Copyright (C) 2019 Sylvain Munaut
  5. * All rights reserved.
  6. *
  7. * LGPL v3+, see LICENSE.lgpl3
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation; either
  12. * version 3 of the License, or (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public License
  20. * along with this program; if not, write to the Free Software Foundation,
  21. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  22. */
  23. #include <stdint.h>
  24. #include <stdbool.h>
  25. #include <string.h>
  26. #include "spi.h"
  27. #include "usb.h"
  28. #include "usb_dfu.h"
  29. #include "usb_dfu_proto.h"
  30. #define DFU_VENDOR_PROTO
  31. #ifdef DFU_VENDOR_PROTO
  32. enum usb_fnd_resp dfu_vendor_ctrl_req(struct usb_ctrl_req *req, struct usb_xfer *xfer);
  33. #endif
  34. #define DFU_POLL_MS 250
  35. static const uint32_t dfu_valid_req[_DFU_MAX_STATE] = {
  36. /* appIDLE */
  37. (1 << USB_REQ_DFU_DETACH) |
  38. (1 << USB_REQ_DFU_GETSTATUS) |
  39. (1 << USB_REQ_DFU_GETSTATE) |
  40. 0,
  41. /* appDETACH */
  42. (1 << USB_REQ_DFU_GETSTATUS) |
  43. (1 << USB_REQ_DFU_GETSTATE) |
  44. 0,
  45. /* dfuIDLE */
  46. (1 << USB_REQ_DFU_DETACH) | /* Non-std */
  47. (1 << USB_REQ_DFU_DNLOAD) |
  48. (1 << USB_REQ_DFU_UPLOAD) |
  49. (1 << USB_REQ_DFU_GETSTATUS) |
  50. (1 << USB_REQ_DFU_GETSTATE) |
  51. (1 << USB_REQ_DFU_ABORT) |
  52. 0,
  53. /* dfuDNLOAD_SYNC */
  54. (1 << USB_REQ_DFU_DNLOAD) |
  55. (1 << USB_REQ_DFU_GETSTATUS) |
  56. (1 << USB_REQ_DFU_GETSTATE) |
  57. (1 << USB_REQ_DFU_ABORT) |
  58. 0,
  59. /* dfuDNBUSY */
  60. 0,
  61. /* dfuDNLOAD_IDLE */
  62. (1 << USB_REQ_DFU_DNLOAD) |
  63. (1 << USB_REQ_DFU_GETSTATUS) |
  64. (1 << USB_REQ_DFU_GETSTATE) |
  65. (1 << USB_REQ_DFU_ABORT) |
  66. 0,
  67. /* dfuMANIFEST_SYNC */
  68. (1 << USB_REQ_DFU_GETSTATUS) |
  69. (1 << USB_REQ_DFU_GETSTATE) |
  70. (1 << USB_REQ_DFU_ABORT) |
  71. 0,
  72. /* dfuMANIFEST */
  73. 0,
  74. /* dfuMANIFEST_WAIT_RESET */
  75. 0,
  76. /* dfuUPLOAD_IDLE */
  77. (1 << USB_REQ_DFU_UPLOAD) |
  78. (1 << USB_REQ_DFU_GETSTATUS) |
  79. (1 << USB_REQ_DFU_GETSTATE) |
  80. (1 << USB_REQ_DFU_ABORT) |
  81. 0,
  82. /* dfuERROR */
  83. (1 << USB_REQ_DFU_GETSTATUS) |
  84. (1 << USB_REQ_DFU_CLRSTATUS) |
  85. (1 << USB_REQ_DFU_GETSTATE) |
  86. 0,
  87. };
  88. static struct {
  89. enum dfu_state state;
  90. enum dfu_status status;
  91. uint8_t tick;
  92. uint8_t intf; // Selected interface number
  93. uint8_t alt; // Selected alt settings
  94. uint8_t buf[4096] __attribute__((aligned(4)));
  95. struct {
  96. uint32_t addr_prog;
  97. uint32_t addr_erase;
  98. uint32_t addr_end;
  99. int op_ofs;
  100. int op_len;
  101. enum {
  102. FL_IDLE = 0,
  103. FL_ERASE,
  104. FL_PROGRAM,
  105. } op;
  106. } flash;
  107. } g_dfu;
  108. static const struct {
  109. uint32_t start;
  110. uint32_t end;
  111. } dfu_zones[2] = {
  112. { 0x00080000, 0x000a0000 }, /* iCE40 bitstream */
  113. { 0x000a0000, 0x000c0000 }, /* RISC-V firmware */
  114. };
  115. static void
  116. _dfu_tick(void)
  117. {
  118. /* Rate limit to once every 10 ms */
  119. if (g_dfu.tick++ < 10)
  120. return;
  121. g_dfu.tick = 0;
  122. /* Anything to do ? Is flash ready ? */
  123. if ((g_dfu.flash.op == FL_IDLE) || (flash_read_sr() & 1))
  124. return;
  125. /* Erase */
  126. if (g_dfu.flash.op == FL_ERASE) {
  127. /* Done ? */
  128. if (g_dfu.flash.addr_erase >= (g_dfu.flash.addr_prog + g_dfu.flash.op_len)) {
  129. /* Yes, move to programming */
  130. g_dfu.flash.op = FL_PROGRAM;
  131. } else{
  132. /* No, issue the next command */
  133. flash_write_enable();
  134. flash_sector_erase(g_dfu.flash.addr_erase);
  135. g_dfu.flash.addr_erase += 4096;
  136. }
  137. }
  138. /* Programming */
  139. if ((g_dfu.flash.op == FL_PROGRAM) && (g_dfu.state == dfuDNLOAD_SYNC)) {
  140. /* Done ? */
  141. if (g_dfu.flash.op_ofs == g_dfu.flash.op_len) {
  142. /* Yes ! */
  143. g_dfu.flash.op = FL_IDLE;
  144. g_dfu.state = dfuDNLOAD_IDLE;
  145. g_dfu.flash.addr_prog += g_dfu.flash.op_len;
  146. } else {
  147. /* Max len */
  148. unsigned l = g_dfu.flash.op_len - g_dfu.flash.op_ofs;
  149. unsigned pl = 256 - ((g_dfu.flash.addr_prog + g_dfu.flash.op_ofs) & 0xff);
  150. if (l > pl)
  151. l = pl;
  152. /* Write page */
  153. flash_write_enable();
  154. flash_page_program(&g_dfu.buf[g_dfu.flash.op_ofs], g_dfu.flash.addr_prog + g_dfu.flash.op_ofs, l);
  155. /* Next page */
  156. g_dfu.flash.op_ofs += l;
  157. }
  158. }
  159. }
  160. static void
  161. _dfu_bus_reset(void)
  162. {
  163. if (g_dfu.state != appDETACH)
  164. usb_dfu_cb_reboot();
  165. }
  166. static void
  167. _dfu_state_chg(enum usb_dev_state state)
  168. {
  169. if (state == USB_DS_CONFIGURED)
  170. g_dfu.state = dfuIDLE;
  171. }
  172. static bool
  173. _dfu_detach_done_cb(struct usb_xfer *xfer)
  174. {
  175. usb_dfu_cb_reboot();
  176. return true;
  177. }
  178. static bool
  179. _dfu_dnload_done_cb(struct usb_xfer *xfer)
  180. {
  181. /* State update */
  182. g_dfu.state = dfuDNLOAD_SYNC;
  183. return true;
  184. }
  185. static enum usb_fnd_resp
  186. _dfu_ctrl_req(struct usb_ctrl_req *req, struct usb_xfer *xfer)
  187. {
  188. uint8_t state;
  189. /* If this a class or vendor request for DFU interface ? */
  190. if (req->wIndex != g_dfu.intf)
  191. return USB_FND_CONTINUE;
  192. #ifdef DFU_VENDOR_PROTO
  193. if ((USB_REQ_TYPE(req) | USB_REQ_RCPT(req)) == (USB_REQ_TYPE_VENDOR | USB_REQ_RCPT_INTF)) {
  194. /* Let vendor code use our large buffer */
  195. xfer->data = g_dfu.buf;
  196. xfer->len = sizeof(g_dfu.buf);
  197. /* Call vendor code */
  198. return dfu_vendor_ctrl_req(req, xfer);
  199. }
  200. #endif
  201. if ((USB_REQ_TYPE(req) | USB_REQ_RCPT(req)) != (USB_REQ_TYPE_CLASS | USB_REQ_RCPT_INTF))
  202. return USB_FND_CONTINUE;
  203. /* Check if this request is allowed in this state */
  204. if ((dfu_valid_req[g_dfu.state] & (1 << req->bRequest)) == 0)
  205. goto error;
  206. /* Handle request */
  207. switch (req->wRequestAndType)
  208. {
  209. case USB_RT_DFU_DETACH:
  210. /* In theory this should be in runtime mode only but we support
  211. * it as a request to reboot to user mode when in DFU mode */
  212. xfer->cb_done = _dfu_detach_done_cb;
  213. break;
  214. case USB_RT_DFU_DNLOAD:
  215. /* Check for last block */
  216. if (req->wLength) {
  217. /* Check length doesn't overflow */
  218. if ((g_dfu.flash.addr_erase + req->wLength) > g_dfu.flash.addr_end)
  219. goto error;
  220. /* Setup buffer for data */
  221. xfer->len = req->wLength;
  222. xfer->data = g_dfu.buf;
  223. xfer->cb_done = _dfu_dnload_done_cb;
  224. /* Prepare flash */
  225. g_dfu.flash.op_ofs = 0;
  226. g_dfu.flash.op_len = req->wLength;
  227. g_dfu.flash.op = FL_ERASE;
  228. } else {
  229. /* Last xfer */
  230. g_dfu.state = dfuIDLE;
  231. }
  232. break;
  233. case USB_RT_DFU_UPLOAD:
  234. /* Not supported */
  235. goto error;
  236. case USB_RT_DFU_GETSTATUS:
  237. /* Update state */
  238. if (g_dfu.state == dfuDNLOAD_SYNC) {
  239. if (g_dfu.flash.op == FL_IDLE) {
  240. g_dfu.state = state = dfuDNLOAD_IDLE;
  241. } else {
  242. state = dfuDNBUSY;
  243. }
  244. } else if (g_dfu.state == dfuMANIFEST_SYNC) {
  245. g_dfu.state = state = dfuIDLE;
  246. } else {
  247. state = g_dfu.state;
  248. }
  249. /* Return data */
  250. xfer->data[0] = g_dfu.status;
  251. xfer->data[1] = (DFU_POLL_MS >> 0) & 0xff;
  252. xfer->data[2] = (DFU_POLL_MS >> 8) & 0xff;
  253. xfer->data[3] = (DFU_POLL_MS >> 16) & 0xff;
  254. xfer->data[4] = state;
  255. xfer->data[5] = 0;
  256. break;
  257. case USB_RT_DFU_CLRSTATUS:
  258. /* Clear error */
  259. g_dfu.state = dfuIDLE;
  260. g_dfu.status = OK;
  261. break;
  262. case USB_RT_DFU_GETSTATE:
  263. /* Return state */
  264. xfer->data[0] = g_dfu.state;
  265. break;
  266. case USB_RT_DFU_ABORT:
  267. /* Go to IDLE */
  268. g_dfu.state = dfuIDLE;
  269. break;
  270. default:
  271. goto error;
  272. }
  273. return USB_FND_SUCCESS;
  274. error:
  275. g_dfu.state = dfuERROR;
  276. g_dfu.status = errUNKNOWN;
  277. return USB_FND_ERROR;
  278. }
  279. static enum usb_fnd_resp
  280. _dfu_set_intf(const struct usb_intf_desc *base, const struct usb_intf_desc *sel)
  281. {
  282. if ((sel->bInterfaceClass != 0xfe) ||
  283. (sel->bInterfaceSubClass != 0x01) ||
  284. (sel->bInterfaceProtocol != 0x02))
  285. return USB_FND_CONTINUE;
  286. g_dfu.state = dfuIDLE;
  287. g_dfu.intf = sel->bInterfaceNumber;
  288. g_dfu.alt = sel->bAlternateSetting;
  289. g_dfu.flash.addr_prog = dfu_zones[g_dfu.alt].start;
  290. g_dfu.flash.addr_erase = dfu_zones[g_dfu.alt].start;
  291. g_dfu.flash.addr_end = dfu_zones[g_dfu.alt].end;
  292. return USB_FND_SUCCESS;
  293. }
  294. static enum usb_fnd_resp
  295. _dfu_get_intf(const struct usb_intf_desc *base, uint8_t *alt)
  296. {
  297. if ((base->bInterfaceClass != 0xfe) ||
  298. (base->bInterfaceSubClass != 0x01) ||
  299. (base->bInterfaceProtocol != 0x02))
  300. return USB_FND_CONTINUE;
  301. *alt = g_dfu.alt;
  302. return USB_FND_SUCCESS;
  303. }
  304. static struct usb_fn_drv _dfu_drv = {
  305. .sof = _dfu_tick,
  306. .bus_reset = _dfu_bus_reset,
  307. .state_chg = _dfu_state_chg,
  308. .ctrl_req = _dfu_ctrl_req,
  309. .set_intf = _dfu_set_intf,
  310. .get_intf = _dfu_get_intf,
  311. };
  312. void __attribute__((weak))
  313. usb_dfu_cb_reboot(void)
  314. {
  315. /* Nothing */
  316. }
  317. void
  318. usb_dfu_init(void)
  319. {
  320. memset(&g_dfu, 0x00, sizeof(g_dfu));
  321. g_dfu.state = appDETACH;
  322. usb_register_function_driver(&_dfu_drv);
  323. }