1bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov#include <alloca.h>
2bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov#include <stdbool.h>
3bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov#include <string.h>
4515f84084123dd42de0ba58445b2d65976132dc7Dmitry Grinberg
5f805306b53d82eef67d8891a5dd5c32d3794a3abAlexey Polyudov#include <variant/variant.h>
6b62d65a623f9c09a5936c69dacae829e0cc9a2baAlexey Polyudov
7f805306b53d82eef67d8891a5dd5c32d3794a3abAlexey Polyudov#include <plat/pwr.h>
8bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov#include <plat/gpio.h>
9bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov#include <plat/cmsis.h>
10a443864c8bd6dd2d8d6f9e018d058081e597986fDmitry Grinberg
11bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov#include <bl.h>
126308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema
13bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudovstruct StmUdid
146308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema{
15bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    volatile uint32_t U_ID[3];
16bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov};
17bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov
18bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudovstruct StmSpi {
19bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    volatile uint32_t CR1;
20bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    volatile uint32_t CR2;
21bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    volatile uint32_t SR;
226308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    volatile uint32_t DR;
23bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    volatile uint32_t CRCPR;
24bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    volatile uint32_t RXCRCR;
25bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    volatile uint32_t TXCRCR;
26bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    volatile uint32_t I2SCFGR;
27bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    volatile uint32_t I2SPR;
28bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov};
29bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov
30bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudovstruct StmGpio {
31bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    volatile uint32_t MODER;
32bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    volatile uint32_t OTYPER;
33bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    volatile uint32_t OSPEEDR;
34bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    volatile uint32_t PUPDR;
356308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    volatile uint32_t IDR;
36bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    volatile uint32_t ODR;
37bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    volatile uint32_t BSRR;
38bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    volatile uint32_t LCKR;
39bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    volatile uint32_t AFR[2];
406308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema};
416308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema
426308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennemastruct StmFlash
436308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema{
446308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    volatile uint32_t ACR;
456308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    volatile uint32_t KEYR;
466308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    volatile uint32_t OPTKEYR;
476308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    volatile uint32_t SR;
486308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    volatile uint32_t CR;
496308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    volatile uint32_t OPTCR;
506308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema};
516308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema
52bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudovstruct StmCrc
53bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov{
54bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    volatile uint32_t DR;
55bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    volatile uint32_t IDR;
56bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    volatile uint32_t CR;
57bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov};
58bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov
596308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennemastruct StmRcc {
606308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    volatile uint32_t CR;
616308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    volatile uint32_t PLLCFGR;
626308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    volatile uint32_t CFGR;
636308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    volatile uint32_t CIR;
646308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    volatile uint32_t AHB1RSTR;
656308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    volatile uint32_t AHB2RSTR;
666308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    volatile uint32_t AHB3RSTR;
676308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    uint8_t unused0[4];
686308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    volatile uint32_t APB1RSTR;
696308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    volatile uint32_t APB2RSTR;
706308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    uint8_t unused1[8];
716308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    volatile uint32_t AHB1ENR;
726308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    volatile uint32_t AHB2ENR;
736308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    volatile uint32_t AHB3ENR;
746308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    uint8_t unused2[4];
756308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    volatile uint32_t APB1ENR;
766308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    volatile uint32_t APB2ENR;
776308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    uint8_t unused3[8];
786308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    volatile uint32_t AHB1LPENR;
796308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    volatile uint32_t AHB2LPENR;
806308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    volatile uint32_t AHB3LPENR;
816308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    uint8_t unused4[4];
826308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    volatile uint32_t APB1LPENR;
836308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    volatile uint32_t APB2LPENR;
846308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    uint8_t unused5[8];
856308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    volatile uint32_t BDCR;
866308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    volatile uint32_t CSR;
876308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    uint8_t unused6[8];
886308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    volatile uint32_t SSCGR;
896308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    volatile uint32_t PLLI2SCFGR;
906308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema};
916308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema
92bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudovtypedef void (*FlashEraseF)(volatile uint32_t *, uint32_t, volatile uint32_t *);
93bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudovtypedef void (*FlashWriteF)(volatile uint8_t *, uint8_t, volatile uint32_t *);
946308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema
95bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudovstatic struct StmSpi *SPI;
96bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudovstatic struct StmGpio *GPIOA;
97bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudovstatic struct StmRcc *RCC;
98bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudovstatic uint32_t mOldApb2State;
99bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudovstatic uint32_t mOldAhb1State;
1006308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema
101bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov#define INT_IN_PIN          (SH_INT_WAKEUP - GPIO_PA(0))
1026308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema
1036308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema#define FLASH_ACR_LAT(x)    ((x) & FLASH_ACR_LAT_MASK)
1046308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema#define FLASH_ACR_LAT_MASK  0x0F
1056308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema#define FLASH_ACR_PRFTEN    0x00000100
1066308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema#define FLASH_ACR_ICEN      0x00000200
1076308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema#define FLASH_ACR_DCEN      0x00000400
1086308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema#define FLASH_ACR_ICRST     0x00000800
1096308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema#define FLASH_ACR_DCRST     0x00001000
1106308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema
1116308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema#define FLASH_SR_EOP        0x00000001
1126308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema#define FLASH_SR_OPERR      0x00000002
1136308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema#define FLASH_SR_WRPERR     0x00000010
1146308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema#define FLASH_SR_PGAERR     0x00000020
1156308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema#define FLASH_SR_PGPERR     0x00000040
1166308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema#define FLASH_SR_PGSERR     0x00000080
1176308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema#define FLASH_SR_RDERR      0x00000100
1186308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema#define FLASH_SR_BSY        0x00010000
1196308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema
1206308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema#define FLASH_CR_PG         0x00000001
1216308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema#define FLASH_CR_SER        0x00000002
1226308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema#define FLASH_CR_MER        0x00000004
1236308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema#define FLASH_CR_SNB(x)     (((x) << FLASH_CR_SNB_SHIFT) & FLASH_CR_SNB_MASK)
1246308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema#define FLASH_CR_SNB_MASK   0x00000078
1256308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema#define FLASH_CR_SNB_SHIFT  3
1266308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema#define FLASH_CR_PSIZE(x)   (((x) << FLASH_CR_PSIZE_SHIFT) & FLASH_CR_PSIZE_MASK)
1276308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema#define FLASH_CR_PSIZE_MASK 0x00000300
1286308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema#define FLASH_CR_PSIZE_SHIFT 8
1296308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema#define FLASH_CR_PSIZE_8    0x0
1306308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema#define FLASH_CR_PSIZE_16   0x1
1316308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema#define FLASH_CR_PSIZE_32   0x2
1326308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema#define FLASH_CR_PSIZE_64   0x3
1336308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema#define FLASH_CR_STRT       0x00010000
1346308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema#define FLASH_CR_EOPIE      0x01000000
1356308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema#define FLASH_CR_ERRIE      0x02000000
1366308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema#define FLASH_CR_LOCK       0x80000000
1376308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema
138bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov//stm defines
139bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov#define BL_MAX_FLASH_CODE   1024
1406308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema
1416308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema/*
1426308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema * Return the address of the erase code and the length of the code
1436308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema *
1446308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema * This code needs to run out of ram and not flash since accessing flash
1456308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema * while erasing is undefined (best case the processor stalls, worst case
1466308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema * it starts executing garbage)
1476308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema *
1486308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema * This function is used to get a pointer to the actual code that does the
1496308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema * erase and polls for completion (so we can copy it to ram) as well as the
1506308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema * length of the code (so we know how much space to allocate for it)
1516308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema *
152e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg * void FlashEraseF(volatile uint32_t *addr, uint32_t value, volatile uint32_t *status)
1536308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema * {
1546308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema *     *addr = value;
1556308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema *     while (*status & FLASH_SR_BSY) ;
1566308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema * }
1576308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema */
158e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinbergstatic void __attribute__((naked)) blGetFlashEraseCode(uint16_t **addr, uint32_t *size)
1596308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema{
1606308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    asm volatile (
1616308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema        "  push {lr}          \n"
1626308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema        "  bl   9f            \n"
1636308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema        "  str  r1, [r0, #0]  \n" // *addr = value
1646308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema        "1:                   \n"
1656308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema        "  ldr  r3, [r2, #0]  \n" // r3 = *status
1666308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema        "  lsls r3, #15       \n" // r3 <<= 15
1676308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema        "  bmi  1b            \n" // if (r3 < 0) goto 1
1686308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema        "  bx   lr            \n" // return
1696308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema        "9:                   \n"
1706308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema        "  bic  lr, #0x1      \n"
1716308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema        "  adr  r3, 9b        \n"
1726308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema        "  sub  r3, lr        \n"
1736308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema        "  str  lr, [r0]      \n"
1746308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema        "  str  r3, [r1]      \n"
1756308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema        "  pop {pc}           \n"
1766308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    );
1776308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema}
1786308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema
179bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudovstatic void _blEraseSectors(uint32_t sector_cnt, uint8_t *erase_mask)
180bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov{
181bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    struct StmFlash *flash = (struct StmFlash *)FLASH_BASE;
182bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    uint16_t *code_src, *code;
183bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    uint32_t i, code_length;
184bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    FlashEraseF func;
185bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov
186bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    blGetFlashEraseCode(&code_src, &code_length);
187bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov
188bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    if (code_length < BL_MAX_FLASH_CODE) {
189bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov        code = (uint16_t *)(((uint32_t)alloca(code_length + 1) + 1) & ~0x1);
190bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov        func = (FlashEraseF)((uint8_t *)code+1);
191bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov
192bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov        for (i = 0; i < code_length / sizeof(uint16_t); i++)
193bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov            code[i] = code_src[i];
194bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov
195bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov        for (i = 0; i < sector_cnt; i++) {
196bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov            if (erase_mask[i]) {
197bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov                flash->CR = (flash->CR & ~(FLASH_CR_SNB_MASK)) |
198bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov                    FLASH_CR_SNB(i) | FLASH_CR_SER;
199bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov                func(&flash->CR, flash->CR | FLASH_CR_STRT, &flash->SR);
200bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov                flash->CR &= ~(FLASH_CR_SNB_MASK | FLASH_CR_SER);
201bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov            }
202bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov        }
203bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    }
204bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov}
205bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov
206bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudovbool blEraseSectors(uint32_t sector_cnt, uint8_t *erase_mask, uint32_t key1, uint32_t key2)
207bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov{
208bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    struct StmFlash *flash = (struct StmFlash *)FLASH_BASE;
209bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    uint32_t acr_cache, cr_cache;
210bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    // disable interrupts
211bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    // otherwise an interrupt during flash write/erase will stall the processor
212bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    // until the write/erase completes
213bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    uint32_t int_state = blDisableInts();
214bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov
215bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    // wait for flash to not be busy (should never be set at this point)
216bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    while (flash->SR & FLASH_SR_BSY);
217bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov
218bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    cr_cache = flash->CR;
219bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov
220bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    if (flash->CR & FLASH_CR_LOCK) {
221bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov        // unlock flash
222bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov        flash->KEYR = key1;
223bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov        flash->KEYR = key2;
224bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    }
225bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov
226bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    if (!(flash->CR & FLASH_CR_LOCK)) {
227bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov        flash->CR = FLASH_CR_PSIZE(FLASH_CR_PSIZE_8);
228bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov        acr_cache = flash->ACR;
229bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov
230bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov        // disable and flush data and instruction caches
231bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov        flash->ACR &= ~(FLASH_ACR_DCEN | FLASH_ACR_ICEN);
232bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov        flash->ACR |= (FLASH_ACR_DCRST | FLASH_ACR_ICRST);
233bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov
234bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov        _blEraseSectors(sector_cnt, erase_mask);
235bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov
236bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov        flash->ACR = acr_cache;
237bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov        flash->CR = cr_cache;
238bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov
239bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov        // restore interrupts
240bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov        blRestoreInts(int_state);
241bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov        return true;
242bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    }
243bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    return false;
244bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov}
245bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov
2466308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema/*
2476308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema * Return the address of the write code and the length of the code
2486308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema *
2496308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema * This code needs to run out of ram and not flash since accessing flash
2506308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema * while writing to flash is undefined (best case the processor stalls, worst
2516308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema * case it starts executing garbage)
2526308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema *
2536308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema * This function is used to get a pointer to the actual code that does the
2546308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema * write and polls for completion (so we can copy it to ram) as well as the
2556308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema * length of the code (so we know how much space to allocate for it)
2566308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema *
257e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg * void FlashWriteF(volatile uint8_t *addr, uint8_t value, volatile uint32_t *status)
2586308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema * {
2596308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema *     *addr = value;
2606308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema *     while (*status & FLASH_SR_BSY) ;
2616308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema * }
2626308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema */
263e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinbergstatic void __attribute__((naked)) blGetFlashWriteCode(uint16_t **addr, uint32_t *size)
2646308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema{
2656308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    asm volatile (
2666308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema        "  push {lr}          \n"
2676308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema        "  bl   9f            \n"
2686308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema        "  strb r1, [r0, #0]  \n" // *addr = value
2696308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema        "1:                   \n"
2706308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema        "  ldr  r3, [r2, #0]  \n" // r3 = *status
2716308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema        "  lsls r3, #15       \n" // r3 <<= 15
2726308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema        "  bmi  1b            \n" // if (r3 < 0) goto 1
2736308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema        "  bx   lr            \n" // return
2746308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema        "9:                   \n"
2756308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema        "  bic  lr, #0x1      \n"
2766308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema        "  adr  r3, 9b        \n"
2776308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema        "  sub  r3, lr        \n"
2786308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema        "  str  lr, [r0]      \n"
2796308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema        "  str  r3, [r1]      \n"
2806308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema        "  pop {pc}           \n"
2816308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    );
2826308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema}
2836308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema
284e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinbergstatic void blWriteBytes(uint8_t *dst, const uint8_t *src, uint32_t length)
285e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg{
286e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg    struct StmFlash *flash = (struct StmFlash *)FLASH_BASE;
287e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg    uint16_t *code_src, *code;
288e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg    uint32_t i, code_length;
289e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg    FlashWriteF func;
290e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg
291e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg    blGetFlashWriteCode(&code_src, &code_length);
292e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg
293e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg    if (code_length < BL_MAX_FLASH_CODE) {
294e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg        code = (uint16_t *)(((uint32_t)alloca(code_length+1) + 1) & ~0x1);
295e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg        func = (FlashWriteF)((uint8_t *)code+1);
296e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg
297e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg        for (i = 0; i < code_length / sizeof(uint16_t); i++)
298e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg            code[i] = code_src[i];
299e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg
300e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg        flash->CR |= FLASH_CR_PG;
301e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg
302e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg        for (i = 0; i < length; i++) {
303e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg            if (dst[i] != src[i])
304e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg                func(&dst[i], src[i], &flash->SR);
305e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg        }
306e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg
307e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg        flash->CR &= ~FLASH_CR_PG;
308e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg    }
309e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg}
310e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg
311bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudovbool blPlatProgramFlash(uint8_t *dst, const uint8_t *src, uint32_t length, uint32_t key1, uint32_t key2)
312e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg{
313e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg    struct StmFlash *flash = (struct StmFlash *)FLASH_BASE;
314bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    uint32_t acr_cache, cr_cache;
315019ae84cb5b18417772b683fded7719450349272Ben Fennema    // disable interrupts
316019ae84cb5b18417772b683fded7719450349272Ben Fennema    // otherwise an interrupt during flash write will stall the processor
317019ae84cb5b18417772b683fded7719450349272Ben Fennema    // until the write completes
318bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    uint32_t int_state = blDisableInts();
319019ae84cb5b18417772b683fded7719450349272Ben Fennema
3206308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    // wait for flash to not be busy (should never be set at this point)
321e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg    while (flash->SR & FLASH_SR_BSY);
3226308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema
3236308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    cr_cache = flash->CR;
3246308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema
3256308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    if (flash->CR & FLASH_CR_LOCK) {
3266308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema        // unlock flash
3276308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema        flash->KEYR = key1;
3286308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema        flash->KEYR = key2;
3296308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    }
3306308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema
3316308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    if (flash->CR & FLASH_CR_LOCK) {
332639605691efc26e9671bf584b1a37782ab688ed1Ben Fennema        // unlock failed, restore interrupts
333e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg        blRestoreInts(int_state);
3346308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema
335e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg        return false;
3366308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    }
3376308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema
3386308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    flash->CR = FLASH_CR_PSIZE(FLASH_CR_PSIZE_8);
3396308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema
3406308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    acr_cache = flash->ACR;
3416308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema
3426308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    // disable and flush data and instruction caches
3436308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    flash->ACR &= ~(FLASH_ACR_DCEN | FLASH_ACR_ICEN);
3446308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    flash->ACR |= (FLASH_ACR_DCRST | FLASH_ACR_ICRST);
3456308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema
346e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg    blWriteBytes(dst, src, length);
3476308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema
3486308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    flash->ACR = acr_cache;
3496308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema    flash->CR = cr_cache;
3506308b4d8391441dbb4158bd6723c7d6cee5f5595Ben Fennema
351e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg    blRestoreInts(int_state);
352bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    return true;
3537704485a8c6171cef203acbcee98f4ed9514f02fDmitry Grinberg}
3547704485a8c6171cef203acbcee98f4ed9514f02fDmitry Grinberg
355bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudovuint32_t blDisableInts(void)
356639605691efc26e9671bf584b1a37782ab688ed1Ben Fennema{
357bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    uint32_t state;
358639605691efc26e9671bf584b1a37782ab688ed1Ben Fennema
359bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    asm volatile (
360bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov        "mrs %0, PRIMASK    \n"
361bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov        "cpsid i            \n"
362bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov        :"=r"(state)
363bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    );
364639605691efc26e9671bf584b1a37782ab688ed1Ben Fennema
365bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    return state;
366d1040d8e06013a383c0d1258db7b88d3d536566bAlexey Polyudov}
367d1040d8e06013a383c0d1258db7b88d3d536566bAlexey Polyudov
368bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudovvoid blRestoreInts(uint32_t state)
369d1040d8e06013a383c0d1258db7b88d3d536566bAlexey Polyudov{
370bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    asm volatile(
371bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov        "msr PRIMASK, %0   \n"
372bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov        ::"r"((uint32_t)state)
373bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    );
374d1040d8e06013a383c0d1258db7b88d3d536566bAlexey Polyudov}
375d1040d8e06013a383c0d1258db7b88d3d536566bAlexey Polyudov
376bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudovvoid blReboot(void)
377d1040d8e06013a383c0d1258db7b88d3d536566bAlexey Polyudov{
378bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    SCB->AIRCR = 0x05FA0004;
379bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    //we never get here
380bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    while(1);
381d1040d8e06013a383c0d1258db7b88d3d536566bAlexey Polyudov}
382d1040d8e06013a383c0d1258db7b88d3d536566bAlexey Polyudov
383bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudovvoid blResetRxData()
384a443864c8bd6dd2d8d6f9e018d058081e597986fDmitry Grinberg{
385bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    (void)SPI->DR;
386bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    while (!(SPI->SR & 1));
387bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    (void)SPI->DR;
388a443864c8bd6dd2d8d6f9e018d058081e597986fDmitry Grinberg}
389a443864c8bd6dd2d8d6f9e018d058081e597986fDmitry Grinberg
390bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudovuint8_t blSpiTxRxByte(uint32_t val)
3912c2c28b9e97ec57ba4f67f0a6394a95b28cb8961Captain Dmitry Grinberg IV{
392bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    while (!(SPI->SR & 2));
393bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    SPI->DR = val;
394bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    while (!(SPI->SR & 1));
395bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    return SPI->DR;
3962c2c28b9e97ec57ba4f67f0a6394a95b28cb8961Captain Dmitry Grinberg IV}
3972c2c28b9e97ec57ba4f67f0a6394a95b28cb8961Captain Dmitry Grinberg IV
398bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudovuint32_t blGetSnum(uint32_t *snum, uint32_t length)
39979b5f7745d88342ddae69c2cbe457221702061cfDmitry Grinberg{
400bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    struct StmUdid *reg = (struct StmUdid *)UDID_BASE;
40179b5f7745d88342ddae69c2cbe457221702061cfDmitry Grinberg    uint32_t i;
40279b5f7745d88342ddae69c2cbe457221702061cfDmitry Grinberg
403bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    if (length > 3)
404bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov        length = 3;
405d1040d8e06013a383c0d1258db7b88d3d536566bAlexey Polyudov
406bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    for (i = 0; i < length; i++)
407bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov        snum[i] = reg->U_ID[i];
408e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg
409bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    return (length << 2);
410e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg}
411e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg
412bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudovvoid blSetup()
413e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg{
414bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    SPI = (struct StmSpi*)SPI1_BASE;
415bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    GPIOA = (struct StmGpio*)GPIOA_BASE;
416bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    RCC = (struct StmRcc*)RCC_BASE;
417e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg
418bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    if (SH_INT_WAKEUP < GPIO_PA(0) || SH_INT_WAKEUP > GPIO_PA(15)) {
419d1040d8e06013a383c0d1258db7b88d3d536566bAlexey Polyudov
420bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov        //link time assert :)
421bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov        extern void ThisIsAnError_BlIntPinNotInGpioA(void);
422bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov        ThisIsAnError_BlIntPinNotInGpioA();
423e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg    }
424e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg
425bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    //SPI & GPIOA on
426bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    mOldApb2State = RCC->APB2ENR;
427bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    mOldAhb1State = RCC->AHB1ENR;
428bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    RCC->APB2ENR |= PERIPH_APB2_SPI1;
429bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    RCC->AHB1ENR |= PERIPH_AHB1_GPIOA;
430e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg
431bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    //reset units
432bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    RCC->APB2RSTR |= PERIPH_APB2_SPI1;
433bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    RCC->AHB1RSTR |= PERIPH_AHB1_GPIOA;
434bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    RCC->APB2RSTR &=~ PERIPH_APB2_SPI1;
435bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    RCC->AHB1RSTR &=~ PERIPH_AHB1_GPIOA;
43667dd3e880c05f246865598a40028c1275e3f3fe3Ben Fennema
437bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    //configure GPIOA for SPI A4..A7 for SPI use (function 5), int pin as not func, high speed, no pullups, not open drain, proper directions
438bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    GPIOA->AFR[0] = (GPIOA->AFR[0] & 0x0000ffff & ~(0x0f << (INT_IN_PIN * 4))) | 0x55550000;
439bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    GPIOA->OSPEEDR |= 0x0000ff00 | (3 << (INT_IN_PIN * 2));
440bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    GPIOA->PUPDR &=~ (0x0000ff00 | (3 << (INT_IN_PIN * 2)));
441bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    GPIOA->OTYPER &=~ (0x00f0 | (1 << INT_IN_PIN));
442bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    GPIOA->MODER = (GPIOA->MODER & 0xffff00ff & ~(0x03 << (INT_IN_PIN * 2))) | 0x0000aa00;
443e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg}
444e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg
445bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudovvoid blCleanup()
446e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg{
447bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    //reset units & return APB2 & AHB1 to initial state
448bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    RCC->APB2RSTR |= PERIPH_APB2_SPI1;
449bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    RCC->AHB1RSTR |= PERIPH_AHB1_GPIOA;
450bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    RCC->APB2RSTR &=~ PERIPH_APB2_SPI1;
451bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    RCC->AHB1RSTR &=~ PERIPH_AHB1_GPIOA;
452bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    RCC->APB2ENR = mOldApb2State;
453bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    RCC->AHB1ENR = mOldAhb1State;
4548b5393ed02b015577c6a845b0311064f99f9512fBen Fennema}
4558b5393ed02b015577c6a845b0311064f99f9512fBen Fennema
456bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudovbool blHostActive()
4578b5393ed02b015577c6a845b0311064f99f9512fBen Fennema{
458bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    return !(GPIOA->IDR & (1 << INT_IN_PIN));
459e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg}
460e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg
461bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudovvoid blConfigIo()
462e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg{
463bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    //config SPI
464bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    SPI->CR1 = 0x00000040; //spi is on, configured same as bootloader would
465bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    SPI->CR2 = 0x00000000; //spi is on, configured same as bootloader would
466e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg}
467e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg
468bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudovbool blSyncWait(uint32_t syncCode)
469e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg{
470bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    uint32_t nRetries;
471bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    //wait for sync
472bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    for (nRetries = 10000; nRetries; nRetries--) {
473bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov        if (SPI->SR & 1) {
474bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov            if (SPI->DR == syncCode)
475bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov                break;
476bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov            (void)SPI->SR; //re-read to clear overlfow condition (if any)
477e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg        }
478e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg    }
479bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    return nRetries > 0;
480e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg}
481e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg
482bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudovstatic void __blEntry(void)
483e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg{
484bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    extern char __code_start[], __bss_end[], __bss_start[], __data_end[], __data_start[], __data_data[];
485b928147358283f2c3e733afe60b96017038eca6eDmitry Grinberg    uint32_t appBase = ((uint32_t)&__code_start) & ~1;
486e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg
487e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg    //make sure we're the vector table and no ints happen (BL does not use them)
488e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg    blDisableInts();
489e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg    SCB->VTOR = (uint32_t)&BL;
490e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg
491515f84084123dd42de0ba58445b2d65976132dc7Dmitry Grinberg    //init things a little for the higher levels
492515f84084123dd42de0ba58445b2d65976132dc7Dmitry Grinberg    memset(__bss_start, 0, __bss_end - __bss_start);
493515f84084123dd42de0ba58445b2d65976132dc7Dmitry Grinberg    memcpy(__data_start, __data_data, __data_end - __data_start);
494515f84084123dd42de0ba58445b2d65976132dc7Dmitry Grinberg
495bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    blMain(appBase);
496e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg
497bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    //call OS with ints off
498e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg    blDisableInts();
499e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg    SCB->VTOR = appBase;
500e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg    asm volatile(
501e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg        "LDR SP, [%0, #0]    \n"
502e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg        "LDR PC, [%0, #4]    \n"
503e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg        :
504e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg        :"r"(appBase)
505e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg        :"memory", "cc"
506e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg    );
507e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg
508e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg    //we should never return here
509e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg    while(1);
510e3aa7770fd83abf57b3a8a5678d2c022216bcc19Dmitry Grinberg}
511bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov
512bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudovstatic void blSpuriousIntHandler(void)
513bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov{
514bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    //BAD!
515bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    blReboot();
516bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov}
517bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov
518bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudovextern uint8_t __stack_top[];
519bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudovuint64_t __attribute__ ((section (".stack"))) _STACK[BL_STACK_SIZE / sizeof(uint64_t)];
520bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov
521bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudovconst struct BlVecTable __attribute__((section(".blvec"))) __BL_VEC =
522bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov{
523bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    .blStackTop             = (uint32_t)&__stack_top,
524bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    .blEntry                = &__blEntry,
525bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    .blNmiHandler           = &blSpuriousIntHandler,
526bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    .blMmuFaultHandler      = &blSpuriousIntHandler,
527bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    .blBusFaultHandler      = &blSpuriousIntHandler,
528bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov    .blUsageFaultHandler    = &blSpuriousIntHandler,
529bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov};
530