blob: 51948326e23ade52755b587bd159a0e9a6b6194d [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 Silverman04fac622014-01-26 18:32:15 -08007#include "cape/util.h"
Brian Silverman44311d62013-12-06 22:03:29 -08008
Brian Silverman3aa0d542014-01-25 17:16:43 -08009// Actually runs the bootloader code.
10// Implemented in bootloader_impl.c.
11void bootloader_start(void) __attribute__((noreturn));
12
Brian Silverman44311d62013-12-06 22:03:29 -080013// Sets everything up and then jumps to the main code.
14static void jump_to_main(void) __attribute__((noreturn));
15static void jump_to_main(void) {
Brian Silvermanaa9183a2013-12-08 10:33:47 -080016 __asm__ __volatile__(
Brian Silverman44311d62013-12-06 22:03:29 -080017 "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 Silvermaned183e62013-12-18 15:51:16 -080024static 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 Silverman1b6fbd02013-12-12 18:08:47 -080028
Brian Silvermaned183e62013-12-18 15:51:16 -080029 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
60void _start(void) {
61 // Enable the GPIO pin clocks.
Brian Silverman3aa0d542014-01-25 17:16:43 -080062 // We don't have anything attached to the 1 port D pin, so don't bother
63 // enabling it.
Brian Silvermaned183e62013-12-18 15:51:16 -080064 RCC->AHB1ENR |=
65 RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN | RCC_AHB1ENR_GPIOCEN;
66 led_init();
Brian Silverman176c6762013-12-19 16:28:09 -080067 led_set(LED_HB, 1);
Brian Silverman04fac622014-01-26 18:32:15 -080068 gpio_set_pupd(GPIOC, 2, 2);
Brian Silvermaned183e62013-12-18 15:51:16 -080069
70 setup_main_clock();
71
Brian Silverman3e0a05b2013-12-22 11:33:42 -080072 RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
Brian Silvermaned183e62013-12-18 15:51:16 -080073 SYSCFG->CMPCR |= SYSCFG_CMPCR_CMP_PD; // enable IO compensation cell
74 while (!(SYSCFG->CMPCR & SYSCFG_CMPCR_READY)) {} // wait for it to be ready
Brian Silverman1b6fbd02013-12-12 18:08:47 -080075
Brian Silverman3aa0d542014-01-25 17:16:43 -080076 if (GPIOC->IDR & (1 << 2)) {
Brian Silverman04fac622014-01-26 18:32:15 -080077 jump_to_main();
Brian Silverman8dc9fd42014-02-10 13:35:43 -080078 } else {
79 bootloader_start();
Brian Silverman3aa0d542014-01-25 17:16:43 -080080 }
Brian Silverman5020be62013-12-06 19:09:07 -080081}