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