coreboot-libre-fam15h-rdimm/3rdparty/chromeec/chip/stm32/flash-stm32l.c

481 lines
11 KiB
C
Raw Normal View History

2024-03-04 11:14:53 +01:00
/* Copyright 2012 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/* Flash memory module for Chrome EC */
#include "clock.h"
#include "console.h"
#include "flash.h"
#include "registers.h"
#include "system.h"
#include "task.h"
#include "timer.h"
#include "util.h"
#include "watchdog.h"
/*
* Approximate number of CPU cycles per iteration of the loop when polling
* the flash status.
*/
#define CYCLE_PER_FLASH_LOOP 10
/* Flash page programming timeout. This is 2x the datasheet max. */
#define FLASH_TIMEOUT_MS 16
static int flash_timeout_loop;
/**
* Lock all the locks.
*/
static void lock(void)
{
ignore_bus_fault(1);
STM32_FLASH_PECR = STM32_FLASH_PECR_PE_LOCK |
STM32_FLASH_PECR_PRG_LOCK | STM32_FLASH_PECR_OPT_LOCK;
ignore_bus_fault(0);
}
/**
* Unlock the specified locks.
*/
static int unlock(int locks)
{
/*
* We may have already locked the flash module and get a bus fault
* in the attempt to unlock. Need to disable bus fault handler now.
*/
ignore_bus_fault(1);
/* Unlock PECR if needed */
if (STM32_FLASH_PECR & STM32_FLASH_PECR_PE_LOCK) {
STM32_FLASH_PEKEYR = STM32_FLASH_PEKEYR_KEY1;
STM32_FLASH_PEKEYR = STM32_FLASH_PEKEYR_KEY2;
}
/* Fail if it didn't unlock */
if (STM32_FLASH_PECR & STM32_FLASH_PECR_PE_LOCK) {
ignore_bus_fault(0);
return EC_ERROR_ACCESS_DENIED;
}
/* Unlock program memory if required */
if ((locks & STM32_FLASH_PECR_PRG_LOCK) &&
(STM32_FLASH_PECR & STM32_FLASH_PECR_PRG_LOCK)) {
STM32_FLASH_PRGKEYR = STM32_FLASH_PRGKEYR_KEY1;
STM32_FLASH_PRGKEYR = STM32_FLASH_PRGKEYR_KEY2;
}
/* Unlock option memory if required */
if ((locks & STM32_FLASH_PECR_OPT_LOCK) &&
(STM32_FLASH_PECR & STM32_FLASH_PECR_OPT_LOCK)) {
STM32_FLASH_OPTKEYR = STM32_FLASH_OPTKEYR_KEY1;
STM32_FLASH_OPTKEYR = STM32_FLASH_OPTKEYR_KEY2;
}
ignore_bus_fault(0);
/* Successful if we unlocked everything we wanted */
if (!(STM32_FLASH_PECR & (locks | STM32_FLASH_PECR_PE_LOCK)))
return EC_SUCCESS;
/* Otherwise relock everything and return error */
lock();
return EC_ERROR_ACCESS_DENIED;
}
/**
* Read an option byte word.
*
* Option bytes are stored in pairs in 32-bit registers; the upper 16 bits is
* the 1's compliment of the lower 16 bits.
*/
static uint16_t read_optb(int offset)
{
return REG16(STM32_OPTB_BASE + offset);
}
/**
* Write an option byte word.
*
* Requires OPT_LOCK unlocked.
*/
static void write_optb(int offset, uint16_t value)
{
REG32(STM32_OPTB_BASE + offset) =
(uint32_t)value | ((uint32_t)(~value) << 16);
}
/**
* Read the at-boot protection option bits.
*/
static uint32_t read_optb_wrp(void)
{
return read_optb(STM32_OPTB_WRP1L) |
((uint32_t)read_optb(STM32_OPTB_WRP1H) << 16);
}
/**
* Write the at-boot protection option bits.
*/
static void write_optb_wrp(uint32_t value)
{
write_optb(STM32_OPTB_WRP1L, (uint16_t)value);
write_optb(STM32_OPTB_WRP1H, value >> 16);
}
/**
* Write data to flash.
*
* This function lives in internal RAM, as we cannot read flash during writing.
* You must not call other functions from this one or declare it static.
*/
void __attribute__((section(".iram.text")))
iram_flash_write(uint32_t *addr, uint32_t *data)
{
int i;
/* Wait for ready */
for (i = 0; (STM32_FLASH_SR & 1) && (i < flash_timeout_loop); i++)
;
/* Set PROG and FPRG bits */
STM32_FLASH_PECR |= STM32_FLASH_PECR_PROG | STM32_FLASH_PECR_FPRG;
/* Send words for the half page */
for (i = 0; i < CONFIG_FLASH_WRITE_SIZE / sizeof(uint32_t); i++)
*addr++ = *data++;
/* Wait for writes to complete */
for (i = 0; ((STM32_FLASH_SR & 9) != 8) && (i < flash_timeout_loop);
i++)
;
/* Disable PROG and FPRG bits */
STM32_FLASH_PECR &= ~(STM32_FLASH_PECR_PROG | STM32_FLASH_PECR_FPRG);
}
int flash_physical_write(int offset, int size, const char *data)
{
uint32_t *data32 = (uint32_t *)data;
uint32_t *address = (uint32_t *)(CONFIG_PROGRAM_MEMORY_BASE + offset);
int res = EC_SUCCESS;
int word_mode = 0;
int i;
/* Fail if offset, size, and data aren't at least word-aligned */
if ((offset | size | (uint32_t)(uintptr_t)data) & 3)
return EC_ERROR_INVAL;
/* Unlock program area */
res = unlock(STM32_FLASH_PECR_PRG_LOCK);
if (res)
goto exit_wr;
/* Clear previous error status */
STM32_FLASH_SR = 0xf00;
/*
* If offset and size aren't on word boundaries, do word writes. This
* is slower, but since we claim to the outside world that writes must
* be half-page size, the only code which hits this path is writing
* pstate (which is just writing one word).
*/
if ((offset | size) & (CONFIG_FLASH_WRITE_SIZE - 1))
word_mode = 1;
/* Update flash timeout based on current clock speed */
flash_timeout_loop = FLASH_TIMEOUT_MS * (clock_get_freq() / MSEC) /
CYCLE_PER_FLASH_LOOP;
while (size > 0) {
/*
* Reload the watchdog timer to avoid watchdog reset when doing
* long writing with interrupt disabled.
*/
watchdog_reload();
if (word_mode) {
/* Word write */
*address++ = *data32++;
/* Wait for writes to complete */
for (i = 0; ((STM32_FLASH_SR & 9) != 8) &&
(i < flash_timeout_loop); i++)
;
size -= sizeof(uint32_t);
} else {
/* Half page write */
interrupt_disable();
iram_flash_write(address, data32);
interrupt_enable();
address += CONFIG_FLASH_WRITE_SIZE / sizeof(uint32_t);
data32 += CONFIG_FLASH_WRITE_SIZE / sizeof(uint32_t);
size -= CONFIG_FLASH_WRITE_SIZE;
}
if (STM32_FLASH_SR & 1) {
res = EC_ERROR_TIMEOUT;
goto exit_wr;
}
/*
* Check for error conditions: erase failed, voltage error,
* protection error
*/
if (STM32_FLASH_SR & 0xf00) {
res = EC_ERROR_UNKNOWN;
goto exit_wr;
}
}
exit_wr:
/* Relock program lock */
lock();
return res;
}
int flash_physical_erase(int offset, int size)
{
uint32_t *address;
int res = EC_SUCCESS;
res = unlock(STM32_FLASH_PECR_PRG_LOCK);
if (res)
return res;
/* Clear previous error status */
STM32_FLASH_SR = 0xf00;
/* Set PROG and ERASE bits */
STM32_FLASH_PECR |= STM32_FLASH_PECR_PROG | STM32_FLASH_PECR_ERASE;
for (address = (uint32_t *)(CONFIG_PROGRAM_MEMORY_BASE + offset);
size > 0; size -= CONFIG_FLASH_ERASE_SIZE,
address += CONFIG_FLASH_ERASE_SIZE / sizeof(uint32_t)) {
timestamp_t deadline;
/* Do nothing if already erased */
if (flash_is_erased((uint32_t)address -
CONFIG_PROGRAM_MEMORY_BASE,
CONFIG_FLASH_ERASE_SIZE))
continue;
/* Start erase */
*address = 0x00000000;
/*
* Reload the watchdog timer to avoid watchdog reset during
* multi-page erase operations.
*/
watchdog_reload();
deadline.val = get_time().val + FLASH_TIMEOUT_MS * MSEC;
/* Wait for erase to complete */
while ((STM32_FLASH_SR & 1) &&
(get_time().val < deadline.val)) {
usleep(300);
}
if (STM32_FLASH_SR & 1) {
res = EC_ERROR_TIMEOUT;
goto exit_er;
}
/*
* Check for error conditions: erase failed, voltage error,
* protection error
*/
if (STM32_FLASH_SR & 0xF00) {
res = EC_ERROR_UNKNOWN;
goto exit_er;
}
}
exit_er:
/* Disable program and erase, and relock PECR */
STM32_FLASH_PECR &= ~(STM32_FLASH_PECR_PROG | STM32_FLASH_PECR_ERASE);
lock();
return res;
}
int flash_physical_get_protect(int block)
{
/*
* If the entire flash interface is locked, then all blocks are
* protected until reboot.
*/
if (flash_physical_get_protect_flags() & EC_FLASH_PROTECT_ALL_NOW)
return 1;
/* Check the active write protect status */
return STM32_FLASH_WRPR & BIT(block);
}
int flash_physical_protect_at_boot(uint32_t new_flags)
{
uint32_t prot;
uint32_t mask = (BIT(WP_BANK_COUNT) - 1) << WP_BANK_OFFSET;
int rv;
if (new_flags & EC_FLASH_PROTECT_ALL_AT_BOOT)
return EC_ERROR_UNIMPLEMENTED;
/* Read the current protection status */
prot = read_optb_wrp();
/* Set/clear bits */
if (new_flags & EC_FLASH_PROTECT_RO_AT_BOOT)
prot |= mask;
else
prot &= ~mask;
if (prot == read_optb_wrp())
return EC_SUCCESS; /* No bits changed */
/* Unlock option bytes */
rv = unlock(STM32_FLASH_PECR_OPT_LOCK);
if (rv)
return rv;
/* Update them */
write_optb_wrp(prot);
/* Relock */
lock();
return EC_SUCCESS;
}
int flash_physical_force_reload(void)
{
int rv = unlock(STM32_FLASH_PECR_OPT_LOCK);
if (rv)
return rv;
/* Force a reboot; this should never return. */
STM32_FLASH_PECR = STM32_FLASH_PECR_OBL_LAUNCH;
while (1)
;
return EC_ERROR_UNKNOWN;
}
uint32_t flash_physical_get_protect_flags(void)
{
uint32_t flags = 0;
/*
* Try to unlock PECR; if that fails, then all flash is protected for
* the current boot.
*/
if (unlock(STM32_FLASH_PECR_PE_LOCK))
flags |= EC_FLASH_PROTECT_ALL_NOW;
lock();
return flags;
}
int flash_physical_protect_now(int all)
{
if (all) {
/* Re-lock the registers if they're unlocked */
lock();
/* Prevent unlocking until reboot */
ignore_bus_fault(1);
STM32_FLASH_PEKEYR = 0;
ignore_bus_fault(0);
return EC_SUCCESS;
} else {
/* No way to protect just the RO flash until next boot */
return EC_ERROR_INVAL;
}
}
uint32_t flash_physical_get_valid_flags(void)
{
return EC_FLASH_PROTECT_RO_AT_BOOT |
EC_FLASH_PROTECT_RO_NOW |
EC_FLASH_PROTECT_ALL_NOW;
}
uint32_t flash_physical_get_writable_flags(uint32_t cur_flags)
{
uint32_t ret = 0;
/* If RO protection isn't enabled, its at-boot state can be changed. */
if (!(cur_flags & EC_FLASH_PROTECT_RO_NOW))
ret |= EC_FLASH_PROTECT_RO_AT_BOOT;
/*
* If entire flash isn't protected at this boot, it can be enabled if
* the WP GPIO is asserted.
*/
if (!(cur_flags & EC_FLASH_PROTECT_ALL_NOW) &&
(cur_flags & EC_FLASH_PROTECT_GPIO_ASSERTED))
ret |= EC_FLASH_PROTECT_ALL_NOW;
return ret;
}
int flash_pre_init(void)
{
uint32_t reset_flags = system_get_reset_flags();
uint32_t prot_flags = flash_get_protect();
int need_reset = 0;
/*
* If we have already jumped between images, an earlier image could
* have applied write protection. Nothing additional needs to be done.
*/
if (reset_flags & EC_RESET_FLAG_SYSJUMP)
return EC_SUCCESS;
if (prot_flags & EC_FLASH_PROTECT_GPIO_ASSERTED) {
if ((prot_flags & EC_FLASH_PROTECT_RO_AT_BOOT) &&
!(prot_flags & EC_FLASH_PROTECT_RO_NOW)) {
/*
* Pstate wants RO protected at boot, but the write
* protect register wasn't set to protect it. Force an
* update to the write protect register and reboot so
* it takes effect.
*/
flash_protect_at_boot(EC_FLASH_PROTECT_RO_AT_BOOT);
need_reset = 1;
}
if (prot_flags & EC_FLASH_PROTECT_ERROR_INCONSISTENT) {
/*
* Write protect register was in an inconsistent state.
* Set it back to a good state and reboot.
*/
flash_protect_at_boot(prot_flags &
EC_FLASH_PROTECT_RO_AT_BOOT);
need_reset = 1;
}
} else if (prot_flags & (EC_FLASH_PROTECT_RO_NOW |
EC_FLASH_PROTECT_ERROR_INCONSISTENT)) {
/*
* Write protect pin unasserted but some section is
* protected. Drop it and reboot.
*/
unlock(STM32_FLASH_PECR_OPT_LOCK);
write_optb_wrp(0);
lock();
need_reset = 1;
}
if (need_reset)
system_reset(SYSTEM_RESET_HARD | SYSTEM_RESET_PRESERVE_FLAGS);
return EC_SUCCESS;
}