diff --git a/src/stm32/Kconfig b/src/stm32/Kconfig index 13cf8d84..dac884a0 100644 --- a/src/stm32/Kconfig +++ b/src/stm32/Kconfig @@ -220,6 +220,15 @@ config STM32F103GD_DISABLE_SWD and PA14 pins from being available. Selecting this option disables SWD at startup and thus makes these pins available. +config STM32_DFU_ROM_ADDRESS + hex + default 0 if !USB + default 0x1fffc400 if MACH_STM32F042 + default 0x1fffc800 if MACH_STM32F072 + default 0x1fff0000 if MACH_STM32F4 || MACH_STM32G0 || MACH_STM32G4 || MACH_STM32L4 + default 0x1ff09800 if MACH_STM32H7 + default 0 + ###################################################################### # Bootloader diff --git a/src/stm32/Makefile b/src/stm32/Makefile index d9efd085..15ea4e2b 100644 --- a/src/stm32/Makefile +++ b/src/stm32/Makefile @@ -31,7 +31,8 @@ CFLAGS_klipper.elf += -T $(OUT)src/generic/armcm_link.ld $(OUT)klipper.elf: $(OUT)src/generic/armcm_link.ld # Add source files -src-y += stm32/watchdog.c stm32/gpio.c stm32/clockline.c generic/crc16_ccitt.c +src-y += stm32/watchdog.c stm32/gpio.c stm32/clockline.c stm32/dfu_reboot.c +src-y += generic/crc16_ccitt.c src-y += generic/armcm_boot.c generic/armcm_irq.c generic/armcm_reset.c src-$(CONFIG_MACH_STM32F0) += ../lib/stm32f0/system_stm32f0xx.c src-$(CONFIG_MACH_STM32F0) += generic/timer_irq.c stm32/stm32f0_timer.c diff --git a/src/stm32/dfu_reboot.c b/src/stm32/dfu_reboot.c new file mode 100644 index 00000000..04952a48 --- /dev/null +++ b/src/stm32/dfu_reboot.c @@ -0,0 +1,57 @@ +// Reboot into stm32 ROM dfu bootloader +// +// Copyright (C) 2019-2022 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "internal.h" // NVIC_SystemReset +#include "board/irq.h" // irq_disable + +// Many stm32 chips have a USB capable "DFU bootloader" in their ROM. +// In order to invoke that bootloader it is necessary to reset the +// chip and jump to a chip specific hardware address. +// +// To reset the chip, the dfu_reboot() code sets a flag in memory (at +// an arbitrary position that is unlikely to be overwritten during a +// chip reset), and resets the chip. If dfu_reboot_check() sees that +// flag on the next boot it will perform a code jump to the ROM +// address. + +// Location of ram address to set internal flag +#if CONFIG_MACH_STM32H7 + #define USB_BOOT_FLAG_ADDR (0x24000000 + 0x8000) // Place flag in "AXI SRAM" +#else + #define USB_BOOT_FLAG_ADDR (CONFIG_RAM_START + CONFIG_RAM_SIZE - 1024) +#endif + +// Signature to set in memory to flag that a dfu reboot is requested +#define USB_BOOT_FLAG 0x55534220424f4f54 // "USB BOOT" + +// Flag that bootloader is desired and reboot +void +dfu_reboot(void) +{ + if (!CONFIG_STM32_DFU_ROM_ADDRESS) + return; + irq_disable(); + uint64_t *bflag = (void*)USB_BOOT_FLAG_ADDR; + *bflag = USB_BOOT_FLAG; +#if CONFIG_MACH_STM32H7 + SCB_CleanDCache_by_Addr((void*)bflag, sizeof(*bflag)); +#endif + NVIC_SystemReset(); +} + +// Check if rebooting into system DFU Bootloader +void +dfu_reboot_check(void) +{ + if (!CONFIG_STM32_DFU_ROM_ADDRESS) + return; + if (*(uint64_t*)USB_BOOT_FLAG_ADDR != USB_BOOT_FLAG) + return; + *(uint64_t*)USB_BOOT_FLAG_ADDR = 0; + uint32_t *sysbase = (uint32_t*)CONFIG_STM32_DFU_ROM_ADDRESS; + asm volatile("mov sp, %0\n bx %1" + : : "r"(sysbase[0]), "r"(sysbase[1])); +} diff --git a/src/stm32/internal.h b/src/stm32/internal.h index 2ba7abe2..b5971ed7 100644 --- a/src/stm32/internal.h +++ b/src/stm32/internal.h @@ -40,6 +40,10 @@ void gpio_peripheral(uint32_t gpio, uint32_t mode, int pullup); void enable_pclock(uint32_t periph_base); int is_enabled_pclock(uint32_t periph_base); +// dfu_reboot.c +void dfu_reboot(void); +void dfu_reboot_check(void); + // stm32??.c struct cline { volatile uint32_t *en, *rst; uint32_t bit; }; struct cline lookup_clock_line(uint32_t periph_base); diff --git a/src/stm32/stm32f0.c b/src/stm32/stm32f0.c index e63f1b5b..72fc1645 100644 --- a/src/stm32/stm32f0.c +++ b/src/stm32/stm32f0.c @@ -134,39 +134,12 @@ hsi14_setup(void) * Bootloader ****************************************************************/ -#define USB_BOOT_FLAG_ADDR (CONFIG_RAM_START + CONFIG_RAM_SIZE - 1024) -#define USB_BOOT_FLAG 0x55534220424f4f54 // "USB BOOT" - -// Flag that bootloader is desired and reboot -static void -usb_reboot_for_dfu_bootloader(void) -{ - irq_disable(); - *(uint64_t*)USB_BOOT_FLAG_ADDR = USB_BOOT_FLAG; - NVIC_SystemReset(); -} - -// Check if rebooting into system DFU Bootloader -static void -check_usb_dfu_bootloader(void) -{ - if (!CONFIG_USB || !CONFIG_MACH_STM32F0x2 - || *(uint64_t*)USB_BOOT_FLAG_ADDR != USB_BOOT_FLAG) - return; - *(uint64_t*)USB_BOOT_FLAG_ADDR = 0; - uint32_t *sysbase = (uint32_t*)0x1fffc400; - if (CONFIG_MACH_STM32F072) - sysbase = (uint32_t*)0x1fffc800; - asm volatile("mov sp, %0\n bx %1" - : : "r"(sysbase[0]), "r"(sysbase[1])); -} - // Handle reboot requests void bootloader_request(void) { try_request_canboot(); - usb_reboot_for_dfu_bootloader(); + dfu_reboot(); } @@ -193,7 +166,7 @@ enable_ram_vectortable(void) void armcm_main(void) { - check_usb_dfu_bootloader(); + dfu_reboot_check(); SystemInit(); enable_pclock(SYSCFG_BASE); diff --git a/src/stm32/stm32f4.c b/src/stm32/stm32f4.c index 4f1dc084..a2060d76 100644 --- a/src/stm32/stm32f4.c +++ b/src/stm32/stm32f4.c @@ -204,30 +204,6 @@ usb_hid_bootloader(void) NVIC_SystemReset(); } -#define USB_BOOT_FLAG_ADDR (CONFIG_RAM_START + CONFIG_RAM_SIZE - 4096) -#define USB_BOOT_FLAG 0x55534220424f4f54 // "USB BOOT" - -// Flag that bootloader is desired and reboot -static void -usb_reboot_for_dfu_bootloader(void) -{ - irq_disable(); - *(uint64_t*)USB_BOOT_FLAG_ADDR = USB_BOOT_FLAG; - NVIC_SystemReset(); -} - -// Check if rebooting into system DFU Bootloader -static void -check_usb_dfu_bootloader(void) -{ - if (!CONFIG_USB || *(uint64_t*)USB_BOOT_FLAG_ADDR != USB_BOOT_FLAG) - return; - *(uint64_t*)USB_BOOT_FLAG_ADDR = 0; - uint32_t *sysbase = (uint32_t*)0x1fff0000; - asm volatile("mov sp, %0\n bx %1" - : : "r"(sysbase[0]), "r"(sysbase[1])); -} - // Handle reboot requests void bootloader_request(void) @@ -235,7 +211,7 @@ bootloader_request(void) try_request_canboot(); if (CONFIG_STM32_FLASH_START_4000) usb_hid_bootloader(); - usb_reboot_for_dfu_bootloader(); + dfu_reboot(); } @@ -247,7 +223,7 @@ bootloader_request(void) void armcm_main(void) { - check_usb_dfu_bootloader(); + dfu_reboot_check(); // Run SystemInit() and then restore VTOR SystemInit(); diff --git a/src/stm32/stm32g0.c b/src/stm32/stm32g0.c index f42ac777..41f7f6f2 100644 --- a/src/stm32/stm32g0.c +++ b/src/stm32/stm32g0.c @@ -128,36 +128,12 @@ clock_setup(void) * Bootloader ****************************************************************/ -#define USB_BOOT_FLAG_ADDR (CONFIG_RAM_START + CONFIG_RAM_SIZE - 1024) -#define USB_BOOT_FLAG 0x55534220424f4f54 // "USB BOOT" - -// Flag that bootloader is desired and reboot -static void -usb_reboot_for_dfu_bootloader(void) -{ - irq_disable(); - *(uint64_t*)USB_BOOT_FLAG_ADDR = USB_BOOT_FLAG; - NVIC_SystemReset(); -} - -// Check if rebooting into system DFU Bootloader -static void -check_usb_dfu_bootloader(void) -{ - if (!CONFIG_USB || *(uint64_t*)USB_BOOT_FLAG_ADDR != USB_BOOT_FLAG) - return; - *(uint64_t*)USB_BOOT_FLAG_ADDR = 0; - uint32_t *sysbase = (uint32_t*)0x1fff0000; - asm volatile("mov sp, %0\n bx %1" - : : "r"(sysbase[0]), "r"(sysbase[1])); -} - // Handle USB reboot requests void bootloader_request(void) { try_request_canboot(); - usb_reboot_for_dfu_bootloader(); + dfu_reboot(); } @@ -185,7 +161,7 @@ armcm_main(void) RCC->APBENR1 = 0x00000000; RCC->APBENR2 = 0x00000000; - check_usb_dfu_bootloader(); + dfu_reboot_check(); // Set flash latency, cache and prefetch; use reset value as base uint32_t acr = 0x00040600; diff --git a/src/stm32/stm32g4.c b/src/stm32/stm32g4.c index a0dd32c0..c3cf0969 100644 --- a/src/stm32/stm32g4.c +++ b/src/stm32/stm32g4.c @@ -139,36 +139,11 @@ clock_setup(void) * Bootloader ****************************************************************/ -#define USB_BOOT_FLAG_ADDR (CONFIG_RAM_START + CONFIG_RAM_SIZE - 4096) -#define USB_BOOT_FLAG 0x55534220424f4f54 // "USB BOOT" - -// Flag that bootloader is desired and reboot -static void -usb_reboot_for_dfu_bootloader(void) -{ - irq_disable(); - // System DFU Bootloader - *(uint64_t*)USB_BOOT_FLAG_ADDR = USB_BOOT_FLAG; - NVIC_SystemReset(); -} - -// Check if rebooting into system DFU Bootloader -static void -check_usb_dfu_bootloader(void) -{ - if (!CONFIG_USB || *(uint64_t*)USB_BOOT_FLAG_ADDR != USB_BOOT_FLAG) - return; - *(uint64_t*)USB_BOOT_FLAG_ADDR = 0; - uint32_t *sysbase = (uint32_t*)0x1fff0000; - asm volatile("mov sp, %0\n bx %1" - : : "r"(sysbase[0]), "r"(sysbase[1])); -} - // Handle USB reboot requests void bootloader_request(void) { - usb_reboot_for_dfu_bootloader(); + dfu_reboot(); } @@ -180,7 +155,7 @@ bootloader_request(void) void armcm_main(void) { - check_usb_dfu_bootloader(); + dfu_reboot_check(); // Run SystemInit() and then restore VTOR SystemInit(); diff --git a/src/stm32/stm32h7.c b/src/stm32/stm32h7.c index 43b7aa6e..dc9a29d1 100644 --- a/src/stm32/stm32h7.c +++ b/src/stm32/stm32h7.c @@ -208,38 +208,12 @@ clock_setup(void) * Bootloader ****************************************************************/ -#define USB_BOOT_FLAG_ADDR (0x24000000 + 0x8000) // Place flag in "AXI SRAM" -#define USB_BOOT_FLAG 0x55534220424f4f54 // "USB BOOT" - -// Flag that bootloader is desired and reboot -static void -usb_reboot_for_dfu_bootloader(void) -{ - irq_disable(); - uint64_t *bflag = (void*)USB_BOOT_FLAG_ADDR; - *bflag = USB_BOOT_FLAG; - SCB_CleanDCache_by_Addr((void*)bflag, sizeof(*bflag)); - NVIC_SystemReset(); -} - -// Check if rebooting into system DFU Bootloader -static void -check_usb_dfu_bootloader(void) -{ - if (!CONFIG_USB || *(uint64_t*)USB_BOOT_FLAG_ADDR != USB_BOOT_FLAG) - return; - *(uint64_t*)USB_BOOT_FLAG_ADDR = 0; - uint32_t *sysbase = (uint32_t*)0x1FF09800; - asm volatile("mov sp, %0\n bx %1" - : : "r"(sysbase[0]), "r"(sysbase[1])); -} - // Handle reboot requests void bootloader_request(void) { try_request_canboot(); - usb_reboot_for_dfu_bootloader(); + dfu_reboot(); } @@ -259,7 +233,7 @@ armcm_main(void) RCC->D3CCIPR = 0x00000000; SCB->VTOR = (uint32_t)VectorTable; - check_usb_dfu_bootloader(); + dfu_reboot_check(); clock_setup(); diff --git a/src/stm32/stm32l4.c b/src/stm32/stm32l4.c index b5c939bb..709473c8 100644 --- a/src/stm32/stm32l4.c +++ b/src/stm32/stm32l4.c @@ -139,36 +139,11 @@ clock_setup(void) * Bootloader ****************************************************************/ -#define USB_BOOT_FLAG_ADDR (CONFIG_RAM_START + CONFIG_RAM_SIZE - 4096) -#define USB_BOOT_FLAG 0x55534220424f4f54 // "USB BOOT" - -// Flag that bootloader is desired and reboot -static void -usb_reboot_for_dfu_bootloader(void) -{ - irq_disable(); - // System DFU Bootloader - *(uint64_t*)USB_BOOT_FLAG_ADDR = USB_BOOT_FLAG; - NVIC_SystemReset(); -} - -// Check if rebooting into system DFU Bootloader -static void -check_usb_dfu_bootloader(void) -{ - if (!CONFIG_USB || *(uint64_t*)USB_BOOT_FLAG_ADDR != USB_BOOT_FLAG) - return; - *(uint64_t*)USB_BOOT_FLAG_ADDR = 0; - uint32_t *sysbase = (uint32_t*)0x1fff0000; - asm volatile("mov sp, %0\n bx %1" - : : "r"(sysbase[0]), "r"(sysbase[1])); -} - // Handle USB reboot requests void bootloader_request(void) { - usb_reboot_for_dfu_bootloader(); + dfu_reboot(); } @@ -180,7 +155,7 @@ bootloader_request(void) void armcm_main(void) { - check_usb_dfu_bootloader(); + dfu_reboot_check(); // Run SystemInit() and then restore VTOR SystemInit();