blob: 199a3d14cc1ccadb85fbf60be744de03208e3399 [file] [log] [blame]
Brian Silverman44311d62013-12-06 22:03:29 -08001#include <stdint.h>
2
Brian Silverman1b6fbd02013-12-12 18:08:47 -08003#include <STM32F2XX.h>
4
Brian Silverman44311d62013-12-06 22:03:29 -08005#include "cape/bootloader_handoff.h"
Brian Silvermaned183e62013-12-18 15:51:16 -08006#include "cape/led.h"
Brian Silverman44311d62013-12-06 22:03:29 -08007
Brian Silverman3aa0d542014-01-25 17:16:43 -08008// Actually runs the bootloader code.
9// Implemented in bootloader_impl.c.
10void bootloader_start(void) __attribute__((noreturn));
11
Brian Silverman44311d62013-12-06 22:03:29 -080012// Sets everything up and then jumps to the main code.
13static void jump_to_main(void) __attribute__((noreturn));
14static void jump_to_main(void) {
Brian Silvermanaa9183a2013-12-08 10:33:47 -080015 __asm__ __volatile__(
Brian Silverman44311d62013-12-06 22:03:29 -080016 "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 Silvermaned183e62013-12-18 15:51:16 -080023static 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 Silverman1b6fbd02013-12-12 18:08:47 -080027
Brian Silvermaned183e62013-12-18 15:51:16 -080028 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
59void _start(void) {
60 // Enable the GPIO pin clocks.
Brian Silverman3aa0d542014-01-25 17:16:43 -080061 // We don't have anything attached to the 1 port D pin, so don't bother
62 // enabling it.
Brian Silvermaned183e62013-12-18 15:51:16 -080063 RCC->AHB1ENR |=
64 RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN | RCC_AHB1ENR_GPIOCEN;
65 led_init();
Brian Silverman176c6762013-12-19 16:28:09 -080066 led_set(LED_HB, 1);
Brian Silvermaned183e62013-12-18 15:51:16 -080067
68 setup_main_clock();
69
Brian Silverman3e0a05b2013-12-22 11:33:42 -080070 RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
Brian Silvermaned183e62013-12-18 15:51:16 -080071 SYSCFG->CMPCR |= SYSCFG_CMPCR_CMP_PD; // enable IO compensation cell
72 while (!(SYSCFG->CMPCR & SYSCFG_CMPCR_READY)) {} // wait for it to be ready
Brian Silverman1b6fbd02013-12-12 18:08:47 -080073
Brian Silverman3aa0d542014-01-25 17:16:43 -080074 if (GPIOC->IDR & (1 << 2)) {
75 jump_to_main();
76 } else {
77 bootloader_start();
78 }
Brian Silverman5020be62013-12-06 19:09:07 -080079}