blob: 7a2b29c7ef96891a1e240395d4c821a3d15e7ce9 [file] [log] [blame] [edit]
#include <string>
#include "firmware-update.hpp"
#include "firmware.hpp"
using namespace blit;
// trimmed FLASH registers
typedef struct
{
volatile uint32_t ACR;
volatile uint32_t KEYR1;
volatile uint32_t OPTKEYR;
volatile uint32_t CR1;
volatile uint32_t SR1;
volatile uint32_t CCR1;
} FLASH_TypeDef;
#define FLASH ((FLASH_TypeDef *) 0x52002000)
#define FLASH_KEY1 0x45670123U
#define FLASH_KEY2 0xCDEF89ABU
#define FLASH_CR_LOCK (1 << 0)
#define FLASH_CR_PG (1 << 1)
#define FLASH_CR_BER (1 << 3)
#define FLASH_CR_PSIZE (3 << 4)
#define FLASH_CR_START (1 << 7)
#define FLASH_SR_BSY (1 << 0)
#define FLASH_SR_QW (1 << 2)
#define FLASH_SR_EOP (1 << 16)
// SCB regs
#define SCB_AIRCR *(volatile uint32_t *)(0xE000ED0C)
#define SCB_CCR *(volatile uint32_t *)(0xE000ED14)
#define SCB_CCSIDR *(volatile uint32_t *)(0xE000ED80)
#define SCB_CSSELR *(volatile uint32_t *)(0xE000ED84)
#define SCB_DCCSW *(volatile uint32_t *)(0xE000EF6C)
__attribute__((section(".persist"))) uint32_t persist_magic;
int rendered = 0;
void init() {
}
void render(uint32_t time_ms) {
screen.pen = Pen(0, 0, 0);
screen.clear();
screen.pen = Pen(255, 255, 255);
screen.text("Updating firmware...", minimal_font, Point(screen.bounds.w / 2, screen.bounds.h / 2), false, TextAlign::center_center);
rendered++;
}
void update(uint32_t time_ms) {
if(rendered < 2) return;
// disable interrupts
asm volatile ("cpsid i" : : : "memory");
// unlock
while(FLASH->SR1 & FLASH_SR_BSY) {}
if(FLASH->CR1 & FLASH_CR_LOCK) {
FLASH->KEYR1 = FLASH_KEY1;
FLASH->KEYR1 = FLASH_KEY2;
}
// erase
FLASH->CR1 |= FLASH_CR_PSIZE;
FLASH->CR1 |= FLASH_CR_BER | FLASH_CR_START;
// wait
while(FLASH->SR1 & FLASH_SR_BSY) {}
if(FLASH->SR1 & FLASH_SR_EOP) {
FLASH->CCR1 |= FLASH_SR_EOP;
}
FLASH->CR1 &= ~FLASH_CR_BER;
// write
auto flash_ptr = reinterpret_cast<volatile uint32_t *>(0x8000000);
auto ptr = reinterpret_cast<const uint32_t *>(firmware_data);
unsigned int length = firmware_data_length;
FLASH->CR1 |= FLASH_CR_PG;
// 8 words at a time
for(unsigned offset = 0; offset < length; offset += 8 * 4) {
asm volatile("dsb 0xF":::"memory");
for(int i = 0; i < 8; i++)
*flash_ptr++ = *ptr++;
asm volatile("dsb 0xF":::"memory");
// wait
while(FLASH->SR1 & FLASH_SR_QW) {}
if(FLASH->SR1 & FLASH_SR_EOP) {
FLASH->CCR1 |= FLASH_SR_EOP;
}
}
FLASH->CR1 &= ~FLASH_CR_PG;
// lock
FLASH->CR1 |= FLASH_CR_LOCK;
persist_magic = 0; // reset all the things
//clean cache
SCB_CSSELR = 0;
asm volatile("dsb 0xF":::"memory");
auto ccsidr = SCB_CCSIDR;
auto sets = (uint32_t)((ccsidr >> 13) & 0x7FFF);
do {
auto ways = (uint32_t)(((ccsidr >> 3) & 0x3FF));
do {
SCB_DCCSW = ((sets & 0x1FF) << 5) | ((ways & 3) << 30);
} while (ways-- != 0U);
} while(sets-- != 0U);
asm volatile("dsb 0xF":::"memory");
asm volatile("isb 0xF":::"memory");
// reset
asm volatile("dsb 0xF":::"memory");
SCB_AIRCR = (0x5FA << 16) /*VECTKEY*/ | (SCB_AIRCR & (7 << 8)) /*PRIGROUP*/ | (1 << 2) /*SYSRESETREQ*/;
asm volatile("dsb 0xF":::"memory");
while(true);
}