diff options
Diffstat (limited to 'tmk_core/common')
-rw-r--r-- | tmk_core/common/avr/bootloader.c | 196 | ||||
-rw-r--r-- | tmk_core/common/avr/bootloader_size.c | 20 |
2 files changed, 125 insertions, 91 deletions
diff --git a/tmk_core/common/avr/bootloader.c b/tmk_core/common/avr/bootloader.c index 34db8d0b0a..ee150817c3 100644 --- a/tmk_core/common/avr/bootloader.c +++ b/tmk_core/common/avr/bootloader.c @@ -6,6 +6,7 @@ #include <avr/wdt.h> #include <util/delay.h> #include "bootloader.h" +#include <avr/boot.h> #ifdef PROTOCOL_LUFA #include <LUFA/Drivers/USB/USB.h> @@ -56,14 +57,17 @@ * | Bootloader | 512B | Bootloader | 1KB * 0x7FFF +---------------+ 0x1FFFF +---------------+ */ -#ifndef BOOTLOADER_SIZE -#warning To use bootloader_jump() you need to define BOOTLOADER_SIZE in config.h. -#define BOOTLOADER_SIZE 4096 -#endif -#define FLASH_SIZE (FLASHEND + 1L) -#define BOOTLOADER_START (FLASH_SIZE - BOOTLOADER_SIZE) +#define FLASH_SIZE (FLASHEND + 1L) + +#if !defined(BOOTLOADER_SIZE) + uint16_t bootloader_start; +#endif +#define BOOT_SIZE_256 0b110 +#define BOOT_SIZE_512 0b100 +#define BOOT_SIZE_1024 0b010 +#define BOOT_SIZE_2048 0b000 /* * Entering the Bootloader via Software @@ -74,34 +78,62 @@ uint32_t reset_key __attribute__ ((section (".noinit"))); /* initialize MCU status by watchdog reset */ void bootloader_jump(void) { - #ifndef CATERINA_BOOTLOADER - - #ifdef PROTOCOL_LUFA - USB_Disable(); - cli(); - _delay_ms(2000); - #endif - - #ifdef PROTOCOL_PJRC - cli(); - UDCON = 1; - USBCON = (1<<FRZCLK); - UCSR1B = 0; - _delay_ms(5); - #endif - - #ifdef BOOTLOADHID_BOOTLOADER - // 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 (;;); + #if !defined(BOOTLOADER_SIZE) + uint8_t high_fuse = boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS); + + if (high_fuse & BOOT_SIZE_256) { + bootloader_start = (FLASH_SIZE - 512) >> 1; + } else if (high_fuse & BOOT_SIZE_512) { + bootloader_start = (FLASH_SIZE - 1024) >> 1; + } else if (high_fuse & BOOT_SIZE_1024) { + bootloader_start = (FLASH_SIZE - 2048) >> 1; + } else { + bootloader_start = (FLASH_SIZE - 4096) >> 1; + } + #endif - #else + // 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 @@ -118,83 +150,65 @@ void bootloader_jump(void) { while(1) {} // wait for watchdog timer to trigger + #else // Assume remaining boards are DFU, even if the flag isn't set + + #ifndef __AVR_ATmega32A__ // 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 + } #ifdef __AVR_ATmega32A__ -// MCUSR is actually called MCUCSR in ATmega32A -#define MCUSR MCUCSR + // MCUSR is actually called MCUCSR in ATmega32A + #define MCUSR MCUCSR #endif /* 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; + #ifndef BOOTLOADER_HALFKAY + if ((MCUSR & (1<<WDRF)) && reset_key == BOOTLOADER_RESET_KEY) { + reset_key = 0; + + // My custom USBasploader requires this to come up. + MCUSR = 0; - // My custom USBasploader requires this to come up. - MCUSR = 0; + // Seems like Teensy halfkay loader requires clearing WDRF and disabling watchdog. + MCUSR &= ~(1<<WDRF); + wdt_disable(); - // Seems like Teensy halfkay loader requires clearing WDRF and disabling watchdog. - MCUSR &= ~(1<<WDRF); - wdt_disable(); - // This is compled into 'icall', address should be in word unit, not byte. - ((void (*)(void))(BOOTLOADER_START/2))(); - } + // 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 } #if 0 -/* Jumping To The Bootloader - * http://www.pjrc.com/teensy/jump_to_bootloader.html - * - * This method doen't work when using LUFA. idk why. - * - needs to initialize more regisers or interrupt setting? - */ -void bootloader_jump(void) { -#ifdef PROTOCOL_LUFA - USB_Disable(); - cli(); - _delay_ms(2000); -#endif - -#ifdef PROTOCOL_PJRC - cli(); - UDCON = 1; - USBCON = (1<<FRZCLK); - UCSR1B = 0; - _delay_ms(5); -#endif - - /* - * Initialize - */ -#if defined(__AVR_AT90USB162__) - 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; -#elif defined(__AVR_ATmega32U4__) - 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; -#elif defined(__AVR_AT90USB646__) - 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; -#elif defined(__AVR_AT90USB1286__) - 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; -#endif - /* - * USBaspLoader + * USBaspLoader - I'm not sure if this is used at all in any projects + * would love to support it if it is -Jack */ #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328P__) // This makes custom USBasploader come up. diff --git a/tmk_core/common/avr/bootloader_size.c b/tmk_core/common/avr/bootloader_size.c new file mode 100644 index 0000000000..0d8d534f84 --- /dev/null +++ b/tmk_core/common/avr/bootloader_size.c @@ -0,0 +1,20 @@ +// Copyright 2017 Jack Humbert +// +// 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 2 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 <avr/io.h> +#include <avr/boot.h> + +// this is not valid C - it's for computing the size available on the chip +AVR_SIZE: FLASHEND + 1 - BOOTLOADER_SIZE
\ No newline at end of file |