blob: 91521c6202fdbae9570eca7d8786084497327991 [file] [log] [blame]
/* Copyright 2017 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/* Flash memory module for STM32L4 family */
#include "clock.h"
#include "common.h"
#include "flash.h"
#include "hooks.h"
#include "panic.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_US 48000
/*
* Cros-Ec common flash APIs use the term 'bank' equivalent to how 'page' is
* used in the STM32 TRMs. Redifining macros here in terms of pages in order to
* match STM32 documentation for write protect computations in this file.
*
* These macros are from the common flash API and mean the following:
* WP_BANK_OFFSET -> index of first RO page
* CONFIG_WP_STORAGE_SIZE -> size of RO region in bytes
*/
#define FLASH_PAGE_SIZE CONFIG_FLASH_BANK_SIZE
#define FLASH_PAGE_MAX_COUNT (CONFIG_FLASH_SIZE_BYTES / FLASH_PAGE_SIZE)
#define FLASH_RO_FIRST_PAGE_IDX WP_BANK_OFFSET
#define FLASH_RO_LAST_PAGE_IDX \
((CONFIG_WP_STORAGE_SIZE / FLASH_PAGE_SIZE) + \
FLASH_RO_FIRST_PAGE_IDX - 1)
#define FLASH_RW_FIRST_PAGE_IDX (FLASH_RO_LAST_PAGE_IDX + 1)
#define FLASH_RW_LAST_PAGE_IDX (FLASH_PAGE_MAX_COUNT - 1)
#define FLASH_PAGE_ROLLBACK_COUNT ROLLBACK_BANK_COUNT
#define FLASH_PAGE_ROLLBACK_FIRST_IDX ROLLBACK_BANK_OFFSET
#define FLASH_PAGE_ROLLBACK_LAST_IDX \
(FLASH_PAGE_ROLLBACK_FIRST_IDX + FLASH_PAGE_ROLLBACK_COUNT - 1)
#ifdef STM32_FLASH_DBANK_MODE
#define FLASH_WRP_MASK (FLASH_PAGE_MAX_COUNT - 1)
#else
#ifdef CHIP_FAMILY_STM32L4
#define FLASH_WRP_MASK 0xFF
#else
#define FLASH_WRP_MASK ((FLASH_PAGE_MAX_COUNT) / 2 - 1)
#endif
#endif /* CONFIG_FLASH_DBANK_MODE */
#define FLASH_WRP_START(val) ((val) & FLASH_WRP_MASK)
#define FLASH_WRP_END(val) (((val) >> 16) & FLASH_WRP_MASK)
#define FLASH_WRP_RANGE(start, end) \
(((start) & FLASH_WRP_MASK) | (((end) & FLASH_WRP_MASK) << 16))
#define FLASH_WRP_RANGE_DISABLED FLASH_WRP_RANGE(FLASH_WRP_MASK, 0x00)
#define FLASH_WRP1X_MASK FLASH_WRP_RANGE(FLASH_WRP_MASK, FLASH_WRP_MASK)
enum wrp_region {
WRP_RO,
WRP_RW,
};
struct wrp_info {
int enable;
int start;
int end;
};
static inline int calculate_flash_timeout(void)
{
return (FLASH_TIMEOUT_US * (clock_get_freq() / SECOND) /
CYCLE_PER_FLASH_LOOP);
}
static int wait_while_busy(void)
{
int timeout = calculate_flash_timeout();
while (STM32_FLASH_SR & FLASH_SR_BUSY && timeout-- > 0)
;
return (timeout > 0) ? EC_SUCCESS : EC_ERROR_TIMEOUT;
}
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 CR if needed */
if (STM32_FLASH_CR & FLASH_CR_LOCK) {
STM32_FLASH_KEYR = FLASH_KEYR_KEY1;
STM32_FLASH_KEYR = FLASH_KEYR_KEY2;
}
/* unlock option memory if required */
if ((locks & FLASH_CR_OPTLOCK) && (STM32_FLASH_CR & FLASH_CR_OPTLOCK)) {
STM32_FLASH_OPTKEYR = FLASH_OPTKEYR_KEY1;
STM32_FLASH_OPTKEYR = FLASH_OPTKEYR_KEY2;
}
/* Re-enable bus fault handler */
ignore_bus_fault(0);
return (STM32_FLASH_CR & (locks | FLASH_CR_LOCK)) ? EC_ERROR_UNKNOWN :
EC_SUCCESS;
}
static void lock(void)
{
STM32_FLASH_CR |= FLASH_CR_LOCK;
}
static void ob_lock(void)
{
STM32_FLASH_CR |= FLASH_CR_OPTLOCK;
}
/*
* Option byte organization
*
* [63:56][55:48][47:40][39:32] [31:24][23:16][15: 8][ 7: 0]
* +--------------+-------------------+------+ +-------------------+------+
* | 0x1FFF7800 | nUSER | nRDP | | USER | RDP |
* +--------------+------------+------+------+ +------------+------+------+
* | 0x1FFF7808 | | nPCROP1_STRT| | | PCROP1_STRT |
* +--------------+------------+-------------+ +------------+-------------+
* | 0x1FFF7810 | | nPCROP1_END | | | PCROP1_END |
* +--------------+------------+-------------+ +------------+-------------+
* | 0x1FFF7818 | |nWRP1A| |nWRP1A| | | WRP1A| | WRP1A|
* | | |_END | |_STRT | | | _END | | _STRT|
* +--------------+------------+-------------+ +------------+-------------+
* | 0x1FFF7820 | |nWRP1B| |nWRP1B| | | WRP1B| | WRP1B|
* | | |_END | |_STRT | | | _END | | _STRT|
* +--------------+------------+-------------+ +------------+-------------+
* | 0x1FFF7828 | |nBOOT | |nSEC_ | | | BOOT | | SEC_ |
* | | |LOCK | |SIZE1 | | | _LOCK| | SIZE1|
* +--------------+------------+-------------+ +------------+-------------+
*
* Note that the variable with n prefix means the complement.
*/
static int unlock_optb(void)
{
int rv;
rv = wait_while_busy();
if (rv)
return rv;
rv = unlock(FLASH_CR_OPTLOCK);
if (rv)
return rv;
return EC_SUCCESS;
}
static int commit_optb(void)
{
int rv;
/*
* Wait for last operation.
*/
rv = wait_while_busy();
if (rv)
return rv;
STM32_FLASH_CR |= FLASH_CR_OPTSTRT;
rv = wait_while_busy();
if (rv)
return rv;
ob_lock();
lock();
return EC_SUCCESS;
}
/*
* There are a minimum of 2 WRP regions that can be set. The STM32G4
* family has both category 2, and category 3 devices. Category 2
* devices have only 2 WRP regions, but category 3 devices have 4 WRP
* regions that can be configured. Category 3 devices also support dual
* flash banks, and this mode is the default setting. When DB mode is enabled,
* then each WRP register can only protect up to 64 2kB pages. This means that
* one WRP register is needed per bank.
*
* 1. WRP1A -> used always for RO
* 2. WRP1B -> used always for RW
* 3. WRP2A -> may be used for RW if dual-bank (DB) mode is enabled
* 4. WRP2B -> currently never used
*
* WRP areas are specified in terms of page indices with a start index
* and an end index. start == end means a single page is protected.
*
* WRPnx_start = WRPnx_end --> WRPnx_start page is protected
* WRPnx_start > WRPnx_end --> No WRP area is specified
* WRPnx_start < WRPnx_end --> Pages WRPnx_start to WRPnx_end
*/
static void optb_get_wrp(enum wrp_region region, struct wrp_info *wrp)
{
#ifdef STM32_FLASH_DBANK_MODE
int start;
int end;
#endif
/* Assume WRP regions are not configured */
wrp->start = FLASH_WRP_MASK;
wrp->end = 0;
wrp->enable = 0;
if (region == WRP_RO) {
/*
* RO write protect is fully described by WRP1AR. Get the
* start/end indices. If end >= start, then RO write protect is
* enabled.
*/
wrp->start = FLASH_WRP_START(STM32_OPTB_WRP1AR);
wrp->end = FLASH_WRP_END(STM32_OPTB_WRP1AR);
wrp->enable = wrp->end >= wrp->start;
} else if (region == WRP_RW) {
/*
* RW write always uses WRP1BR. If dual-bank mode is being used,
* then WRP2AR must also be check to determine the full range of
* flash page indices being protected.
*/
wrp->start = FLASH_WRP_START(STM32_OPTB_WRP1BR);
wrp->end = FLASH_WRP_END(STM32_OPTB_WRP1BR);
wrp->enable = wrp->end >= wrp->start;
#ifdef STM32_FLASH_DBANK_MODE
start = FLASH_WRP_START(STM32_FLASH_WRP2AR);
end = FLASH_WRP_END(STM32_FLASH_WRP2AR);
/*
* If WRP2AR protection is enabled, then need to adjust either
* the start, end, or both indices.
*/
if (end >= start) {
if (wrp->enable) {
/* WRP1BR is active, only need to adjust end */
wrp->end += end;
} else {
/*
* WRP1BR is not active, so RW protection, if
* enabled, is fully controlled by WRP2AR.
*/
wrp->start = start;
wrp->end = end;
wrp->enable = 1;
}
}
#endif
}
}
static void optb_set_wrp(enum wrp_region region, struct wrp_info *wrp)
{
int start = wrp->start;
int end = wrp->end;
if (!wrp->enable) {
/*
* If enable is not set, then ignore the passed in start/end
* values and set start/end to the default not protected range
* which satisfies start > end
*/
start = FLASH_WRP_MASK;
end = 0;
}
if (region == WRP_RO) {
/* For RO can always use start/end directly */
STM32_FLASH_WRP1AR = FLASH_WRP_RANGE(start, end);
} else if (region == WRP_RW) {
#ifdef STM32_FLASH_DBANK_MODE
/*
* In the dual-bank flash case (STM32G4 Category 3 devices with
* DB bit set), RW write protect can use both WRP1BR and WRP2AR
* registers in order to span the full flash memory range.
*/
if (wrp->enable) {
int rw_end;
/*
* If the 1st RW flash page is in the 1st half of
* memory, then at least one block will be protected by
* WRP1BR. If the end flash page is in the 2nd half of
* memory, then cap the end for WRP1BR to its max
* value. Otherwise, can use end passed in directly.
*/
if (start <= FLASH_WRP_MASK) {
rw_end = end > FLASH_WRP_MASK ? FLASH_WRP_MASK :
end;
STM32_FLASH_WRP1BR =
FLASH_WRP_RANGE(start, rw_end);
}
/*
* If the last RW flash page is in the 2nd half of
* memory, then at least one block will be protected by
* WRP2AR. If the start flash page is in the 2nd half of
* memory, can use start directly. Otherwise, start
* needs to be set to 0 here.
*/
if (end > FLASH_WRP_MASK) {
rw_end = end & FLASH_WRP_MASK;
STM32_FLASH_WRP2AR = FLASH_WRP_RANGE(0, rw_end);
}
} else {
/*
* RW write protect is being disabled. Set both WRP1BR
* and WRP2AR to default start > end not protected
* state.
*/
STM32_FLASH_WRP1BR = FLASH_WRP_RANGE(start, end);
STM32_FLASH_WRP2AR = FLASH_WRP_RANGE(start, end);
}
#else
/* Single bank case, WRP1BR can cover the full memory range */
STM32_FLASH_WRP1BR = FLASH_WRP_RANGE(start, end);
#endif
}
}
static void unprotect_all_blocks(void)
{
struct wrp_info wrp;
/* Set info values to unprotected */
wrp.start = FLASH_WRP_MASK;
wrp.end = 0;
wrp.enable = 0;
unlock_optb();
/* Disable RO WRP */
optb_set_wrp(WRP_RO, &wrp);
/* Disable RW WRP */
optb_set_wrp(WRP_RW, &wrp);
commit_optb();
}
int crec_flash_physical_protect_at_boot(uint32_t new_flags)
{
struct wrp_info wrp_ro;
struct wrp_info wrp_rw;
wrp_ro.start = FLASH_WRP_MASK;
wrp_ro.end = 0;
wrp_ro.enable = 0;
wrp_rw.start = FLASH_WRP_MASK;
wrp_rw.end = 0;
wrp_rw.enable = 0;
/*
* Default operation for this function is to disable both RO and RW
* write protection in the option bytes. Based on new_flags either RO or
* RW or both regions write protect may be set.
*/
if (new_flags &
(EC_FLASH_PROTECT_ALL_AT_BOOT | EC_FLASH_PROTECT_RO_AT_BOOT)) {
wrp_ro.start = FLASH_RO_FIRST_PAGE_IDX;
wrp_ro.end = FLASH_RO_LAST_PAGE_IDX;
wrp_ro.enable = 1;
}
if (new_flags & EC_FLASH_PROTECT_ALL_AT_BOOT) {
wrp_rw.start = FLASH_RW_FIRST_PAGE_IDX;
wrp_rw.end = FLASH_RW_LAST_PAGE_IDX;
wrp_rw.enable = 1;
} else {
/*
* Start index will be 1st index following RO region index. The
* end index is initialized as 'no protect' value. Only if end
* gets changed based on either rollback or RW protection will
* the 2nd memory protection area get written in option bytes.
*/
int start = FLASH_RW_FIRST_PAGE_IDX;
int end = 0;
#ifdef CONFIG_ROLLBACK
if (new_flags & EC_FLASH_PROTECT_ROLLBACK_AT_BOOT) {
start = FLASH_PAGE_ROLLBACK_FIRST_IDX;
end = FLASH_PAGE_ROLLBACK_LAST_IDX;
} else {
start = FLASH_PAGE_ROLLBACK_LAST_IDX;
}
#endif /* !CONFIG_ROLLBACK */
#ifdef CONFIG_FLASH_PROTECT_RW
if (new_flags & EC_FLASH_PROTECT_RW_AT_BOOT)
end = FLASH_RW_LAST_PAGE_IDX;
#endif /* CONFIG_FLASH_PROTECT_RW */
if (end) {
wrp_rw.start = start;
wrp_rw.end = end;
wrp_rw.enable = 1;
}
}
unlock_optb();
#ifdef CONFIG_FLASH_READOUT_PROTECTION
/*
* Set a permanent protection by increasing RDP to level 1,
* trying to unprotected the flash will trigger a full erase.
*/
STM32_FLASH_OPTR = (STM32_FLASH_OPTR & ~0xff) | 0x11;
#endif
optb_set_wrp(WRP_RO, &wrp_ro);
optb_set_wrp(WRP_RW, &wrp_rw);
commit_optb();
return EC_SUCCESS;
}
/**
* Check if write protect register state is inconsistent with RO_AT_BOOT and
* ALL_AT_BOOT state.
*
* @return zero if consistent, non-zero if inconsistent.
*/
static int registers_need_reset(void)
{
uint32_t flags = crec_flash_get_protect();
int ro_at_boot = (flags & EC_FLASH_PROTECT_RO_AT_BOOT) ? 1 : 0;
/* The RO region is write-protected by the WRP1AR range. */
uint32_t wrp1ar = STM32_OPTB_WRP1AR;
uint32_t ro_range = ro_at_boot ?
FLASH_WRP_RANGE(FLASH_RO_FIRST_PAGE_IDX,
FLASH_RO_LAST_PAGE_IDX) :
FLASH_WRP_RANGE_DISABLED;
return ro_range != (wrp1ar & FLASH_WRP1X_MASK);
}
/*****************************************************************************/
/* Physical layer APIs */
int crec_flash_physical_write(int offset, int size, const char *data)
{
uint32_t *address = (void *)(CONFIG_PROGRAM_MEMORY_BASE + offset);
int res = EC_SUCCESS;
int timeout = calculate_flash_timeout();
int i;
int unaligned = (uint32_t)data & (STM32_FLASH_MIN_WRITE_SIZE - 1);
uint32_t *data32 = (void *)data;
/* Check Flash offset */
if (offset % STM32_FLASH_MIN_WRITE_SIZE)
return EC_ERROR_MEMORY_ALLOCATION;
if (unlock(FLASH_CR_LOCK) != EC_SUCCESS)
return EC_ERROR_UNKNOWN;
/* Clear previous error status */
STM32_FLASH_SR = FLASH_SR_ERR_MASK;
/* set PG bit */
STM32_FLASH_CR |= FLASH_CR_PG;
for (; size > 0; size -= STM32_FLASH_MIN_WRITE_SIZE) {
/*
* Reload the watchdog timer to avoid watchdog reset when doing
* long writing.
*/
watchdog_reload();
/* wait to be ready */
for (i = 0; (STM32_FLASH_SR & FLASH_SR_BUSY) && (i < timeout);
i++)
;
if (STM32_FLASH_SR & FLASH_SR_BUSY) {
res = EC_ERROR_TIMEOUT;
goto exit_wr;
}
/* write the 2 words */
if (unaligned) {
*address++ = (uint32_t)data[0] | (data[1] << 8) |
(data[2] << 16) | (data[3] << 24);
*address++ = (uint32_t)data[4] | (data[5] << 8) |
(data[6] << 16) | (data[7] << 24);
data += STM32_FLASH_MIN_WRITE_SIZE;
} else {
*address++ = *data32++;
*address++ = *data32++;
}
/* Wait for writes to complete */
for (i = 0; (STM32_FLASH_SR & FLASH_SR_BUSY) && (i < timeout);
i++)
;
if (STM32_FLASH_SR & FLASH_SR_BUSY) {
res = EC_ERROR_TIMEOUT;
goto exit_wr;
}
/*
* Check for error conditions - erase failed, voltage error,
* protection error.
*/
if (STM32_FLASH_SR & FLASH_SR_ERR_MASK) {
res = EC_ERROR_UNKNOWN;
goto exit_wr;
}
}
exit_wr:
/* Disable PG bit */
STM32_FLASH_CR &= ~FLASH_CR_PG;
lock();
return res;
}
int crec_flash_physical_erase(int offset, int size)
{
int res = EC_SUCCESS;
int pg;
int last;
if (unlock(FLASH_CR_LOCK) != EC_SUCCESS)
return EC_ERROR_UNKNOWN;
/* Clear previous error status */
STM32_FLASH_SR = FLASH_SR_ERR_MASK;
last = (offset + size) / CONFIG_FLASH_ERASE_SIZE;
for (pg = offset / CONFIG_FLASH_ERASE_SIZE; pg < last; pg++) {
timestamp_t deadline;
/* select page to erase and PER bit */
STM32_FLASH_CR = (STM32_FLASH_CR & ~FLASH_CR_PNB_MASK) |
FLASH_CR_PER | FLASH_CR_PNB(pg);
/* set STRT bit : start erase */
STM32_FLASH_CR |= FLASH_CR_STRT;
/*
* Reload the watchdog timer to avoid watchdog reset during a
* long erase operation.
*/
watchdog_reload();
deadline.val = get_time().val + FLASH_TIMEOUT_US;
/* Wait for erase to complete */
while ((STM32_FLASH_SR & FLASH_SR_BUSY) &&
(get_time().val < deadline.val)) {
crec_usleep(300);
}
if (STM32_FLASH_SR & FLASH_SR_BUSY) {
res = EC_ERROR_TIMEOUT;
goto exit_er;
}
/*
* Check for error conditions - erase failed, voltage error,
* protection error
*/
if (STM32_FLASH_SR & FLASH_SR_ERR_MASK) {
res = EC_ERROR_UNKNOWN;
goto exit_er;
}
}
exit_er:
/* reset PER bit */
STM32_FLASH_CR &= ~(FLASH_CR_PER | FLASH_CR_PNB_MASK);
lock();
return res;
}
int crec_flash_physical_get_protect(int block)
{
struct wrp_info wrp_ro;
struct wrp_info wrp_rw;
optb_get_wrp(WRP_RO, &wrp_ro);
optb_get_wrp(WRP_RW, &wrp_rw);
return ((block >= wrp_ro.start) && (block <= wrp_ro.end)) ||
((block >= wrp_rw.start) && (block <= wrp_rw.end));
}
/*
* Note: This does not need to update _NOW flags, as get_protect_flags
* in common code already does so.
*/
uint32_t crec_flash_physical_get_protect_flags(void)
{
uint32_t flags = 0;
struct wrp_info wrp_ro;
struct wrp_info wrp_rw;
optb_get_wrp(WRP_RO, &wrp_ro);
optb_get_wrp(WRP_RW, &wrp_rw);
/* Check if RO is fully protected */
if (wrp_ro.start == FLASH_RO_FIRST_PAGE_IDX &&
wrp_ro.end == FLASH_RO_LAST_PAGE_IDX)
flags |= EC_FLASH_PROTECT_RO_AT_BOOT;
if (wrp_rw.enable) {
#ifdef CONFIG_ROLLBACK
if (wrp_rw.start <= FLASH_PAGE_ROLLBACK_FIRST_IDX &&
wrp_rw.end >= FLASH_PAGE_ROLLBACK_LAST_IDX)
flags |= EC_FLASH_PROTECT_ROLLBACK_AT_BOOT;
#endif /* CONFIG_ROLLBACK */
#ifdef CONFIG_FLASH_PROTECT_RW
if (wrp_rw.end == PHYSICAL_BANKS)
flags |= EC_FLASH_PROTECT_RW_AT_BOOT;
#endif /* CONFIG_FLASH_PROTECT_RW */
if (wrp_rw.end == PHYSICAL_BANKS &&
wrp_rw.start == WP_BANK_OFFSET + WP_BANK_COUNT &&
flags & EC_FLASH_PROTECT_RO_AT_BOOT)
flags |= EC_FLASH_PROTECT_ALL_AT_BOOT;
}
return flags;
}
int crec_flash_physical_protect_now(bool all)
{
return EC_ERROR_INVAL;
}
uint32_t crec_flash_physical_get_valid_flags(void)
{
return EC_FLASH_PROTECT_RO_AT_BOOT | EC_FLASH_PROTECT_RO_NOW |
#ifdef CONFIG_FLASH_PROTECT_RW
EC_FLASH_PROTECT_RW_AT_BOOT | EC_FLASH_PROTECT_RW_NOW |
#endif
#ifdef CONFIG_ROLLBACK
EC_FLASH_PROTECT_ROLLBACK_AT_BOOT |
EC_FLASH_PROTECT_ROLLBACK_NOW |
#endif
EC_FLASH_PROTECT_ALL_AT_BOOT | EC_FLASH_PROTECT_ALL_NOW;
}
uint32_t crec_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;
/*
* ALL/RW at-boot state can be set if WP GPIO is asserted and can always
* be cleared.
*/
if (cur_flags &
(EC_FLASH_PROTECT_ALL_AT_BOOT | EC_FLASH_PROTECT_GPIO_ASSERTED))
ret |= EC_FLASH_PROTECT_ALL_AT_BOOT;
#ifdef CONFIG_FLASH_PROTECT_RW
if (cur_flags &
(EC_FLASH_PROTECT_RW_AT_BOOT | EC_FLASH_PROTECT_GPIO_ASSERTED))
ret |= EC_FLASH_PROTECT_RW_AT_BOOT;
#endif
#ifdef CONFIG_ROLLBACK
if (cur_flags & (EC_FLASH_PROTECT_ROLLBACK_AT_BOOT |
EC_FLASH_PROTECT_GPIO_ASSERTED))
ret |= EC_FLASH_PROTECT_ROLLBACK_AT_BOOT;
#endif
return ret;
}
int crec_flash_physical_force_reload(void)
{
int rv = unlock(FLASH_CR_OPTLOCK);
if (rv)
return rv;
/* Force a reboot; this should never return. */
STM32_FLASH_CR = FLASH_CR_OBL_LAUNCH;
while (1)
;
return EC_ERROR_UNKNOWN;
}
int crec_flash_pre_init(void)
{
uint32_t reset_flags = system_get_reset_flags();
uint32_t prot_flags = crec_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.
*/
crec_flash_physical_protect_at_boot(
EC_FLASH_PROTECT_RO_AT_BOOT);
need_reset = 1;
}
if (registers_need_reset()) {
/*
* Write protect register was in an inconsistent state.
* Set it back to a good state and reboot.
*
* TODO(crosbug.com/p/23798): this seems really similar
* to the check above. One of them should be able to
* go away.
*/
crec_flash_protect_at_boot(prot_flags &
EC_FLASH_PROTECT_RO_AT_BOOT);
need_reset = 1;
}
} else {
if (prot_flags & EC_FLASH_PROTECT_RO_NOW) {
/*
* Write protect pin unasserted but some section is
* protected. Drop it and reboot.
*/
unprotect_all_blocks();
need_reset = 1;
}
}
if ((crec_flash_physical_get_valid_flags() &
EC_FLASH_PROTECT_ALL_AT_BOOT) &&
(!!(prot_flags & EC_FLASH_PROTECT_ALL_AT_BOOT) !=
!!(prot_flags & EC_FLASH_PROTECT_ALL_NOW))) {
/*
* ALL_AT_BOOT and ALL_NOW should be both set or both unset
* at boot. If they are not, it must be that the chip requires
* OBL_LAUNCH to be set to reload option bytes. Let's reset
* the system with OBL_LAUNCH set.
* This assumes OBL_LAUNCH is used for hard reset in
* chip/stm32/system.c.
*/
need_reset = 1;
}
#ifdef CONFIG_FLASH_PROTECT_RW
if ((crec_flash_physical_get_valid_flags() &
EC_FLASH_PROTECT_RW_AT_BOOT) &&
(!!(prot_flags & EC_FLASH_PROTECT_RW_AT_BOOT) !=
!!(prot_flags & EC_FLASH_PROTECT_RW_NOW))) {
/* RW_AT_BOOT and RW_NOW do not match. */
need_reset = 1;
}
#endif
#ifdef CONFIG_ROLLBACK
if ((crec_flash_physical_get_valid_flags() &
EC_FLASH_PROTECT_ROLLBACK_AT_BOOT) &&
(!!(prot_flags & EC_FLASH_PROTECT_ROLLBACK_AT_BOOT) !=
!!(prot_flags & EC_FLASH_PROTECT_ROLLBACK_NOW))) {
/* ROLLBACK_AT_BOOT and ROLLBACK_NOW do not match. */
need_reset = 1;
}
#endif
if (need_reset)
system_reset(SYSTEM_RESET_HARD | SYSTEM_RESET_PRESERVE_FLAGS);
return EC_SUCCESS;
}