summaryrefslogtreecommitdiff
path: root/platforms
diff options
context:
space:
mode:
authorRyan <fauxpark@gmail.com>2021-12-27 21:10:07 +1100
committerGitHub <noreply@github.com>2021-12-27 21:10:07 +1100
commit6bc870d899c474bce82457699ec4b753d1538123 (patch)
tree600b8dda41f4b90f98199d4afd3037374a679a74 /platforms
parentcffe143ca20d938c910b59410dcd3d96dd7d433b (diff)
downloadqmk_firmware-6bc870d899c474bce82457699ec4b753d1538123.tar.gz
qmk_firmware-6bc870d899c474bce82457699ec4b753d1538123.zip
Refactor `bootloader_jump()` implementations (#15450)
* Refactor `bootloader_jump()` implementations * Fix tests? * Rename `atmel-samba` to `md-boot`
Diffstat (limited to 'platforms')
-rw-r--r--platforms/arm_atsam/bootloaders/md_boot.c (renamed from platforms/arm_atsam/bootloader.c)43
-rw-r--r--platforms/avr/bootloader.c293
-rw-r--r--platforms/avr/bootloaders/bootloadhid.c34
-rw-r--r--platforms/avr/bootloaders/caterina.c39
-rw-r--r--platforms/avr/bootloaders/dfu.c53
-rw-r--r--platforms/avr/bootloaders/halfkay.c129
-rw-r--r--platforms/avr/bootloaders/none.c20
-rw-r--r--platforms/avr/bootloaders/usbasploader.c57
-rw-r--r--platforms/chibios/bootloader.c145
-rw-r--r--platforms/chibios/bootloaders/gd32v_dfu.c40
-rw-r--r--platforms/chibios/bootloaders/halfkay.c26
-rw-r--r--platforms/chibios/bootloaders/kiibohd.c33
-rw-r--r--platforms/chibios/bootloaders/none.c20
-rw-r--r--platforms/chibios/bootloaders/stm32_dfu.c96
-rw-r--r--platforms/chibios/bootloaders/stm32duino.c24
-rw-r--r--platforms/chibios/bootloaders/tinyuf2.c35
-rw-r--r--platforms/common.mk2
-rw-r--r--platforms/test/bootloaders/none.c (renamed from platforms/test/bootloader.c)2
18 files changed, 634 insertions, 457 deletions
diff --git a/platforms/arm_atsam/bootloader.c b/platforms/arm_atsam/bootloaders/md_boot.c
index 9015b00aab..fe07389487 100644
--- a/platforms/arm_atsam/bootloader.c
+++ b/platforms/arm_atsam/bootloaders/md_boot.c
@@ -15,13 +15,18 @@
*/
#include "bootloader.h"
+
#include "samd51j18a.h"
-#include "md_bootloader.h"
-// Set watchdog timer to reset. Directs the bootloader to stay in programming mode.
-void bootloader_jump(void) {
#ifdef KEYBOARD_massdrop_ctrl
- // CTRL keyboards released with bootloader version below must use RAM method. Otherwise use WDT method.
+// WARNING: These are only for CTRL bootloader release "v2.18Jun 22 2018 17:28:08" for bootloader_jump support
+extern uint32_t _eram;
+
+#define BOOTLOADER_MAGIC 0x3B9ACA00
+#define MAGIC_ADDR (uint32_t *)((intptr_t)(&_eram) - 4)
+
+// CTRL keyboards released with bootloader version below must use RAM method. Otherwise use WDT method.
+void bootloader_jump(void) {
uint8_t ver_ram_method[] = "v2.18Jun 22 2018 17:28:08"; // The version to match (NULL terminated by compiler)
uint8_t *ver_check = ver_ram_method; // Pointer to version match string for traversal
uint8_t *ver_rom = (uint8_t *)0x21A0; // Pointer to address in ROM where this specific bootloader version would exist
@@ -34,24 +39,28 @@ void bootloader_jump(void) {
if (!*ver_check) { // If check version pointer is NULL, all characters have matched
*MAGIC_ADDR = BOOTLOADER_MAGIC; // Set magic number into RAM
NVIC_SystemReset(); // Perform system reset
- while (1) {
- } // Won't get here
+
+ while (1); // Won't get here
}
-#endif
+}
+#else
+
+// Set watchdog timer to reset. Directs the bootloader to stay in programming mode.
+void bootloader_jump(void) {
WDT->CTRLA.bit.ENABLE = 0;
- while (WDT->SYNCBUSY.bit.ENABLE) {
- }
- while (WDT->CTRLA.bit.ENABLE) {
- }
+
+ while (WDT->SYNCBUSY.bit.ENABLE);
+ while (WDT->CTRLA.bit.ENABLE);
+
WDT->CONFIG.bit.WINDOW = 0;
WDT->CONFIG.bit.PER = 0;
WDT->EWCTRL.bit.EWOFFSET = 0;
WDT->CTRLA.bit.ENABLE = 1;
- while (WDT->SYNCBUSY.bit.ENABLE) {
- }
- while (!WDT->CTRLA.bit.ENABLE) {
- }
- while (1) {
- } // Wait on timeout
+
+ while (WDT->SYNCBUSY.bit.ENABLE);
+ while (!WDT->CTRLA.bit.ENABLE);
+
+ while (1); // Wait on timeout
}
+#endif
diff --git a/platforms/avr/bootloader.c b/platforms/avr/bootloader.c
deleted file mode 100644
index c0272903b8..0000000000
--- a/platforms/avr/bootloader.c
+++ /dev/null
@@ -1,293 +0,0 @@
-#include <stdint.h>
-#include <stdbool.h>
-#include <avr/io.h>
-#include <avr/eeprom.h>
-#include <avr/interrupt.h>
-#include <avr/wdt.h>
-#include <util/delay.h>
-#include "bootloader.h"
-#include <avr/boot.h>
-
-#ifdef PROTOCOL_LUFA
-# include <LUFA/Drivers/USB/USB.h>
-#endif
-
-/** \brief Bootloader Size in *bytes*
- *
- * AVR Boot section size are defined by setting BOOTSZ fuse in fact. Consult with your MCU datasheet.
- * Note that 'Word'(2 bytes) size and address are used in datasheet while TMK uses 'Byte'.
- *
- * Size of Bootloaders in bytes:
- * Atmel DFU loader(ATmega32U4) 4096
- * Atmel DFU loader(AT90USB128) 8192
- * LUFA bootloader(ATmega32U4) 4096
- * Arduino Caterina(ATmega32U4) 4096
- * USBaspLoader(ATmega***) 2048
- * Teensy halfKay(ATmega32U4) 512
- * Teensy++ halfKay(AT90USB128) 1024
- *
- * AVR Boot section is located at the end of Flash memory like the followings.
- *
- * byte Atmel/LUFA(ATMega32u4) byte Atmel(AT90SUB128)
- * 0x0000 +---------------+ 0x00000 +---------------+
- * | | | |
- * | | | |
- * | Application | | Application |
- * | | | |
- * = = = =
- * | | 32KB-4KB | | 128KB-8KB
- * 0x7000 +---------------+ 0x1E000 +---------------+
- * | Bootloader | 4KB | Bootloader | 8KB
- * 0x7FFF +---------------+ 0x1FFFF +---------------+
- *
- *
- * byte Teensy(ATMega32u4) byte Teensy++(AT90SUB128)
- * 0x0000 +---------------+ 0x00000 +---------------+
- * | | | |
- * | | | |
- * | Application | | Application |
- * | | | |
- * = = = =
- * | | 32KB-512B | | 128KB-1KB
- * 0x7E00 +---------------+ 0x1FC00 +---------------+
- * | Bootloader | 512B | Bootloader | 1KB
- * 0x7FFF +---------------+ 0x1FFFF +---------------+
- */
-#define FLASH_SIZE (FLASHEND + 1L)
-
-#if !defined(BOOTLOADER_SIZE)
-uint16_t bootloader_start;
-#endif
-
-// compatibility between ATMega8 and ATMega88
-#if !defined(MCUCSR)
-# if defined(MCUSR)
-# define MCUCSR MCUSR
-# endif
-#endif
-
-/** \brief Entering the Bootloader via Software
- *
- * http://www.fourwalledcubicle.com/files/LUFA/Doc/120730/html/_page__software_bootloader_start.html
- */
-#define BOOTLOADER_RESET_KEY 0xB007B007
-uint32_t reset_key __attribute__((section(".noinit,\"aw\",@nobits;")));
-
-/** \brief initialize MCU status by watchdog reset
- *
- * FIXME: needs doc
- */
-__attribute__((weak)) void bootloader_jump(void) {
-#if !defined(BOOTLOADER_SIZE)
- uint8_t high_fuse = boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS);
-
- if (high_fuse & ~(FUSE_BOOTSZ0 & FUSE_BOOTSZ1)) {
- bootloader_start = (FLASH_SIZE - 512) >> 1;
- } else if (high_fuse & ~(FUSE_BOOTSZ1)) {
- bootloader_start = (FLASH_SIZE - 1024) >> 1;
- } else if (high_fuse & ~(FUSE_BOOTSZ0)) {
- bootloader_start = (FLASH_SIZE - 2048) >> 1;
- } else {
- bootloader_start = (FLASH_SIZE - 4096) >> 1;
- }
-#endif
-
- // Something like this might work, but it compiled larger than the block above
- // bootloader_start = FLASH_SIZE - (256 << (~high_fuse & 0b110 >> 1));
-
-#if defined(BOOTLOADER_HALFKAY)
- // http://www.pjrc.com/teensy/jump_to_bootloader.html
- cli();
- // disable watchdog, if enabled (it's not)
- // disable all peripherals
- // a shutdown call might make sense here
- UDCON = 1;
- USBCON = (1 << FRZCLK); // disable USB
- UCSR1B = 0;
- _delay_ms(5);
-# if defined(__AVR_AT90USB162__) // Teensy 1.0
- EIMSK = 0;
- PCICR = 0;
- SPCR = 0;
- ACSR = 0;
- EECR = 0;
- TIMSK0 = 0;
- TIMSK1 = 0;
- UCSR1B = 0;
- DDRB = 0;
- DDRC = 0;
- DDRD = 0;
- PORTB = 0;
- PORTC = 0;
- PORTD = 0;
- asm volatile("jmp 0x3E00");
-# elif defined(__AVR_ATmega32U4__) // Teensy 2.0
- EIMSK = 0;
- PCICR = 0;
- SPCR = 0;
- ACSR = 0;
- EECR = 0;
- ADCSRA = 0;
- TIMSK0 = 0;
- TIMSK1 = 0;
- TIMSK3 = 0;
- TIMSK4 = 0;
- UCSR1B = 0;
- TWCR = 0;
- DDRB = 0;
- DDRC = 0;
- DDRD = 0;
- DDRE = 0;
- DDRF = 0;
- TWCR = 0;
- PORTB = 0;
- PORTC = 0;
- PORTD = 0;
- PORTE = 0;
- PORTF = 0;
- asm volatile("jmp 0x7E00");
-# elif defined(__AVR_AT90USB646__) // Teensy++ 1.0
- EIMSK = 0;
- PCICR = 0;
- SPCR = 0;
- ACSR = 0;
- EECR = 0;
- ADCSRA = 0;
- TIMSK0 = 0;
- TIMSK1 = 0;
- TIMSK2 = 0;
- TIMSK3 = 0;
- UCSR1B = 0;
- TWCR = 0;
- DDRA = 0;
- DDRB = 0;
- DDRC = 0;
- DDRD = 0;
- DDRE = 0;
- DDRF = 0;
- PORTA = 0;
- PORTB = 0;
- PORTC = 0;
- PORTD = 0;
- PORTE = 0;
- PORTF = 0;
- asm volatile("jmp 0xFC00");
-# elif defined(__AVR_AT90USB1286__) // Teensy++ 2.0
- EIMSK = 0;
- PCICR = 0;
- SPCR = 0;
- ACSR = 0;
- EECR = 0;
- ADCSRA = 0;
- TIMSK0 = 0;
- TIMSK1 = 0;
- TIMSK2 = 0;
- TIMSK3 = 0;
- UCSR1B = 0;
- TWCR = 0;
- DDRA = 0;
- DDRB = 0;
- DDRC = 0;
- DDRD = 0;
- DDRE = 0;
- DDRF = 0;
- PORTA = 0;
- PORTB = 0;
- PORTC = 0;
- PORTD = 0;
- PORTE = 0;
- PORTF = 0;
- asm volatile("jmp 0x1FC00");
-# endif
-
-#elif defined(BOOTLOADER_CATERINA)
- // this block may be optional
- // TODO: figure it out
-
- uint16_t *const bootKeyPtr = (uint16_t *)0x0800;
-
- // Value used by Caterina bootloader use to determine whether to run the
- // sketch or the bootloader programmer.
- uint16_t bootKey = 0x7777;
-
- *bootKeyPtr = bootKey;
-
- // setup watchdog timeout
- wdt_enable(WDTO_60MS);
-
- while (1) {
- } // wait for watchdog timer to trigger
-
-#elif defined(BOOTLOADER_USBASP)
- // Taken with permission of Stephan Baerwolf from https://github.com/tinyusbboard/API/blob/master/apipage.c
- wdt_enable(WDTO_15MS);
- wdt_reset();
- asm volatile("cli \n\t"
- "ldi r29 , %[ramendhi] \n\t"
- "ldi r28 , %[ramendlo] \n\t"
-# if (FLASHEND > 131071)
- "ldi r18 , %[bootaddrhi] \n\t"
- "st Y+, r18 \n\t"
-# endif
- "ldi r18 , %[bootaddrme] \n\t"
- "st Y+, r18 \n\t"
- "ldi r18 , %[bootaddrlo] \n\t"
- "st Y+, r18 \n\t"
- "out %[mcucsrio], __zero_reg__ \n\t"
- "bootloader_startup_loop%=: \n\t"
- "rjmp bootloader_startup_loop%= \n\t"
- :
- : [mcucsrio] "I"(_SFR_IO_ADDR(MCUCSR)),
-# if (FLASHEND > 131071)
- [ramendhi] "M"(((RAMEND - 2) >> 8) & 0xff), [ramendlo] "M"(((RAMEND - 2) >> 0) & 0xff), [bootaddrhi] "M"((((FLASH_SIZE - BOOTLOADER_SIZE) >> 1) >> 16) & 0xff),
-# else
- [ramendhi] "M"(((RAMEND - 1) >> 8) & 0xff), [ramendlo] "M"(((RAMEND - 1) >> 0) & 0xff),
-# endif
- [bootaddrme] "M"((((FLASH_SIZE - BOOTLOADER_SIZE) >> 1) >> 8) & 0xff), [bootaddrlo] "M"((((FLASH_SIZE - BOOTLOADER_SIZE) >> 1) >> 0) & 0xff));
-
-#else // Assume remaining boards are DFU, even if the flag isn't set
-
-# if !(defined(__AVR_ATmega32A__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__) || defined(__AVR_ATtiny85__)) // no USB - maybe BOOTLOADER_BOOTLOADHID instead though?
- UDCON = 1;
- USBCON = (1 << FRZCLK); // disable USB
- UCSR1B = 0;
- _delay_ms(5); // 5 seems to work fine
-# endif
-
-# ifdef BOOTLOADER_BOOTLOADHID
- // force bootloadHID to stay in bootloader mode, so that it waits
- // for a new firmware to be flashed
- eeprom_write_byte((uint8_t *)1, 0x00);
-# endif
-
- // watchdog reset
- reset_key = BOOTLOADER_RESET_KEY;
- wdt_enable(WDTO_250MS);
- for (;;)
- ;
-#endif
-}
-
-/* this runs before main() */
-void bootloader_jump_after_watchdog_reset(void) __attribute__((used, naked, section(".init3")));
-void bootloader_jump_after_watchdog_reset(void) {
-#ifndef BOOTLOADER_HALFKAY
- if ((MCUCSR & (1 << WDRF)) && reset_key == BOOTLOADER_RESET_KEY) {
- reset_key = 0;
-
- // My custom USBasploader requires this to come up.
- MCUCSR = 0;
-
- // Seems like Teensy halfkay loader requires clearing WDRF and disabling watchdog.
- MCUCSR &= ~(1 << WDRF);
- wdt_disable();
-
-// This is compled into 'icall', address should be in word unit, not byte.
-# ifdef BOOTLOADER_SIZE
- ((void (*)(void))((FLASH_SIZE - BOOTLOADER_SIZE) >> 1))();
-# else
- asm("ijmp" ::"z"(bootloader_start));
-# endif
- }
-#endif
-}
diff --git a/platforms/avr/bootloaders/bootloadhid.c b/platforms/avr/bootloaders/bootloadhid.c
new file mode 100644
index 0000000000..8d18114613
--- /dev/null
+++ b/platforms/avr/bootloaders/bootloadhid.c
@@ -0,0 +1,34 @@
+/* Copyright 2021 QMK
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "bootloader.h"
+
+#include <avr/eeprom.h>
+#include <avr/wdt.h>
+
+__attribute__((weak))
+void bootloader_jump(void) {
+ // force bootloadHID to stay in bootloader mode, so that it waits
+ // for a new firmware to be flashed
+ // NOTE: this byte is part of QMK's "magic number" - changing it causes the EEPROM to be re-initialized
+ // thus every time the device is flashed the EEPROM will be wiped
+ eeprom_write_byte((uint8_t *)1, 0x00);
+
+ // watchdog reset
+ wdt_enable(WDTO_250MS);
+ for (;;)
+ ;
+}
diff --git a/platforms/avr/bootloaders/caterina.c b/platforms/avr/bootloaders/caterina.c
new file mode 100644
index 0000000000..1b43ed4e44
--- /dev/null
+++ b/platforms/avr/bootloaders/caterina.c
@@ -0,0 +1,39 @@
+/* Copyright 2021 QMK
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "bootloader.h"
+
+#include <avr/wdt.h>
+
+__attribute__((weak))
+void bootloader_jump(void) {
+ // this block may be optional
+ // TODO: figure it out
+
+ uint16_t *const bootKeyPtr = (uint16_t *)0x0800;
+
+ // Value used by Caterina bootloader use to determine whether to run the
+ // sketch or the bootloader programmer.
+ uint16_t bootKey = 0x7777;
+
+ *bootKeyPtr = bootKey;
+
+ // setup watchdog timeout
+ wdt_enable(WDTO_60MS);
+
+ // wait for watchdog timer to trigger
+ while (1) { }
+}
diff --git a/platforms/avr/bootloaders/dfu.c b/platforms/avr/bootloaders/dfu.c
new file mode 100644
index 0000000000..bdf5908934
--- /dev/null
+++ b/platforms/avr/bootloaders/dfu.c
@@ -0,0 +1,53 @@
+/* Copyright 2021 QMK
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "bootloader.h"
+
+#include <avr/wdt.h>
+#include <util/delay.h>
+
+#define FLASH_SIZE (FLASHEND + 1L)
+
+/** \brief Entering the Bootloader via Software
+ *
+ * http://www.fourwalledcubicle.com/files/LUFA/Doc/120730/html/_page__software_bootloader_start.html
+ */
+#define BOOTLOADER_RESET_KEY 0xB007B007
+uint32_t reset_key __attribute__((section(".noinit,\"aw\",@nobits;")));
+
+__attribute__((weak))
+void bootloader_jump(void) {
+ UDCON = 1;
+ USBCON = (1 << FRZCLK); // disable USB
+ UCSR1B = 0;
+ _delay_ms(5); // 5 seems to work fine
+
+ // watchdog reset
+ reset_key = BOOTLOADER_RESET_KEY;
+ wdt_enable(WDTO_250MS);
+ for (;;)
+ ;
+}
+
+/* this runs before main() */
+void bootloader_jump_after_watchdog_reset(void) __attribute__((used, naked, section(".init3")));
+void bootloader_jump_after_watchdog_reset(void) {
+ if ((MCUSR & (1 << WDRF)) && reset_key == BOOTLOADER_RESET_KEY) {
+ reset_key = 0;
+
+ ((void (*)(void))((FLASH_SIZE - BOOTLOADER_SIZE) >> 1))();
+ }
+}
diff --git a/platforms/avr/bootloaders/halfkay.c b/platforms/avr/bootloaders/halfkay.c
new file mode 100644
index 0000000000..abef86980b
--- /dev/null
+++ b/platforms/avr/bootloaders/halfkay.c
@@ -0,0 +1,129 @@
+/* Copyright 2021 QMK
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "bootloader.h"
+
+#include <avr/interrupt.h>
+#include <util/delay.h>
+
+__attribute__((weak))
+void bootloader_jump(void) {
+ // http://www.pjrc.com/teensy/jump_to_bootloader.html
+
+ cli();
+ // disable watchdog, if enabled (it's not)
+ // disable all peripherals
+ // a shutdown call might make sense here
+ UDCON = 1;
+ USBCON = (1 << FRZCLK); // disable USB
+ UCSR1B = 0;
+ _delay_ms(5);
+
+#if defined(__AVR_AT90USB162__) // Teensy 1.0
+ EIMSK = 0;
+ PCICR = 0;
+ SPCR = 0;
+ ACSR = 0;
+ EECR = 0;
+ TIMSK0 = 0;
+ TIMSK1 = 0;
+ UCSR1B = 0;
+ DDRB = 0;
+ DDRC = 0;
+ DDRD = 0;
+ PORTB = 0;
+ PORTC = 0;
+ PORTD = 0;
+ asm volatile("jmp 0x3E00");
+#elif defined(__AVR_ATmega32U4__) // Teensy 2.0
+ EIMSK = 0;
+ PCICR = 0;
+ SPCR = 0;
+ ACSR = 0;
+ EECR = 0;
+ ADCSRA = 0;
+ TIMSK0 = 0;
+ TIMSK1 = 0;
+ TIMSK3 = 0;
+ TIMSK4 = 0;
+ UCSR1B = 0;
+ TWCR = 0;
+ DDRB = 0;
+ DDRC = 0;
+ DDRD = 0;
+ DDRE = 0;
+ DDRF = 0;
+ TWCR = 0;
+ PORTB = 0;
+ PORTC = 0;
+ PORTD = 0;
+ PORTE = 0;
+ PORTF = 0;
+ asm volatile("jmp 0x7E00");
+#elif defined(__AVR_AT90USB646__) // Teensy++ 1.0
+ EIMSK = 0;
+ PCICR = 0;
+ SPCR = 0;
+ ACSR = 0;
+ EECR = 0;
+ ADCSRA = 0;
+ TIMSK0 = 0;
+ TIMSK1 = 0;
+ TIMSK2 = 0;
+ TIMSK3 = 0;
+ UCSR1B = 0;
+ TWCR = 0;
+ DDRA = 0;
+ DDRB = 0;
+ DDRC = 0;
+ DDRD = 0;
+ DDRE = 0;
+ DDRF = 0;
+ PORTA = 0;
+ PORTB = 0;
+ PORTC = 0;
+ PORTD = 0;
+ PORTE = 0;
+ PORTF = 0;
+ asm volatile("jmp 0xFC00");
+#elif defined(__AVR_AT90USB1286__) // Teensy++ 2.0
+ EIMSK = 0;
+ PCICR = 0;
+ SPCR = 0;
+ ACSR = 0;
+ EECR = 0;
+ ADCSRA = 0;
+ TIMSK0 = 0;
+ TIMSK1 = 0;
+ TIMSK2 = 0;
+ TIMSK3 = 0;
+ UCSR1B = 0;
+ TWCR = 0;
+ DDRA = 0;
+ DDRB = 0;
+ DDRC = 0;
+ DDRD = 0;
+ DDRE = 0;
+ DDRF = 0;
+ PORTA = 0;
+ PORTB = 0;
+ PORTC = 0;
+ PORTD = 0;
+ PORTE = 0;
+ PORTF = 0;
+ asm volatile("jmp 0x1FC00");
+#endif
+}
diff --git a/platforms/avr/bootloaders/none.c b/platforms/avr/bootloaders/none.c
new file mode 100644
index 0000000000..8af151c04d
--- /dev/null
+++ b/platforms/avr/bootloaders/none.c
@@ -0,0 +1,20 @@
+/* Copyright 2021 QMK
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "bootloader.h"
+
+__attribute__((weak))
+void bootloader_jump(void) { }
diff --git a/platforms/avr/bootloaders/usbasploader.c b/platforms/avr/bootloaders/usbasploader.c
new file mode 100644
index 0000000000..b3e9b2d72d
--- /dev/null
+++ b/platforms/avr/bootloaders/usbasploader.c
@@ -0,0 +1,57 @@
+/* Copyright 2021 QMK
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "bootloader.h"
+
+#include <avr/wdt.h>
+
+#define FLASH_SIZE (FLASHEND + 1L)
+
+#if !defined(MCUCSR)
+# if defined(MCUSR)
+# define MCUCSR MCUSR
+# endif
+#endif
+
+__attribute__((weak))
+void bootloader_jump(void) {
+ // Taken with permission of Stephan Baerwolf from https://github.com/tinyusbboard/API/blob/master/apipage.c
+
+ wdt_enable(WDTO_15MS);
+ wdt_reset();
+ asm volatile("cli \n\t"
+ "ldi r29 , %[ramendhi] \n\t"
+ "ldi r28 , %[ramendlo] \n\t"
+#if (FLASHEND > 131071)
+ "ldi r18 , %[bootaddrhi] \n\t"
+ "st Y+, r18 \n\t"
+#endif
+ "ldi r18 , %[bootaddrme] \n\t"
+ "st Y+, r18 \n\t"
+ "ldi r18 , %[bootaddrlo] \n\t"
+ "st Y+, r18 \n\t"
+ "out %[mcucsrio], __zero_reg__ \n\t"
+ "bootloader_startup_loop%=: \n\t"
+ "rjmp bootloader_startup_loop%= \n\t"
+ :
+ : [mcucsrio] "I"(_SFR_IO_ADDR(MCUCSR)),
+#if (FLASHEND > 131071)
+ [ramendhi] "M"(((RAMEND - 2) >> 8) & 0xff), [ramendlo] "M"(((RAMEND - 2) >> 0) & 0xff), [bootaddrhi] "M"((((FLASH_SIZE - BOOTLOADER_SIZE) >> 1) >> 16) & 0xff),
+#else
+ [ramendhi] "M"(((RAMEND - 1) >> 8) & 0xff), [ramendlo] "M"(((RAMEND - 1) >> 0) & 0xff),
+#endif
+ [bootaddrme] "M"((((FLASH_SIZE - BOOTLOADER_SIZE) >> 1) >> 8) & 0xff), [bootaddrlo] "M"((((FLASH_SIZE - BOOTLOADER_SIZE) >> 1) >> 0) & 0xff));
+}
diff --git a/platforms/chibios/bootloader.c b/platforms/chibios/bootloader.c
deleted file mode 100644
index 58212948b0..0000000000
--- a/platforms/chibios/bootloader.c
+++ /dev/null
@@ -1,145 +0,0 @@
-#include "bootloader.h"
-
-#include <ch.h>
-#include <hal.h>
-#include "wait.h"
-
-/* This code should be checked whether it runs correctly on platforms */
-#define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0))
-#define BOOTLOADER_MAGIC 0xDEADBEEF
-#define MAGIC_ADDR (unsigned long *)(SYMVAL(__ram0_end__) - 4)
-
-#ifndef STM32_BOOTLOADER_DUAL_BANK
-# define STM32_BOOTLOADER_DUAL_BANK FALSE
-#endif
-
-#ifdef BOOTLOADER_TINYUF2
-
-# define DBL_TAP_MAGIC 0xf01669ef // From tinyuf2's board_api.h
-
-// defined by linker script
-extern uint32_t _board_dfu_dbl_tap[];
-# define DBL_TAP_REG _board_dfu_dbl_tap[0]
-
-void bootloader_jump(void) {
- DBL_TAP_REG = DBL_TAP_MAGIC;
- NVIC_SystemReset();
-}
-
-void enter_bootloader_mode_if_requested(void) { /* not needed, no two-stage reset */
-}
-
-#elif STM32_BOOTLOADER_DUAL_BANK
-
-// Need pin definitions
-# include "config_common.h"
-
-# ifndef STM32_BOOTLOADER_DUAL_BANK_GPIO
-# error "No STM32_BOOTLOADER_DUAL_BANK_GPIO defined, don't know which pin to toggle"
-# endif
-
-# ifndef STM32_BOOTLOADER_DUAL_BANK_POLARITY
-# define STM32_BOOTLOADER_DUAL_BANK_POLARITY 0
-# endif
-
-# ifndef STM32_BOOTLOADER_DUAL_BANK_DELAY
-# define STM32_BOOTLOADER_DUAL_BANK_DELAY 100000
-# endif
-
-extern uint32_t __ram0_end__;
-
-__attribute__((weak)) void bootloader_jump(void) {
- // For STM32 MCUs with dual-bank flash, and we're incapable of jumping to the bootloader. The first valid flash
- // bank is executed unconditionally after a reset, so it doesn't enter DFU unless BOOT0 is high. Instead, we do
- // it with hardware...in this case, we pull a GPIO high/low depending on the configuration, connects 3.3V to
- // BOOT0's RC charging circuit, lets it charge the capacitor, and issue a system reset. See the QMK discord
- // #hardware channel pins for an example circuit.
- palSetPadMode(PAL_PORT(STM32_BOOTLOADER_DUAL_BANK_GPIO), PAL_PAD(STM32_BOOTLOADER_DUAL_BANK_GPIO), PAL_MODE_OUTPUT_PUSHPULL);
-# if STM32_BOOTLOADER_DUAL_BANK_POLARITY
- palSetPad(PAL_PORT(STM32_BOOTLOADER_DUAL_BANK_GPIO), PAL_PAD(STM32_BOOTLOADER_DUAL_BANK_GPIO));
-# else
- palClearPad(PAL_PORT(STM32_BOOTLOADER_DUAL_BANK_GPIO), PAL_PAD(STM32_BOOTLOADER_DUAL_BANK_GPIO));
-# endif
-
- // Wait for a while for the capacitor to charge
- wait_ms(100);
-
- // Issue a system reset to get the ROM bootloader to execute, with BOOT0 high
- NVIC_SystemReset();
-}
-
-void enter_bootloader_mode_if_requested(void) {} // not needed at all, but if anybody attempts to invoke it....
-
-#elif defined(STM32_BOOTLOADER_ADDRESS) // STM32_BOOTLOADER_DUAL_BANK
-
-extern uint32_t __ram0_end__;
-
-__attribute__((weak)) void bootloader_jump(void) {
- *MAGIC_ADDR = BOOTLOADER_MAGIC; // set magic flag => reset handler will jump into boot loader
- NVIC_SystemReset();
-}
-
-void enter_bootloader_mode_if_requested(void) {
- unsigned long *check = MAGIC_ADDR;
- if (*check == BOOTLOADER_MAGIC) {
- *check = 0;
- __set_CONTROL(0);
- __set_MSP(*(__IO uint32_t *)STM32_BOOTLOADER_ADDRESS);
- __enable_irq();
-
- typedef void (*BootJump_t)(void);
- BootJump_t boot_jump = *(BootJump_t *)(STM32_BOOTLOADER_ADDRESS + 4);
- boot_jump();
- while (1)
- ;
- }
-}
-
-#elif defined(GD32VF103)
-
-# define DBGMCU_KEY_UNLOCK 0x4B5A6978
-# define DBGMCU_CMD_RESET 0x1
-
-__IO uint32_t *DBGMCU_KEY = (uint32_t *)DBGMCU_BASE + 0x0CU;
-__IO uint32_t *DBGMCU_CMD = (uint32_t *)DBGMCU_BASE + 0x08U;
-
-__attribute__((weak)) void bootloader_jump(void) {
- /* The MTIMER unit of the GD32VF103 doesn't have the MSFRST
- * register to generate a software reset request.
- * BUT instead two undocumented registers in the debug peripheral
- * that allow issueing a software reset. WHO would need the MSFRST
- * register anyway? Source:
- * https://github.com/esmil/gd32vf103inator/blob/master/include/gd32vf103/dbg.h */
- *DBGMCU_KEY = DBGMCU_KEY_UNLOCK;
- *DBGMCU_CMD = DBGMCU_CMD_RESET;
-}
-
-void enter_bootloader_mode_if_requested(void) { /* Jumping to bootloader is not possible from user code. */
-}
-
-#elif defined(KL2x) || defined(K20x) || defined(MK66F18) || defined(MIMXRT1062) // STM32_BOOTLOADER_DUAL_BANK // STM32_BOOTLOADER_ADDRESS
-/* Kinetis */
-
-# if defined(BOOTLOADER_KIIBOHD)
-/* Kiibohd Bootloader (MCHCK and Infinity KB) */
-# define SCB_AIRCR_VECTKEY_WRITEMAGIC 0x05FA0000
-const uint8_t sys_reset_to_loader_magic[] = "\xff\x00\x7fRESET TO LOADER\x7f\x00\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
-__attribute__((weak)) void bootloader_jump(void) {
- void *volatile vbat = (void *)VBAT;
- __builtin_memcpy(vbat, (const void *)sys_reset_to_loader_magic, sizeof(sys_reset_to_loader_magic));
- // request reset
- SCB->AIRCR = SCB_AIRCR_VECTKEY_WRITEMAGIC | SCB_AIRCR_SYSRESETREQ_Msk;
-}
-
-# else /* defined(BOOTLOADER_KIIBOHD) */
-/* Default for Kinetis - expecting an ARM Teensy */
-# include "wait.h"
-__attribute__((weak)) void bootloader_jump(void) {
- wait_ms(100);
- __BKPT(0);
-}
-# endif /* defined(BOOTLOADER_KIIBOHD) */
-
-#else /* neither STM32 nor KINETIS */
-__attribute__((weak)) void bootloader_jump(void) {}
-#endif
diff --git a/platforms/chibios/bootloaders/gd32v_dfu.c b/platforms/chibios/bootloaders/gd32v_dfu.c
new file mode 100644
index 0000000000..1ab0882084
--- /dev/null
+++ b/platforms/chibios/bootloaders/gd32v_dfu.c
@@ -0,0 +1,40 @@
+/* Copyright 2021 QMK
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "bootloader.h"
+
+#include <ch.h>
+
+#define DBGMCU_KEY_UNLOCK 0x4B5A6978
+#define DBGMCU_CMD_RESET 0x1
+
+__IO uint32_t *DBGMCU_KEY = (uint32_t *)DBGMCU_BASE + 0x0CU;
+__IO uint32_t *DBGMCU_CMD = (uint32_t *)DBGMCU_BASE + 0x08U;
+
+__attribute__((weak))
+void bootloader_jump(void) {
+ /* The MTIMER unit of the GD32VF103 doesn't have the MSFRST
+ * register to generate a software reset request.
+ * BUT instead two undocumented registers in the debug peripheral
+ * that allow issueing a software reset. WHO would need the MSFRST
+ * register anyway? Source:
+ * https://github.com/esmil/gd32vf103inator/blob/master/include/gd32vf103/dbg.h */
+ *DBGMCU_KEY = DBGMCU_KEY_UNLOCK;
+ *DBGMCU_CMD = DBGMCU_CMD_RESET;
+}
+
+/* Jumping to bootloader is not possible from user code. */
+void enter_bootloader_mode_if_requested(void) { }
diff --git a/platforms/chibios/bootloaders/halfkay.c b/platforms/chibios/bootloaders/halfkay.c
new file mode 100644
index 0000000000..fb9b73dfb3
--- /dev/null
+++ b/platforms/chibios/bootloaders/halfkay.c
@@ -0,0 +1,26 @@
+/* Copyright 2021 QMK
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "bootloader.h"
+
+#include <ch.h>
+#include "wait.h"
+
+__attribute__((weak))
+void bootloader_jump(void) {
+ wait_ms(100);
+ __BKPT(0);
+}
diff --git a/platforms/chibios/bootloaders/kiibohd.c b/platforms/chibios/bootloaders/kiibohd.c
new file mode 100644
index 0000000000..f4bb18f058
--- /dev/null
+++ b/platforms/chibios/bootloaders/kiibohd.c
@@ -0,0 +1,33 @@
+/* Copyright 2021 QMK
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "bootloader.h"
+
+#include <ch.h>
+
+/* Kiibohd Bootloader (MCHCK and Infinity KB) */
+#define SCB_AIRCR_VECTKEY_WRITEMAGIC 0x05FA0000
+
+const uint8_t sys_reset_to_loader_magic[] = "\xff\x00\x7fRESET TO LOADER\x7f\x00\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
+
+__attribute__((weak))
+void bootloader_jump(void) {
+ void *volatile vbat = (void *)VBAT;
+ __builtin_memcpy(vbat, (const void *)sys_reset_to_loader_magic, sizeof(sys_reset_to_loader_magic));
+
+ // request reset
+ SCB->AIRCR = SCB_AIRCR_VECTKEY_WRITEMAGIC | SCB_AIRCR_SYSRESETREQ_Msk;
+}
diff --git a/platforms/chibios/bootloaders/none.c b/platforms/chibios/bootloaders/none.c
new file mode 100644
index 0000000000..8af151c04d
--- /dev/null
+++ b/platforms/chibios/bootloaders/none.c
@@ -0,0 +1,20 @@
+/* Copyright 2021 QMK
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "bootloader.h"
+
+__attribute__((weak))
+void bootloader_jump(void) { }
diff --git a/platforms/chibios/bootloaders/stm32_dfu.c b/platforms/chibios/bootloaders/stm32_dfu.c
new file mode 100644
index 0000000000..f4bd8554bf
--- /dev/null
+++ b/platforms/chibios/bootloaders/stm32_dfu.c
@@ -0,0 +1,96 @@
+/* Copyright 2021 QMK
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "bootloader.h"
+
+#include <ch.h>
+#include <hal.h>
+#include "wait.h"
+
+extern uint32_t __ram0_end__;
+
+#ifndef STM32_BOOTLOADER_DUAL_BANK
+# define STM32_BOOTLOADER_DUAL_BANK FALSE
+#endif
+
+#if STM32_BOOTLOADER_DUAL_BANK
+# include "config_common.h"
+
+# ifndef STM32_BOOTLOADER_DUAL_BANK_GPIO
+# error "No STM32_BOOTLOADER_DUAL_BANK_GPIO defined, don't know which pin to toggle"
+# endif
+
+# ifndef STM32_BOOTLOADER_DUAL_BANK_POLARITY
+# define STM32_BOOTLOADER_DUAL_BANK_POLARITY 0
+# endif
+
+# ifndef STM32_BOOTLOADER_DUAL_BANK_DELAY
+# define STM32_BOOTLOADER_DUAL_BANK_DELAY 100000
+# endif
+
+__attribute__((weak))
+void bootloader_jump(void) {
+ // For STM32 MCUs with dual-bank flash, and we're incapable of jumping to the bootloader. The first valid flash
+ // bank is executed unconditionally after a reset, so it doesn't enter DFU unless BOOT0 is high. Instead, we do
+ // it with hardware...in this case, we pull a GPIO high/low depending on the configuration, connects 3.3V to
+ // BOOT0's RC charging circuit, lets it charge the capacitor, and issue a system reset. See the QMK discord
+ // #hardware channel pins for an example circuit.
+ palSetPadMode(PAL_PORT(STM32_BOOTLOADER_DUAL_BANK_GPIO), PAL_PAD(STM32_BOOTLOADER_DUAL_BANK_GPIO), PAL_MODE_OUTPUT_PUSHPULL);
+# if STM32_BOOTLOADER_DUAL_BANK_POLARITY
+ palSetPad(PAL_PORT(STM32_BOOTLOADER_DUAL_BANK_GPIO), PAL_PAD(STM32_BOOTLOADER_DUAL_BANK_GPIO));
+# else
+ palClearPad(PAL_PORT(STM32_BOOTLOADER_DUAL_BANK_GPIO), PAL_PAD(STM32_BOOTLOADER_DUAL_BANK_GPIO));
+# endif
+
+ // Wait for a while for the capacitor to charge
+ wait_ms(100);
+
+ // Issue a system reset to get the ROM bootloader to execute, with BOOT0 high
+ NVIC_SystemReset();
+}
+
+// not needed at all, but if anybody attempts to invoke it....
+void enter_bootloader_mode_if_requested(void) { }
+
+#else
+
+/* This code should be checked whether it runs correctly on platforms */
+#define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0))
+#define BOOTLOADER_MAGIC 0xDEADBEEF
+#define MAGIC_ADDR (unsigned long *)(SYMVAL(__ram0_end__) - 4)
+
+__attribute__((weak))
+void bootloader_jump(void) {
+ *MAGIC_ADDR = BOOTLOADER_MAGIC; // set magic flag => reset handler will jump into boot loader
+ NVIC_SystemReset();
+}
+
+void enter_bootloader_mode_if_requested(void) {
+ unsigned long *check = MAGIC_ADDR;
+ if (*check == BOOTLOADER_MAGIC) {
+ *check = 0;
+ __set_CONTROL(0);
+ __set_MSP(*(__IO uint32_t *)STM32_BOOTLOADER_ADDRESS);
+ __enable_irq();
+
+ typedef void (*BootJump_t)(void);
+ BootJump_t boot_jump = *(BootJump_t *)(STM32_BOOTLOADER_ADDRESS + 4);
+ boot_jump();
+ while (1)
+ ;
+ }
+}
+#endif
diff --git a/platforms/chibios/bootloaders/stm32duino.c b/platforms/chibios/bootloaders/stm32duino.c
new file mode 100644
index 0000000000..6ff9e28b4d
--- /dev/null
+++ b/platforms/chibios/bootloaders/stm32duino.c
@@ -0,0 +1,24 @@
+/* Copyright 2021 QMK
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "bootloader.h"
+
+#include <ch.h>
+
+__attribute__((weak))
+void bootloader_jump(void) {
+ NVIC_SystemReset();
+}
diff --git a/platforms/chibios/bootloaders/tinyuf2.c b/platforms/chibios/bootloaders/tinyuf2.c
new file mode 100644
index 0000000000..ce82fa0c49
--- /dev/null
+++ b/platforms/chibios/bootloaders/tinyuf2.c
@@ -0,0 +1,35 @@
+/* Copyright 2021 QMK
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "bootloader.h"
+
+#include <ch.h>
+
+// From tinyuf2's board_api.h
+#define DBL_TAP_MAGIC 0xF01669EF
+
+// defined by linker script
+extern uint32_t _board_dfu_dbl_tap[];
+#define DBL_TAP_REG _board_dfu_dbl_tap[0]
+
+__attribute__((weak))
+void bootloader_jump(void) {
+ DBL_TAP_REG = DBL_TAP_MAGIC;
+ NVIC_SystemReset();
+}
+
+/* not needed, no two-stage reset */
+void enter_bootloader_mode_if_requested(void) { }
diff --git a/platforms/common.mk b/platforms/common.mk
index f7a0fc7028..12ab45f823 100644
--- a/platforms/common.mk
+++ b/platforms/common.mk
@@ -4,7 +4,7 @@ TMK_COMMON_SRC += \
$(PLATFORM_COMMON_DIR)/platform.c \
$(PLATFORM_COMMON_DIR)/suspend.c \
$(PLATFORM_COMMON_DIR)/timer.c \
- $(PLATFORM_COMMON_DIR)/bootloader.c \
+ $(PLATFORM_COMMON_DIR)/bootloaders/$(BOOTLOADER_TYPE).c
# Search Path
VPATH += $(PLATFORM_PATH)
diff --git a/platforms/test/bootloader.c b/platforms/test/bootloaders/none.c
index 5155d9ff04..2920c68f18 100644
--- a/platforms/test/bootloader.c
+++ b/platforms/test/bootloaders/none.c
@@ -16,4 +16,4 @@
#include "bootloader.h"
-void bootloader_jump(void) {}
+void bootloader_jump(void) { }