stm32: Avoid read-modify-write operations in flash.c

Avoid read-modify-write operations on the FLASH->CR register.  Write
out the desired valid explicitly.

Use writew() and writel() to write the flash bytes out to avoid gcc
reordering the memory write relative to the flash register writes.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2022-05-15 19:25:25 -04:00 committed by Eric Callahan
parent 8316d2f0af
commit 9f9a872176

View File

@ -5,6 +5,7 @@
// This file may be distributed under the terms of the GNU GPLv3 license. // This file may be distributed under the terms of the GNU GPLv3 license.
#include "autoconf.h" // CONFIG_MACH_STM32F103 #include "autoconf.h" // CONFIG_MACH_STM32F103
#include "board/io.h" // writew
#include "flash.h" // flash_write_page #include "flash.h" // flash_write_page
#include "internal.h" // FLASH #include "internal.h" // FLASH
@ -27,32 +28,37 @@ flash_get_page_size(void)
return CONFIG_MAX_FLASH_PAGE_SIZE; return CONFIG_MAX_FLASH_PAGE_SIZE;
} }
static void
wait_flash(void)
{
while (FLASH->SR & FLASH_SR_BSY)
;
}
static void static void
unlock_flash(void) unlock_flash(void)
{ {
// Unlock Flash Erase if (FLASH->CR & FLASH_CR_LOCK) {
FLASH->KEYR = FLASH_KEY1; // Unlock Flash Erase
FLASH->KEYR = FLASH_KEY2; FLASH->KEYR = FLASH_KEY1;
while (FLASH->SR & FLASH_SR_BSY); FLASH->KEYR = FLASH_KEY2;
}
wait_flash();
} }
void static void
flash_complete(void) lock_flash(void)
{ {
// Lock flash when done FLASH->CR = FLASH_CR_LOCK;
FLASH->CR |= FLASH_CR_LOCK;
} }
void static void
flash_write_stm32f4xx(uint32_t page_address, uint32_t *data) flash_write_stm32f4xx(uint32_t page_address, uint32_t *data)
{ {
#if CONFIG_MACH_STM32F4 #if CONFIG_MACH_STM32F4
uint32_t flash_page_size = flash_get_page_size(); uint32_t flash_page_size = flash_get_page_size();
uint32_t* page = (uint32_t*)(page_address); uint32_t* page = (uint32_t*)(page_address);
if (FLASH->CR & FLASH_CR_LOCK)
unlock_flash();
uint8_t need_erase = 0; uint8_t need_erase = 0;
uint32_t offset_addr = page_address - CONFIG_FLASH_START; uint32_t offset_addr = page_address - CONFIG_FLASH_START;
uint32_t sector_index = offset_addr / STM32F4_MAX_SECTOR_SIZE; uint32_t sector_index = offset_addr / STM32F4_MAX_SECTOR_SIZE;
@ -67,36 +73,29 @@ flash_write_stm32f4xx(uint32_t page_address, uint32_t *data)
need_erase = ((page_address % STM32F4_MAX_SECTOR_SIZE) == 0); need_erase = ((page_address % STM32F4_MAX_SECTOR_SIZE) == 0);
sector_index += 4; sector_index += 4;
} }
while (FLASH->SR & FLASH_SR_BSY);
FLASH->CR &= ~FLASH_CR_PSIZE; // make sure flash is unlocked
FLASH->CR &= ~FLASH_CR_SNB; unlock_flash();
// Erase page
if (need_erase) { if (need_erase) {
FLASH->CR |= FLASH_CR_PSIZE_1; FLASH->CR = (FLASH_CR_PSIZE_1 | FLASH_CR_STRT | FLASH_CR_SER
FLASH->CR |= FLASH_CR_SER | ((sector_index & 0xF) << 3); | ((sector_index & 0xF) << 3));
FLASH->CR |= FLASH_CR_STRT; wait_flash();
while (FLASH->SR & FLASH_SR_BSY);
FLASH->CR &= ~FLASH_CR_SNB;
do {
FLASH->CR &= ~FLASH_CR_SER;
} while(FLASH->CR & FLASH_CR_SER);
} }
FLASH->CR |= FLASH_CR_PSIZE_1; // Write page
FLASH->CR |= FLASH_CR_PG; FLASH->CR = FLASH_CR_PSIZE_1 | FLASH_CR_PG;
for (uint16_t i = 0; i < flash_page_size / 4; i++) for (int i = 0; i < flash_page_size / 4; i++) {
{ writel(&page[i], data[i]);
page[i] = data[i]; wait_flash();
while (FLASH->SR & FLASH_SR_BSY);
} }
do {
FLASH->CR &= ~FLASH_CR_PG;
} while(FLASH->CR & FLASH_CR_PG);
FLASH->CR |= FLASH_CR_LOCK; lock_flash();
#endif #endif
} }
void static void
flash_write_stm32f1xx(uint32_t page_address, uint16_t *data) flash_write_stm32f1xx(uint32_t page_address, uint16_t *data)
{ {
#if CONFIG_MACH_STM32F0 || CONFIG_MACH_STM32F1 #if CONFIG_MACH_STM32F0 || CONFIG_MACH_STM32F1
@ -104,30 +103,22 @@ flash_write_stm32f1xx(uint32_t page_address, uint16_t *data)
uint16_t* page = (uint16_t*)(page_address); uint16_t* page = (uint16_t*)(page_address);
// make sure flash is unlocked // make sure flash is unlocked
if (FLASH->CR & FLASH_CR_LOCK) unlock_flash();
unlock_flash();
// Erase page // Erase page
FLASH->CR |= FLASH_CR_PER; FLASH->CR = FLASH_CR_PER;
FLASH->AR = (uint32_t)page; FLASH->AR = page_address;
FLASH->CR |= FLASH_CR_STRT; FLASH->CR = FLASH_CR_PER | FLASH_CR_STRT;
while (FLASH->SR & FLASH_SR_BSY); wait_flash();
do {
FLASH->CR &= ~FLASH_CR_PER;
} while (FLASH->CR & FLASH_CR_PER);
// Write page // Write page
FLASH->CR |= FLASH_CR_PG; FLASH->CR = FLASH_CR_PG;
for (uint16_t i = 0; i < flash_page_size / 2; i++) for (int i = 0; i < flash_page_size / 2; i++) {
{ writew(&page[i], data[i]);
page[i] = data[i]; wait_flash();
while (FLASH->SR & FLASH_SR_BSY);
} }
do {
FLASH->CR &= ~FLASH_CR_PG;
} while (FLASH->CR & FLASH_CR_PG);
FLASH->CR |= FLASH_CR_LOCK; lock_flash();
#endif #endif
} }
@ -140,3 +131,9 @@ flash_write_page(uint32_t page_address, void *data)
flash_write_stm32f1xx(page_address, (uint16_t *)data); flash_write_stm32f1xx(page_address, (uint16_t *)data);
} }
} }
void
flash_complete(void)
{
lock_flash();
}