]> mj.ucw.cz Git - home-hw.git/blob - lib/dfu-bootloader.c
README
[home-hw.git] / lib / dfu-bootloader.c
1 /*
2  *      Generic DFU Bootloader
3  *
4  *      (c) 2020 Martin Mareš <mj@ucw.cz>
5  *
6  *      Based on example code from the libopencm3 project, which is
7  *      Copyright (C) 2010 Gareth McMullin <gareth@blacksphere.co.nz>
8  *
9  *      Licensed under the GNU LGPL v3 or any later version.
10  */
11
12 #include "util.h"
13
14 #include <libopencm3/cm3/cortex.h>
15 #include <libopencm3/cm3/nvic.h>
16 #include <libopencm3/cm3/scb.h>
17 #include <libopencm3/cm3/systick.h>
18 #include <libopencm3/stm32/rcc.h>
19 #include <libopencm3/stm32/crc.h>
20 #include <libopencm3/stm32/gpio.h>
21 #include <libopencm3/stm32/flash.h>
22 #include <libopencm3/stm32/usart.h>
23 #include <libopencm3/stm32/desig.h>
24 #include <libopencm3/usb/usbd.h>
25 #include <libopencm3/usb/dfu.h>
26
27 #include <string.h>
28
29 #ifdef BOOTLOADER_DEBUG
30 #define DEBUG(x...) debug_printf(x)
31 #else
32 #define DEBUG(x...) do { } while (0)
33 #endif
34
35 // Offsets to firmware header fields (see tools/dfu-sign.c)
36 #define HDR_LENGTH 0x1c
37 #define HDR_FLASH_IN_PROGRESS 0x20
38
39 // DFU blocks should be equal to erase blocks of the flash
40 #define BLOCK_SIZE 1024
41 byte usbd_control_buffer[BLOCK_SIZE];
42
43 static enum dfu_state dfu_state = STATE_DFU_IDLE;
44 static uint timeout;
45 #define DEFAULT_TIMEOUT 5000   // ms
46 #define DFU_TIMEOUT 2000
47
48 static struct {
49         byte buf[sizeof(usbd_control_buffer)];
50         u16 blocknum;
51         u16 len;
52 } prog;
53
54 static char usb_serial_number[13];
55
56 enum usb_string {
57         STR_MANUFACTURER = 1,
58         STR_PRODUCT,
59         STR_SERIAL,
60 };
61
62 static const char *usb_strings[] = {
63         BOOTLOADER_MFG_NAME,
64         BOOTLOADER_PROD_NAME,
65         usb_serial_number,
66 };
67
68 const struct usb_device_descriptor dev = {
69         .bLength = USB_DT_DEVICE_SIZE,
70         .bDescriptorType = USB_DT_DEVICE,
71         .bcdUSB = 0x0200,
72         .bDeviceClass = 0,
73         .bDeviceSubClass = 0,
74         .bDeviceProtocol = 0,
75         .bMaxPacketSize0 = 64,
76         .idVendor = BOOTLOADER_MFG_ID,
77         .idProduct = BOOTLOADER_PROD_ID,
78         .bcdDevice = BOOTLOADER_PROD_VERSION,
79         .iManufacturer = STR_MANUFACTURER,
80         .iProduct = STR_PRODUCT,
81         .iSerialNumber = STR_SERIAL,
82         .bNumConfigurations = 1,
83 };
84
85 const struct usb_dfu_descriptor dfu_function = {
86         .bLength = sizeof(struct usb_dfu_descriptor),
87         .bDescriptorType = DFU_FUNCTIONAL,
88         .bmAttributes = USB_DFU_CAN_DOWNLOAD | USB_DFU_WILL_DETACH,
89         .wDetachTimeout = 255,
90         .wTransferSize = BLOCK_SIZE,
91         .bcdDFUVersion = 0x0100,
92 };
93
94 const struct usb_interface_descriptor iface = {
95         .bLength = USB_DT_INTERFACE_SIZE,
96         .bDescriptorType = USB_DT_INTERFACE,
97         .bInterfaceNumber = 0,
98         .bAlternateSetting = 0,
99         .bNumEndpoints = 0,
100         .bInterfaceClass = 0xFE, /* Device Firmware Upgrade */
101         .bInterfaceSubClass = 1,
102         .bInterfaceProtocol = 2,
103         .extra = &dfu_function,
104         .extralen = sizeof(dfu_function),
105 };
106
107 const struct usb_interface ifaces[] = {{
108         .num_altsetting = 1,
109         .altsetting = &iface,
110 }};
111
112 const struct usb_config_descriptor config = {
113         .bLength = USB_DT_CONFIGURATION_SIZE,
114         .bDescriptorType = USB_DT_CONFIGURATION,
115         .wTotalLength = 0,
116         .bNumInterfaces = 1,
117         .bConfigurationValue = 1,
118         .iConfiguration = 0,
119         .bmAttributes = USB_CONFIG_ATTR_DEFAULT,        // bus-powered
120         .bMaxPower = 50,                                // multiplied by 2 mA
121         .interface = ifaces,
122 };
123
124 static inline u32 get_u32(u32 addr)
125 {
126         return *(u32*)addr;
127 }
128
129 static inline u16 get_u16(u32 addr)
130 {
131         return *(u16*)addr;
132 }
133
134 static bool verify_firmware(void)
135 {
136         u32 len = get_u32(BOOTLOADER_APP_START + HDR_LENGTH);
137         u16 flash_in_progress = get_u16(BOOTLOADER_APP_START + HDR_FLASH_IN_PROGRESS);
138
139         // FIXME: Should check if len is reasonable
140
141         crc_reset();
142         u32 crc = crc_calculate_block((u32 *)BOOTLOADER_APP_START, len/4);
143         u32 want_crc = get_u32(BOOTLOADER_APP_START + len);
144         DEBUG("DFU: fip=%04x crc=%08x/%08x len=%u\n", (uint) flash_in_progress, (uint) crc, (uint) want_crc, (uint) len);
145         if (flash_in_progress || crc != want_crc) {
146                 DEBUG("DFU: Bad firmware\n");
147                 return 0;
148         }
149
150         return 1;
151 }
152
153 static byte dfu_getstatus(usbd_device *usbd_dev UNUSED, u32 *bwPollTimeout)
154 {
155         switch (dfu_state) {
156         case STATE_DFU_DNLOAD_SYNC:
157                 dfu_state = STATE_DFU_DNBUSY;
158                 *bwPollTimeout = 100;
159                 return DFU_STATUS_OK;
160         case STATE_DFU_MANIFEST_SYNC:
161                 /* Device will reset when read is complete. */
162                 dfu_state = STATE_DFU_MANIFEST;
163                 return DFU_STATUS_OK;
164         case STATE_DFU_ERROR:
165                 return DFU_STATUS_ERR_VERIFY;
166         default:
167                 return DFU_STATUS_OK;
168         }
169 }
170
171 static void dfu_getstatus_complete(usbd_device *usbd_dev UNUSED, struct usb_setup_data *req UNUSED)
172 {
173         switch (dfu_state) {
174         case STATE_DFU_DNBUSY:
175                 if (prog.blocknum == 0) {
176                         // The "flash in progress" word is programmed as 0xffff first and reset later
177                         *(u16*)(prog.buf + HDR_FLASH_IN_PROGRESS) = 0xffff;
178                 }
179                 u32 baseaddr = BOOTLOADER_APP_START + prog.blocknum * BLOCK_SIZE;
180                 DEBUG("DFU: Block %u -> %08x + %u\n", prog.blocknum, (uint) baseaddr, prog.len);
181                 flash_unlock();
182                 flash_erase_page(baseaddr);
183                 for (uint i = 0; i < prog.len; i += 2)
184                         flash_program_half_word(baseaddr + i, *(u16*)(prog.buf + i));
185                 flash_lock();
186                 for (uint i = 0; i < prog.len; i++) {
187                         if (*(byte *)(baseaddr + i) != prog.buf[i]) {
188                                 DEBUG("DFU: Verification failed\n");
189                                 dfu_state = STATE_DFU_ERROR;
190                         }
191                 }
192                 dfu_state = STATE_DFU_DNLOAD_IDLE;
193                 return;
194         case STATE_DFU_MANIFEST:
195                 // At the very end, re-flash the "flash in progress" word
196                 flash_unlock();
197                 flash_program_half_word(BOOTLOADER_APP_START + 0x20, 0);
198                 flash_lock();
199                 if (verify_firmware())
200                         dfu_state = STATE_DFU_MANIFEST_WAIT_RESET;
201                 else
202                         dfu_state = STATE_DFU_ERROR;
203                 return;
204         default:
205                 return;
206         }
207 }
208
209 static enum usbd_request_return_codes dfu_control_request(usbd_device *usbd_dev,
210         struct usb_setup_data *req,
211         byte **buf,
212         u16 *len,
213         void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req))
214 {
215         if ((req->bmRequestType & 0x7F) != 0x21)
216                 return USBD_REQ_NOTSUPP; /* Only accept class request. */
217
218         DEBUG("DFU: Request %02x in state %d\n", req->bRequest, dfu_state);
219         timeout = DFU_TIMEOUT;
220
221         switch (req->bRequest) {
222         case DFU_DNLOAD:
223                 if (len == NULL || *len == 0) {
224                         dfu_state = STATE_DFU_MANIFEST_SYNC;
225                 } else {
226                         /* Copy download data for use on GET_STATUS. */
227                         prog.blocknum = req->wValue;
228                         prog.len = *len;
229                         memcpy(prog.buf, *buf, *len);
230                         dfu_state = STATE_DFU_DNLOAD_SYNC;
231                 }
232                 return USBD_REQ_HANDLED;
233         case DFU_CLRSTATUS:
234                 /* Clear error and return to dfuIDLE. */
235                 if (dfu_state == STATE_DFU_ERROR)
236                         dfu_state = STATE_DFU_IDLE;
237                 return USBD_REQ_HANDLED;
238         case DFU_ABORT:
239                 /* Abort returns to dfuIDLE state. */
240                 dfu_state = STATE_DFU_IDLE;
241                 return USBD_REQ_HANDLED;
242         case DFU_UPLOAD:
243                 /* Upload not supported for now. */
244                 return USBD_REQ_NOTSUPP;
245         case DFU_GETSTATUS: {
246                 u32 bwPollTimeout = 0; /* 24-bit number of milliseconds */
247                 (*buf)[0] = dfu_getstatus(usbd_dev, &bwPollTimeout);
248                 (*buf)[1] = bwPollTimeout & 0xFF;
249                 (*buf)[2] = (bwPollTimeout >> 8) & 0xFF;
250                 (*buf)[3] = (bwPollTimeout >> 16) & 0xFF;
251                 (*buf)[4] = dfu_state;
252                 (*buf)[5] = 0; /* iString not used here */
253                 *len = 6;
254                 *complete = dfu_getstatus_complete;
255                 return USBD_REQ_HANDLED;
256                 }
257         case DFU_GETSTATE:
258                 /* Return state with no state transition. */
259                 *buf[0] = dfu_state;
260                 *len = 1;
261                 return USBD_REQ_HANDLED;
262         }
263
264         return USBD_REQ_NOTSUPP;
265 }
266
267 static void dfu_set_config(usbd_device *usbd_dev, u16 wValue UNUSED)
268 {
269         usbd_register_control_callback(
270                 usbd_dev,
271                 USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
272                 USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
273                 dfu_control_request);
274 }
275
276 static void dfu_reset(void)
277 {
278         dfu_state = STATE_DFU_IDLE;
279 }
280
281 /*
282  *  This is a modified version of rcc_clock_setup_in_hsi_out_48mhz(),
283  *  which properly turns off the PLL before setting its parameters.
284  */
285 static void my_rcc_clock_setup_in_hsi_out_48mhz(void)
286 {
287         /* Enable internal high-speed oscillator. */
288         rcc_osc_on(RCC_HSI);
289         rcc_wait_for_osc_ready(RCC_HSI);
290
291         /* Select HSI as SYSCLK source. */
292         rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSICLK);
293
294         // XXX: Disable PLL
295         rcc_osc_off(RCC_PLL);
296
297         /*
298          * Set prescalers for AHB, ADC, ABP1, ABP2.
299          * Do this before touching the PLL (TODO: why?).
300          */
301         rcc_set_hpre(RCC_CFGR_HPRE_SYSCLK_NODIV);       /*Set.48MHz Max.72MHz */
302         rcc_set_adcpre(RCC_CFGR_ADCPRE_PCLK2_DIV8);     /*Set. 6MHz Max.14MHz */
303         rcc_set_ppre1(RCC_CFGR_PPRE1_HCLK_DIV2);        /*Set.24MHz Max.36MHz */
304         rcc_set_ppre2(RCC_CFGR_PPRE2_HCLK_NODIV);       /*Set.48MHz Max.72MHz */
305         rcc_set_usbpre(RCC_CFGR_USBPRE_PLL_CLK_NODIV);  /*Set.48MHz Max.48MHz */
306
307         /*
308          * Sysclk runs with 48MHz -> 1 waitstates.
309          * 0WS from 0-24MHz
310          * 1WS from 24-48MHz
311          * 2WS from 48-72MHz
312          */
313         flash_set_ws(FLASH_ACR_LATENCY_1WS);
314
315         /*
316          * Set the PLL multiplication factor to 12.
317          * 8MHz (internal) * 12 (multiplier) / 2 (PLLSRC_HSI_CLK_DIV2) = 48MHz
318          */
319         rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_PLL_CLK_MUL12);
320
321         /* Select HSI/2 as PLL source. */
322         rcc_set_pll_source(RCC_CFGR_PLLSRC_HSI_CLK_DIV2);
323
324         /* Enable PLL oscillator and wait for it to stabilize. */
325         rcc_osc_on(RCC_PLL);
326         rcc_wait_for_osc_ready(RCC_PLL);
327
328         /* Select PLL as SYSCLK source. */
329         rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_PLLCLK);
330
331         /* Set the peripheral clock frequencies used */
332         rcc_ahb_frequency = 48000000;
333         rcc_apb1_frequency = 24000000;
334         rcc_apb2_frequency = 48000000;
335 }
336
337 static void clock_plain_hsi(void)
338 {
339         // Select HSI as SYSCLK source
340         rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSICLK);
341
342         // Disable PLL
343         rcc_osc_off(RCC_PLL);
344
345         // Set prescalers for AHB, ADC, ABP1, ABP2, USB to defaults
346         rcc_set_hpre(RCC_CFGR_HPRE_SYSCLK_NODIV);
347         rcc_set_adcpre(RCC_CFGR_ADCPRE_PCLK2_DIV2);
348         rcc_set_ppre1(RCC_CFGR_PPRE1_HCLK_NODIV);
349         rcc_set_ppre2(RCC_CFGR_PPRE2_HCLK_NODIV);
350         rcc_set_usbpre(RCC_CFGR_USBPRE_PLL_VCO_CLK_DIV3);
351 }
352
353 static void reset_peripherals(void)
354 {
355         // Turn off clock to all peripherals and reset them
356         RCC_AHBENR = 0x00000014;
357         RCC_APB1ENR = 0;
358         RCC_APB2ENR = 0;
359         RCC_APB1RSTR = 0x22fec9ff;
360         RCC_APB2RSTR = 0x0038fffd;
361         RCC_APB1RSTR = 0;
362         RCC_APB2RSTR = 0;
363 }
364
365 static void configure_hardware(void)
366 {
367         rcc_periph_clock_enable(RCC_GPIOA);
368         rcc_periph_clock_enable(RCC_GPIOC);
369         rcc_periph_clock_enable(RCC_USB);
370         rcc_periph_clock_enable(RCC_CRC);
371
372 #ifdef DEBUG_USART
373         // Currently, only USART1 is supported
374         rcc_periph_clock_enable(RCC_USART1);
375         rcc_periph_reset_pulse(RST_USART1);
376         gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO9);
377
378         usart_set_baudrate(USART1, 115200);
379         usart_set_databits(USART1, 8);
380         usart_set_stopbits(USART1, USART_STOPBITS_1);
381         usart_set_mode(USART1, USART_MODE_TX);
382         usart_set_parity(USART1, USART_PARITY_NONE);
383         usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE);
384
385         usart_enable(USART1);
386 #endif
387
388 #ifdef DEBUG_LED_BLUEPILL
389         // BluePill LED
390         gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO13);
391         debug_led(1);
392 #endif
393
394         // Systick: set to overflow in 1 ms, will use only the overflow flag, no interrupts
395         systick_set_frequency(1000, CPU_CLOCK_MHZ * 1000000);
396         systick_clear();
397         systick_counter_enable();
398 }
399
400 static void usb_disconnect(void)
401 {
402         gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO11 | GPIO12);
403         gpio_clear(GPIOA, GPIO11 | GPIO12);
404         for (uint i=0; i<100; i++) {
405                 while (!systick_get_countflag())
406                         ;
407         }
408 }
409
410 int main(void)
411 {
412         usbd_device *usbd_dev;
413
414         reset_peripherals();
415
416         // Flash programming requires running on the internal oscillator
417         my_rcc_clock_setup_in_hsi_out_48mhz();
418
419         configure_hardware();
420         desig_get_unique_id_as_dfu(usb_serial_number);
421
422         DEBUG("DFU: Started (SN %s)\n", usb_serial_number);
423
424         usb_disconnect();
425
426         DEBUG("DFU: Ready\n");
427         debug_led(0);
428
429         usbd_dev = usbd_init(&st_usbfs_v1_usb_driver, &dev, &config, usb_strings, ARRAY_SIZE(usb_strings), usbd_control_buffer, sizeof(usbd_control_buffer));
430         usbd_register_reset_callback(usbd_dev, dfu_reset);
431         usbd_register_set_config_callback(usbd_dev, dfu_set_config);
432
433 restart: ;
434
435         timeout = DEFAULT_TIMEOUT;
436         while (timeout || (dfu_state != STATE_DFU_IDLE && dfu_state != STATE_DFU_MANIFEST_WAIT_RESET)) {
437                 usbd_poll(usbd_dev);
438                 if (timeout && systick_get_countflag()) {
439                         timeout--;
440                         // FIXME: Blink LED even after timeout
441                         if (!(timeout & 0x3f))
442                                 debug_led_toggle();
443                 }
444         }
445
446         if (!verify_firmware())
447                 goto restart;
448
449         u32 sp = get_u32(BOOTLOADER_APP_START);
450         u32 pc = get_u32(BOOTLOADER_APP_START + 4);
451         DEBUG("DFU: Boot (sp=%08x pc=%08x)\n", (uint) sp, (uint) pc);
452
453 #ifdef DEBUG_USART
454         debug_flush();
455 #endif
456         debug_led(0);
457
458         reset_peripherals();
459         clock_plain_hsi();
460
461         /* Set vector table base address. */
462         SCB_VTOR = BOOTLOADER_APP_START;
463
464         /* Initialize master stack pointer. */
465         asm volatile("msr msp, %0"::"g" (sp));
466
467         /* Jump to application. */
468         ((void (*)(void)) pc)();
469 }