diff options
Diffstat (limited to 'chip/stm32/flash-stm32g4-l4.c')
-rw-r--r-- | chip/stm32/flash-stm32g4-l4.c | 792 |
1 files changed, 0 insertions, 792 deletions
diff --git a/chip/stm32/flash-stm32g4-l4.c b/chip/stm32/flash-stm32g4-l4.c deleted file mode 100644 index f792da6e3c..0000000000 --- a/chip/stm32/flash-stm32g4-l4.c +++ /dev/null @@ -1,792 +0,0 @@ -/* Copyright 2017 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 STM32L4 family */ - -#include "common.h" -#include "clock.h" -#include "flash.h" -#include "hooks.h" -#include "registers.h" -#include "panic.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)) { - 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(int 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; -} |