fw_update.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. /*
  2. * fw_update.c
  3. *
  4. * Update bootloader for main firmware.
  5. *
  6. * Written & released by Keir Fraser <keir.xen@gmail.com>
  7. *
  8. * This is free and unencumbered software released into the public domain.
  9. * See the file COPYING for more details, or visit <http://unlicense.org>.
  10. */
  11. #if MCU == STM32F1
  12. /* 8kB-64kB (56kB total) */
  13. #define FIRMWARE_START 0x08002000
  14. #define FIRMWARE_END 0x08010000
  15. #elif MCU == STM32F7 || MCU == AT32F4
  16. /* 16kB-64KB (48kB total) */
  17. #define FIRMWARE_START 0x08004000
  18. #define FIRMWARE_END 0x08010000
  19. #endif
  20. int EXC_reset(void) __attribute__((alias("main")));
  21. static struct {
  22. time_t time;
  23. bool_t state;
  24. } blink;
  25. static enum {
  26. ST_inactive,
  27. ST_command_wait,
  28. ST_update,
  29. } state = ST_inactive;
  30. static uint8_t u_buf[2048] aligned(4);
  31. static uint32_t u_prod;
  32. static bool_t upd_strapped;
  33. struct gw_info gw_info = {
  34. .is_main_firmware = 0,
  35. .max_cmd = CMD_MAX,
  36. .hw_model = MCU
  37. };
  38. static void blink_init(void)
  39. {
  40. blink.time = time_now();
  41. blink.state = FALSE;
  42. act_led(FALSE);
  43. }
  44. static void update_reset(void)
  45. {
  46. blink_init();
  47. state = ST_inactive;
  48. }
  49. static void update_configure(void)
  50. {
  51. blink_init();
  52. state = ST_command_wait;
  53. u_prod = 0;
  54. }
  55. const struct usb_class_ops usb_cdc_acm_ops = {
  56. .reset = update_reset,
  57. .configure = update_configure
  58. };
  59. static void end_command(void *ack, unsigned int ack_len)
  60. {
  61. if (state == ST_command_wait)
  62. blink_init();
  63. usb_write(EP_TX, ack, ack_len);
  64. u_prod = 0;
  65. }
  66. static struct {
  67. uint32_t len;
  68. uint32_t cur;
  69. } update;
  70. static void erase_old_firmware(void)
  71. {
  72. uint32_t p;
  73. for (p = FIRMWARE_START; p < FIRMWARE_END; p += FLASH_PAGE_SIZE)
  74. fpec_page_erase(p);
  75. }
  76. static void update_prep(uint32_t len)
  77. {
  78. fpec_init();
  79. erase_old_firmware();
  80. state = ST_update;
  81. update.cur = 0;
  82. update.len = len;
  83. printk("Update: %u bytes\n", len);
  84. }
  85. static void update_continue(void)
  86. {
  87. int len;
  88. if ((len = ep_rx_ready(EP_RX)) >= 0) {
  89. len = min_t(int, len, update.len - update.cur);
  90. usb_read(EP_RX, &u_buf[u_prod], len);
  91. u_prod += len;
  92. }
  93. if ((len = u_prod) >= 2) {
  94. int nr = len & ~1;
  95. fpec_write(u_buf, nr, FIRMWARE_START + update.cur);
  96. update.cur += nr;
  97. u_prod -= nr;
  98. memcpy(u_buf, &u_buf[nr], u_prod);
  99. }
  100. if ((update.cur >= update.len) && ep_tx_ready(EP_TX)) {
  101. uint16_t crc = crc16_ccitt((void *)FIRMWARE_START, update.len, 0xffff);
  102. printk("Final CRC: %04x (%s)\n", crc, crc ? "FAIL" : "OK");
  103. u_buf[0] = !!crc;
  104. state = ST_command_wait;
  105. end_command(u_buf, 1);
  106. if (crc)
  107. erase_old_firmware();
  108. }
  109. }
  110. static void process_command(void)
  111. {
  112. uint8_t cmd = u_buf[0];
  113. uint8_t len = u_buf[1];
  114. uint8_t resp_sz = 2;
  115. act_led(TRUE);
  116. switch (cmd) {
  117. case CMD_GET_INFO: {
  118. uint8_t idx = u_buf[2];
  119. if ((len != 3) || (idx != 0))
  120. goto bad_command;
  121. memset(&u_buf[2], 0, 32);
  122. gw_info.fw_major = fw_major;
  123. gw_info.fw_minor = fw_minor;
  124. /* sample_freq is used as flags: bit 0 indicates if we entered
  125. * the bootloader because the update jumper is strapped. */
  126. gw_info.sample_freq = upd_strapped;
  127. memcpy(&u_buf[2], &gw_info, sizeof(gw_info));
  128. resp_sz += 32;
  129. break;
  130. }
  131. case CMD_UPDATE: {
  132. uint32_t u_len = *(uint32_t *)&u_buf[2];
  133. if (len != 6) goto bad_command;
  134. if (u_len & 3) goto bad_command;
  135. update_prep(u_len);
  136. break;
  137. }
  138. case CMD_SWITCH_FW_MODE: {
  139. uint8_t mode = u_buf[2];
  140. if ((len != 3) || (mode & ~1))
  141. goto bad_command;
  142. if (mode == FW_MODE_NORMAL) {
  143. usb_deinit();
  144. delay_ms(500);
  145. system_reset();
  146. }
  147. break;
  148. }
  149. default:
  150. goto bad_command;
  151. }
  152. u_buf[1] = ACK_OKAY;
  153. out:
  154. end_command(u_buf, resp_sz);
  155. return;
  156. bad_command:
  157. u_buf[1] = ACK_BAD_COMMAND;
  158. goto out;
  159. }
  160. static void update_process(void)
  161. {
  162. int len;
  163. time_t now = time_now();
  164. switch (state) {
  165. case ST_command_wait:
  166. if (time_diff(blink.time, now) > time_ms(200)) {
  167. blink.time = now;
  168. blink.state ^= 1;
  169. act_led(blink.state);
  170. }
  171. len = ep_rx_ready(EP_RX);
  172. if ((len >= 0) && (len < (sizeof(u_buf)-u_prod))) {
  173. usb_read(EP_RX, &u_buf[u_prod], len);
  174. u_prod += len;
  175. }
  176. if ((u_prod >= 2) && (u_prod >= u_buf[1]) && ep_tx_ready(EP_TX)) {
  177. process_command();
  178. }
  179. break;
  180. case ST_update:
  181. update_continue();
  182. break;
  183. default:
  184. break;
  185. }
  186. }
  187. #if MCU == STM32F1
  188. static bool_t check_update_strapped(void)
  189. {
  190. /* Turn on AFIO and GPIOA clocks. */
  191. rcc->apb2enr = RCC_APB2ENR_IOPAEN | RCC_APB2ENR_AFIOEN;
  192. /* Turn off serial-wire JTAG and reclaim the GPIOs. */
  193. afio->mapr = AFIO_MAPR_SWJ_CFG_DISABLED;
  194. /* Enable GPIOA, set all pins as floating, except PA14 = weak pull-up. */
  195. gpioa->odr = 0xffffu;
  196. gpioa->crh = 0x48444444u;
  197. gpioa->crl = 0x44444444u;
  198. /* Wait for PA14 to be pulled HIGH. */
  199. cpu_relax();
  200. cpu_relax();
  201. /* Enter update mode only if PA14 (DCLK) is strapped to GND. */
  202. upd_strapped = !gpio_read_pin(gpioa, 14);
  203. return upd_strapped;
  204. }
  205. #else
  206. static bool_t check_update_strapped(void)
  207. {
  208. int i;
  209. /* Enable SysTick counter. */
  210. stk->load = STK_MASK;
  211. stk->ctrl = STK_CTRL_ENABLE;
  212. /* Check whether the Serial TX/RX lines (PA9/PA10) are strapped. */
  213. #if MCU == STM32F7
  214. rcc->ahb1enr |= RCC_AHB1ENR_GPIOAEN;
  215. (void)rcc->ahb1enr;
  216. #else
  217. rcc->apb2enr |= RCC_APB2ENR_IOPAEN;
  218. #endif
  219. gpio_configure_pin(gpioa, 9, GPO_pushpull(IOSPD_LOW, HIGH));
  220. gpio_configure_pin(gpioa, 10, GPI_pull_up);
  221. for (i = 0; i < 10; i++) {
  222. gpio_write_pin(gpioa, 9, i&1);
  223. early_delay_us(100);
  224. if (gpio_read_pin(gpioa, 10) != (i&1))
  225. return FALSE;
  226. }
  227. return TRUE;
  228. }
  229. #endif
  230. static bool_t check_update_requested(void)
  231. {
  232. /* Check-and-clear a magic value poked into SRAM1 by the main firmware. */
  233. bool_t match = (_reset_flag == 0xdeadbeef);
  234. _reset_flag = 0;
  235. return match;
  236. }
  237. static bool_t enter_bootloader(void)
  238. {
  239. bool_t upd_requested = check_update_requested();
  240. upd_strapped = check_update_strapped();
  241. return upd_requested || upd_strapped;
  242. }
  243. int main(void)
  244. {
  245. /* Relocate DATA. Initialise BSS. */
  246. if (_sdat != _ldat)
  247. memcpy(_sdat, _ldat, _edat-_sdat);
  248. memset(_sbss, 0, _ebss-_sbss);
  249. if (!enter_bootloader()) {
  250. /* Nope, so jump straight at the main firmware. */
  251. uint32_t sp = *(uint32_t *)FIRMWARE_START;
  252. uint32_t pc = *(uint32_t *)(FIRMWARE_START + 4);
  253. if (sp != ~0u) { /* only if firmware is apparently not erased */
  254. asm volatile (
  255. "mov sp,%0 ; blx %1"
  256. :: "r" (sp), "r" (pc));
  257. }
  258. }
  259. stm32_init();
  260. time_init();
  261. console_init();
  262. console_crash_on_input();
  263. board_init();
  264. printk("\n** Greaseweazle Update Bootloader v%u.%u\n", fw_major, fw_minor);
  265. printk("** Keir Fraser <keir.xen@gmail.com>\n");
  266. printk("** https://github.com/keirf/Greaseweazle\n\n");
  267. usb_init();
  268. for (;;) {
  269. usb_process();
  270. update_process();
  271. }
  272. return 0;
  273. }
  274. /*
  275. * Local variables:
  276. * mode: C
  277. * c-file-style: "Linux"
  278. * c-basic-offset: 4
  279. * tab-width: 4
  280. * indent-tabs-mode: nil
  281. * End:
  282. */