usb_dfu.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  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_POLL_MS 250
  31. static const uint32_t dfu_valid_req[_DFU_MAX_STATE] = {
  32. /* appIDLE */
  33. (1 << USB_REQ_DFU_DETACH) |
  34. (1 << USB_REQ_DFU_GETSTATUS) |
  35. (1 << USB_REQ_DFU_GETSTATE) |
  36. 0,
  37. /* appDETACH */
  38. (1 << USB_REQ_DFU_GETSTATUS) |
  39. (1 << USB_REQ_DFU_GETSTATE) |
  40. 0,
  41. /* dfuIDLE */
  42. (1 << USB_REQ_DFU_DETACH) | /* Non-std */
  43. (1 << USB_REQ_DFU_DNLOAD) |
  44. (1 << USB_REQ_DFU_UPLOAD) |
  45. (1 << USB_REQ_DFU_GETSTATUS) |
  46. (1 << USB_REQ_DFU_GETSTATE) |
  47. (1 << USB_REQ_DFU_ABORT) |
  48. 0,
  49. /* dfuDNLOAD_SYNC */
  50. (1 << USB_REQ_DFU_DNLOAD) |
  51. (1 << USB_REQ_DFU_GETSTATUS) |
  52. (1 << USB_REQ_DFU_GETSTATE) |
  53. (1 << USB_REQ_DFU_ABORT) |
  54. 0,
  55. /* dfuDNBUSY */
  56. 0,
  57. /* dfuDNLOAD_IDLE */
  58. (1 << USB_REQ_DFU_DNLOAD) |
  59. (1 << USB_REQ_DFU_GETSTATUS) |
  60. (1 << USB_REQ_DFU_GETSTATE) |
  61. (1 << USB_REQ_DFU_ABORT) |
  62. 0,
  63. /* dfuMANIFEST_SYNC */
  64. (1 << USB_REQ_DFU_GETSTATUS) |
  65. (1 << USB_REQ_DFU_GETSTATE) |
  66. (1 << USB_REQ_DFU_ABORT) |
  67. 0,
  68. /* dfuMANIFEST */
  69. 0,
  70. /* dfuMANIFEST_WAIT_RESET */
  71. 0,
  72. /* dfuUPLOAD_IDLE */
  73. (1 << USB_REQ_DFU_UPLOAD) |
  74. (1 << USB_REQ_DFU_GETSTATUS) |
  75. (1 << USB_REQ_DFU_GETSTATE) |
  76. (1 << USB_REQ_DFU_ABORT) |
  77. 0,
  78. /* dfuERROR */
  79. (1 << USB_REQ_DFU_GETSTATUS) |
  80. (1 << USB_REQ_DFU_CLRSTATUS) |
  81. (1 << USB_REQ_DFU_GETSTATE) |
  82. 0,
  83. };
  84. static struct {
  85. enum dfu_state state;
  86. enum dfu_status status;
  87. uint8_t tick;
  88. uint8_t intf; // Selected interface number
  89. uint8_t alt; // Selected alt settings
  90. uint8_t buf[4096] __attribute__((aligned(4)));
  91. struct {
  92. uint32_t addr_prog;
  93. uint32_t addr_erase;
  94. uint32_t addr_end;
  95. int op_ofs;
  96. int op_len;
  97. enum {
  98. FL_IDLE = 0,
  99. FL_ERASE,
  100. FL_PROGRAM,
  101. } op;
  102. } flash;
  103. } g_dfu;
  104. static const struct {
  105. uint32_t start;
  106. uint32_t end;
  107. } dfu_zones[2] = {
  108. { 0x00080000, 0x000a0000 }, /* iCE40 bitstream */
  109. { 0x000a0000, 0x000c0000 }, /* RISC-V firmware */
  110. };
  111. static void
  112. _dfu_tick(void)
  113. {
  114. /* Rate limit to once every 10 ms */
  115. if (g_dfu.tick++ < 10)
  116. return;
  117. g_dfu.tick = 0;
  118. /* Anything to do ? Is flash ready ? */
  119. if ((g_dfu.flash.op == FL_IDLE) || (flash_read_sr() & 1))
  120. return;
  121. /* Erase */
  122. if (g_dfu.flash.op == FL_ERASE) {
  123. /* Done ? */
  124. if (g_dfu.flash.addr_erase >= (g_dfu.flash.addr_prog + g_dfu.flash.op_len)) {
  125. /* Yes, move to programming */
  126. g_dfu.flash.op = FL_PROGRAM;
  127. } else{
  128. /* No, issue the next command */
  129. flash_write_enable();
  130. flash_sector_erase(g_dfu.flash.addr_erase);
  131. g_dfu.flash.addr_erase += 4096;
  132. }
  133. }
  134. /* Programming */
  135. if ((g_dfu.flash.op == FL_PROGRAM) && (g_dfu.state == dfuDNLOAD_SYNC)) {
  136. /* Done ? */
  137. if (g_dfu.flash.op_ofs == g_dfu.flash.op_len) {
  138. /* Yes ! */
  139. g_dfu.flash.op = FL_IDLE;
  140. g_dfu.state = dfuDNLOAD_IDLE;
  141. g_dfu.flash.addr_prog += g_dfu.flash.op_len;
  142. } else {
  143. /* Max len */
  144. unsigned l = g_dfu.flash.op_len - g_dfu.flash.op_ofs;
  145. unsigned pl = 256 - ((g_dfu.flash.addr_prog + g_dfu.flash.op_ofs) & 0xff);
  146. if (l > pl)
  147. l = pl;
  148. /* Write page */
  149. flash_write_enable();
  150. flash_page_program(&g_dfu.buf[g_dfu.flash.op_ofs], g_dfu.flash.addr_prog + g_dfu.flash.op_ofs, l);
  151. /* Next page */
  152. g_dfu.flash.op_ofs += l;
  153. }
  154. }
  155. }
  156. static void
  157. _dfu_bus_reset(void)
  158. {
  159. if (g_dfu.state != appDETACH)
  160. usb_dfu_cb_reboot();
  161. }
  162. static void
  163. _dfu_state_chg(enum usb_dev_state state)
  164. {
  165. if (state == USB_DS_CONFIGURED)
  166. g_dfu.state = dfuIDLE;
  167. }
  168. static bool
  169. _dfu_detach_done_cb(struct usb_xfer *xfer)
  170. {
  171. usb_dfu_cb_reboot();
  172. return true;
  173. }
  174. static bool
  175. _dfu_dnload_done_cb(struct usb_xfer *xfer)
  176. {
  177. /* State update */
  178. g_dfu.state = dfuDNLOAD_SYNC;
  179. return true;
  180. }
  181. static enum usb_fnd_resp
  182. _dfu_ctrl_req(struct usb_ctrl_req *req, struct usb_xfer *xfer)
  183. {
  184. uint8_t state;
  185. /* If this a class request for DFU interface ? */
  186. if (USB_REQ_TYPE_RCPT(req) != (USB_REQ_TYPE_CLASS | USB_REQ_RCPT_INTF))
  187. return USB_FND_CONTINUE;
  188. if (req->wIndex != g_dfu.intf)
  189. return USB_FND_CONTINUE;
  190. /* Check if this request is allowed in this state */
  191. if ((dfu_valid_req[g_dfu.state] & (1 << req->bRequest)) == 0)
  192. goto error;
  193. /* Handle request */
  194. switch (req->wRequestAndType)
  195. {
  196. case USB_RT_DFU_DETACH:
  197. /* In theory this should be in runtime mode only but we support
  198. * it as a request to reboot to user mode when in DFU mode */
  199. xfer->cb_done = _dfu_detach_done_cb;
  200. break;
  201. case USB_RT_DFU_DNLOAD:
  202. /* Check for last block */
  203. if (req->wLength) {
  204. /* Check length doesn't overflow */
  205. if ((g_dfu.flash.addr_erase + req->wLength) > g_dfu.flash.addr_end)
  206. goto error;
  207. /* Setup buffer for data */
  208. xfer->len = req->wLength;
  209. xfer->data = g_dfu.buf;
  210. xfer->cb_done = _dfu_dnload_done_cb;
  211. /* Prepare flash */
  212. g_dfu.flash.op_ofs = 0;
  213. g_dfu.flash.op_len = req->wLength;
  214. g_dfu.flash.op = FL_ERASE;
  215. } else {
  216. /* Last xfer */
  217. g_dfu.state = dfuIDLE;
  218. }
  219. break;
  220. case USB_RT_DFU_UPLOAD:
  221. /* Not supported */
  222. goto error;
  223. case USB_RT_DFU_GETSTATUS:
  224. /* Update state */
  225. if (g_dfu.state == dfuDNLOAD_SYNC) {
  226. if (g_dfu.flash.op == FL_IDLE) {
  227. g_dfu.state = state = dfuDNLOAD_IDLE;
  228. } else {
  229. state = dfuDNBUSY;
  230. }
  231. } else if (g_dfu.state == dfuMANIFEST_SYNC) {
  232. g_dfu.state = state = dfuIDLE;
  233. } else {
  234. state = g_dfu.state;
  235. }
  236. /* Return data */
  237. xfer->data[0] = g_dfu.status;
  238. xfer->data[1] = (DFU_POLL_MS >> 0) & 0xff;
  239. xfer->data[2] = (DFU_POLL_MS >> 8) & 0xff;
  240. xfer->data[3] = (DFU_POLL_MS >> 16) & 0xff;
  241. xfer->data[4] = state;
  242. xfer->data[5] = 0;
  243. break;
  244. case USB_RT_DFU_CLRSTATUS:
  245. /* Clear error */
  246. g_dfu.state = dfuIDLE;
  247. g_dfu.status = OK;
  248. break;
  249. case USB_RT_DFU_GETSTATE:
  250. /* Return state */
  251. xfer->data[0] = g_dfu.state;
  252. break;
  253. case USB_RT_DFU_ABORT:
  254. /* Go to IDLE */
  255. g_dfu.state = dfuIDLE;
  256. break;
  257. default:
  258. goto error;
  259. }
  260. return USB_FND_SUCCESS;
  261. error:
  262. g_dfu.state = dfuERROR;
  263. g_dfu.status = errUNKNOWN;
  264. return USB_FND_ERROR;
  265. }
  266. static enum usb_fnd_resp
  267. _dfu_set_intf(const struct usb_intf_desc *base, const struct usb_intf_desc *sel)
  268. {
  269. if ((sel->bInterfaceClass != 0xfe) ||
  270. (sel->bInterfaceSubClass != 0x01) ||
  271. (sel->bInterfaceProtocol != 0x02))
  272. return USB_FND_CONTINUE;
  273. g_dfu.state = dfuIDLE;
  274. g_dfu.intf = sel->bInterfaceNumber;
  275. g_dfu.alt = sel->bAlternateSetting;
  276. g_dfu.flash.addr_prog = dfu_zones[g_dfu.alt].start;
  277. g_dfu.flash.addr_erase = dfu_zones[g_dfu.alt].start;
  278. g_dfu.flash.addr_end = dfu_zones[g_dfu.alt].end;
  279. return USB_FND_SUCCESS;
  280. }
  281. static enum usb_fnd_resp
  282. _dfu_get_intf(const struct usb_intf_desc *base, uint8_t *alt)
  283. {
  284. if ((base->bInterfaceClass != 0xfe) ||
  285. (base->bInterfaceSubClass != 0x01) ||
  286. (base->bInterfaceProtocol != 0x02))
  287. return USB_FND_CONTINUE;
  288. *alt = g_dfu.alt;
  289. return USB_FND_SUCCESS;
  290. }
  291. static struct usb_fn_drv _dfu_drv = {
  292. .sof = _dfu_tick,
  293. .bus_reset = _dfu_bus_reset,
  294. .state_chg = _dfu_state_chg,
  295. .ctrl_req = _dfu_ctrl_req,
  296. .set_intf = _dfu_set_intf,
  297. .get_intf = _dfu_get_intf,
  298. };
  299. void __attribute__((weak))
  300. usb_dfu_cb_reboot(void)
  301. {
  302. /* Nothing */
  303. }
  304. void
  305. usb_dfu_init(void)
  306. {
  307. memset(&g_dfu, 0x00, sizeof(g_dfu));
  308. g_dfu.state = appDETACH;
  309. usb_register_function_driver(&_dfu_drv);
  310. }