[FL-2269] Core2 OTA (#1144)
* C2OTA: wip * Update Cube to 1.13.3 * Fixed prio * Functional Core2 updater * Removed hardware CRC usage; code cleanup & linter fixes * Moved hardcoded stack params to copro.mk * Fixing CI bundling of core2 fw * Removed last traces of hardcoded radio stack * OB processing draft * Python scripts cleanup * Support for comments in ob data * Sacrificed SD card icon in favor of faster update. Waiting for Storage fix * Additional handling for OB mismatched values * Description for new furi_hal apis; spelling fixes * Rework of OB write, WIP * Properly restarting OB verification loop * Split update_task_workers.c * Checking OBs after enabling post-update mode * Moved OB verification before flashing * Removed ob.data for custom stacks * Fixed progress calculation for OB * Removed unnecessary OB mask cast Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
@@ -6,7 +6,8 @@
|
||||
|
||||
#include <stm32wbxx.h>
|
||||
|
||||
#define FURI_HAL_TAG "FuriHalFlash"
|
||||
#define TAG "FuriHalFlash"
|
||||
|
||||
#define FURI_HAL_CRITICAL_MSG "Critical flash operation fail"
|
||||
#define FURI_HAL_FLASH_READ_BLOCK 8
|
||||
#define FURI_HAL_FLASH_WRITE_BLOCK 8
|
||||
@@ -14,13 +15,17 @@
|
||||
#define FURI_HAL_FLASH_CYCLES_COUNT 10000
|
||||
#define FURI_HAL_FLASH_TIMEOUT 1000
|
||||
#define FURI_HAL_FLASH_KEY1 0x45670123U
|
||||
|
||||
#define FURI_HAL_FLASH_KEY2 0xCDEF89ABU
|
||||
#define FURI_HAL_FLASH_TOTAL_PAGES 256
|
||||
#define FURI_HAL_FLASH_SR_ERRORS \
|
||||
(FLASH_SR_OPERR | FLASH_SR_PROGERR | FLASH_SR_WRPERR | FLASH_SR_PGAERR | FLASH_SR_SIZERR | \
|
||||
FLASH_SR_PGSERR | FLASH_SR_MISERR | FLASH_SR_FASTERR | FLASH_SR_RDERR | FLASH_SR_OPTVERR)
|
||||
|
||||
//#define FURI_HAL_FLASH_OB_START_ADDRESS 0x1FFF8000
|
||||
#define FURI_HAL_FLASH_OPT_KEY1 0x08192A3B
|
||||
#define FURI_HAL_FLASH_OPT_KEY2 0x4C5D6E7F
|
||||
#define FURI_HAL_FLASH_OB_TOTAL_WORDS (0x80 / (sizeof(uint32_t) * 2))
|
||||
|
||||
#define IS_ADDR_ALIGNED_64BITS(__VALUE__) (((__VALUE__)&0x7U) == (0x00UL))
|
||||
#define IS_FLASH_PROGRAM_ADDRESS(__VALUE__) \
|
||||
(((__VALUE__) >= FLASH_BASE) && ((__VALUE__) <= (FLASH_BASE + FLASH_SIZE - 8UL)) && \
|
||||
@@ -88,7 +93,7 @@ static void furi_hal_flash_unlock() {
|
||||
WRITE_REG(FLASH->KEYR, FURI_HAL_FLASH_KEY1);
|
||||
WRITE_REG(FLASH->KEYR, FURI_HAL_FLASH_KEY2);
|
||||
|
||||
/* verify Flash is unlock */
|
||||
/* verify Flash is unlocked */
|
||||
furi_check(READ_BIT(FLASH->CR, FLASH_CR_LOCK) == 0U);
|
||||
}
|
||||
|
||||
@@ -386,4 +391,125 @@ int16_t furi_hal_flash_get_page_number(size_t address) {
|
||||
}
|
||||
|
||||
return (address - flash_base) / FURI_HAL_FLASH_PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t furi_hal_flash_ob_get_word(size_t word_idx, bool complementary) {
|
||||
furi_check(word_idx <= FURI_HAL_FLASH_OB_TOTAL_WORDS);
|
||||
const uint32_t* ob_data = (const uint32_t*)(OPTION_BYTE_BASE);
|
||||
size_t raw_word_idx = word_idx * 2;
|
||||
if(complementary) {
|
||||
raw_word_idx += 1;
|
||||
}
|
||||
return ob_data[raw_word_idx];
|
||||
}
|
||||
|
||||
void furi_hal_flash_ob_unlock() {
|
||||
furi_check(READ_BIT(FLASH->CR, FLASH_CR_OPTLOCK) != 0U);
|
||||
furi_hal_flash_begin(true);
|
||||
WRITE_REG(FLASH->OPTKEYR, FURI_HAL_FLASH_OPT_KEY1);
|
||||
__ISB();
|
||||
WRITE_REG(FLASH->OPTKEYR, FURI_HAL_FLASH_OPT_KEY2);
|
||||
/* verify OB area is unlocked */
|
||||
furi_check(READ_BIT(FLASH->CR, FLASH_CR_OPTLOCK) == 0U);
|
||||
}
|
||||
|
||||
void furi_hal_flash_ob_lock() {
|
||||
furi_check(READ_BIT(FLASH->CR, FLASH_CR_OPTLOCK) == 0U);
|
||||
SET_BIT(FLASH->CR, FLASH_CR_OPTLOCK);
|
||||
furi_hal_flash_end(true);
|
||||
furi_check(READ_BIT(FLASH->CR, FLASH_CR_OPTLOCK) != 0U);
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
FuriHalFlashObInvalid,
|
||||
FuriHalFlashObRegisterUserRead,
|
||||
FuriHalFlashObRegisterPCROP1AStart,
|
||||
FuriHalFlashObRegisterPCROP1AEnd,
|
||||
FuriHalFlashObRegisterWRPA,
|
||||
FuriHalFlashObRegisterWRPB,
|
||||
FuriHalFlashObRegisterPCROP1BStart,
|
||||
FuriHalFlashObRegisterPCROP1BEnd,
|
||||
FuriHalFlashObRegisterIPCCMail,
|
||||
FuriHalFlashObRegisterSecureFlash,
|
||||
FuriHalFlashObRegisterC2Opts,
|
||||
} FuriHalFlashObRegister;
|
||||
|
||||
typedef struct {
|
||||
FuriHalFlashObRegister ob_reg;
|
||||
uint32_t* ob_register_address;
|
||||
} FuriHalFlashObMapping;
|
||||
|
||||
#define OB_REG_DEF(INDEX, REG) \
|
||||
{ .ob_reg = INDEX, .ob_register_address = (uint32_t*)(REG) }
|
||||
|
||||
static const FuriHalFlashObMapping furi_hal_flash_ob_reg_map[FURI_HAL_FLASH_OB_TOTAL_WORDS] = {
|
||||
OB_REG_DEF(FuriHalFlashObRegisterUserRead, (&FLASH->OPTR)),
|
||||
OB_REG_DEF(FuriHalFlashObRegisterPCROP1AStart, (&FLASH->PCROP1ASR)),
|
||||
OB_REG_DEF(FuriHalFlashObRegisterPCROP1AEnd, (&FLASH->PCROP1AER)),
|
||||
OB_REG_DEF(FuriHalFlashObRegisterWRPA, (&FLASH->WRP1AR)),
|
||||
OB_REG_DEF(FuriHalFlashObRegisterWRPB, (&FLASH->WRP1BR)),
|
||||
OB_REG_DEF(FuriHalFlashObRegisterPCROP1BStart, (&FLASH->PCROP1BSR)),
|
||||
OB_REG_DEF(FuriHalFlashObRegisterPCROP1BEnd, (&FLASH->PCROP1BER)),
|
||||
|
||||
OB_REG_DEF(FuriHalFlashObInvalid, (NULL)),
|
||||
OB_REG_DEF(FuriHalFlashObInvalid, (NULL)),
|
||||
OB_REG_DEF(FuriHalFlashObInvalid, (NULL)),
|
||||
OB_REG_DEF(FuriHalFlashObInvalid, (NULL)),
|
||||
OB_REG_DEF(FuriHalFlashObInvalid, (NULL)),
|
||||
OB_REG_DEF(FuriHalFlashObInvalid, (NULL)),
|
||||
|
||||
OB_REG_DEF(FuriHalFlashObRegisterIPCCMail, (NULL)),
|
||||
OB_REG_DEF(FuriHalFlashObRegisterSecureFlash, (NULL)),
|
||||
OB_REG_DEF(FuriHalFlashObRegisterC2Opts, (NULL)),
|
||||
};
|
||||
|
||||
void furi_hal_flash_ob_apply() {
|
||||
furi_hal_flash_ob_unlock();
|
||||
/* OBL_LAUNCH: When set to 1, this bit forces the option byte reloading.
|
||||
* It cannot be written if OPTLOCK is set */
|
||||
SET_BIT(FLASH->CR, FLASH_CR_OBL_LAUNCH);
|
||||
furi_check(furi_hal_flash_wait_last_operation(FURI_HAL_FLASH_TIMEOUT));
|
||||
furi_hal_flash_ob_lock();
|
||||
}
|
||||
|
||||
bool furi_hal_flash_ob_set_word(size_t word_idx, const uint32_t value) {
|
||||
furi_check(word_idx < FURI_HAL_FLASH_OB_TOTAL_WORDS);
|
||||
|
||||
const FuriHalFlashObMapping* reg_def = &furi_hal_flash_ob_reg_map[word_idx];
|
||||
if(reg_def->ob_register_address == NULL) {
|
||||
FURI_LOG_E(TAG, "Attempt to set RO OB word %d", word_idx);
|
||||
return false;
|
||||
}
|
||||
|
||||
FURI_LOG_W(
|
||||
TAG,
|
||||
"Setting OB reg %d for word %d (addr 0x%08X) to 0x%08X",
|
||||
reg_def->ob_reg,
|
||||
word_idx,
|
||||
reg_def->ob_register_address,
|
||||
value);
|
||||
|
||||
/* 1. Clear OPTLOCK option lock bit with the clearing sequence */
|
||||
furi_hal_flash_ob_unlock();
|
||||
|
||||
/* 2. Write the desired options value in the options registers */
|
||||
*reg_def->ob_register_address = value;
|
||||
|
||||
/* 3. Check that no Flash memory operation is on going by checking the BSY && PESD */
|
||||
furi_check(furi_hal_flash_wait_last_operation(FURI_HAL_FLASH_TIMEOUT));
|
||||
while(LL_FLASH_IsActiveFlag_OperationSuspended()) {
|
||||
osThreadYield();
|
||||
};
|
||||
|
||||
/* 4. Set the Options start bit OPTSTRT */
|
||||
SET_BIT(FLASH->CR, FLASH_CR_OPTSTRT);
|
||||
|
||||
/* 5. Wait for the BSY bit to be cleared. */
|
||||
furi_check(furi_hal_flash_wait_last_operation(FURI_HAL_FLASH_TIMEOUT));
|
||||
furi_hal_flash_ob_lock();
|
||||
return true;
|
||||
}
|
||||
|
||||
const FuriHalFlashRawOptionByteData* furi_hal_flash_ob_get_raw_ptr() {
|
||||
return (const FuriHalFlashRawOptionByteData*)OPTION_BYTE_BASE;
|
||||
}
|
||||
|
Reference in New Issue
Block a user