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