Brian Silverman | 44311d6 | 2013-12-06 22:03:29 -0800 | [diff] [blame] | 1 | #include <stdint.h> |
| 2 | |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 3 | #include <STM32F2XX.h> |
| 4 | |
Brian Silverman | 44311d6 | 2013-12-06 22:03:29 -0800 | [diff] [blame] | 5 | #include "cape/bootloader_handoff.h" |
Brian Silverman | ed183e6 | 2013-12-18 15:51:16 -0800 | [diff] [blame] | 6 | #include "cape/led.h" |
Brian Silverman | 44311d6 | 2013-12-06 22:03:29 -0800 | [diff] [blame] | 7 | |
Brian Silverman | 3aa0d54 | 2014-01-25 17:16:43 -0800 | [diff] [blame^] | 8 | // Actually runs the bootloader code. |
| 9 | // Implemented in bootloader_impl.c. |
| 10 | void bootloader_start(void) __attribute__((noreturn)); |
| 11 | |
Brian Silverman | 44311d6 | 2013-12-06 22:03:29 -0800 | [diff] [blame] | 12 | // Sets everything up and then jumps to the main code. |
| 13 | static void jump_to_main(void) __attribute__((noreturn)); |
| 14 | static void jump_to_main(void) { |
Brian Silverman | aa9183a | 2013-12-08 10:33:47 -0800 | [diff] [blame] | 15 | __asm__ __volatile__( |
Brian Silverman | 44311d6 | 2013-12-06 22:03:29 -0800 | [diff] [blame] | 16 | "mov sp, %[stack]\n\t" |
| 17 | "bx %[reset]" : : |
| 18 | [stack]"r"(RAM_START + RAM_SIZE), [reset]"r"(MAIN_FLASH_START | 1) |
| 19 | : "memory"); |
| 20 | __builtin_unreachable(); |
| 21 | } |
| 22 | |
Brian Silverman | ed183e6 | 2013-12-18 15:51:16 -0800 | [diff] [blame] | 23 | static void setup_main_clock(void) { |
| 24 | // We set up a couple of registers here separately from the actual register to |
| 25 | // avoid having to think about what happens when the value is in some |
| 26 | // intermediate state. |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 27 | |
Brian Silverman | ed183e6 | 2013-12-18 15:51:16 -0800 | [diff] [blame] | 28 | RCC->CR |= RCC_CR_HSEON; // get the HSE oscillator going |
| 29 | |
| 30 | FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_DCEN | |
| 31 | FLASH_ACR_LATENCY_3WS; |
| 32 | |
| 33 | uint32_t rcc_pllcfgr = 0; |
| 34 | rcc_pllcfgr |= RCC_PLLCFGR_PLLSRC; // use the external oscillator |
| 35 | // 8MHz * 120 / 4 / 2 = 120MHz |
| 36 | rcc_pllcfgr |= 120 << 6; // multiplier |
| 37 | rcc_pllcfgr |= 4; // divider |
| 38 | rcc_pllcfgr |= 5 << 24; // other stuff divider = 5, just in case |
| 39 | RCC->PLLCFGR = rcc_pllcfgr; |
| 40 | |
| 41 | uint32_t rcc_cfgr = 0; |
| 42 | rcc_cfgr |= 4 << 13; // APB2 divider = 2 |
| 43 | rcc_cfgr |= 5 << 10; // APB1 divider = 4 |
| 44 | rcc_cfgr |= 2; // use the PLL |
| 45 | |
| 46 | // Wait for the HSE oscillator to be stable. |
| 47 | while (!(RCC->CR & RCC_CR_HSERDY)) {} |
| 48 | |
| 49 | RCC->CR |= RCC_CR_PLLON; |
| 50 | // Wait for the main PLL to be stable. |
| 51 | while (!(RCC->CR & RCC_CR_PLLRDY)) {} |
| 52 | // Wait until the flash is using 3 wait states. |
| 53 | while ((FLASH->ACR & 7) != 3) {} |
| 54 | RCC->CFGR = rcc_cfgr; |
| 55 | // Wait until we are using the PLL as our main clock source. |
| 56 | while ((RCC->CFGR & (3 << 2)) != (2 << 2)) {} |
| 57 | } |
| 58 | |
| 59 | void _start(void) { |
| 60 | // Enable the GPIO pin clocks. |
Brian Silverman | 3aa0d54 | 2014-01-25 17:16:43 -0800 | [diff] [blame^] | 61 | // We don't have anything attached to the 1 port D pin, so don't bother |
| 62 | // enabling it. |
Brian Silverman | ed183e6 | 2013-12-18 15:51:16 -0800 | [diff] [blame] | 63 | RCC->AHB1ENR |= |
| 64 | RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN | RCC_AHB1ENR_GPIOCEN; |
| 65 | led_init(); |
Brian Silverman | 176c676 | 2013-12-19 16:28:09 -0800 | [diff] [blame] | 66 | led_set(LED_HB, 1); |
Brian Silverman | ed183e6 | 2013-12-18 15:51:16 -0800 | [diff] [blame] | 67 | |
| 68 | setup_main_clock(); |
| 69 | |
Brian Silverman | 3e0a05b | 2013-12-22 11:33:42 -0800 | [diff] [blame] | 70 | RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; |
Brian Silverman | ed183e6 | 2013-12-18 15:51:16 -0800 | [diff] [blame] | 71 | SYSCFG->CMPCR |= SYSCFG_CMPCR_CMP_PD; // enable IO compensation cell |
| 72 | while (!(SYSCFG->CMPCR & SYSCFG_CMPCR_READY)) {} // wait for it to be ready |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 73 | |
Brian Silverman | 3aa0d54 | 2014-01-25 17:16:43 -0800 | [diff] [blame^] | 74 | if (GPIOC->IDR & (1 << 2)) { |
| 75 | jump_to_main(); |
| 76 | } else { |
| 77 | bootloader_start(); |
| 78 | } |
Brian Silverman | 5020be6 | 2013-12-06 19:09:07 -0800 | [diff] [blame] | 79 | } |